diff --git a/.github/workflows/validate-published-build.yml b/.github/workflows/validate-published-build.yml new file mode 100644 index 00000000000..8b6384c51ca --- /dev/null +++ b/.github/workflows/validate-published-build.yml @@ -0,0 +1,201 @@ +# 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 + version: + description: 'Exact Aspire CLI version to validate' + required: true + type: string + +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 + with: + persist-credentials: false + + - 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 + env: + ALL_TESTS: ${{ steps.generate_tests_matrix.outputs.all_tests }} + run: | + $allTests = $env: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_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 "$TRX_FILE_NAME" \ + --results-directory ${{ github.workspace }}/testresults \ + --filter-class "$TEST_CLASS" \ + --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"