From 8540934a7ca203ace625a266b1075bd10fd53f54 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Wed, 27 May 2026 02:11:45 -0400 Subject: [PATCH 1/4] Run daily CLI E2E smoke tests against staging The daily CLI smoke workflow only ran classes matching *SmokeTests and installed the dev daily channel by default. That left most CLI end-to-end coverage out of the daily signal and did not exercise the staging channel. Change the workflow dispatch default to staging, enumerate the CLI E2E class-split matrix, and run each test class as its own matrix job. The matrix jobs load the prebuilt CLI E2E Docker images and pass ASPIRE_E2E_QUALITY through so the tests install the requested daily channel instead of using source-built CLI artifacts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/tests-daily-smoke.yml | 83 ++++++++++++++++++++----- 1 file changed, 67 insertions(+), 16 deletions(-) diff --git a/.github/workflows/tests-daily-smoke.yml b/.github/workflows/tests-daily-smoke.yml index 62c86da7cf0..e49f1f7934e 100644 --- a/.github/workflows/tests-daily-smoke.yml +++ b/.github/workflows/tests-daily-smoke.yml @@ -1,7 +1,7 @@ -# Runs CLI E2E smoke tests against the daily build to catch regressions early. +# Runs CLI E2E tests against the daily build to catch regressions early. # # This workflow installs the latest daily Aspire CLI (not from source) and runs -# a minimal set of E2E tests to verify core scenarios still work. +# E2E tests to verify CLI scenarios still work. # name: Daily CLI Smoke Tests @@ -11,7 +11,7 @@ on: quality: description: 'Install quality (dev, staging, release)' required: false - default: 'dev' + default: 'staging' type: choice options: - dev @@ -26,17 +26,52 @@ permissions: contents: read jobs: + setup_cli_e2e_tests: + name: Setup CLI E2E test matrix + runs-on: ubuntu-latest + outputs: + cli_e2e_matrix: ${{ steps.filter_cli_e2e.outputs.cli_e2e_matrix }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - uses: ./.github/actions/enumerate-tests + id: generate_tests_matrix + with: + buildArgs: '/p:IncludeCliE2ETests=true' + + - name: Filter CLI E2E test matrix + id: filter_cli_e2e + shell: pwsh + run: | + $allTests = '${{ steps.generate_tests_matrix.outputs.all_tests }}' | ConvertFrom-Json + $cliE2ETests = @($allTests.include | Where-Object { + $_.projectName -eq 'Aspire.Cli.EndToEnd.Tests' -and $_.type -eq 'class' + }) + + if ($cliE2ETests.Count -eq 0) { + Write-Error "No Aspire.Cli.EndToEnd.Tests class entries were found in the generated test matrix." + exit 1 + } + + $matrix = ConvertTo-Json @{ include = @($cliE2ETests) } -Compress -Depth 10 + "cli_e2e_matrix=$matrix" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + build_cli_e2e_image: name: Build CLI E2E Docker image uses: ./.github/workflows/build-cli-e2e-image.yml + needs: setup_cli_e2e_tests with: - includePolyglotImages: false + includePolyglotImages: true smoke-test: - name: CLI Smoke Test (${{ inputs.quality || 'dev' }}) - needs: build_cli_e2e_image + name: ${{ matrix.shortname }} (${{ inputs.quality || 'staging' }}) + needs: [setup_cli_e2e_tests, build_cli_e2e_image] + if: ${{ fromJson(needs.setup_cli_e2e_tests.outputs.cli_e2e_matrix).include[0] != null }} runs-on: ubuntu-latest - timeout-minutes: 30 + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.setup_cli_e2e_tests.outputs.cli_e2e_matrix) }} steps: - name: Checkout @@ -61,29 +96,44 @@ jobs: name: cli-e2e-dotnet-image path: ${{ github.workspace }}/cli-e2e-image - - name: Load prebuilt CLI E2E Docker image + - name: Download prebuilt CLI E2E polyglot Docker image + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: cli-e2e-polyglot-image + path: ${{ github.workspace }}/cli-e2e-image + + - name: Download prebuilt CLI E2E Java Docker image + if: ${{ contains(matrix.shortname, 'Java') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: cli-e2e-polyglot-java-image + path: ${{ github.workspace }}/cli-e2e-image + + - name: Load prebuilt CLI E2E Docker images shell: bash run: | set -euo pipefail eng/scripts/load-cli-e2e-images.sh \ --image-dir "${{ github.workspace }}/cli-e2e-image" \ - --require-dotnet true + --require-dotnet true \ + --require-polyglot true \ + --require-java "${{ contains(matrix.shortname, 'Java') }}" - name: Build E2E test project run: dotnet build tests/Aspire.Cli.EndToEnd.Tests/Aspire.Cli.EndToEnd.Tests.csproj - - name: Run smoke tests against daily build + - name: Run CLI E2E tests against daily build env: - ASPIRE_E2E_QUALITY: ${{ inputs.quality || 'dev' }} + ASPIRE_E2E_QUALITY: ${{ inputs.quality || 'staging' }} ASPIRE_E2E_CLI_VERSION_OUTPUT_DIR: ${{ github.workspace }}/testresults/cli-versions run: | dotnet test --project tests/Aspire.Cli.EndToEnd.Tests/Aspire.Cli.EndToEnd.Tests.csproj \ --no-build \ -- \ --report-trx \ - --report-trx-filename "DailyCliSmoke.trx" \ + --report-trx-filename "${{ matrix.shortname }}.trx" \ --results-directory ${{ github.workspace }}/testresults \ - --filter-class "*SmokeTests" \ + --filter-class "${{ matrix.classname }}" \ --filter-not-trait "quarantined=true" \ --filter-not-trait "outerloop=true" \ --hangdump --hangdump-type none --hangdump-timeout 15m @@ -93,7 +143,7 @@ jobs: if: always() uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: - name: smoke-test-results-${{ inputs.quality || 'dev' }} + name: smoke-test-results-${{ inputs.quality || 'staging' }}-${{ matrix.shortname }} path: | testresults/** **/TestResults/**/*.log @@ -256,8 +306,9 @@ jobs: uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 continue-on-error: true with: - name: smoke-test-results-${{ inputs.quality || 'dev' }} + pattern: smoke-test-results-${{ inputs.quality || 'staging' }}-* path: smoke-test-results + merge-multiple: true - name: Create GitHub Issue uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 @@ -268,7 +319,7 @@ jobs: const path = require('node:path'); const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; - const quality = context.payload.inputs?.quality ?? 'dev'; + const quality = context.payload.inputs?.quality ?? 'staging'; const date = new Date().toISOString().split('T')[0]; const cliVersionSummary = getCliVersionSummary(process.env.GITHUB_WORKSPACE, message => core.warning(message)); From 646ce2e35f63f7613faddb7778af95d136db0988 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Wed, 27 May 2026 02:14:04 -0400 Subject: [PATCH 2/4] Include CLI E2E tests in daily matrix enumeration The daily workflow runs outside pull request events, so the CLI E2E project is skipped during test enumeration unless the workflow explicitly overrides that skip. Without this, the generated class matrix is empty even though the workflow asks to include CLI E2E tests. Pass SkipTests=false when building the daily matrix so the CLI E2E project emits its class partitions for the staging daily workflow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/tests-daily-smoke.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests-daily-smoke.yml b/.github/workflows/tests-daily-smoke.yml index e49f1f7934e..fc0a7c9b599 100644 --- a/.github/workflows/tests-daily-smoke.yml +++ b/.github/workflows/tests-daily-smoke.yml @@ -37,7 +37,7 @@ jobs: - uses: ./.github/actions/enumerate-tests id: generate_tests_matrix with: - buildArgs: '/p:IncludeCliE2ETests=true' + buildArgs: '/p:IncludeCliE2ETests=true /p:SkipTests=false' - name: Filter CLI E2E test matrix id: filter_cli_e2e From cb3c7869d7b16f713adc1a604a951fe44cf1201f Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Wed, 27 May 2026 02:53:49 -0400 Subject: [PATCH 3/4] Add published CLI validation workflow The full CLI E2E validation should run as a post-publish check instead of expanding the scheduled daily smoke workflow. Daily smoke stays focused on its small smoke-test subset, while validate-published-build enumerates the same class-split CLI E2E matrix used by PR validation and runs each class as its own GitHub Actions job against the selected install-script quality. Wire the internal Azure DevOps build to dispatch the new workflow after the WinGet and Homebrew installer preparation jobs complete. The trigger reuses the existing GitHub App dispatch helper from the release pipeline, maps stable installer builds to the release quality and prerelease builds to the staging quality, and waits for the GitHub Actions run to finish. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/tests-daily-smoke.yml | 83 ++------ .../workflows/validate-published-build.yml | 190 ++++++++++++++++++ eng/pipelines/azure-pipelines.yml | 60 ++++++ 3 files changed, 266 insertions(+), 67 deletions(-) create mode 100644 .github/workflows/validate-published-build.yml diff --git a/.github/workflows/tests-daily-smoke.yml b/.github/workflows/tests-daily-smoke.yml index fc0a7c9b599..62c86da7cf0 100644 --- a/.github/workflows/tests-daily-smoke.yml +++ b/.github/workflows/tests-daily-smoke.yml @@ -1,7 +1,7 @@ -# Runs CLI E2E tests against the daily build to catch regressions early. +# Runs CLI E2E smoke tests against the daily build to catch regressions early. # # This workflow installs the latest daily Aspire CLI (not from source) and runs -# E2E tests to verify CLI scenarios still work. +# a minimal set of E2E tests to verify core scenarios still work. # name: Daily CLI Smoke Tests @@ -11,7 +11,7 @@ on: quality: description: 'Install quality (dev, staging, release)' required: false - default: 'staging' + default: 'dev' type: choice options: - dev @@ -26,52 +26,17 @@ permissions: contents: read jobs: - setup_cli_e2e_tests: - name: Setup CLI E2E test matrix - runs-on: ubuntu-latest - outputs: - cli_e2e_matrix: ${{ steps.filter_cli_e2e.outputs.cli_e2e_matrix }} - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - uses: ./.github/actions/enumerate-tests - id: generate_tests_matrix - with: - buildArgs: '/p:IncludeCliE2ETests=true /p:SkipTests=false' - - - name: Filter CLI E2E test matrix - id: filter_cli_e2e - shell: pwsh - run: | - $allTests = '${{ steps.generate_tests_matrix.outputs.all_tests }}' | ConvertFrom-Json - $cliE2ETests = @($allTests.include | Where-Object { - $_.projectName -eq 'Aspire.Cli.EndToEnd.Tests' -and $_.type -eq 'class' - }) - - if ($cliE2ETests.Count -eq 0) { - Write-Error "No Aspire.Cli.EndToEnd.Tests class entries were found in the generated test matrix." - exit 1 - } - - $matrix = ConvertTo-Json @{ include = @($cliE2ETests) } -Compress -Depth 10 - "cli_e2e_matrix=$matrix" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append - build_cli_e2e_image: name: Build CLI E2E Docker image uses: ./.github/workflows/build-cli-e2e-image.yml - needs: setup_cli_e2e_tests with: - includePolyglotImages: true + includePolyglotImages: false smoke-test: - name: ${{ matrix.shortname }} (${{ inputs.quality || 'staging' }}) - needs: [setup_cli_e2e_tests, build_cli_e2e_image] - if: ${{ fromJson(needs.setup_cli_e2e_tests.outputs.cli_e2e_matrix).include[0] != null }} + name: CLI Smoke Test (${{ inputs.quality || 'dev' }}) + needs: build_cli_e2e_image runs-on: ubuntu-latest - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup_cli_e2e_tests.outputs.cli_e2e_matrix) }} + timeout-minutes: 30 steps: - name: Checkout @@ -96,44 +61,29 @@ jobs: name: cli-e2e-dotnet-image path: ${{ github.workspace }}/cli-e2e-image - - name: Download prebuilt CLI E2E polyglot Docker image - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: cli-e2e-polyglot-image - path: ${{ github.workspace }}/cli-e2e-image - - - name: Download prebuilt CLI E2E Java Docker image - if: ${{ contains(matrix.shortname, 'Java') }} - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: cli-e2e-polyglot-java-image - path: ${{ github.workspace }}/cli-e2e-image - - - name: Load prebuilt CLI E2E Docker images + - name: Load prebuilt CLI E2E Docker image shell: bash run: | set -euo pipefail eng/scripts/load-cli-e2e-images.sh \ --image-dir "${{ github.workspace }}/cli-e2e-image" \ - --require-dotnet true \ - --require-polyglot true \ - --require-java "${{ contains(matrix.shortname, 'Java') }}" + --require-dotnet true - name: Build E2E test project run: dotnet build tests/Aspire.Cli.EndToEnd.Tests/Aspire.Cli.EndToEnd.Tests.csproj - - name: Run CLI E2E tests against daily build + - name: Run smoke tests against daily build env: - ASPIRE_E2E_QUALITY: ${{ inputs.quality || 'staging' }} + ASPIRE_E2E_QUALITY: ${{ inputs.quality || 'dev' }} ASPIRE_E2E_CLI_VERSION_OUTPUT_DIR: ${{ github.workspace }}/testresults/cli-versions run: | dotnet test --project tests/Aspire.Cli.EndToEnd.Tests/Aspire.Cli.EndToEnd.Tests.csproj \ --no-build \ -- \ --report-trx \ - --report-trx-filename "${{ matrix.shortname }}.trx" \ + --report-trx-filename "DailyCliSmoke.trx" \ --results-directory ${{ github.workspace }}/testresults \ - --filter-class "${{ matrix.classname }}" \ + --filter-class "*SmokeTests" \ --filter-not-trait "quarantined=true" \ --filter-not-trait "outerloop=true" \ --hangdump --hangdump-type none --hangdump-timeout 15m @@ -143,7 +93,7 @@ jobs: if: always() uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: - name: smoke-test-results-${{ inputs.quality || 'staging' }}-${{ matrix.shortname }} + name: smoke-test-results-${{ inputs.quality || 'dev' }} path: | testresults/** **/TestResults/**/*.log @@ -306,9 +256,8 @@ jobs: uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 continue-on-error: true with: - pattern: smoke-test-results-${{ inputs.quality || 'staging' }}-* + name: smoke-test-results-${{ inputs.quality || 'dev' }} path: smoke-test-results - merge-multiple: true - name: Create GitHub Issue uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 @@ -319,7 +268,7 @@ jobs: const path = require('node:path'); const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; - const quality = context.payload.inputs?.quality ?? 'staging'; + const quality = context.payload.inputs?.quality ?? 'dev'; const date = new Date().toISOString().split('T')[0]; const cliVersionSummary = getCliVersionSummary(process.env.GITHUB_WORKSPACE, message => core.warning(message)); diff --git a/.github/workflows/validate-published-build.yml b/.github/workflows/validate-published-build.yml new file mode 100644 index 00000000000..e07a2c9edd1 --- /dev/null +++ b/.github/workflows/validate-published-build.yml @@ -0,0 +1,190 @@ +# Validates an Aspire CLI build after it has been published to a public channel. +# +# This workflow is dispatched by the Azure DevOps release build after publishing +# and installer preparation complete. It intentionally runs every CLI E2E test +# class as a separate GitHub Actions job so the shape matches PR validation. +name: Validate Published Build + +on: + workflow_dispatch: + inputs: + quality: + description: 'Install quality to validate (dev, staging, release)' + required: false + default: 'staging' + type: choice + options: + - dev + - staging + - release + +permissions: + contents: read + +jobs: + setup_cli_e2e_tests: + name: Setup CLI E2E test matrix + runs-on: ubuntu-latest + outputs: + cli_e2e_matrix: ${{ steps.filter_cli_e2e.outputs.cli_e2e_matrix }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - uses: ./.github/actions/enumerate-tests + id: generate_tests_matrix + with: + buildArgs: '/p:IncludeCliE2ETests=true /p:SkipTests=false' + + - name: Filter CLI E2E test matrix + id: filter_cli_e2e + shell: pwsh + run: | + $allTests = '${{ steps.generate_tests_matrix.outputs.all_tests }}' | ConvertFrom-Json + $cliE2ETests = @($allTests.include | Where-Object { + $_.projectName -eq 'Aspire.Cli.EndToEnd.Tests' -and $_.type -eq 'class' + }) + + if ($cliE2ETests.Count -eq 0) { + Write-Error "No Aspire.Cli.EndToEnd.Tests class entries were found in the generated test matrix." + exit 1 + } + + $matrix = ConvertTo-Json @{ include = @($cliE2ETests) } -Compress -Depth 10 + "cli_e2e_matrix=$matrix" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + + build_cli_e2e_image: + name: Build CLI E2E Docker image + uses: ./.github/workflows/build-cli-e2e-image.yml + needs: setup_cli_e2e_tests + with: + includePolyglotImages: true + + validate-published-build: + name: ${{ matrix.shortname }} (${{ inputs.quality || 'staging' }}) + needs: [setup_cli_e2e_tests, build_cli_e2e_image] + if: ${{ fromJson(needs.setup_cli_e2e_tests.outputs.cli_e2e_matrix).include[0] != null }} + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.setup_cli_e2e_tests.outputs.cli_e2e_matrix) }} + + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Setup .NET + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 + with: + global-json-file: global.json + + - name: Restore + run: ./restore.sh + + - name: Verify Docker is running + run: docker info + + - name: Download prebuilt CLI E2E Docker image + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: cli-e2e-dotnet-image + path: ${{ github.workspace }}/cli-e2e-image + + - name: Download prebuilt CLI E2E polyglot Docker image + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: cli-e2e-polyglot-image + path: ${{ github.workspace }}/cli-e2e-image + + - name: Download prebuilt CLI E2E Java Docker image + if: ${{ contains(matrix.shortname, 'Java') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: cli-e2e-polyglot-java-image + path: ${{ github.workspace }}/cli-e2e-image + + - name: Load prebuilt CLI E2E Docker images + shell: bash + run: | + set -euo pipefail + eng/scripts/load-cli-e2e-images.sh \ + --image-dir "${{ github.workspace }}/cli-e2e-image" \ + --require-dotnet true \ + --require-polyglot true \ + --require-java "${{ contains(matrix.shortname, 'Java') }}" + + - name: Build E2E test project + run: dotnet build tests/Aspire.Cli.EndToEnd.Tests/Aspire.Cli.EndToEnd.Tests.csproj + + - name: Run CLI E2E tests against published build + env: + ASPIRE_E2E_QUALITY: ${{ inputs.quality || 'staging' }} + ASPIRE_E2E_CLI_VERSION_OUTPUT_DIR: ${{ github.workspace }}/testresults/cli-versions + run: | + dotnet test --project tests/Aspire.Cli.EndToEnd.Tests/Aspire.Cli.EndToEnd.Tests.csproj \ + --no-build \ + -- \ + --report-trx \ + --report-trx-filename "${{ matrix.shortname }}.trx" \ + --results-directory ${{ github.workspace }}/testresults \ + --filter-class "${{ matrix.classname }}" \ + --filter-not-trait "quarantined=true" \ + --filter-not-trait "outerloop=true" \ + --hangdump --hangdump-type none --hangdump-timeout 15m + + - name: Upload logs and test results + id: upload-logs + if: always() + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: validate-published-build-${{ inputs.quality || 'staging' }}-${{ matrix.shortname }} + path: | + testresults/** + **/TestResults/**/*.log + if-no-files-found: ignore + + - name: Generate test results summary + if: always() + continue-on-error: true + env: + TEST_RESULTS_ARTIFACT_URL: ${{ steps.upload-logs.outputs.artifact-url }} + run: | + if [ -d "${{ github.workspace }}/testresults" ]; then + summary_args=( + run + --project + "${{ github.workspace }}/tools/GenerateTestSummary/GenerateTestSummary.csproj" + -- + "${{ github.workspace }}/testresults" + ) + + artifact_url="${TEST_RESULTS_ARTIFACT_URL:-}" + if [ -n "$artifact_url" ]; then + summary_args+=("-u" "$artifact_url") + fi + + dotnet "${summary_args[@]}" + fi + + - name: Add Aspire CLI version summary + if: always() + continue-on-error: true + run: | + versions_dir="${{ github.workspace }}/testresults/cli-versions" + + { + echo "" + echo "## Aspire CLI versions installed" + echo "" + + if compgen -G "$versions_dir/*.env" > /dev/null; then + for version_file in "$versions_dir"/*.env; do + echo "- \`$(basename "$version_file" .env)\`" + sed 's/^/ - /' "$version_file" + done + else + echo "No Aspire CLI version records were produced." + fi + } >> "$GITHUB_STEP_SUMMARY" diff --git a/eng/pipelines/azure-pipelines.yml b/eng/pipelines/azure-pipelines.yml index 9184a94e07a..76428a85b76 100644 --- a/eng/pipelines/azure-pipelines.yml +++ b/eng/pipelines/azure-pipelines.yml @@ -55,6 +55,11 @@ variables: - ${{ if eq(parameters.publishVSCodeExtension, true) }}: - group: Aspire-Release-Secrets + # Contains the aspire-repo-bot GitHub App credentials used to dispatch the + # post-publish GitHub Actions validation workflow. Keep this out of PR builds. + - ${{ if notin(variables['Build.Reason'], 'PullRequest') }}: + - group: Aspire-Secrets + - name: _BuildConfig value: Release - name: Build.Arcade.ArtifactsPath @@ -527,3 +532,58 @@ extends: version: $(aspireVersion) channel: $(installerChannel) archiveRoot: $(Pipeline.Workspace)/native-archives + + - job: ValidatePublishedBuild + displayName: Validate Published Build + dependsOn: + - WinGet + - Homebrew + condition: | + and( + succeeded(), + eq(lower(variables['_PackagesPublished']), 'true') + ) + timeoutInMinutes: 180 + pool: + name: NetCore1ESPool-Internal + image: windows.vs2026preview.scout.amd64 + os: windows + steps: + - checkout: self + displayName: Checkout repo + fetchDepth: 1 + + - pwsh: | + $ErrorActionPreference = 'Stop' + + $installerChannel = '$(installerChannel)' + $quality = if ($installerChannel -eq 'stable') { 'release' } else { 'staging' } + + Write-Host "Installer channel: $installerChannel" + Write-Host "Validation quality: $quality" + + $inputs = @{ + quality = $quality + } + + & "$(Build.SourcesDirectory)/eng/pipelines/scripts/dispatch-release-github-tasks.ps1" ` + -AppId "$env:ASPIRE_BOT_APP_ID" ` + -PrivateKeyPem "$env:ASPIRE_BOT_PRIVATE_KEY" ` + -Owner 'microsoft' ` + -Repo 'aspire' ` + -WorkflowFile 'validate-published-build.yml' ` + -Ref 'main' ` + -Inputs $inputs ` + -PollTimeoutMinutes 180 + displayName: Dispatch validate-published-build workflow + env: + ASPIRE_BOT_APP_ID: $(aspire-bot-app-id) + ASPIRE_BOT_PRIVATE_KEY: $(aspire-bot-private-key) + + - powershell: | + Write-Host "" + Write-Host "Dispatched run: $env:DISPATCHED_RUN_URL" + displayName: Print dispatched run URL + condition: always() + env: + DISPATCHED_RUN_URL: $(DispatchedRunUrl) From 9b7a4375f168f26c63c7943ec2f43274e574f5f5 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Wed, 27 May 2026 03:08:38 -0400 Subject: [PATCH 4/4] Keep published build validation GitHub-only Move the published-build validation branch back to a GitHub-only change by removing the Azure DevOps dispatch wiring from this branch. The new workflow remains manually dispatchable and validates an exact published Aspire CLI version, with the CLI E2E tests split by class to match PR validation shape. Harden the workflow based on self-review by avoiding direct template expansion in shell scripts, disabling checkout credential persistence during matrix setup, and preserving the MTP no-tests exit-code handling used by the main test runner. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../workflows/validate-published-build.yml | 19 ++++-- eng/pipelines/azure-pipelines.yml | 60 ------------------- 2 files changed, 15 insertions(+), 64 deletions(-) diff --git a/.github/workflows/validate-published-build.yml b/.github/workflows/validate-published-build.yml index e07a2c9edd1..8b6384c51ca 100644 --- a/.github/workflows/validate-published-build.yml +++ b/.github/workflows/validate-published-build.yml @@ -17,6 +17,10 @@ on: - dev - staging - release + version: + description: 'Exact Aspire CLI version to validate' + required: true + type: string permissions: contents: read @@ -29,6 +33,8 @@ jobs: cli_e2e_matrix: ${{ steps.filter_cli_e2e.outputs.cli_e2e_matrix }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: ./.github/actions/enumerate-tests id: generate_tests_matrix @@ -38,8 +44,10 @@ jobs: - name: Filter CLI E2E test matrix id: filter_cli_e2e shell: pwsh + env: + ALL_TESTS: ${{ steps.generate_tests_matrix.outputs.all_tests }} run: | - $allTests = '${{ steps.generate_tests_matrix.outputs.all_tests }}' | ConvertFrom-Json + $allTests = $env:ALL_TESTS | ConvertFrom-Json $cliE2ETests = @($allTests.include | Where-Object { $_.projectName -eq 'Aspire.Cli.EndToEnd.Tests' -and $_.type -eq 'class' }) @@ -120,16 +128,19 @@ jobs: - name: Run CLI E2E tests against published build env: - ASPIRE_E2E_QUALITY: ${{ inputs.quality || 'staging' }} + ASPIRE_E2E_VERSION: ${{ inputs.version }} ASPIRE_E2E_CLI_VERSION_OUTPUT_DIR: ${{ github.workspace }}/testresults/cli-versions + TEST_CLASS: ${{ matrix.classname }} + TRX_FILE_NAME: ${{ matrix.shortname }}.trx run: | dotnet test --project tests/Aspire.Cli.EndToEnd.Tests/Aspire.Cli.EndToEnd.Tests.csproj \ --no-build \ -- \ + --ignore-exit-code 8 \ --report-trx \ - --report-trx-filename "${{ matrix.shortname }}.trx" \ + --report-trx-filename "$TRX_FILE_NAME" \ --results-directory ${{ github.workspace }}/testresults \ - --filter-class "${{ matrix.classname }}" \ + --filter-class "$TEST_CLASS" \ --filter-not-trait "quarantined=true" \ --filter-not-trait "outerloop=true" \ --hangdump --hangdump-type none --hangdump-timeout 15m diff --git a/eng/pipelines/azure-pipelines.yml b/eng/pipelines/azure-pipelines.yml index 76428a85b76..9184a94e07a 100644 --- a/eng/pipelines/azure-pipelines.yml +++ b/eng/pipelines/azure-pipelines.yml @@ -55,11 +55,6 @@ variables: - ${{ if eq(parameters.publishVSCodeExtension, true) }}: - group: Aspire-Release-Secrets - # Contains the aspire-repo-bot GitHub App credentials used to dispatch the - # post-publish GitHub Actions validation workflow. Keep this out of PR builds. - - ${{ if notin(variables['Build.Reason'], 'PullRequest') }}: - - group: Aspire-Secrets - - name: _BuildConfig value: Release - name: Build.Arcade.ArtifactsPath @@ -532,58 +527,3 @@ extends: version: $(aspireVersion) channel: $(installerChannel) archiveRoot: $(Pipeline.Workspace)/native-archives - - - job: ValidatePublishedBuild - displayName: Validate Published Build - dependsOn: - - WinGet - - Homebrew - condition: | - and( - succeeded(), - eq(lower(variables['_PackagesPublished']), 'true') - ) - timeoutInMinutes: 180 - pool: - name: NetCore1ESPool-Internal - image: windows.vs2026preview.scout.amd64 - os: windows - steps: - - checkout: self - displayName: Checkout repo - fetchDepth: 1 - - - pwsh: | - $ErrorActionPreference = 'Stop' - - $installerChannel = '$(installerChannel)' - $quality = if ($installerChannel -eq 'stable') { 'release' } else { 'staging' } - - Write-Host "Installer channel: $installerChannel" - Write-Host "Validation quality: $quality" - - $inputs = @{ - quality = $quality - } - - & "$(Build.SourcesDirectory)/eng/pipelines/scripts/dispatch-release-github-tasks.ps1" ` - -AppId "$env:ASPIRE_BOT_APP_ID" ` - -PrivateKeyPem "$env:ASPIRE_BOT_PRIVATE_KEY" ` - -Owner 'microsoft' ` - -Repo 'aspire' ` - -WorkflowFile 'validate-published-build.yml' ` - -Ref 'main' ` - -Inputs $inputs ` - -PollTimeoutMinutes 180 - displayName: Dispatch validate-published-build workflow - env: - ASPIRE_BOT_APP_ID: $(aspire-bot-app-id) - ASPIRE_BOT_PRIVATE_KEY: $(aspire-bot-private-key) - - - powershell: | - Write-Host "" - Write-Host "Dispatched run: $env:DISPATCHED_RUN_URL" - displayName: Print dispatched run URL - condition: always() - env: - DISPATCHED_RUN_URL: $(DispatchedRunUrl)