From 901af6ffd037092603a875b20c6b7b055550beda Mon Sep 17 00:00:00 2001 From: dgandhi62 Date: Wed, 19 Aug 2026 16:49:24 -0400 Subject: [PATCH 1/2] 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 d599b69bc..cdfe794e1 100644 --- a/.projenrc.ts +++ b/.projenrc.ts @@ -1770,6 +1770,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 bb92d256eae8b5399758c913ae7b7ab3358a35fe Mon Sep 17 00:00:00 2001 From: dgandhi62 Date: Thu, 20 Aug 2026 17:19:13 -0400 Subject: [PATCH 2/2] 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'), }, ],