From d408b585edc3b60fd7917d1373ac5736f8dd7640 Mon Sep 17 00:00:00 2001 From: dgandhi62 Date: Wed, 19 Aug 2026 16:49:24 -0400 Subject: [PATCH 1/4] feat(cli-integ): run the integ suites on Windows, nightly and on label Adds Windows instances of the five integ suites and decides when they run. Windows is slow and flaky-prone, so it does not gate every PR: - nightly at 06:00 UTC, where it runs unattended and reports a failure by filing (or commenting on) a tracking issue - on a PR that opts in with the 'pr/test-windows' label - on a manual workflow_dispatch, which is the only one of the three reachable from a branch Linux is excluded from the nightly, since it already runs on every PR. Supporting workflow changes: a Dev Drive for TEMP and the npm cache, since the suites are dominated by small-file writes; bash as the default shell so the shared step scripts run unchanged under Git Bash; a Windows skip list for tests that need Linux Docker images; approval bypass and checkout fallbacks for events that carry no pull request. Requires the 'pr/test-windows' and 'windows-integ-nightly' labels to exist in the repository. --- .github/workflows/integ.yml | 989 ++++++++++++++++++++++++++++++-- .projenrc.ts | 4 + projenrc/cdk-cli-integ-tests.ts | 354 +++++++++++- 3 files changed, 1290 insertions(+), 57 deletions(-) diff --git a/.github/workflows/integ.yml b/.github/workflows/integ.yml index e6a059ff5..c9d838317 100644 --- a/.github/workflows/integ.yml +++ b/.github/workflows/integ.yml @@ -4,8 +4,16 @@ name: integ on: pull_request_target: branches: [] + types: + - opened + - synchronize + - reopened + - labeled + - unlabeled merge_group: {} workflow_dispatch: {} + schedule: + - cron: 0 6 * * * jobs: determine_env: runs-on: ubuntu-latest @@ -17,9 +25,9 @@ jobs: - name: Start requiring approval id: start_requiring_approval run: echo integ-approval > .envname - - name: Skip approval for mergeGroup or PR created from this repo - id: skip_approval_for_mergegroup_or_pr_created_from_this_repo - if: ${{ github.event_name == 'merge_group' || github.event.pull_request.head.repo.full_name == github.repository }} + - name: Skip approval for mergeGroup, schedule, or PR created from this repo + id: skip_approval_for_mergegroup_schedule_or_pr_created_from_this_repo + if: ${{ github.event_name == 'merge_group' || github.event_name == 'schedule' || github.event.pull_request.head.repo.full_name == github.repository }} run: echo no-approval > .envname - name: Output the value id: output @@ -44,8 +52,8 @@ jobs: id: checkout uses: actions/checkout@v7 with: - ref: ${{ github.event.pull_request.head.sha }} - repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.sha || github.sha }} + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} allow-unsafe-pr-checkout: true - name: Fetch tags from origin repo id: fetch_tags_from_origin_repo @@ -74,24 +82,672 @@ jobs: env: RELEASE: "true" run: yarn projen build + - name: Bundle Verdaccio for the test jobs + id: bundle_verdaccio_for_the_test_jobs + run: |- + mkdir -p /tmp/verdaccio-bundle + (cd /tmp/verdaccio-bundle && npm install --no-bin-links --no-audit --no-fund --loglevel=error verdaccio@6.8) + tar czf .projen/verdaccio-bundle.tgz -C /tmp/verdaccio-bundle node_modules - name: Upload artifact id: build-artifact uses: actions/upload-artifact@v7 with: - name: build-artifact - path: packages/**/dist/js/*.tgz + name: build-artifact + path: packages/**/dist/js/*.tgz + overwrite: true + - name: Upload artifact + id: script-artifact + uses: actions/upload-artifact@v7 + with: + name: script-artifact + path: |- + .projen/*.sh + .projen/verdaccio-bundle.tgz + overwrite: true + include-hidden-files: true + integ_cli: + needs: prepare + runs-on: aws-cdk_ubuntu-latest_16-core + permissions: + contents: read + id-token: write + environment: run-tests + env: + NODE_NO_WARNINGS: "1" + MAVEN_ARGS: --no-transfer-progress + IS_CANARY: "true" + CI: "true" + defaults: + run: + shell: bash + if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && github.event_name != 'schedule' + steps: + - name: Download artifact + id: download_artifact + uses: actions/download-artifact@v8 + with: + artifact-ids: ${{needs.prepare.outputs.packagesArtifact}} + path: packages + - name: Download artifact + id: download_artifact_2 + uses: actions/download-artifact@v8 + with: + artifact-ids: ${{needs.prepare.outputs.scriptsArtifact}} + path: .projen + - name: Setup Node.js + id: setup_node_js + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node }} + package-manager-cache: false + - name: Set up JDK 18 + id: set_up_jdk_18 + if: matrix.suite == 'init-java' || matrix.suite == 'cli-integ-tests' + uses: actions/setup-java@v5 + with: + java-version: "18" + distribution: corretto + - name: Set git identity + id: set_git_identity + run: |- + git config --global user.name "aws-cdk-cli-integ" + git config --global user.email "noreply@example.com" + - name: Prepare Verdaccio + id: prepare_verdaccio + run: chmod +x .projen/prepare-verdaccio.sh && .projen/prepare-verdaccio.sh + - name: Download and install the test artifact + id: download_and_install_the_test_artifact + run: npm install @aws-cdk-testing/cli-integ + - name: Determine latest package versions + id: versions + run: |- + CLI_VERSION=$(cd ${TMPDIR:-/tmp} && npm view aws-cdk version) + echo "CLI version: ${CLI_VERSION}" + echo "cli_version=${CLI_VERSION}" >> $GITHUB_OUTPUT + LIB_VERSION=$(cd ${TMPDIR:-/tmp} && npm view aws-cdk-lib version) + echo "lib version: ${LIB_VERSION}" + echo "lib_version=${LIB_VERSION}" >> $GITHUB_OUTPUT + - name: Authenticate Via OIDC Role + id: creds + uses: aws-actions/configure-aws-credentials@v6 + with: + aws-region: us-east-1 + role-duration-seconds: 3600 + role-to-assume: ${{ vars.CDK_ATMOSPHERE_PROD_OIDC_ROLE }} + role-session-name: run-tests@aws-cdk-cli-integ + output-credentials: true + - name: "Run the test suite: ${{ matrix.suite }}" + id: run_the_test_suite_matrix_suite + env: + JSII_SILENCE_WARNING_DEPRECATED_NODE_VERSION: "true" + JSII_SILENCE_WARNING_UNTESTED_NODE_VERSION: "true" + JSII_SILENCE_WARNING_KNOWN_BROKEN_NODE_VERSION: "true" + DOCKERHUB_DISABLED: "true" + CDK_INTEG_ATMOSPHERE_ENABLED: "true" + CDK_INTEG_ATMOSPHERE_ENDPOINT: ${{ vars.CDK_ATMOSPHERE_PROD_ENDPOINT }} + CDK_INTEG_ATMOSPHERE_POOL: ${{ vars.CDK_INTEG_ATMOSPHERE_POOL }} + CDK_MAJOR_VERSION: "2" + RELEASE_TAG: latest + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + INTEG_LOGS: logs + run: npx run-suite --shard="${{ matrix.shard }}/12" --use-cli-release=${{ steps.versions.outputs.cli_version }} --framework-version=${{ steps.versions.outputs.lib_version }} ${{ matrix.suite }} + - name: Set workflow summary + id: set_workflow_summary + if: always() + run: |- + if compgen -G "logs/md/*.md" > /dev/null; then + cat logs/md/*.md >> $GITHUB_STEP_SUMMARY; + fi + - name: Slugify artifact id + id: artifactid + if: always() + env: + INPUT: logs-${{ matrix.suite }}-${{ matrix.node }}-${{ matrix.shard }} + run: |- + slug=$(node -p 'process.env.INPUT.replace(/[^a-z0-9._-]/gi, "-")') + echo "slug=$slug" >> "$GITHUB_OUTPUT" + - name: Upload logs + id: logupload + if: always() + uses: actions/upload-artifact@v7 + with: + name: ${{ steps.artifactid.outputs.slug }} + path: logs/ + overwrite: true + - name: Append artifact URL + id: append_artifact_url + if: always() + run: |- + echo "" >> $GITHUB_STEP_SUMMARY + echo "[Logs](${{ steps.logupload.outputs.artifact-url }})" >> $GITHUB_STEP_SUMMARY + strategy: + fail-fast: false + matrix: + suite: + - cli-integ-tests + node: + - lts/* + shard: + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + integ_toolkit-lib: + needs: prepare + runs-on: aws-cdk_ubuntu-latest_16-core + permissions: + contents: read + id-token: write + environment: run-tests + env: + NODE_NO_WARNINGS: "1" + MAVEN_ARGS: --no-transfer-progress + IS_CANARY: "true" + CI: "true" + defaults: + run: + shell: bash + if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && github.event_name != 'schedule' + steps: + - name: Download artifact + id: download_artifact + uses: actions/download-artifact@v8 + with: + artifact-ids: ${{needs.prepare.outputs.packagesArtifact}} + path: packages + - name: Download artifact + id: download_artifact_2 + uses: actions/download-artifact@v8 + with: + artifact-ids: ${{needs.prepare.outputs.scriptsArtifact}} + path: .projen + - name: Setup Node.js + id: setup_node_js + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node }} + package-manager-cache: false + - name: Set up JDK 18 + id: set_up_jdk_18 + if: matrix.suite == 'init-java' || matrix.suite == 'cli-integ-tests' + uses: actions/setup-java@v5 + with: + java-version: "18" + distribution: corretto + - name: Set git identity + id: set_git_identity + run: |- + git config --global user.name "aws-cdk-cli-integ" + git config --global user.email "noreply@example.com" + - name: Prepare Verdaccio + id: prepare_verdaccio + run: chmod +x .projen/prepare-verdaccio.sh && .projen/prepare-verdaccio.sh + - name: Download and install the test artifact + id: download_and_install_the_test_artifact + run: npm install @aws-cdk-testing/cli-integ + - name: Determine latest package versions + id: versions + run: |- + CLI_VERSION=$(cd ${TMPDIR:-/tmp} && npm view aws-cdk version) + echo "CLI version: ${CLI_VERSION}" + echo "cli_version=${CLI_VERSION}" >> $GITHUB_OUTPUT + LIB_VERSION=$(cd ${TMPDIR:-/tmp} && npm view aws-cdk-lib version) + echo "lib version: ${LIB_VERSION}" + echo "lib_version=${LIB_VERSION}" >> $GITHUB_OUTPUT + - name: Authenticate Via OIDC Role + id: creds + uses: aws-actions/configure-aws-credentials@v6 + with: + aws-region: us-east-1 + role-duration-seconds: 3600 + role-to-assume: ${{ vars.CDK_ATMOSPHERE_PROD_OIDC_ROLE }} + role-session-name: run-tests@aws-cdk-cli-integ + output-credentials: true + - name: "Run the test suite: ${{ matrix.suite }}" + id: run_the_test_suite_matrix_suite + env: + JSII_SILENCE_WARNING_DEPRECATED_NODE_VERSION: "true" + JSII_SILENCE_WARNING_UNTESTED_NODE_VERSION: "true" + JSII_SILENCE_WARNING_KNOWN_BROKEN_NODE_VERSION: "true" + DOCKERHUB_DISABLED: "true" + CDK_INTEG_ATMOSPHERE_ENABLED: "true" + CDK_INTEG_ATMOSPHERE_ENDPOINT: ${{ vars.CDK_ATMOSPHERE_PROD_ENDPOINT }} + CDK_INTEG_ATMOSPHERE_POOL: ${{ vars.CDK_INTEG_ATMOSPHERE_POOL }} + CDK_MAJOR_VERSION: "2" + RELEASE_TAG: latest + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + INTEG_LOGS: logs + run: npx run-suite --use-cli-release=${{ steps.versions.outputs.cli_version }} --framework-version=${{ steps.versions.outputs.lib_version }} ${{ matrix.suite }} + - name: Set workflow summary + id: set_workflow_summary + if: always() + run: |- + if compgen -G "logs/md/*.md" > /dev/null; then + cat logs/md/*.md >> $GITHUB_STEP_SUMMARY; + fi + - name: Slugify artifact id + id: artifactid + if: always() + env: + INPUT: logs-${{ matrix.suite }}-${{ matrix.node }} + run: |- + slug=$(node -p 'process.env.INPUT.replace(/[^a-z0-9._-]/gi, "-")') + echo "slug=$slug" >> "$GITHUB_OUTPUT" + - name: Upload logs + id: logupload + if: always() + uses: actions/upload-artifact@v7 + with: + name: ${{ steps.artifactid.outputs.slug }} + path: logs/ + overwrite: true + - name: Append artifact URL + id: append_artifact_url + if: always() + run: |- + echo "" >> $GITHUB_STEP_SUMMARY + echo "[Logs](${{ steps.logupload.outputs.artifact-url }})" >> $GITHUB_STEP_SUMMARY + strategy: + fail-fast: false + matrix: + suite: + - toolkit-lib-integ-tests + node: + - lts/* + - "20" + - "22" + - "24" + integ_telemetry: + needs: prepare + runs-on: aws-cdk_ubuntu-latest_16-core + permissions: + contents: read + id-token: write + environment: run-tests + env: + NODE_NO_WARNINGS: "1" + MAVEN_ARGS: --no-transfer-progress + IS_CANARY: "true" + CI: "true" + defaults: + run: + shell: bash + if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && github.event_name != 'schedule' + steps: + - name: Download artifact + id: download_artifact + uses: actions/download-artifact@v8 + with: + artifact-ids: ${{needs.prepare.outputs.packagesArtifact}} + path: packages + - name: Download artifact + id: download_artifact_2 + uses: actions/download-artifact@v8 + with: + artifact-ids: ${{needs.prepare.outputs.scriptsArtifact}} + path: .projen + - name: Setup Node.js + id: setup_node_js + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node }} + package-manager-cache: false + - name: Set up JDK 18 + id: set_up_jdk_18 + if: matrix.suite == 'init-java' || matrix.suite == 'cli-integ-tests' + uses: actions/setup-java@v5 + with: + java-version: "18" + distribution: corretto + - name: Set git identity + id: set_git_identity + run: |- + git config --global user.name "aws-cdk-cli-integ" + git config --global user.email "noreply@example.com" + - name: Prepare Verdaccio + id: prepare_verdaccio + run: chmod +x .projen/prepare-verdaccio.sh && .projen/prepare-verdaccio.sh + - name: Download and install the test artifact + id: download_and_install_the_test_artifact + run: npm install @aws-cdk-testing/cli-integ + - name: Determine latest package versions + id: versions + run: |- + CLI_VERSION=$(cd ${TMPDIR:-/tmp} && npm view aws-cdk version) + echo "CLI version: ${CLI_VERSION}" + echo "cli_version=${CLI_VERSION}" >> $GITHUB_OUTPUT + LIB_VERSION=$(cd ${TMPDIR:-/tmp} && npm view aws-cdk-lib version) + echo "lib version: ${LIB_VERSION}" + echo "lib_version=${LIB_VERSION}" >> $GITHUB_OUTPUT + - name: Authenticate Via OIDC Role + id: creds + uses: aws-actions/configure-aws-credentials@v6 + with: + aws-region: us-east-1 + role-duration-seconds: 3600 + role-to-assume: ${{ vars.CDK_ATMOSPHERE_PROD_OIDC_ROLE }} + role-session-name: run-tests@aws-cdk-cli-integ + output-credentials: true + - name: "Run the test suite: ${{ matrix.suite }}" + id: run_the_test_suite_matrix_suite + env: + JSII_SILENCE_WARNING_DEPRECATED_NODE_VERSION: "true" + JSII_SILENCE_WARNING_UNTESTED_NODE_VERSION: "true" + JSII_SILENCE_WARNING_KNOWN_BROKEN_NODE_VERSION: "true" + DOCKERHUB_DISABLED: "true" + CDK_INTEG_ATMOSPHERE_ENABLED: "true" + CDK_INTEG_ATMOSPHERE_ENDPOINT: ${{ vars.CDK_ATMOSPHERE_PROD_ENDPOINT }} + CDK_INTEG_ATMOSPHERE_POOL: ${{ vars.CDK_INTEG_ATMOSPHERE_POOL }} + CDK_MAJOR_VERSION: "2" + RELEASE_TAG: latest + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + INTEG_LOGS: logs + run: npx run-suite --use-cli-release=${{ steps.versions.outputs.cli_version }} --framework-version=${{ steps.versions.outputs.lib_version }} ${{ matrix.suite }} + - name: Set workflow summary + id: set_workflow_summary + if: always() + run: |- + if compgen -G "logs/md/*.md" > /dev/null; then + cat logs/md/*.md >> $GITHUB_STEP_SUMMARY; + fi + - name: Slugify artifact id + id: artifactid + if: always() + env: + INPUT: logs-${{ matrix.suite }}-${{ matrix.node }} + run: |- + slug=$(node -p 'process.env.INPUT.replace(/[^a-z0-9._-]/gi, "-")') + echo "slug=$slug" >> "$GITHUB_OUTPUT" + - name: Upload logs + id: logupload + if: always() + uses: actions/upload-artifact@v7 + with: + name: ${{ steps.artifactid.outputs.slug }} + path: logs/ + overwrite: true + - name: Append artifact URL + id: append_artifact_url + if: always() + run: |- + echo "" >> $GITHUB_STEP_SUMMARY + echo "[Logs](${{ steps.logupload.outputs.artifact-url }})" >> $GITHUB_STEP_SUMMARY + strategy: + fail-fast: false + matrix: + suite: + - telemetry-integ-tests + node: + - lts/* + integ_init-templates: + needs: prepare + runs-on: aws-cdk_ubuntu-latest_16-core + permissions: + contents: read + id-token: write + environment: run-tests + env: + NODE_NO_WARNINGS: "1" + MAVEN_ARGS: --no-transfer-progress + IS_CANARY: "true" + CI: "true" + defaults: + run: + shell: bash + if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && github.event_name != 'schedule' + steps: + - name: Download artifact + id: download_artifact + uses: actions/download-artifact@v8 + with: + artifact-ids: ${{needs.prepare.outputs.packagesArtifact}} + path: packages + - name: Download artifact + id: download_artifact_2 + uses: actions/download-artifact@v8 + with: + artifact-ids: ${{needs.prepare.outputs.scriptsArtifact}} + path: .projen + - name: Setup Node.js + id: setup_node_js + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node }} + package-manager-cache: false + - name: Set up JDK 18 + id: set_up_jdk_18 + if: matrix.suite == 'init-java' || matrix.suite == 'cli-integ-tests' + uses: actions/setup-java@v5 + with: + java-version: "18" + distribution: corretto + - name: Set git identity + id: set_git_identity + run: |- + git config --global user.name "aws-cdk-cli-integ" + git config --global user.email "noreply@example.com" + - name: Prepare Verdaccio + id: prepare_verdaccio + run: chmod +x .projen/prepare-verdaccio.sh && .projen/prepare-verdaccio.sh + - name: Download and install the test artifact + id: download_and_install_the_test_artifact + run: npm install @aws-cdk-testing/cli-integ + - name: Determine latest package versions + id: versions + run: |- + CLI_VERSION=$(cd ${TMPDIR:-/tmp} && npm view aws-cdk version) + echo "CLI version: ${CLI_VERSION}" + echo "cli_version=${CLI_VERSION}" >> $GITHUB_OUTPUT + LIB_VERSION=$(cd ${TMPDIR:-/tmp} && npm view aws-cdk-lib version) + echo "lib version: ${LIB_VERSION}" + echo "lib_version=${LIB_VERSION}" >> $GITHUB_OUTPUT + - name: Authenticate Via OIDC Role + id: creds + uses: aws-actions/configure-aws-credentials@v6 + with: + aws-region: us-east-1 + role-duration-seconds: 3600 + role-to-assume: ${{ vars.CDK_ATMOSPHERE_PROD_OIDC_ROLE }} + role-session-name: run-tests@aws-cdk-cli-integ + output-credentials: true + - name: "Run the test suite: ${{ matrix.suite }}" + id: run_the_test_suite_matrix_suite + env: + JSII_SILENCE_WARNING_DEPRECATED_NODE_VERSION: "true" + JSII_SILENCE_WARNING_UNTESTED_NODE_VERSION: "true" + JSII_SILENCE_WARNING_KNOWN_BROKEN_NODE_VERSION: "true" + DOCKERHUB_DISABLED: "true" + CDK_INTEG_ATMOSPHERE_ENABLED: "true" + CDK_INTEG_ATMOSPHERE_ENDPOINT: ${{ vars.CDK_ATMOSPHERE_PROD_ENDPOINT }} + CDK_INTEG_ATMOSPHERE_POOL: ${{ vars.CDK_INTEG_ATMOSPHERE_POOL }} + CDK_MAJOR_VERSION: "2" + RELEASE_TAG: latest + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + INTEG_LOGS: logs + run: npx run-suite --use-cli-release=${{ steps.versions.outputs.cli_version }} --framework-version=${{ steps.versions.outputs.lib_version }} ${{ matrix.suite }} + - name: Set workflow summary + id: set_workflow_summary + if: always() + run: |- + if compgen -G "logs/md/*.md" > /dev/null; then + cat logs/md/*.md >> $GITHUB_STEP_SUMMARY; + fi + - name: Slugify artifact id + id: artifactid + if: always() + env: + INPUT: logs-${{ matrix.suite }}-${{ matrix.node }} + run: |- + slug=$(node -p 'process.env.INPUT.replace(/[^a-z0-9._-]/gi, "-")') + echo "slug=$slug" >> "$GITHUB_OUTPUT" + - name: Upload logs + id: logupload + if: always() + uses: actions/upload-artifact@v7 + with: + name: ${{ steps.artifactid.outputs.slug }} + path: logs/ overwrite: true - - name: Upload artifact - id: script-artifact + - name: Append artifact URL + id: append_artifact_url + if: always() + run: |- + echo "" >> $GITHUB_STEP_SUMMARY + echo "[Logs](${{ steps.logupload.outputs.artifact-url }})" >> $GITHUB_STEP_SUMMARY + strategy: + fail-fast: false + matrix: + include: + - suite: init-typescript-app + node: "20" + - suite: init-typescript-app + node: "22" + - suite: init-typescript-app + node: "24" + suite: + - init-csharp + - init-fsharp + - init-go + - init-java + - init-javascript + - init-python + - init-typescript-app + - init-typescript-lib + node: + - lts/* + integ_tool-integrations: + needs: prepare + runs-on: aws-cdk_ubuntu-latest_16-core + permissions: + contents: read + id-token: write + environment: run-tests + env: + NODE_NO_WARNINGS: "1" + MAVEN_ARGS: --no-transfer-progress + IS_CANARY: "true" + CI: "true" + defaults: + run: + shell: bash + if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && github.event_name != 'schedule' + steps: + - name: Download artifact + id: download_artifact + uses: actions/download-artifact@v8 + with: + artifact-ids: ${{needs.prepare.outputs.packagesArtifact}} + path: packages + - name: Download artifact + id: download_artifact_2 + uses: actions/download-artifact@v8 + with: + artifact-ids: ${{needs.prepare.outputs.scriptsArtifact}} + path: .projen + - name: Setup Node.js + id: setup_node_js + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node }} + package-manager-cache: false + - name: Set up JDK 18 + id: set_up_jdk_18 + if: matrix.suite == 'init-java' || matrix.suite == 'cli-integ-tests' + uses: actions/setup-java@v5 + with: + java-version: "18" + distribution: corretto + - name: Set git identity + id: set_git_identity + run: |- + git config --global user.name "aws-cdk-cli-integ" + git config --global user.email "noreply@example.com" + - name: Prepare Verdaccio + id: prepare_verdaccio + run: chmod +x .projen/prepare-verdaccio.sh && .projen/prepare-verdaccio.sh + - name: Download and install the test artifact + id: download_and_install_the_test_artifact + run: npm install @aws-cdk-testing/cli-integ + - name: Determine latest package versions + id: versions + run: |- + CLI_VERSION=$(cd ${TMPDIR:-/tmp} && npm view aws-cdk version) + echo "CLI version: ${CLI_VERSION}" + echo "cli_version=${CLI_VERSION}" >> $GITHUB_OUTPUT + LIB_VERSION=$(cd ${TMPDIR:-/tmp} && npm view aws-cdk-lib version) + echo "lib version: ${LIB_VERSION}" + echo "lib_version=${LIB_VERSION}" >> $GITHUB_OUTPUT + - name: Authenticate Via OIDC Role + id: creds + uses: aws-actions/configure-aws-credentials@v6 + with: + aws-region: us-east-1 + role-duration-seconds: 3600 + role-to-assume: ${{ vars.CDK_ATMOSPHERE_PROD_OIDC_ROLE }} + role-session-name: run-tests@aws-cdk-cli-integ + output-credentials: true + - name: "Run the test suite: ${{ matrix.suite }}" + id: run_the_test_suite_matrix_suite + env: + JSII_SILENCE_WARNING_DEPRECATED_NODE_VERSION: "true" + JSII_SILENCE_WARNING_UNTESTED_NODE_VERSION: "true" + JSII_SILENCE_WARNING_KNOWN_BROKEN_NODE_VERSION: "true" + DOCKERHUB_DISABLED: "true" + CDK_INTEG_ATMOSPHERE_ENABLED: "true" + CDK_INTEG_ATMOSPHERE_ENDPOINT: ${{ vars.CDK_ATMOSPHERE_PROD_ENDPOINT }} + CDK_INTEG_ATMOSPHERE_POOL: ${{ vars.CDK_INTEG_ATMOSPHERE_POOL }} + CDK_MAJOR_VERSION: "2" + RELEASE_TAG: latest + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + INTEG_LOGS: logs + run: npx run-suite --use-cli-release=${{ steps.versions.outputs.cli_version }} --framework-version=${{ steps.versions.outputs.lib_version }} ${{ matrix.suite }} + - name: Set workflow summary + id: set_workflow_summary + if: always() + run: |- + if compgen -G "logs/md/*.md" > /dev/null; then + cat logs/md/*.md >> $GITHUB_STEP_SUMMARY; + fi + - name: Slugify artifact id + id: artifactid + if: always() + env: + INPUT: logs-${{ matrix.suite }}-${{ matrix.node }} + run: |- + slug=$(node -p 'process.env.INPUT.replace(/[^a-z0-9._-]/gi, "-")') + echo "slug=$slug" >> "$GITHUB_OUTPUT" + - name: Upload logs + id: logupload + if: always() uses: actions/upload-artifact@v7 with: - name: script-artifact - path: .projen/*.sh + name: ${{ steps.artifactid.outputs.slug }} + path: logs/ overwrite: true - include-hidden-files: true - integ_cli: + - name: Append artifact URL + id: append_artifact_url + if: always() + run: |- + echo "" >> $GITHUB_STEP_SUMMARY + echo "[Logs](${{ steps.logupload.outputs.artifact-url }})" >> $GITHUB_STEP_SUMMARY + strategy: + fail-fast: false + matrix: + suite: + - tool-integrations + node: + - "20" + integ_cli_windows: needs: prepare - runs-on: aws-cdk_ubuntu-latest_16-core + runs-on: windows-latest permissions: contents: read id-token: write @@ -101,8 +757,48 @@ jobs: MAVEN_ARGS: --no-transfer-progress IS_CANARY: "true" CI: "true" - if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') + CDK_INTEG_SKIP_TESTS_FILE: ${{ github.workspace }}\windows-skip-tests.txt + defaults: + run: + shell: bash + if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'pr/test-windows')) steps: + - name: Set up Dev Drive for TEMP and npm cache + id: set_up_dev_drive_for_temp_and_npm_cache + run: |- + $vhd = "C:\devdrive.vhdx" + $drive = (New-VHD -Path $vhd -SizeBytes 40GB -Dynamic | Mount-VHD -PassThru | Initialize-Disk -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -DevDrive -Confirm:$false).DriveLetter + New-Item -ItemType Directory -Path "${drive}:\temp" | Out-Null + New-Item -ItemType Directory -Path "${drive}:\npm-cache" | Out-Null + echo "TEMP=${drive}:\temp" >> $env:GITHUB_ENV + echo "TMP=${drive}:\temp" >> $env:GITHUB_ENV + echo "npm_config_cache=${drive}:\npm-cache" >> $env:GITHUB_ENV + shell: powershell + - name: Write Windows skip-tests file + id: write_windows_skip-tests_file + run: |- + cat > windows-skip-tests.txt << 'EOF' + deploy same docker asset to multiple regions + deploy same docker asset to multiple stacks + deploy stack with multiple docker assets + deploy stack with docker asset + cdk-assets smoke test + deploy new style synthesis to new style bootstrap (with docker image) + Garbage Collection untags in-use ecr images + Garbage Collection keeps in use ecr images + Garbage Collection deletes unused ecr images + Garbage Collection tags unused ecr images + all calls from isolated container go through proxy + docker-credential-cdk-assets can assume role and fetch ECR credentials + toolkit deploy stack with multiple docker assets + CDK synth bundled functions as expected + CDK synth add the metadata properties expected by sam + can deploy with session tags on the deploy, lookup, file asset, and image asset publishing roles + generating and loading assembly + test resource import with construct that requires bundling + hotswap deployment supports Bedrock AgentCore Runtime + sam can locally test the synthesized cdk application + EOF - name: Download artifact id: download_artifact uses: actions/download-artifact@v8 @@ -183,7 +879,7 @@ jobs: id: artifactid if: always() env: - INPUT: logs-${{ matrix.suite }}-${{ matrix.node }}-${{ matrix.shard }} + INPUT: logs_windows-${{ matrix.suite }}-${{ matrix.node }}-${{ matrix.shard }} run: |- slug=$(node -p 'process.env.INPUT.replace(/[^a-z0-9._-]/gi, "-")') echo "slug=$slug" >> "$GITHUB_OUTPUT" @@ -201,6 +897,7 @@ jobs: run: |- echo "" >> $GITHUB_STEP_SUMMARY echo "[Logs](${{ steps.logupload.outputs.artifact-url }})" >> $GITHUB_STEP_SUMMARY + timeout-minutes: 90 strategy: fail-fast: false matrix: @@ -221,9 +918,9 @@ jobs: - 10 - 11 - 12 - integ_toolkit-lib: + integ_toolkit-lib_windows: needs: prepare - runs-on: aws-cdk_ubuntu-latest_16-core + runs-on: windows-latest permissions: contents: read id-token: write @@ -233,8 +930,48 @@ jobs: MAVEN_ARGS: --no-transfer-progress IS_CANARY: "true" CI: "true" - if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') + CDK_INTEG_SKIP_TESTS_FILE: ${{ github.workspace }}\windows-skip-tests.txt + defaults: + run: + shell: bash + if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'pr/test-windows')) steps: + - name: Set up Dev Drive for TEMP and npm cache + id: set_up_dev_drive_for_temp_and_npm_cache + run: |- + $vhd = "C:\devdrive.vhdx" + $drive = (New-VHD -Path $vhd -SizeBytes 40GB -Dynamic | Mount-VHD -PassThru | Initialize-Disk -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -DevDrive -Confirm:$false).DriveLetter + New-Item -ItemType Directory -Path "${drive}:\temp" | Out-Null + New-Item -ItemType Directory -Path "${drive}:\npm-cache" | Out-Null + echo "TEMP=${drive}:\temp" >> $env:GITHUB_ENV + echo "TMP=${drive}:\temp" >> $env:GITHUB_ENV + echo "npm_config_cache=${drive}:\npm-cache" >> $env:GITHUB_ENV + shell: powershell + - name: Write Windows skip-tests file + id: write_windows_skip-tests_file + run: |- + cat > windows-skip-tests.txt << 'EOF' + deploy same docker asset to multiple regions + deploy same docker asset to multiple stacks + deploy stack with multiple docker assets + deploy stack with docker asset + cdk-assets smoke test + deploy new style synthesis to new style bootstrap (with docker image) + Garbage Collection untags in-use ecr images + Garbage Collection keeps in use ecr images + Garbage Collection deletes unused ecr images + Garbage Collection tags unused ecr images + all calls from isolated container go through proxy + docker-credential-cdk-assets can assume role and fetch ECR credentials + toolkit deploy stack with multiple docker assets + CDK synth bundled functions as expected + CDK synth add the metadata properties expected by sam + can deploy with session tags on the deploy, lookup, file asset, and image asset publishing roles + generating and loading assembly + test resource import with construct that requires bundling + hotswap deployment supports Bedrock AgentCore Runtime + sam can locally test the synthesized cdk application + EOF - name: Download artifact id: download_artifact uses: actions/download-artifact@v8 @@ -315,7 +1052,7 @@ jobs: id: artifactid if: always() env: - INPUT: logs-${{ matrix.suite }}-${{ matrix.node }} + INPUT: logs_windows-${{ matrix.suite }}-${{ matrix.node }} run: |- slug=$(node -p 'process.env.INPUT.replace(/[^a-z0-9._-]/gi, "-")') echo "slug=$slug" >> "$GITHUB_OUTPUT" @@ -333,6 +1070,7 @@ jobs: run: |- echo "" >> $GITHUB_STEP_SUMMARY echo "[Logs](${{ steps.logupload.outputs.artifact-url }})" >> $GITHUB_STEP_SUMMARY + timeout-minutes: 90 strategy: fail-fast: false matrix: @@ -343,9 +1081,9 @@ jobs: - "20" - "22" - "24" - integ_telemetry: + integ_telemetry_windows: needs: prepare - runs-on: aws-cdk_ubuntu-latest_16-core + runs-on: windows-latest permissions: contents: read id-token: write @@ -355,8 +1093,48 @@ jobs: MAVEN_ARGS: --no-transfer-progress IS_CANARY: "true" CI: "true" - if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') + CDK_INTEG_SKIP_TESTS_FILE: ${{ github.workspace }}\windows-skip-tests.txt + defaults: + run: + shell: bash + if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'pr/test-windows')) steps: + - name: Set up Dev Drive for TEMP and npm cache + id: set_up_dev_drive_for_temp_and_npm_cache + run: |- + $vhd = "C:\devdrive.vhdx" + $drive = (New-VHD -Path $vhd -SizeBytes 40GB -Dynamic | Mount-VHD -PassThru | Initialize-Disk -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -DevDrive -Confirm:$false).DriveLetter + New-Item -ItemType Directory -Path "${drive}:\temp" | Out-Null + New-Item -ItemType Directory -Path "${drive}:\npm-cache" | Out-Null + echo "TEMP=${drive}:\temp" >> $env:GITHUB_ENV + echo "TMP=${drive}:\temp" >> $env:GITHUB_ENV + echo "npm_config_cache=${drive}:\npm-cache" >> $env:GITHUB_ENV + shell: powershell + - name: Write Windows skip-tests file + id: write_windows_skip-tests_file + run: |- + cat > windows-skip-tests.txt << 'EOF' + deploy same docker asset to multiple regions + deploy same docker asset to multiple stacks + deploy stack with multiple docker assets + deploy stack with docker asset + cdk-assets smoke test + deploy new style synthesis to new style bootstrap (with docker image) + Garbage Collection untags in-use ecr images + Garbage Collection keeps in use ecr images + Garbage Collection deletes unused ecr images + Garbage Collection tags unused ecr images + all calls from isolated container go through proxy + docker-credential-cdk-assets can assume role and fetch ECR credentials + toolkit deploy stack with multiple docker assets + CDK synth bundled functions as expected + CDK synth add the metadata properties expected by sam + can deploy with session tags on the deploy, lookup, file asset, and image asset publishing roles + generating and loading assembly + test resource import with construct that requires bundling + hotswap deployment supports Bedrock AgentCore Runtime + sam can locally test the synthesized cdk application + EOF - name: Download artifact id: download_artifact uses: actions/download-artifact@v8 @@ -437,7 +1215,7 @@ jobs: id: artifactid if: always() env: - INPUT: logs-${{ matrix.suite }}-${{ matrix.node }} + INPUT: logs_windows-${{ matrix.suite }}-${{ matrix.node }} run: |- slug=$(node -p 'process.env.INPUT.replace(/[^a-z0-9._-]/gi, "-")') echo "slug=$slug" >> "$GITHUB_OUTPUT" @@ -455,6 +1233,7 @@ jobs: run: |- echo "" >> $GITHUB_STEP_SUMMARY echo "[Logs](${{ steps.logupload.outputs.artifact-url }})" >> $GITHUB_STEP_SUMMARY + timeout-minutes: 90 strategy: fail-fast: false matrix: @@ -462,9 +1241,9 @@ jobs: - telemetry-integ-tests node: - lts/* - integ_init-templates: + integ_init-templates_windows: needs: prepare - runs-on: aws-cdk_ubuntu-latest_16-core + runs-on: windows-latest permissions: contents: read id-token: write @@ -474,8 +1253,48 @@ jobs: MAVEN_ARGS: --no-transfer-progress IS_CANARY: "true" CI: "true" - if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') + CDK_INTEG_SKIP_TESTS_FILE: ${{ github.workspace }}\windows-skip-tests.txt + defaults: + run: + shell: bash + if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'pr/test-windows')) steps: + - name: Set up Dev Drive for TEMP and npm cache + id: set_up_dev_drive_for_temp_and_npm_cache + run: |- + $vhd = "C:\devdrive.vhdx" + $drive = (New-VHD -Path $vhd -SizeBytes 40GB -Dynamic | Mount-VHD -PassThru | Initialize-Disk -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -DevDrive -Confirm:$false).DriveLetter + New-Item -ItemType Directory -Path "${drive}:\temp" | Out-Null + New-Item -ItemType Directory -Path "${drive}:\npm-cache" | Out-Null + echo "TEMP=${drive}:\temp" >> $env:GITHUB_ENV + echo "TMP=${drive}:\temp" >> $env:GITHUB_ENV + echo "npm_config_cache=${drive}:\npm-cache" >> $env:GITHUB_ENV + shell: powershell + - name: Write Windows skip-tests file + id: write_windows_skip-tests_file + run: |- + cat > windows-skip-tests.txt << 'EOF' + deploy same docker asset to multiple regions + deploy same docker asset to multiple stacks + deploy stack with multiple docker assets + deploy stack with docker asset + cdk-assets smoke test + deploy new style synthesis to new style bootstrap (with docker image) + Garbage Collection untags in-use ecr images + Garbage Collection keeps in use ecr images + Garbage Collection deletes unused ecr images + Garbage Collection tags unused ecr images + all calls from isolated container go through proxy + docker-credential-cdk-assets can assume role and fetch ECR credentials + toolkit deploy stack with multiple docker assets + CDK synth bundled functions as expected + CDK synth add the metadata properties expected by sam + can deploy with session tags on the deploy, lookup, file asset, and image asset publishing roles + generating and loading assembly + test resource import with construct that requires bundling + hotswap deployment supports Bedrock AgentCore Runtime + sam can locally test the synthesized cdk application + EOF - name: Download artifact id: download_artifact uses: actions/download-artifact@v8 @@ -556,7 +1375,7 @@ jobs: id: artifactid if: always() env: - INPUT: logs-${{ matrix.suite }}-${{ matrix.node }} + INPUT: logs_windows-${{ matrix.suite }}-${{ matrix.node }} run: |- slug=$(node -p 'process.env.INPUT.replace(/[^a-z0-9._-]/gi, "-")') echo "slug=$slug" >> "$GITHUB_OUTPUT" @@ -574,6 +1393,7 @@ jobs: run: |- echo "" >> $GITHUB_STEP_SUMMARY echo "[Logs](${{ steps.logupload.outputs.artifact-url }})" >> $GITHUB_STEP_SUMMARY + timeout-minutes: 90 strategy: fail-fast: false matrix: @@ -595,9 +1415,9 @@ jobs: - init-typescript-lib node: - lts/* - integ_tool-integrations: + integ_tool-integrations_windows: needs: prepare - runs-on: aws-cdk_ubuntu-latest_16-core + runs-on: windows-latest permissions: contents: read id-token: write @@ -607,8 +1427,48 @@ jobs: MAVEN_ARGS: --no-transfer-progress IS_CANARY: "true" CI: "true" - if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') + CDK_INTEG_SKIP_TESTS_FILE: ${{ github.workspace }}\windows-skip-tests.txt + defaults: + run: + shell: bash + if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'pr/test-windows')) steps: + - name: Set up Dev Drive for TEMP and npm cache + id: set_up_dev_drive_for_temp_and_npm_cache + run: |- + $vhd = "C:\devdrive.vhdx" + $drive = (New-VHD -Path $vhd -SizeBytes 40GB -Dynamic | Mount-VHD -PassThru | Initialize-Disk -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -DevDrive -Confirm:$false).DriveLetter + New-Item -ItemType Directory -Path "${drive}:\temp" | Out-Null + New-Item -ItemType Directory -Path "${drive}:\npm-cache" | Out-Null + echo "TEMP=${drive}:\temp" >> $env:GITHUB_ENV + echo "TMP=${drive}:\temp" >> $env:GITHUB_ENV + echo "npm_config_cache=${drive}:\npm-cache" >> $env:GITHUB_ENV + shell: powershell + - name: Write Windows skip-tests file + id: write_windows_skip-tests_file + run: |- + cat > windows-skip-tests.txt << 'EOF' + deploy same docker asset to multiple regions + deploy same docker asset to multiple stacks + deploy stack with multiple docker assets + deploy stack with docker asset + cdk-assets smoke test + deploy new style synthesis to new style bootstrap (with docker image) + Garbage Collection untags in-use ecr images + Garbage Collection keeps in use ecr images + Garbage Collection deletes unused ecr images + Garbage Collection tags unused ecr images + all calls from isolated container go through proxy + docker-credential-cdk-assets can assume role and fetch ECR credentials + toolkit deploy stack with multiple docker assets + CDK synth bundled functions as expected + CDK synth add the metadata properties expected by sam + can deploy with session tags on the deploy, lookup, file asset, and image asset publishing roles + generating and loading assembly + test resource import with construct that requires bundling + hotswap deployment supports Bedrock AgentCore Runtime + sam can locally test the synthesized cdk application + EOF - name: Download artifact id: download_artifact uses: actions/download-artifact@v8 @@ -689,7 +1549,7 @@ jobs: id: artifactid if: always() env: - INPUT: logs-${{ matrix.suite }}-${{ matrix.node }} + INPUT: logs_windows-${{ matrix.suite }}-${{ matrix.node }} run: |- slug=$(node -p 'process.env.INPUT.replace(/[^a-z0-9._-]/gi, "-")') echo "slug=$slug" >> "$GITHUB_OUTPUT" @@ -707,6 +1567,7 @@ jobs: run: |- echo "" >> $GITHUB_STEP_SUMMARY echo "[Logs](${{ steps.logupload.outputs.artifact-url }})" >> $GITHUB_STEP_SUMMARY + timeout-minutes: 90 strategy: fail-fast: false matrix: @@ -721,6 +1582,11 @@ jobs: - integ_telemetry - integ_init-templates - integ_tool-integrations + - integ_cli_windows + - integ_toolkit-lib_windows + - integ_telemetry_windows + - integ_init-templates_windows + - integ_tool-integrations_windows runs-on: ubuntu-latest permissions: {} if: always() @@ -740,7 +1606,64 @@ jobs: - name: integ_tool-integrations result id: integ_tool-integrations_result run: echo ${{ needs.integ_tool-integrations.result }} + - name: integ_cli_windows result + id: integ_cli_windows_result + run: echo ${{ needs.integ_cli_windows.result }} + - name: integ_toolkit-lib_windows result + id: integ_toolkit-lib_windows_result + run: echo ${{ needs.integ_toolkit-lib_windows.result }} + - name: integ_telemetry_windows result + id: integ_telemetry_windows_result + run: echo ${{ needs.integ_telemetry_windows.result }} + - name: integ_init-templates_windows result + id: integ_init-templates_windows_result + run: echo ${{ needs.integ_init-templates_windows.result }} + - name: integ_tool-integrations_windows result + id: integ_tool-integrations_windows_result + run: echo ${{ needs.integ_tool-integrations_windows.result }} - name: Set status based on test results id: set_status_based_on_test_results - if: ${{ !(contains(fromJSON('["success", "skipped"]'), needs.integ_cli.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_toolkit-lib.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_telemetry.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_init-templates.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_tool-integrations.result)) }} + if: ${{ !(contains(fromJSON('["success", "skipped"]'), needs.integ_cli.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_toolkit-lib.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_telemetry.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_init-templates.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_tool-integrations.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_cli_windows.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_toolkit-lib_windows.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_telemetry_windows.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_init-templates_windows.result) && contains(fromJSON('["success", "skipped"]'), needs.integ_tool-integrations_windows.result)) }} run: exit 1 + integ_windows_report_failure: + needs: + - integ_cli_windows + - integ_toolkit-lib_windows + - integ_telemetry_windows + - integ_init-templates_windows + - integ_tool-integrations_windows + runs-on: ubuntu-latest + permissions: + contents: read + issues: write + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + if: ${{ always() && github.event_name == 'schedule' && contains(needs.*.result, 'failure') }} + steps: + - name: File or update the tracking issue + id: file_or_update_the_tracking_issue + run: |- + set -euo pipefail + + BODY="Nightly Windows integ run failed: $RUN_URL" + + # '// empty' yields an empty string when no issue is open, rather than "null". + EXISTING=$(gh issue list \ + --label 'windows-integ-nightly' \ + --state open \ + --limit 1 \ + --json number \ + --jq '.[0].number // empty') + + if [ -n "$EXISTING" ]; then + echo "Commenting on existing issue #$EXISTING" + gh issue comment "$EXISTING" --body "$BODY" + else + echo "Filing a new issue" + gh issue create \ + --title 'Windows integ nightly is failing' \ + --label 'windows-integ-nightly' \ + --body "$BODY" + fi diff --git a/.projenrc.ts b/.projenrc.ts index 5ed4f49d1..6d5518f3b 100644 --- a/.projenrc.ts +++ b/.projenrc.ts @@ -1773,6 +1773,10 @@ new CdkCliIntegTestsWorkflow(repo, { testEnvironment: TEST_ENVIRONMENT, buildRunsOn: POWERFUL_RUNNER, testRunsOn: POWERFUL_RUNNER, + // Also run the integ suites on Windows to catch platform-specific + // regressions (paths, subprocess spawning). Uses the free standard runner + // for now; switch to a larger runner label once one is provisioned. + windowsTestRunsOn: 'windows-latest', allowUpstreamVersions: [ // cloud-assembly-schema gets referenced under multiple versions diff --git a/projenrc/cdk-cli-integ-tests.ts b/projenrc/cdk-cli-integ-tests.ts index 3f670e331..3690b57a2 100644 --- a/projenrc/cdk-cli-integ-tests.ts +++ b/projenrc/cdk-cli-integ-tests.ts @@ -12,6 +12,74 @@ export function fixupTestTask(project: Project, taskName = 'test'): void { const NOT_FLAGGED_EXPR = "!contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test')"; +/** + * Label that opts a pull request into the Windows integ suites. + * + * Apply it to a PR touching platform-sensitive code (paths, subprocess + * spawning, shell quoting); a failure then blocks the PR like any other integ + * failure. + */ +const WINDOWS_LABEL = 'pr/test-windows'; + +/** + * Marker label on the issue that tracks nightly Windows failures. + * + * MUST exist in the repository's label set, otherwise `gh issue create` in the + * failure report job will fail. + */ +const WINDOWS_FAILURE_LABEL = 'windows-integ-nightly'; + +/** The nightly (schedule) event. */ +const IS_SCHEDULE = "github.event_name == 'schedule'"; + +/** + * Windows runs on the nightly, on a manual dispatch, or on a PR that opted in + * via label. + * + * `workflow_dispatch` is the only one of the three reachable from a branch (a + * schedule fires only on the default branch, and `pull_request_target` reads + * the workflow from the base branch), so it is what makes these jobs testable + * before they merge. + */ +const WINDOWS_REQUESTED_EXPR = [ + IS_SCHEDULE, + "github.event_name == 'workflow_dispatch'", + `contains(github.event.pull_request.labels.*.name, '${WINDOWS_LABEL}')`, +].join(' || '); + +/** + * Tests that build or run Linux Docker images. + * + * GitHub-hosted Windows runners run Docker in Windows-containers mode and + * cannot pull or build Linux images ('no matching manifest for windows/amd64'), + * so these tests are skipped on Windows. + */ +const DOCKER_TESTS_SKIPPED_ON_WINDOWS = [ + 'deploy same docker asset to multiple regions', + 'deploy same docker asset to multiple stacks', + 'deploy stack with multiple docker assets', + 'deploy stack with docker asset', + 'cdk-assets smoke test', + 'deploy new style synthesis to new style bootstrap (with docker image)', + 'Garbage Collection untags in-use ecr images', + 'Garbage Collection keeps in use ecr images', + 'Garbage Collection deletes unused ecr images', + 'Garbage Collection tags unused ecr images', + 'all calls from isolated container go through proxy', + 'docker-credential-cdk-assets can assume role and fetch ECR credentials', + 'toolkit deploy stack with multiple docker assets', + // These do not have 'docker' in the name, but build Linux images as a side + // effect: python lambda bundling, SAM asset bundling, a DockerImageAsset in + // the fixture stack, and a docker-app deploy from a copied assembly. + 'CDK synth bundled functions as expected', + 'CDK synth add the metadata properties expected by sam', + 'can deploy with session tags on the deploy, lookup, file asset, and image asset publishing roles', + 'generating and loading assembly', + 'test resource import with construct that requires bundling', + 'hotswap deployment supports Bedrock AgentCore Runtime', + 'sam can locally test the synthesized cdk application', +]; + function setupNodeStep(nodeVersion: string): github.workflows.JobStep { return { name: 'Setup Node.js', @@ -130,6 +198,17 @@ export interface CdkCliIntegTestsWorkflowProps { */ readonly testRunsOn: string; + /** + * If given, additionally run every integ test matrix job on this Windows + * runner (in addition to the `testRunsOn` runner). + * + * The Windows jobs are suffixed with `_windows` and run all steps under Git + * Bash so the shared bash step scripts keep working. + * + * @default - integ tests only run on `testRunsOn` + */ + readonly windowsTestRunsOn?: string; + /** * GitHub environment name for approvals * @@ -289,11 +368,33 @@ export class CdkCliIntegTestsWorkflow extends Component { committed: false, lines: [ '#!/bin/bash', - 'npm install -g verdaccio pm2', + // Verdaccio was installed once in the 'prepare' job and shipped here + // as a tarball; extracting it is much faster than an npm install, + // especially on Windows. No process manager: Verdaccio only has to + // outlive this job, and the runner kills leftover processes at job + // teardown. + // + // Fallback: if the tarball is not present (e.g. when pull_request_target + // uses the base branch workflow which lacks the bundle step), install + // Verdaccio on the fly. Slower, but keeps the run working. + 'mkdir -p $HOME/verdaccio-app', + 'if [ -f .projen/verdaccio-bundle.tgz ]; then', + ' tar xzf .projen/verdaccio-bundle.tgz -C $HOME/verdaccio-app', + 'else', + ' npm install --prefix $HOME/verdaccio-app --no-bin-links --no-audit --no-fund --loglevel=error verdaccio@6.8', + 'fi', 'mkdir -p $HOME/.config/verdaccio', `echo '${JSON.stringify(verdaccioConfig)}' > $HOME/.config/verdaccio/config.yaml`, - 'pm2 start verdaccio -- --config $HOME/.config/verdaccio/config.yaml', - 'sleep 5', // Wait for Verdaccio to start + // Point at Verdaccio's JS entrypoint; bin shims were not created + // (--no-bin-links) and would not be bash-spawnable on Windows anyway. + 'VERDACCIO_BIN="$HOME/verdaccio-app/node_modules/verdaccio/bin/verdaccio"', + 'nohup node "$VERDACCIO_BIN" --config $HOME/.config/verdaccio/config.yaml > verdaccio.log 2>&1 &', + // Wait for Verdaccio to accept requests instead of sleeping a fixed time + 'for i in $(seq 1 60); do', + ' if curl -fsS -o /dev/null http://localhost:4873/; then break; fi', + ' if [ $i -eq 60 ]; then echo "Verdaccio did not start:"; cat verdaccio.log; exit 1; fi', + ' sleep 1', + 'done', // Configure NPM to use local registry 'echo \'//localhost:4873/:_authToken="MWRjNDU3OTE1NTljYWUyOTFkMWJkOGUyYTIwZWMwNTI6YTgwZjkyNDE0NzgwYWQzNQ=="\' > ~/.npmrc', 'echo \'registry=http://localhost:4873/\' >> ~/.npmrc', @@ -307,11 +408,18 @@ export class CdkCliIntegTestsWorkflow extends Component { this.workflow.on({ pullRequestTarget: { branches: [], + // 'labeled'/'unlabeled' are not in GitHub's default set, and without + // them the Windows opt-in label would not take effect (or stop taking + // effect) until the next push. + types: ['opened', 'synchronize', 'reopened', 'labeled', 'unlabeled'], }, // Needs to trigger and report success on merge queue builds as well mergeGroup: {}, // Never hurts to be able to run this manually workflowDispatch: {}, + // Nightly Windows run: too slow to gate every PR on, so it runs + // unattended here and reports failures by filing an issue. + schedule: [{ cron: '0 6 * * *' }], }); // Determine the environment dynamically: PRs from the same repo and merge_group // events skip the approval environment, while external PRs require approval. @@ -333,8 +441,10 @@ export class CdkCliIntegTestsWorkflow extends Component { run: `echo ${this.props.approvalEnvironment} > .envname`, }, { - name: 'Skip approval for mergeGroup or PR created from this repo', - if: "${{ github.event_name == 'merge_group' || github.event.pull_request.head.repo.full_name == github.repository }}", + // The nightly is included because there is nobody waiting to approve + // it; without this it would hang. + name: 'Skip approval for mergeGroup, schedule, or PR created from this repo', + if: `\${{ github.event_name == 'merge_group' || ${IS_SCHEDULE} || github.event.pull_request.head.repo.full_name == github.repository }}`, run: 'echo no-approval > .envname', }, { @@ -388,8 +498,11 @@ export class CdkCliIntegTestsWorkflow extends Component { with: { // IMPORTANT! This must be `head.sha` not `head.ref`, otherwise we // are vulnerable to a TOCTOU attack. - 'ref': '${{ github.event.pull_request.head.sha }}', - 'repository': '${{ github.event.pull_request.head.repo.full_name }}', + // + // The fallbacks cover events with no pull request attached + // (schedule, workflow_dispatch), and resolve to the default branch. + 'ref': '${{ github.event.pull_request.head.sha || github.sha }}', + 'repository': '${{ github.event.pull_request.head.repo.full_name || github.repository }}', // Need to allow forks, the workflow has been reviewed and getting OIDC credentials is the point // Other credentials are environment protected // @see https://docs.github.com/en/actions/reference/security/securely-using-pull_request_target @@ -426,6 +539,26 @@ export class CdkCliIntegTestsWorkflow extends Component { RELEASE: 'true', }, }, + { + // Install Verdaccio once here and ship it to the test jobs as a + // tarball. Installing it in every job through npm costs ~60s on + // Windows runners (thousands of small file writes); extracting a + // single archive is much faster. Verdaccio has no native or + // platform-specific dependencies, so a Linux-built tree runs + // anywhere; --no-bin-links keeps symlinks out of the archive + // (jobs invoke the JS entrypoint directly). + name: 'Bundle Verdaccio for the test jobs', + run: [ + 'mkdir -p /tmp/verdaccio-bundle', + // The bundle is built once but runs under every Node version in + // the test matrix, so Verdaccio's engine range must include the + // oldest of them: 6.9 requires Node >= 22, 6.8 still allows 20. + // (A per-job npm install used to hide this by resolving an + // engines-compatible version for each job's own Node.) + '(cd /tmp/verdaccio-bundle && npm install --no-bin-links --no-audit --no-fund --loglevel=error verdaccio@6.8)', + 'tar czf .projen/verdaccio-bundle.tgz -C /tmp/verdaccio-bundle node_modules', + ].join('\n'), + }, github.WorkflowSteps.uploadArtifact({ id: 'build-artifact', with: { @@ -438,7 +571,10 @@ export class CdkCliIntegTestsWorkflow extends Component { id: 'script-artifact', with: { name: 'script-artifact', - path: '.projen/*.sh', + path: [ + '.projen/*.sh', + '.projen/verdaccio-bundle.tgz', + ].join('\n'), overwrite: true, includeHiddenFiles: true, }, @@ -449,36 +585,37 @@ export class CdkCliIntegTestsWorkflow extends Component { // Ensure this is an array const additionalNodeVersionsToTest = this.props.additionalNodeVersionsToTest ?? []; - const testJobs = [ + // The integ test suites, defined once and instantiated per platform. + const suites: Array<[string, MatrixIntegTestProps]> = [ // cli-integ-tests - this.addMatrixJob('cli', { + ['cli', { domain: { suite: ['cli-integ-tests'], shards: 12, }, - }), + }], // toolkit-lib - this.addMatrixJob('toolkit-lib', { + ['toolkit-lib', { domain: { suite: [ 'toolkit-lib-integ-tests', ], node: ['lts/*', ...additionalNodeVersionsToTest], }, - }), + }], // telemetry - this.addMatrixJob('telemetry', { + ['telemetry', { domain: { suite: [ 'telemetry-integ-tests', ], }, - }), + }], // init-templates - this.addMatrixJob('init-templates', { + ['init-templates', { domain: { suite: [ 'init-csharp', @@ -497,17 +634,37 @@ export class CdkCliIntegTestsWorkflow extends Component { suite: 'init-typescript-app', node, })), - }), + }], // We are finding that Amplify works on Node 20, but fails on Node >=22.10. Remove the 'lts/*' test and use a Node 20 for now. - this.addMatrixJob('tool-integrations', { + ['tool-integrations', { domain: { suite: ['tool-integrations'], node: ['20'], }, - }), + }], ]; + const linuxJobs = suites.map(([name, jobProps]) => this.addMatrixJob(name, jobProps, { + runsOn: this.props.testRunsOn, + // The nightly exists to cover Windows; Linux already runs on every PR, so + // repeating it there would consume Atmosphere environments for no signal. + extraCondition: "github.event_name != 'schedule'", + })); + + const windowsJobs = this.props.windowsTestRunsOn + ? suites.map(([name, jobProps]) => this.addMatrixJob(name, jobProps, { + runsOn: this.props.windowsTestRunsOn!, + suffix: '_windows', + windows: true, + // Only on the nightly, a manual dispatch, or when a PR opts in by label. + extraCondition: `(${WINDOWS_REQUESTED_EXPR})`, + timeoutMinutes: 90, + })) + : []; + + const testJobs = [...linuxJobs, ...windowsJobs]; + // Add a job that collates all matrix jobs into a single status // This is required so that we can setup required status checks // and if we ever change the test matrix, we don't need to update @@ -530,14 +687,77 @@ export class CdkCliIntegTestsWorkflow extends Component { }, ], }); + + if (windowsJobs.length > 0) { + this.addWindowsFailureReportJob(windowsJobs); + } + } + + /** + * File an issue when the nightly Windows run fails. + * + * Schedule-only: a failure on a label-triggered PR run already surfaces as a + * red check there. Comments on an already-open issue rather than filing a + * duplicate for every night of a persistent breakage. + */ + private addWindowsFailureReportJob(windowsJobs: string[]): void { + this.workflow.addJob('integ_windows_report_failure', { + runsOn: ['ubuntu-latest'], + needs: windowsJobs, + permissions: { + contents: github.workflows.JobPermission.READ, + issues: github.workflows.JobPermission.WRITE, + }, + if: `\${{ always() && ${IS_SCHEDULE} && contains(needs.*.result, 'failure') }}`, + env: { + GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}', + // This job does not check out the repo, so `gh` cannot infer the + // repository from a git remote and needs it passed explicitly. + GH_REPO: '${{ github.repository }}', + // Interpolated here rather than in the `run` body: CheckGhaExpressions + // rejects `github.*` inside shell steps as an injection vector, so the + // step references it as a quoted shell variable instead. + RUN_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}', + }, + steps: [ + { + name: 'File or update the tracking issue', + run: [ + 'set -euo pipefail', + '', + 'BODY="Nightly Windows integ run failed: $RUN_URL"', + '', + '# \'// empty\' yields an empty string when no issue is open, rather than "null".', + 'EXISTING=$(gh issue list \\', + ` --label '${WINDOWS_FAILURE_LABEL}' \\`, + ' --state open \\', + ' --limit 1 \\', + ' --json number \\', + ' --jq \'.[0].number // empty\')', + '', + 'if [ -n "$EXISTING" ]; then', + ' echo "Commenting on existing issue #$EXISTING"', + ' gh issue comment "$EXISTING" --body "$BODY"', + 'else', + ' echo "Filing a new issue"', + ' gh issue create \\', + ' --title \'Windows integ nightly is failing\' \\', + ` --label '${WINDOWS_FAILURE_LABEL}' \\`, + ' --body "$BODY"', + 'fi', + ].join('\n'), + }, + ], + }); } - private addMatrixJob(testName: string, props: MatrixIntegTestProps): string { - const jobName = `integ_${testName}`; + private addMatrixJob(testName: string, props: MatrixIntegTestProps, platform: PlatformOptions): string { + const suffix = platform.suffix ?? ''; + const jobName = `integ_${testName}${suffix}`; let shard: any; let shardArg = ''; - let logName = 'logs-${{ matrix.suite }}-${{ matrix.node }}'; + let logName = `logs${suffix}-\${{ matrix.suite }}-\${{ matrix.node }}`; if (props.domain.shards) { shard = Array(props.domain.shards).fill(0).map((_, i) => i + 1); shardArg = ` --shard="\${{ matrix.shard }}/${props.domain.shards}"`; @@ -546,12 +766,19 @@ export class CdkCliIntegTestsWorkflow extends Component { this.workflow.addJob(jobName, { environment: this.props.testEnvironment, - runsOn: [this.props.testRunsOn], + runsOn: [platform.runsOn], needs: [this.JOB_PREPARE], permissions: { contents: github.workflows.JobPermission.READ, idToken: github.workflows.JobPermission.WRITE, }, + // The step scripts are written for bash; on Windows runners use Git Bash + // (preinstalled) so they run unchanged while still exercising Windows. + defaults: { + run: { + shell: 'bash', + }, + }, env: { // Integ tests heavily rely on processing stdout, node warnings (mostly deprecations) are muddying this. // We can disable any warnings here, there's plenty of other places we will see them. @@ -562,12 +789,23 @@ export class CdkCliIntegTestsWorkflow extends Component { // assumptions about the availability of source packages. IS_CANARY: 'true', CI: 'true', + ...platform.windows ? { + // The skip file is newline-separated; the CDK_INTEG_SKIP_TESTS + // environment variable is comma-separated and cannot express + // test names that contain commas. + CDK_INTEG_SKIP_TESTS_FILE: '${{ github.workspace }}\\windows-skip-tests.txt', + } : {}, // add extra env at end so it can override ...props.extraEnv, }, + ...platform.timeoutMinutes ? { timeoutMinutes: platform.timeoutMinutes } : {}, // Don't run again on the merge queue, we already got confirmation that it works and the // tests are quite expensive. - if: `github.event_name != 'merge_group' && ${NOT_FLAGGED_EXPR}`, + if: [ + "github.event_name != 'merge_group'", + NOT_FLAGGED_EXPR, + ...platform.extraCondition ? [platform.extraCondition] : [], + ].join(' && '), strategy: { failFast: false, matrix: { @@ -581,6 +819,33 @@ export class CdkCliIntegTestsWorkflow extends Component { }, }, steps: [ + ...platform.windows ? [{ + // The integ tests are dominated by npm installs and toolchain builds: + // many small file writes, which are slow on the runner's NTFS OS disk. + // A Dev Drive (ReFS VHDX) is much faster for this pattern. Create one + // and point TEMP at it, which is where all test fixtures live + // (the harness creates its working directories under os.tmpdir()). + name: 'Set up Dev Drive for TEMP and npm cache', + shell: 'powershell', + run: [ + '$vhd = "C:\\devdrive.vhdx"', + '$drive = (New-VHD -Path $vhd -SizeBytes 40GB -Dynamic | Mount-VHD -PassThru | Initialize-Disk -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -DevDrive -Confirm:$false).DriveLetter', + 'New-Item -ItemType Directory -Path "${drive}:\\temp" | Out-Null', + 'New-Item -ItemType Directory -Path "${drive}:\\npm-cache" | Out-Null', + 'echo "TEMP=${drive}:\\temp" >> $env:GITHUB_ENV', + 'echo "TMP=${drive}:\\temp" >> $env:GITHUB_ENV', + // Every npm invocation in the job (global installs, per-test installs) + // reads and writes the cache, so move it onto the Dev Drive too + 'echo "npm_config_cache=${drive}:\\npm-cache" >> $env:GITHUB_ENV', + ].join('\n'), + }, { + name: 'Write Windows skip-tests file', + run: [ + 'cat > windows-skip-tests.txt << \'EOF\'', + ...DOCKER_TESTS_SKIPPED_ON_WINDOWS, + 'EOF', + ].join('\n'), + }] : [], github.WorkflowSteps.downloadArtifact({ with: { artifactIds: [`\${{needs.${this.JOB_PREPARE}.outputs.packagesArtifact}}`], @@ -689,3 +954,44 @@ interface MatrixIntegTestProps { readonly exclude?: github.workflows.JobMatrix['exclude']; readonly extraEnv?: Record; } + +interface PlatformOptions { + /** + * The runner label to run this instance of the job on. + */ + readonly runsOn: string; + + /** + * Suffix appended to the job name and log artifact names, to disambiguate + * multiple platform instances of the same suite. + * + * @default - no suffix + */ + readonly suffix?: string; + + /** + * Whether this job runs on a Windows runner. + * + * Adds Windows-specific setup steps. + * + * @default false + */ + readonly windows?: boolean; + + /** + * Hard cap on job duration, instead of GitHub's 6 hour default. + * + * Note this does not pre-empt AWS session expiry: Atmosphere credentials last + * 1 hour and are obtained part-way into the job, at a variable offset. + * + * @default - GitHub's default + */ + readonly timeoutMinutes?: number; + + /** + * Additional expression ANDed onto the job's `if` condition. + * + * @default - no additional condition + */ + readonly extraCondition?: string; +} From b743e3cb81932bd9fc70b3dd826647ff42563a91 Mon Sep 17 00:00:00 2001 From: dgandhi62 Date: Thu, 20 Aug 2026 17:19:13 -0400 Subject: [PATCH 2/4] The nightly Windows integ run has nobody watching it, so a failure now files a GitHub issue labelled 'potential-regression', which is already wired up to page the team. Only on the schedule. A PR that opts into the Windows suites via the 'pr/test-windows' label files nothing: the failure is already a red check on the PR, and the label is there so a contributor can try Windows out, not to page anyone. The issue records the commit SHA as well as the run URL. Dependency upgrades merge unattended at 00:00 UTC and the nightly runs at 06:00, so consecutive nightlies do not necessarily test the same commit. The job MUST keep the default GITHUB_TOKEN. Issues created with it do not trigger other workflow runs, which is what stops issue-regression-labeler from stripping 'potential-regression' off an issue whose body has no regression checkbox. A PAT here would silently stop the page. --- .github/workflows/integ.yml | 30 ++++++------------- projenrc/cdk-cli-integ-tests.ts | 52 ++++++++++++++++----------------- 2 files changed, 34 insertions(+), 48 deletions(-) diff --git a/.github/workflows/integ.yml b/.github/workflows/integ.yml index c9d838317..11a68d462 100644 --- a/.github/workflows/integ.yml +++ b/.github/workflows/integ.yml @@ -1640,30 +1640,18 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + RUN_SHA: ${{ github.sha }} if: ${{ always() && github.event_name == 'schedule' && contains(needs.*.result, 'failure') }} steps: - - name: File or update the tracking issue - id: file_or_update_the_tracking_issue + - name: File an issue + id: file_an_issue run: |- set -euo pipefail - BODY="Nightly Windows integ run failed: $RUN_URL" + gh issue create \ + --title 'Windows integ nightly failed' \ + --label 'potential-regression' \ + --body "Nightly Windows integ run failed. - # '// empty' yields an empty string when no issue is open, rather than "null". - EXISTING=$(gh issue list \ - --label 'windows-integ-nightly' \ - --state open \ - --limit 1 \ - --json number \ - --jq '.[0].number // empty') - - if [ -n "$EXISTING" ]; then - echo "Commenting on existing issue #$EXISTING" - gh issue comment "$EXISTING" --body "$BODY" - else - echo "Filing a new issue" - gh issue create \ - --title 'Windows integ nightly is failing' \ - --label 'windows-integ-nightly' \ - --body "$BODY" - fi + Run: $RUN_URL + Commit: $RUN_SHA" diff --git a/projenrc/cdk-cli-integ-tests.ts b/projenrc/cdk-cli-integ-tests.ts index 3690b57a2..d01087f7a 100644 --- a/projenrc/cdk-cli-integ-tests.ts +++ b/projenrc/cdk-cli-integ-tests.ts @@ -22,12 +22,13 @@ const NOT_FLAGGED_EXPR = "!contains(github.event.pull_request.labels.*.name, 'pr const WINDOWS_LABEL = 'pr/test-windows'; /** - * Marker label on the issue that tracks nightly Windows failures. + * Label applied to the issue filed when the nightly Windows run fails. * - * MUST exist in the repository's label set, otherwise `gh issue create` in the - * failure report job will fail. + * This is the repository's existing regression label, which is already wired up + * to page the team. `issue-regression-labeler` also manages it, so it is + * guaranteed to exist in the repository's label set. */ -const WINDOWS_FAILURE_LABEL = 'windows-integ-nightly'; +const REGRESSION_LABEL = 'potential-regression'; /** The nightly (schedule) event. */ const IS_SCHEDULE = "github.event_name == 'schedule'"; @@ -696,9 +697,9 @@ export class CdkCliIntegTestsWorkflow extends Component { /** * File an issue when the nightly Windows run fails. * - * Schedule-only: a failure on a label-triggered PR run already surfaces as a - * red check there. Comments on an already-open issue rather than filing a - * duplicate for every night of a persistent breakage. + * Schedule-only. A label-triggered PR run deliberately does not file an + * issue: the failure is already visible as a red check on the PR, and the + * label exists so a contributor can try Windows out, not to page anyone. */ private addWindowsFailureReportJob(windowsJobs: string[]): void { this.workflow.addJob('integ_windows_report_failure', { @@ -710,6 +711,12 @@ export class CdkCliIntegTestsWorkflow extends Component { }, if: `\${{ always() && ${IS_SCHEDULE} && contains(needs.*.result, 'failure') }}`, env: { + // MUST stay the default GITHUB_TOKEN. Issues created with it do not + // trigger other workflow runs, which is what keeps + // `issue-regression-labeler` from firing: that workflow strips + // 'potential-regression' from any issue whose body lacks the regression + // checkbox, and would silently undo the label we set here. Switching + // this to a PAT would stop the page from ever going out. GH_TOKEN: '${{ secrets.GITHUB_TOKEN }}', // This job does not check out the repo, so `gh` cannot infer the // repository from a git remote and needs it passed explicitly. @@ -718,33 +725,24 @@ export class CdkCliIntegTestsWorkflow extends Component { // rejects `github.*` inside shell steps as an injection vector, so the // step references it as a quoted shell variable instead. RUN_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}', + // Dependency upgrades merge unattended overnight, so the nightly does + // not necessarily run against the same commit as the night before. + // Record what it did run against. + RUN_SHA: '${{ github.sha }}', }, steps: [ { - name: 'File or update the tracking issue', + name: 'File an issue', run: [ 'set -euo pipefail', '', - 'BODY="Nightly Windows integ run failed: $RUN_URL"', + 'gh issue create \\', + ' --title \'Windows integ nightly failed\' \\', + ` --label '${REGRESSION_LABEL}' \\`, + ' --body "Nightly Windows integ run failed.', '', - '# \'// empty\' yields an empty string when no issue is open, rather than "null".', - 'EXISTING=$(gh issue list \\', - ` --label '${WINDOWS_FAILURE_LABEL}' \\`, - ' --state open \\', - ' --limit 1 \\', - ' --json number \\', - ' --jq \'.[0].number // empty\')', - '', - 'if [ -n "$EXISTING" ]; then', - ' echo "Commenting on existing issue #$EXISTING"', - ' gh issue comment "$EXISTING" --body "$BODY"', - 'else', - ' echo "Filing a new issue"', - ' gh issue create \\', - ' --title \'Windows integ nightly is failing\' \\', - ` --label '${WINDOWS_FAILURE_LABEL}' \\`, - ' --body "$BODY"', - 'fi', + 'Run: $RUN_URL', + 'Commit: $RUN_SHA"', ].join('\n'), }, ], From 88771032d817b08058523658ad8d034b06121da1 Mon Sep 17 00:00:00 2001 From: dgandhi62 Date: Fri, 28 Aug 2026 14:23:30 -0400 Subject: [PATCH 3/4] Keep the Linux integ jobs unaffected by the Windows work. Two things were reaching past the Windows jobs into the five Linux jobs that gate every pull request. The bash shell default is now set on the Windows jobs only. Windows needs it so Git Bash picks up the shared step scripts, but naming the shell explicitly also switches it to `bash --noprofile --norc -eo pipefail`, where GitHub's implicit Linux shell is `bash -e`. No Linux step pipes anything today, so nothing was breaking; the point is not to change the shell semantics of the PR-gating tests as a side effect. 'labeled'/'unlabeled' are dropped from the pull_request_target trigger. They made WINDOWS_LABEL take effect immediately, but the trigger cannot be filtered by label name, so any label on any pull request started a whole run with the Linux jobs included. Labels here are largely applied by automation: pr-labeler copies them off the linked issue, dependency upgrades carry 'auto-approve', triage adds p1/p2/effort-*. With no concurrency group on this workflow those runs accumulate concurrently instead of superseding each other, each holding Atmosphere environments. WINDOWS_LABEL now takes effect on the next push to the pull request. Re-running an existing run does not pick it up, because a re-run replays the original event payload and github.event.pull_request.labels still holds the old list. This matches 'pr/exempt-integ-test', which is read from the same job condition and has only ever applied from the next run. The Linux jobs now differ from main by a single line, the `github.event_name != 'schedule'` guard that keeps them off the nightly. --- .github/workflows/integ.yml | 21 --------------------- projenrc/cdk-cli-integ-tests.ts | 25 +++++++++++++++---------- 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/.github/workflows/integ.yml b/.github/workflows/integ.yml index 11a68d462..db5414753 100644 --- a/.github/workflows/integ.yml +++ b/.github/workflows/integ.yml @@ -4,12 +4,6 @@ name: integ on: pull_request_target: branches: [] - types: - - opened - - synchronize - - reopened - - labeled - - unlabeled merge_group: {} workflow_dispatch: {} schedule: @@ -117,9 +111,6 @@ jobs: MAVEN_ARGS: --no-transfer-progress IS_CANARY: "true" CI: "true" - defaults: - run: - shell: bash if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && github.event_name != 'schedule' steps: - name: Download artifact @@ -252,9 +243,6 @@ jobs: MAVEN_ARGS: --no-transfer-progress IS_CANARY: "true" CI: "true" - defaults: - run: - shell: bash if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && github.event_name != 'schedule' steps: - name: Download artifact @@ -377,9 +365,6 @@ jobs: MAVEN_ARGS: --no-transfer-progress IS_CANARY: "true" CI: "true" - defaults: - run: - shell: bash if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && github.event_name != 'schedule' steps: - name: Download artifact @@ -499,9 +484,6 @@ jobs: MAVEN_ARGS: --no-transfer-progress IS_CANARY: "true" CI: "true" - defaults: - run: - shell: bash if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && github.event_name != 'schedule' steps: - name: Download artifact @@ -635,9 +617,6 @@ jobs: MAVEN_ARGS: --no-transfer-progress IS_CANARY: "true" CI: "true" - defaults: - run: - shell: bash if: github.event_name != 'merge_group' && !contains(github.event.pull_request.labels.*.name, 'pr/exempt-integ-test') && github.event_name != 'schedule' steps: - name: Download artifact diff --git a/projenrc/cdk-cli-integ-tests.ts b/projenrc/cdk-cli-integ-tests.ts index d01087f7a..365b9100e 100644 --- a/projenrc/cdk-cli-integ-tests.ts +++ b/projenrc/cdk-cli-integ-tests.ts @@ -409,10 +409,11 @@ export class CdkCliIntegTestsWorkflow extends Component { this.workflow.on({ pullRequestTarget: { branches: [], - // 'labeled'/'unlabeled' are not in GitHub's default set, and without - // them the Windows opt-in label would not take effect (or stop taking - // effect) until the next push. - types: ['opened', 'synchronize', 'reopened', 'labeled', 'unlabeled'], + // Label changes do not start a run. The trigger cannot be filtered by + // label name, so subscribing to 'labeled' costs a full run (Linux jobs + // included) for every label on every pull request, and most labels here + // are applied by automation. WINDOWS_LABEL takes effect on the next + // push to the pull request. }, // Needs to trigger and report success on merge queue builds as well mergeGroup: {}, @@ -770,13 +771,17 @@ export class CdkCliIntegTestsWorkflow extends Component { contents: github.workflows.JobPermission.READ, idToken: github.workflows.JobPermission.WRITE, }, - // The step scripts are written for bash; on Windows runners use Git Bash - // (preinstalled) so they run unchanged while still exercising Windows. - defaults: { - run: { - shell: 'bash', + // Run the steps under Git Bash (preinstalled) so the shared bash step + // scripts work unchanged on Windows. Windows only: naming the shell + // explicitly also switches it to `bash --noprofile --norc -eo pipefail`, + // and the Linux jobs stay on GitHub's implicit `bash -e`. + ...platform.windows ? { + defaults: { + run: { + shell: 'bash', + }, }, - }, + } : {}, env: { // Integ tests heavily rely on processing stdout, node warnings (mostly deprecations) are muddying this. // We can disable any warnings here, there's plenty of other places we will see them. From 96009ce14100f704d4aadf69874a655dc0bc741d Mon Sep 17 00:00:00 2001 From: dgandhi62 Date: Fri, 28 Aug 2026 14:38:37 -0400 Subject: [PATCH 4/4] chore: remove comment --- projenrc/cdk-cli-integ-tests.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/projenrc/cdk-cli-integ-tests.ts b/projenrc/cdk-cli-integ-tests.ts index 365b9100e..676336075 100644 --- a/projenrc/cdk-cli-integ-tests.ts +++ b/projenrc/cdk-cli-integ-tests.ts @@ -409,11 +409,6 @@ export class CdkCliIntegTestsWorkflow extends Component { this.workflow.on({ pullRequestTarget: { branches: [], - // Label changes do not start a run. The trigger cannot be filtered by - // label name, so subscribing to 'labeled' costs a full run (Linux jobs - // included) for every label on every pull request, and most labels here - // are applied by automation. WINDOWS_LABEL takes effect on the next - // push to the pull request. }, // Needs to trigger and report success on merge queue builds as well mergeGroup: {},