Python: Samples: deterministic action-boundary validation middleware (#5366) #22390
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # | |
| # This workflow will build all .slnx files in the dotnet folder, and run all unit tests and integration tests using dotnet docker containers, | |
| # each targeting a single version of the dotnet SDK. | |
| # | |
| name: dotnet-build-and-test | |
| on: | |
| workflow_dispatch: | |
| pull_request: | |
| branches: ["main", "feature*"] | |
| merge_group: | |
| branches: ["main", "feature*"] | |
| push: | |
| branches: ["main", "feature*"] | |
| schedule: | |
| - cron: "0 0 * * *" # Run at midnight UTC daily | |
| env: | |
| COVERAGE_THRESHOLD: 80 | |
| COVERAGE_FRAMEWORK: net10.0 # framework target for which we run/report code coverage | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| id-token: "write" | |
| jobs: | |
| paths-filter: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| outputs: | |
| dotnetChanges: ${{ steps.filter.outputs.dotnet }} | |
| cosmosDbChanges: ${{ steps.filter.outputs.cosmosdb }} | |
| foundryHostingChanges: ${{ steps.filter.outputs.foundryHosting }} | |
| functionsChanged: ${{ steps.filter.outputs.functions }} | |
| coreChanged: ${{ steps.filter.outputs.core }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - uses: dorny/paths-filter@d1c1ffe0248fe513906c8e24db8ea791d46f8590 # v3 | |
| id: filter | |
| with: | |
| filters: | | |
| dotnet: | |
| - 'dotnet/**' | |
| cosmosdb: | |
| - 'dotnet/src/Microsoft.Agents.AI.CosmosNoSql/**' | |
| # The Foundry hosted-agent IT is costly (builds a container, pushes to ACR, | |
| # provisions live agents). Only run it when the project under test, its | |
| # dependency chain, the test container, the test fixture, or their tooling | |
| # changed. Keep this list in sync with $hashedDirs in scripts/it-build-image.ps1. | |
| foundryHosting: | |
| - 'dotnet/src/Microsoft.Agents.AI.Foundry.Hosting/**' | |
| - 'dotnet/src/Microsoft.Agents.AI.Foundry/**' | |
| - 'dotnet/src/Microsoft.Agents.AI/**' | |
| - 'dotnet/src/Microsoft.Agents.AI.Abstractions/**' | |
| - 'dotnet/src/Microsoft.Agents.AI.Workflows/**' | |
| - 'dotnet/tests/Foundry.Hosting.IntegrationTests/**' | |
| - 'dotnet/tests/Foundry.Hosting.IntegrationTests.TestContainer/**' | |
| - 'dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-AzureSearchRag/**' | |
| - 'dotnet/Directory.Packages.props' | |
| - 'dotnet/tests/Foundry.Hosting.IntegrationTests/scripts/it-build-image.ps1' | |
| - '.github/workflows/dotnet-build-and-test.yml' | |
| functions: | |
| - 'dotnet/src/Microsoft.Agents.AI.DurableTask/**' | |
| - 'dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/**' | |
| - 'dotnet/tests/Microsoft.Agents.AI.DurableTask.IntegrationTests/**' | |
| - 'dotnet/tests/Microsoft.Agents.AI.Hosting.AzureFunctions.IntegrationTests/**' | |
| - '.github/actions/azure-functions-integration-setup/**' | |
| - '.github/workflows/dotnet-build-and-test.yml' | |
| core: | |
| - 'dotnet/src/Microsoft.Agents.AI/**' | |
| - 'dotnet/src/Microsoft.Agents.AI.Abstractions/**' | |
| - 'dotnet/src/Microsoft.Agents.AI.OpenAI/**' | |
| - 'dotnet/src/Microsoft.Agents.AI.Workflows/**' | |
| - 'dotnet/src/Microsoft.Agents.AI.Workflows.Generators/**' | |
| - 'dotnet/eng/scripts/New-FilteredSolution.ps1' | |
| - 'dotnet/tests/Directory.Build.props' | |
| - 'dotnet/Directory.Packages.props' | |
| - 'dotnet/global.json' | |
| - '.github/workflows/dotnet-build-and-test.yml' | |
| # run only if 'dotnet' files were changed | |
| - name: dotnet tests | |
| if: steps.filter.outputs.dotnet == 'true' | |
| run: echo "Dotnet file" | |
| - name: dotnet CosmosDB tests | |
| if: steps.filter.outputs.cosmosdb == 'true' | |
| run: echo "Dotnet CosmosDB changes" | |
| # run only if not 'dotnet' files were changed | |
| - name: not dotnet tests | |
| if: steps.filter.outputs.dotnet != 'true' | |
| run: echo "NOT dotnet file" | |
| # Build the full solution (including samples) on all TFMs. No tests. | |
| dotnet-build: | |
| needs: paths-filter | |
| if: needs.paths-filter.outputs.dotnetChanges == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { targetFramework: "net10.0", os: "ubuntu-latest", configuration: Release } | |
| - { targetFramework: "net9.0", os: "windows-latest", configuration: Debug } | |
| - { targetFramework: "net8.0", os: "ubuntu-latest", configuration: Release } | |
| - { targetFramework: "net472", os: "windows-latest", configuration: Release } | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| sparse-checkout: | | |
| . | |
| .github | |
| dotnet | |
| python | |
| declarative-agents | |
| - name: Free runner disk space | |
| uses: ./.github/actions/free-runner-disk-space | |
| - name: Setup dotnet | |
| uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 | |
| with: | |
| global-json-file: ${{ github.workspace }}/dotnet/global.json | |
| - name: Build dotnet solutions | |
| shell: bash | |
| run: | | |
| export SOLUTIONS=$(find ./dotnet/ -type f -name "*.slnx" | tr '\n' ' ') | |
| for solution in $SOLUTIONS; do | |
| dotnet build $solution -c ${{ matrix.configuration }} --warnaserror | |
| done | |
| - name: Package install check | |
| shell: bash | |
| # All frameworks are only built for the release configuration, so we only run this step for the release configuration | |
| # and dotnet new doesn't support net472 | |
| if: matrix.configuration == 'Release' && matrix.targetFramework != 'net472' | |
| run: | | |
| TEMP_DIR=$(mktemp -d) | |
| export SOLUTIONS=$(find ./dotnet/ -type f -name "*.slnx" | tr '\n' ' ') | |
| for solution in $SOLUTIONS; do | |
| dotnet pack $solution /property:TargetFrameworks=${{ matrix.targetFramework }} -c ${{ matrix.configuration }} --no-build --no-restore --output "$TEMP_DIR/artifacts" | |
| done | |
| pushd "$TEMP_DIR" | |
| # Create a new console app to test the package installation | |
| dotnet new console -f ${{ matrix.targetFramework }} --name packcheck --output consoleapp | |
| # Create minimal nuget.config and use only dotnet nuget commands | |
| echo '<?xml version="1.0" encoding="utf-8"?><configuration><packageSources><clear /></packageSources></configuration>' > consoleapp/nuget.config | |
| # Add sources with local first using dotnet nuget commands | |
| dotnet nuget add source ../artifacts --name local --configfile consoleapp/nuget.config | |
| dotnet nuget add source https://api.nuget.org/v3/index.json --name nuget.org --configfile consoleapp/nuget.config | |
| # Change to project directory to ensure local nuget.config is used | |
| pushd consoleapp | |
| dotnet add packcheck.csproj package Microsoft.Agents.AI --prerelease | |
| dotnet build -f ${{ matrix.targetFramework }} -c ${{ matrix.configuration }} packcheck.csproj | |
| # Clean up | |
| popd | |
| popd | |
| rm -rf "$TEMP_DIR" | |
| # Build src+tests only (no samples) for a single TFM and run tests. | |
| dotnet-test: | |
| needs: paths-filter | |
| if: needs.paths-filter.outputs.dotnetChanges == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { targetFramework: "net10.0", os: "ubuntu-latest", configuration: Release, integration-tests: true, environment: "integration" } | |
| - { targetFramework: "net472", os: "windows-latest", configuration: Release, integration-tests: true, environment: "integration" } | |
| runs-on: ${{ matrix.os }} | |
| environment: ${{ matrix.environment }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| sparse-checkout: | | |
| . | |
| .github | |
| dotnet | |
| python | |
| declarative-agents | |
| - name: Free runner disk space | |
| uses: ./.github/actions/free-runner-disk-space | |
| # Start Cosmos DB Emulator for all integration tests and only for unit tests when CosmosDB changes happened) | |
| - name: Start Azure Cosmos DB Emulator | |
| if: ${{ runner.os == 'Windows' && (needs.paths-filter.outputs.cosmosDbChanges == 'true' || (github.event_name != 'pull_request' && matrix.integration-tests)) }} | |
| shell: pwsh | |
| run: | | |
| Write-Host "Launching Azure Cosmos DB Emulator" | |
| Import-Module "$env:ProgramFiles\Azure Cosmos DB Emulator\PSModules\Microsoft.Azure.CosmosDB.Emulator" | |
| Start-CosmosDbEmulator -NoUI -Key "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==" | |
| echo "COSMOSDB_EMULATOR_AVAILABLE=true" >> $env:GITHUB_ENV | |
| - name: Setup dotnet | |
| uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 | |
| with: | |
| global-json-file: ${{ github.workspace }}/dotnet/global.json | |
| - name: Generate test solution (no samples) | |
| shell: pwsh | |
| run: | | |
| ./dotnet/eng/scripts/New-FilteredSolution.ps1 ` | |
| -Solution dotnet/agent-framework-dotnet.slnx ` | |
| -TargetFramework ${{ matrix.targetFramework }} ` | |
| -Configuration ${{ matrix.configuration }} ` | |
| -ExcludeSamples ` | |
| -OutputPath dotnet/filtered.slnx ` | |
| -Verbose | |
| - name: Build src and tests | |
| shell: bash | |
| run: dotnet build dotnet/filtered.slnx -c ${{ matrix.configuration }} -f ${{ matrix.targetFramework }} --warnaserror | |
| - name: Generate test-type filtered solutions | |
| shell: pwsh | |
| run: | | |
| $commonArgs = @{ | |
| Solution = "dotnet/filtered.slnx" | |
| TargetFramework = "${{ matrix.targetFramework }}" | |
| Configuration = "${{ matrix.configuration }}" | |
| Verbose = $true | |
| } | |
| ./dotnet/eng/scripts/New-FilteredSolution.ps1 @commonArgs ` | |
| -TestProjectNameIncludeFilter "*UnitTests*" ` | |
| -OutputPath dotnet/filtered-unit.slnx | |
| ./dotnet/eng/scripts/New-FilteredSolution.ps1 @commonArgs ` | |
| -TestProjectNameIncludeFilter "*IntegrationTests*" ` | |
| -TestProjectNameExcludeFilter "*DurableTask.IntegrationTests*","*AzureFunctions.IntegrationTests*" ` | |
| -OutputPath dotnet/filtered-integration.slnx | |
| - name: Run Unit Tests | |
| shell: pwsh | |
| working-directory: dotnet | |
| run: | | |
| $coverageSettings = Join-Path $PWD "tests/coverage.runsettings" | |
| $coverageArgs = @() | |
| if ("${{ matrix.targetFramework }}" -eq "${{ env.COVERAGE_FRAMEWORK }}") { | |
| $coverageArgs = @( | |
| "--coverage", | |
| "--coverage-output-format", "cobertura", | |
| "--coverage-settings", $coverageSettings, | |
| "--results-directory", "../TestResults/Coverage/" | |
| ) | |
| } | |
| dotnet test --solution ./filtered-unit.slnx ` | |
| -f ${{ matrix.targetFramework }} ` | |
| -c ${{ matrix.configuration }} ` | |
| --no-build -v Normal ` | |
| --report-xunit-trx ` | |
| --ignore-exit-code 8 ` | |
| @coverageArgs | |
| env: | |
| # Cosmos DB Emulator connection settings | |
| COSMOSDB_ENDPOINT: https://localhost:8081 | |
| COSMOSDB_KEY: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw== | |
| - name: Log event name and matrix integration-tests | |
| shell: bash | |
| run: echo "github.event_name:${{ github.event_name }} matrix.integration-tests:${{ matrix.integration-tests }} github.event.action:${{ github.event.action }} github.event.pull_request.merged:${{ github.event.pull_request.merged }}" | |
| - name: Azure CLI Login | |
| if: github.event_name != 'pull_request' && matrix.integration-tests | |
| uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2 | |
| with: | |
| client-id: ${{ secrets.AZURE_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} | |
| - name: Run Integration Tests | |
| shell: pwsh | |
| working-directory: dotnet | |
| if: github.event_name != 'pull_request' && matrix.integration-tests | |
| run: | | |
| dotnet test --solution ./filtered-integration.slnx ` | |
| -f ${{ matrix.targetFramework }} ` | |
| -c ${{ matrix.configuration }} ` | |
| --no-build -v Normal ` | |
| --report-xunit-trx ` | |
| --report-junit ` | |
| --results-directory ../IntegrationTestResults/ ` | |
| --ignore-exit-code 8 ` | |
| --filter-not-trait "Category=IntegrationDisabled" ` | |
| --filter-not-trait "Category=FoundryHostedAgents" ` | |
| --parallel-algorithm aggressive ` | |
| --max-threads 2.0x | |
| env: | |
| # Cosmos DB Emulator connection settings | |
| COSMOSDB_ENDPOINT: https://localhost:8081 | |
| COSMOSDB_KEY: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw== | |
| # OpenAI Models | |
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | |
| OPENAI_CHAT_MODEL_NAME: ${{ vars.OPENAI_CHAT_MODEL_NAME }} | |
| OPENAI_REASONING_MODEL_NAME: ${{ vars.OPENAI_REASONING_MODEL_NAME }} | |
| # Azure OpenAI Models | |
| AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME }} | |
| AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME }} | |
| AZURE_OPENAI_ENDPOINT: ${{ vars.AZURE_OPENAI_ENDPOINT }} | |
| # Azure AI Foundry | |
| AZURE_AI_PROJECT_ENDPOINT: ${{ vars.AZURE_AI_PROJECT_ENDPOINT }} | |
| AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZURE_AI_MODEL_DEPLOYMENT_NAME }} | |
| AZURE_AI_BING_CONNECTION_ID: ${{ vars.AZURE_AI_BING_CONNECTION_ID }} | |
| # Anthropic Models | |
| # Disable Anthropic tests by not providing environment vars until 404 failure is resolved | |
| # ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| # ANTHROPIC_CHAT_MODEL_NAME: ${{ vars.ANTHROPIC_CHAT_MODEL_NAME }} | |
| # ANTHROPIC_REASONING_MODEL_NAME: ${{ vars.ANTHROPIC_REASONING_MODEL_NAME }} | |
| # Generate test reports and check coverage | |
| - name: Generate test reports | |
| if: matrix.targetFramework == env.COVERAGE_FRAMEWORK | |
| uses: danielpalme/ReportGenerator-GitHub-Action@2a82782178b2816d9d6960a7345fdd164791b323 # 5.5.3 | |
| with: | |
| reports: "./TestResults/Coverage/**/*.cobertura.xml" | |
| targetdir: "./TestResults/Reports" | |
| reporttypes: "HtmlInline;JsonSummary" | |
| - name: Upload coverage report artifact | |
| if: matrix.targetFramework == env.COVERAGE_FRAMEWORK | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: CoverageReport-${{ matrix.os }}-${{ matrix.targetFramework }}-${{ matrix.configuration }} # Artifact name | |
| path: ./TestResults/Reports # Directory containing files to upload | |
| - name: Check coverage | |
| if: matrix.targetFramework == env.COVERAGE_FRAMEWORK | |
| shell: pwsh | |
| run: ./dotnet/eng/scripts/dotnet-check-coverage.ps1 -JsonReportPath "TestResults/Reports/Summary.json" -CoverageThreshold $env:COVERAGE_THRESHOLD | |
| - name: Upload integration test results | |
| if: always() && github.event_name != 'pull_request' && matrix.integration-tests | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: dotnet-test-results-${{ matrix.targetFramework }}-${{ matrix.os }} | |
| path: IntegrationTestResults/**/*.junit | |
| if-no-files-found: ignore | |
| # The Foundry hosted-agent IT is costly (it builds a container, pushes to ACR, and provisions | |
| # live agents on a separate Foundry project). Running it in its own job keeps the overall | |
| # workflow time roughly flat: it executes in parallel to dotnet-build and dotnet-test and is | |
| # gated on paths-filter.outputs.foundryHostingChanges so unrelated edits skip the work. | |
| dotnet-foundry-hosted-it: | |
| needs: paths-filter | |
| if: github.event_name != 'pull_request' && needs.paths-filter.outputs.foundryHostingChanges == 'true' | |
| runs-on: ubuntu-latest | |
| environment: integration | |
| env: | |
| configuration: Release | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| sparse-checkout: | | |
| . | |
| .github | |
| dotnet | |
| python | |
| - name: Free runner disk space | |
| uses: ./.github/actions/free-runner-disk-space | |
| - name: Setup dotnet | |
| uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 | |
| with: | |
| global-json-file: ${{ github.workspace }}/dotnet/global.json | |
| # Build the test csproj directly instead of a filtered slnx + -f override. | |
| # The test project pins TargetFrameworks=net10.0 and its ProjectReference closure | |
| # gives MSBuild a single-rooted graph, so each multi-targeted dependency is invoked | |
| # exactly once for net10.0. This avoids the MSB3026/MSB3491/MSB4018/MSB3883 file-lock | |
| # collisions caused by parallel inner-builds racing on shared bin/obj output paths | |
| # under the previous slnx + global TFM override approach. | |
| - name: Build Foundry hosted IT (and its deps) | |
| shell: bash | |
| run: dotnet build dotnet/tests/Foundry.Hosting.IntegrationTests/Foundry.Hosting.IntegrationTests.csproj -c "$configuration" --warnaserror | |
| - name: Azure CLI Login | |
| uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2 | |
| with: | |
| client-id: ${{ secrets.AZURE_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} | |
| # We rebuild and push the test container image on every IT run so framework code changes | |
| # are picked up; the image tag is content-hashed across the test container source AND its | |
| # framework project references, so identical content is a no-op push. | |
| # | |
| # The script always passes --no-dependencies to dotnet publish so publish never re-touches | |
| # the framework lib DLLs the prior "Build Foundry hosted IT (and its deps)" step produced. | |
| # This structurally eliminates the MSB3026 collision that VBCSCompiler from the prebuild | |
| # would otherwise cause by holding file handles to those DLLs. Do not remove the prebuild | |
| # step: the subsequent `dotnet test --no-build` step and the publish's ProjectReference | |
| # resolution both depend on the prebuilt outputs being present. | |
| - name: Build and push Foundry Hosted Agents test container | |
| id: build-foundry-hosted-image | |
| shell: pwsh | |
| working-directory: ${{ github.workspace }} | |
| run: | | |
| $registry = "${{ vars.IT_HOSTED_AGENT_REGISTRY }}" | |
| if ([string]::IsNullOrWhiteSpace($registry)) { | |
| throw "IT_HOSTED_AGENT_REGISTRY not set in the integration environment." | |
| } | |
| & "${{ github.workspace }}/dotnet/tests/Foundry.Hosting.IntegrationTests/scripts/it-build-image.ps1" -Registry $registry | Tee-Object -FilePath $env:GITHUB_ENV -Append | |
| - name: Run Foundry Hosted Agents Integration Tests | |
| shell: pwsh | |
| working-directory: dotnet | |
| run: | | |
| dotnet test --project tests/Foundry.Hosting.IntegrationTests/Foundry.Hosting.IntegrationTests.csproj ` | |
| -c $env:configuration ` | |
| --no-build -v Normal ` | |
| --report-xunit-trx ` | |
| --ignore-exit-code 8 ` | |
| --filter-trait "Category=FoundryHostedAgents" | |
| env: | |
| AZURE_AI_PROJECT_ENDPOINT: ${{ vars.IT_HOSTED_AGENT_PROJECT_ENDPOINT }} | |
| AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.IT_HOSTED_AGENT_MODEL_DEPLOYMENT_NAME }} | |
| # Azure AI Search (for the azure-search-rag scenario). Reuses the integration | |
| # environment secrets shared with python-sample-validation.yml. The index is | |
| # provisioned out of band; see dotnet/tests/Foundry.Hosting.IntegrationTests/README.md | |
| # for the required schema and seed content. | |
| AZURE_SEARCH_ENDPOINT: ${{ secrets.AZURE_SEARCH_ENDPOINT }} | |
| AZURE_SEARCH_INDEX_NAME: ${{ secrets.AZURE_SEARCH_INDEX_NAME }} | |
| # IT_HOSTED_AGENT_IMAGE was exported into $GITHUB_ENV by the previous step. | |
| # DurableTask and AzureFunctions integration tests (ubuntu/net10.0 only). | |
| # Split from main dotnet-test job for path-based filtering and parallelism. | |
| dotnet-test-functions: | |
| needs: [paths-filter] | |
| if: > | |
| github.event_name != 'pull_request' && | |
| (needs.paths-filter.outputs.functionsChanged == 'true' || | |
| needs.paths-filter.outputs.coreChanged == 'true' || | |
| github.event_name == 'schedule' || | |
| github.event_name == 'workflow_dispatch') | |
| runs-on: ubuntu-latest | |
| environment: integration | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| sparse-checkout: | | |
| . | |
| .github | |
| dotnet | |
| python | |
| declarative-agents | |
| - name: Free runner disk space | |
| uses: ./.github/actions/free-runner-disk-space | |
| - name: Setup dotnet | |
| uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 | |
| with: | |
| global-json-file: ${{ github.workspace }}/dotnet/global.json | |
| - name: Build functions integration test projects | |
| shell: bash | |
| working-directory: dotnet | |
| run: | | |
| dotnet build ./tests/Microsoft.Agents.AI.DurableTask.IntegrationTests -c Release -f net10.0 --warnaserror | |
| dotnet build ./tests/Microsoft.Agents.AI.Hosting.AzureFunctions.IntegrationTests -c Release -f net10.0 --warnaserror | |
| - name: Azure CLI Login | |
| uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2 | |
| with: | |
| client-id: ${{ secrets.AZURE_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} | |
| - name: Set up Durable Task and Azure Functions Integration Test Emulators | |
| uses: ./.github/actions/azure-functions-integration-setup | |
| id: azure-functions-setup | |
| - name: Run Functions Integration Tests | |
| shell: pwsh | |
| working-directory: dotnet | |
| run: | | |
| # Run DurableTask integration tests | |
| dotnet test ` | |
| --project ./tests/Microsoft.Agents.AI.DurableTask.IntegrationTests ` | |
| -f net10.0 ` | |
| -c Release ` | |
| --no-build -v Normal ` | |
| --report-xunit-trx ` | |
| --report-junit ` | |
| --results-directory ../IntegrationTestResults/ ` | |
| --ignore-exit-code 8 ` | |
| --filter-not-trait "Category=IntegrationDisabled" ` | |
| --parallel-algorithm aggressive ` | |
| --max-threads 2.0x | |
| # Run AzureFunctions integration tests | |
| dotnet test ` | |
| --project ./tests/Microsoft.Agents.AI.Hosting.AzureFunctions.IntegrationTests ` | |
| -f net10.0 ` | |
| -c Release ` | |
| --no-build -v Normal ` | |
| --report-xunit-trx ` | |
| --report-junit ` | |
| --results-directory ../IntegrationTestResults/ ` | |
| --ignore-exit-code 8 ` | |
| --filter-not-trait "Category=IntegrationDisabled" ` | |
| --parallel-algorithm aggressive ` | |
| --max-threads 2.0x | |
| env: | |
| # OpenAI Models | |
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | |
| OPENAI_CHAT_MODEL_NAME: ${{ vars.OPENAI_CHAT_MODEL_NAME }} | |
| OPENAI_REASONING_MODEL_NAME: ${{ vars.OPENAI_REASONING_MODEL_NAME }} | |
| # Azure OpenAI Models | |
| AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME }} | |
| AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME }} | |
| AZURE_OPENAI_ENDPOINT: ${{ vars.AZURE_OPENAI_ENDPOINT }} | |
| # Azure AI Foundry | |
| AZURE_AI_PROJECT_ENDPOINT: ${{ vars.AZURE_AI_PROJECT_ENDPOINT }} | |
| AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZURE_AI_MODEL_DEPLOYMENT_NAME }} | |
| AZURE_AI_BING_CONNECTION_ID: ${{ vars.AZURE_AI_BING_CONNECTION_ID }} | |
| - name: Upload functions test results | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: dotnet-test-results-functions-net10.0-ubuntu-latest | |
| path: IntegrationTestResults/**/*.junit | |
| if-no-files-found: ignore | |
| # This final job is required to satisfy the merge queue. It must only run (or succeed) if no tests failed | |
| dotnet-build-and-test-check: | |
| if: always() | |
| runs-on: ubuntu-latest | |
| needs: [dotnet-build, dotnet-test, dotnet-foundry-hosted-it, dotnet-test-functions] | |
| steps: | |
| - name: Get Date | |
| shell: bash | |
| run: | | |
| echo "date=$(date +'%m/%d/%Y %H:%M:%S')" >> "$GITHUB_ENV" | |
| - name: Run Type is Daily | |
| if: ${{ github.event_name == 'schedule' }} | |
| shell: bash | |
| run: | | |
| echo "run_type=Daily" >> "$GITHUB_ENV" | |
| - name: Run Type is Manual | |
| if: ${{ github.event_name == 'workflow_dispatch' }} | |
| shell: bash | |
| run: | | |
| echo "run_type=Manual" >> "$GITHUB_ENV" | |
| - name: Run Type is ${{ github.event_name }} | |
| if: ${{ github.event_name != 'schedule' && github.event_name != 'workflow_dispatch'}} | |
| shell: bash | |
| run: | | |
| echo "run_type=${{ github.event_name }}" >> "$GITHUB_ENV" | |
| - name: Fail workflow if tests failed | |
| id: check_tests_failed | |
| if: contains(join(needs.*.result, ','), 'failure') | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 | |
| with: | |
| script: core.setFailed('Integration Tests Failed!') | |
| - name: Fail workflow if tests cancelled | |
| id: check_tests_cancelled | |
| if: contains(join(needs.*.result, ','), 'cancelled') | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 | |
| with: | |
| script: core.setFailed('Integration Tests Cancelled!') | |
| # Integration test trend report (aggregates JUnit XML results from dotnet test jobs) | |
| dotnet-integration-test-report: | |
| name: Integration Test Report | |
| if: > | |
| always() && | |
| github.event_name != 'pull_request' && | |
| (contains(join(needs.*.result, ','), 'success') || | |
| contains(join(needs.*.result, ','), 'failure')) | |
| needs: [dotnet-test, dotnet-test-functions] | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: python | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| persist-credentials: false | |
| sparse-checkout: | | |
| .github/actions/python-setup | |
| python | |
| - name: Set up python and install the project | |
| uses: ./.github/actions/python-setup | |
| with: | |
| python-version: "3.13" | |
| os: ${{ runner.os }} | |
| - name: Download all test results from current run | |
| uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 | |
| with: | |
| pattern: dotnet-test-results-* | |
| path: dotnet-test-results/ | |
| - name: Restore report history cache | |
| uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 | |
| with: | |
| path: python/dotnet-integration-report-history.json | |
| key: dotnet-integration-report-history-${{ github.run_id }} | |
| restore-keys: | | |
| dotnet-integration-report-history- | |
| - name: Generate trend report | |
| run: > | |
| uv run python scripts/integration_test_report/aggregate.py | |
| ../dotnet-test-results/ | |
| dotnet-integration-report-history.json | |
| dotnet-integration-test-report.md | |
| - name: Post to Job Summary | |
| if: always() | |
| run: cat dotnet-integration-test-report.md >> $GITHUB_STEP_SUMMARY | |
| - name: Save report history cache | |
| if: always() | |
| uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 | |
| with: | |
| path: python/dotnet-integration-report-history.json | |
| key: dotnet-integration-report-history-${{ github.run_id }} | |
| - name: Upload trend report | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: dotnet-integration-test-report | |
| path: | | |
| python/dotnet-integration-test-report.md | |
| python/dotnet-integration-report-history.json |