From ae9a540518e77ddf8bd0c38728c91539fb85f55a Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Fri, 20 Feb 2026 14:15:13 -0800 Subject: [PATCH 01/12] Updated merge test permissions --- .github/workflows/python-merge-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-merge-tests.yml b/.github/workflows/python-merge-tests.yml index 8704ec56c1..57241c4253 100644 --- a/.github/workflows/python-merge-tests.yml +++ b/.github/workflows/python-merge-tests.yml @@ -17,7 +17,7 @@ on: - cron: "0 0 * * *" # Run at midnight UTC daily permissions: - contents: write + contents: read id-token: write env: From d6ad111e3b4656c3655d4861eae1b04669f1978f Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Fri, 20 Feb 2026 14:21:14 -0800 Subject: [PATCH 02/12] Removed repo check --- .github/workflows/integration-tests-manual.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/integration-tests-manual.yml b/.github/workflows/integration-tests-manual.yml index eb7c9859b4..3b9d3d975f 100644 --- a/.github/workflows/integration-tests-manual.yml +++ b/.github/workflows/integration-tests-manual.yml @@ -45,7 +45,6 @@ jobs: PR_NUMBER: ${{ github.event.inputs.pr-number }} BRANCH: ${{ github.event.inputs.branch }} REPO: ${{ github.repository }} - REPO_OWNER: ${{ github.repository_owner }} run: | if [ -n "$PR_NUMBER" ] && [ -n "$BRANCH" ]; then echo "::error::Please provide either a PR number or a branch name, not both." @@ -63,20 +62,14 @@ jobs: exit 1 fi - PR_DATA=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json state,headRepository,headRepositoryOwner) + PR_DATA=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json state) PR_STATE=$(echo "$PR_DATA" | jq -r '.state') - HEAD_OWNER=$(echo "$PR_DATA" | jq -r '.headRepositoryOwner.login') if [ "$PR_STATE" != "OPEN" ]; then echo "::error::PR #$PR_NUMBER is not open (state: $PR_STATE)" exit 1 fi - if [ "$HEAD_OWNER" != "$REPO_OWNER" ]; then - echo "::error::PR #$PR_NUMBER is from a fork ($HEAD_OWNER). Running integration tests against fork PRs is not allowed for security reasons." - exit 1 - fi - echo "checkout-ref=refs/pull/$PR_NUMBER/head" >> "$GITHUB_OUTPUT" echo "Running integration tests for PR #$PR_NUMBER" else From e63f40b75630a436b08416f6cdd75b0da43a65e5 Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Fri, 20 Feb 2026 14:36:13 -0800 Subject: [PATCH 03/12] Added fetch from main for comparison --- .github/workflows/dotnet-build-and-test.yml | 4 ++++ .github/workflows/python-merge-tests.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/dotnet-build-and-test.yml b/.github/workflows/dotnet-build-and-test.yml index 2d079f488e..5fe8e5ba77 100644 --- a/.github/workflows/dotnet-build-and-test.yml +++ b/.github/workflows/dotnet-build-and-test.yml @@ -48,9 +48,13 @@ jobs: - uses: actions/checkout@v6 with: ref: ${{ inputs.checkout-ref }} + - name: Fetch base branch for comparison + if: ${{ inputs.checkout-ref != '' }} + run: git fetch origin main --depth=1 - uses: dorny/paths-filter@v3 id: filter with: + base: ${{ inputs.checkout-ref != '' && 'main' || '' }} filters: | dotnet: - 'dotnet/**' diff --git a/.github/workflows/python-merge-tests.yml b/.github/workflows/python-merge-tests.yml index 57241c4253..4db9001bc8 100644 --- a/.github/workflows/python-merge-tests.yml +++ b/.github/workflows/python-merge-tests.yml @@ -38,9 +38,13 @@ jobs: - uses: actions/checkout@v6 with: ref: ${{ inputs.checkout-ref }} + - name: Fetch base branch for comparison + if: ${{ inputs.checkout-ref != '' }} + run: git fetch origin main --depth=1 - uses: dorny/paths-filter@v3 id: filter with: + base: ${{ inputs.checkout-ref != '' && 'main' || '' }} filters: | python: - 'python/**' From 30c3abdbf02855ce7b1f4bf561fe38fda5189c51 Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Fri, 20 Feb 2026 15:29:52 -0800 Subject: [PATCH 04/12] Updated path detection logic --- .github/workflows/dotnet-build-and-test.yml | 9 ++--- .../workflows/integration-tests-manual.yml | 35 +++++++++++++++++++ .github/workflows/python-merge-tests.yml | 10 ++---- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/.github/workflows/dotnet-build-and-test.yml b/.github/workflows/dotnet-build-and-test.yml index 5fe8e5ba77..365c10c28b 100644 --- a/.github/workflows/dotnet-build-and-test.yml +++ b/.github/workflows/dotnet-build-and-test.yml @@ -42,19 +42,16 @@ jobs: contents: read pull-requests: read outputs: - dotnetChanges: ${{ steps.filter.outputs.dotnet }} - cosmosDbChanges: ${{ steps.filter.outputs.cosmosdb }} + dotnetChanges: ${{ inputs.checkout-ref != '' && 'true' || steps.filter.outputs.dotnet }} + cosmosDbChanges: ${{ inputs.checkout-ref != '' && 'true' || steps.filter.outputs.cosmosdb }} steps: - uses: actions/checkout@v6 with: ref: ${{ inputs.checkout-ref }} - - name: Fetch base branch for comparison - if: ${{ inputs.checkout-ref != '' }} - run: git fetch origin main --depth=1 - uses: dorny/paths-filter@v3 + if: ${{ inputs.checkout-ref == '' }} id: filter with: - base: ${{ inputs.checkout-ref != '' && 'main' || '' }} filters: | dotnet: - 'dotnet/**' diff --git a/.github/workflows/integration-tests-manual.yml b/.github/workflows/integration-tests-manual.yml index 3b9d3d975f..6cadbdc1c1 100644 --- a/.github/workflows/integration-tests-manual.yml +++ b/.github/workflows/integration-tests-manual.yml @@ -4,6 +4,7 @@ # # It reuses the existing dotnet-build-and-test and python-merge-tests workflows, # passing a ref so they check out and test the correct code. +# Changed paths are detected here so only the relevant test suites run. # name: Integration Tests (Manual) @@ -37,6 +38,8 @@ jobs: runs-on: ubuntu-latest outputs: checkout-ref: ${{ steps.resolve.outputs.checkout-ref }} + dotnet-changes: ${{ steps.detect-changes.outputs.dotnet }} + python-changes: ${{ steps.detect-changes.outputs.python }} steps: - name: Resolve checkout ref id: resolve @@ -82,9 +85,40 @@ jobs: echo "Running integration tests for branch $BRANCH" fi + - name: Detect changed paths + id: detect-changes + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.inputs.pr-number }} + BRANCH: ${{ github.event.inputs.branch }} + REPO: ${{ github.repository }} + run: | + if [ -n "$PR_NUMBER" ]; then + CHANGED_FILES=$(gh pr diff "$PR_NUMBER" --repo "$REPO" --name-only) + else + # For branches, compare against main using the GitHub API + CHANGED_FILES=$(gh api "repos/$REPO/compare/main...$BRANCH" --jq '.files[].filename') + fi + + DOTNET_CHANGES=false + PYTHON_CHANGES=false + + if echo "$CHANGED_FILES" | grep -q '^dotnet/'; then + DOTNET_CHANGES=true + fi + + if echo "$CHANGED_FILES" | grep -q '^python/'; then + PYTHON_CHANGES=true + fi + + echo "dotnet=$DOTNET_CHANGES" >> "$GITHUB_OUTPUT" + echo "python=$PYTHON_CHANGES" >> "$GITHUB_OUTPUT" + echo "Detected changes — dotnet: $DOTNET_CHANGES, python: $PYTHON_CHANGES" + dotnet-integration-tests: name: .NET Integration Tests needs: resolve-ref + if: needs.resolve-ref.outputs.dotnet-changes == 'true' uses: ./.github/workflows/dotnet-build-and-test.yml with: checkout-ref: ${{ needs.resolve-ref.outputs.checkout-ref }} @@ -93,6 +127,7 @@ jobs: python-integration-tests: name: Python Integration Tests needs: resolve-ref + if: needs.resolve-ref.outputs.python-changes == 'true' uses: ./.github/workflows/python-merge-tests.yml with: checkout-ref: ${{ needs.resolve-ref.outputs.checkout-ref }} diff --git a/.github/workflows/python-merge-tests.yml b/.github/workflows/python-merge-tests.yml index 4db9001bc8..37bebced6b 100644 --- a/.github/workflows/python-merge-tests.yml +++ b/.github/workflows/python-merge-tests.yml @@ -33,18 +33,14 @@ jobs: contents: read pull-requests: read outputs: - pythonChanges: ${{ steps.filter.outputs.python}} + pythonChanges: ${{ inputs.checkout-ref != '' && 'true' || steps.filter.outputs.python }} steps: - uses: actions/checkout@v6 - with: - ref: ${{ inputs.checkout-ref }} - - name: Fetch base branch for comparison - if: ${{ inputs.checkout-ref != '' }} - run: git fetch origin main --depth=1 + if: ${{ inputs.checkout-ref == '' }} - uses: dorny/paths-filter@v3 + if: ${{ inputs.checkout-ref == '' }} id: filter with: - base: ${{ inputs.checkout-ref != '' && 'main' || '' }} filters: | python: - 'python/**' From 661f8588a1b7fe59f1fa45f0a50d1598284b6c84 Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Fri, 20 Feb 2026 15:40:29 -0800 Subject: [PATCH 05/12] Small updates --- .github/workflows/dotnet-build-and-test.yml | 16 +++++++++++----- ...ntegration-tests-manual.yml => int-tests.yml} | 2 ++ .github/workflows/python-merge-tests.yml | 9 +++++++-- 3 files changed, 20 insertions(+), 7 deletions(-) rename .github/workflows/{integration-tests-manual.yml => int-tests.yml} (98%) diff --git a/.github/workflows/dotnet-build-and-test.yml b/.github/workflows/dotnet-build-and-test.yml index 365c10c28b..ae8dcf5c21 100644 --- a/.github/workflows/dotnet-build-and-test.yml +++ b/.github/workflows/dotnet-build-and-test.yml @@ -14,6 +14,11 @@ on: required: false type: string default: "" + integration-only: + description: "Run only integration tests (skip unit tests, coverage, and non-integration matrix entries)" + required: false + type: boolean + default: false pull_request: branches: ["main", "feature*"] merge_group: @@ -71,7 +76,7 @@ jobs: dotnet-build-and-test: needs: paths-filter - if: needs.paths-filter.outputs.dotnetChanges == 'true' + if: needs.paths-filter.outputs.dotnetChanges == 'true' && (inputs.integration-only != true || matrix.integration-tests) strategy: fail-fast: false matrix: @@ -120,7 +125,7 @@ jobs: 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' + if: inputs.integration-only != true && matrix.configuration == 'Release' && matrix.targetFramework != 'net472' run: | TEMP_DIR=$(mktemp -d) @@ -152,6 +157,7 @@ jobs: rm -rf "$TEMP_DIR" - name: Run Unit Tests + if: inputs.integration-only != true shell: bash run: | export UT_PROJECTS=$(find ./dotnet -type f -name "*.UnitTests.csproj" | tr '\n' ' ') @@ -233,7 +239,7 @@ jobs: # Generate test reports and check coverage - name: Generate test reports - if: matrix.targetFramework == env.COVERAGE_FRAMEWORK + if: inputs.integration-only != true && matrix.targetFramework == env.COVERAGE_FRAMEWORK uses: danielpalme/ReportGenerator-GitHub-Action@5.5.1 with: reports: "./TestResults/Coverage/**/coverage.cobertura.xml" @@ -241,14 +247,14 @@ jobs: reporttypes: "HtmlInline;JsonSummary" - name: Upload coverage report artifact - if: matrix.targetFramework == env.COVERAGE_FRAMEWORK + if: inputs.integration-only != true && matrix.targetFramework == env.COVERAGE_FRAMEWORK uses: actions/upload-artifact@v6 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 + if: inputs.integration-only != true && matrix.targetFramework == env.COVERAGE_FRAMEWORK shell: pwsh run: .github/workflows/dotnet-check-coverage.ps1 -JsonReportPath "TestResults/Reports/Summary.json" -CoverageThreshold $env:COVERAGE_THRESHOLD diff --git a/.github/workflows/integration-tests-manual.yml b/.github/workflows/int-tests.yml similarity index 98% rename from .github/workflows/integration-tests-manual.yml rename to .github/workflows/int-tests.yml index 6cadbdc1c1..28866c39ff 100644 --- a/.github/workflows/integration-tests-manual.yml +++ b/.github/workflows/int-tests.yml @@ -122,6 +122,7 @@ jobs: uses: ./.github/workflows/dotnet-build-and-test.yml with: checkout-ref: ${{ needs.resolve-ref.outputs.checkout-ref }} + integration-only: true secrets: inherit python-integration-tests: @@ -131,4 +132,5 @@ jobs: uses: ./.github/workflows/python-merge-tests.yml with: checkout-ref: ${{ needs.resolve-ref.outputs.checkout-ref }} + integration-only: true secrets: inherit diff --git a/.github/workflows/python-merge-tests.yml b/.github/workflows/python-merge-tests.yml index 37bebced6b..3ac5cf6846 100644 --- a/.github/workflows/python-merge-tests.yml +++ b/.github/workflows/python-merge-tests.yml @@ -9,6 +9,11 @@ on: required: false type: string default: "" + integration-only: + description: "Run only integration tests (skip sample tests)" + required: false + type: boolean + default: false pull_request: branches: ["main"] merge_group: @@ -111,7 +116,7 @@ jobs: working-directory: ./python - name: Test core samples timeout-minutes: 10 - if: env.RUN_SAMPLES_TESTS == 'true' + if: inputs.integration-only != true && env.RUN_SAMPLES_TESTS == 'true' run: uv run pytest tests/samples/ -m "openai" -m "azure" working-directory: ./python - name: Surface failing tests @@ -170,7 +175,7 @@ jobs: working-directory: ./python - name: Test Azure AI samples timeout-minutes: 10 - if: env.RUN_SAMPLES_TESTS == 'true' + if: inputs.integration-only != true && env.RUN_SAMPLES_TESTS == 'true' run: uv run pytest tests/samples/ -m "azure-ai" working-directory: ./python - name: Surface failing tests From b41dd2b6c61f39dcd3ee9f414310b8d0e4e4046c Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Fri, 20 Feb 2026 15:42:37 -0800 Subject: [PATCH 06/12] Reverted file rename --- .github/workflows/{int-tests.yml => integration-tests-manual.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{int-tests.yml => integration-tests-manual.yml} (100%) diff --git a/.github/workflows/int-tests.yml b/.github/workflows/integration-tests-manual.yml similarity index 100% rename from .github/workflows/int-tests.yml rename to .github/workflows/integration-tests-manual.yml From 93930eeea4b04d07b134ac30bcce3d4f87b67b4e Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Fri, 20 Feb 2026 16:13:56 -0800 Subject: [PATCH 07/12] Created dedicated workflows for integration tests --- .github/workflows/dotnet-build-and-test.yml | 31 ++--- .../workflows/dotnet-integration-tests.yml | 102 ++++++++++++++++ .../workflows/integration-tests-manual.yml | 8 +- .../workflows/python-integration-tests.yml | 112 ++++++++++++++++++ .github/workflows/python-merge-tests.yml | 24 +--- 5 files changed, 227 insertions(+), 50 deletions(-) create mode 100644 .github/workflows/dotnet-integration-tests.yml create mode 100644 .github/workflows/python-integration-tests.yml diff --git a/.github/workflows/dotnet-build-and-test.yml b/.github/workflows/dotnet-build-and-test.yml index ae8dcf5c21..95842e703a 100644 --- a/.github/workflows/dotnet-build-and-test.yml +++ b/.github/workflows/dotnet-build-and-test.yml @@ -7,18 +7,6 @@ name: dotnet-build-and-test on: workflow_dispatch: - workflow_call: - inputs: - checkout-ref: - description: "Git ref to checkout (e.g., a commit SHA from a PR)" - required: false - type: string - default: "" - integration-only: - description: "Run only integration tests (skip unit tests, coverage, and non-integration matrix entries)" - required: false - type: boolean - default: false pull_request: branches: ["main", "feature*"] merge_group: @@ -47,14 +35,11 @@ jobs: contents: read pull-requests: read outputs: - dotnetChanges: ${{ inputs.checkout-ref != '' && 'true' || steps.filter.outputs.dotnet }} - cosmosDbChanges: ${{ inputs.checkout-ref != '' && 'true' || steps.filter.outputs.cosmosdb }} + dotnetChanges: ${{ steps.filter.outputs.dotnet }} + cosmosDbChanges: ${{ steps.filter.outputs.cosmosdb }} steps: - uses: actions/checkout@v6 - with: - ref: ${{ inputs.checkout-ref }} - uses: dorny/paths-filter@v3 - if: ${{ inputs.checkout-ref == '' }} id: filter with: filters: | @@ -76,7 +61,7 @@ jobs: dotnet-build-and-test: needs: paths-filter - if: needs.paths-filter.outputs.dotnetChanges == 'true' && (inputs.integration-only != true || matrix.integration-tests) + if: needs.paths-filter.outputs.dotnetChanges == 'true' strategy: fail-fast: false matrix: @@ -91,7 +76,6 @@ jobs: steps: - uses: actions/checkout@v6 with: - ref: ${{ inputs.checkout-ref }} persist-credentials: false sparse-checkout: | . @@ -125,7 +109,7 @@ jobs: 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: inputs.integration-only != true && matrix.configuration == 'Release' && matrix.targetFramework != 'net472' + if: matrix.configuration == 'Release' && matrix.targetFramework != 'net472' run: | TEMP_DIR=$(mktemp -d) @@ -157,7 +141,6 @@ jobs: rm -rf "$TEMP_DIR" - name: Run Unit Tests - if: inputs.integration-only != true shell: bash run: | export UT_PROJECTS=$(find ./dotnet -type f -name "*.UnitTests.csproj" | tr '\n' ' ') @@ -239,7 +222,7 @@ jobs: # Generate test reports and check coverage - name: Generate test reports - if: inputs.integration-only != true && matrix.targetFramework == env.COVERAGE_FRAMEWORK + if: matrix.targetFramework == env.COVERAGE_FRAMEWORK uses: danielpalme/ReportGenerator-GitHub-Action@5.5.1 with: reports: "./TestResults/Coverage/**/coverage.cobertura.xml" @@ -247,14 +230,14 @@ jobs: reporttypes: "HtmlInline;JsonSummary" - name: Upload coverage report artifact - if: inputs.integration-only != true && matrix.targetFramework == env.COVERAGE_FRAMEWORK + if: matrix.targetFramework == env.COVERAGE_FRAMEWORK uses: actions/upload-artifact@v6 with: name: CoverageReport-${{ matrix.os }}-${{ matrix.targetFramework }}-${{ matrix.configuration }} # Artifact name path: ./TestResults/Reports # Directory containing files to upload - name: Check coverage - if: inputs.integration-only != true && matrix.targetFramework == env.COVERAGE_FRAMEWORK + if: matrix.targetFramework == env.COVERAGE_FRAMEWORK shell: pwsh run: .github/workflows/dotnet-check-coverage.ps1 -JsonReportPath "TestResults/Reports/Summary.json" -CoverageThreshold $env:COVERAGE_THRESHOLD diff --git a/.github/workflows/dotnet-integration-tests.yml b/.github/workflows/dotnet-integration-tests.yml new file mode 100644 index 0000000000..364fb9732d --- /dev/null +++ b/.github/workflows/dotnet-integration-tests.yml @@ -0,0 +1,102 @@ +# +# Dedicated .NET integration tests workflow, called from the manual integration test orchestrator. +# Only runs integration test matrix entries (net10.0 and net472). No unit tests, no coverage. +# + +name: dotnet-integration-tests + +on: + workflow_call: + inputs: + checkout-ref: + description: "Git ref to checkout (e.g., refs/pull/123/head)" + required: true + type: string + +permissions: + contents: read + id-token: write + +jobs: + dotnet-integration-tests: + strategy: + fail-fast: false + matrix: + include: + - { targetFramework: "net10.0", os: "ubuntu-latest", configuration: Release } + - { targetFramework: "net472", os: "windows-latest", configuration: Release } + runs-on: ${{ matrix.os }} + environment: integration + timeout-minutes: 60 + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ inputs.checkout-ref }} + persist-credentials: false + sparse-checkout: | + . + .github + dotnet + python + workflow-samples + + - name: Start Azure Cosmos DB Emulator + if: runner.os == 'Windows' + 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 "COSMOS_EMULATOR_AVAILABLE=true" >> $env:GITHUB_ENV + + - name: Setup dotnet + uses: actions/setup-dotnet@v5.1.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: Azure CLI Login + uses: azure/login@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 + if: matrix.os == 'ubuntu-latest' + uses: ./.github/actions/azure-functions-integration-setup + + - name: Run Integration Tests + shell: bash + run: | + export INTEGRATION_TEST_PROJECTS=$(find ./dotnet -type f -name "*IntegrationTests.csproj" | tr '\n' ' ') + for project in $INTEGRATION_TEST_PROJECTS; do + target_frameworks=$(dotnet msbuild $project -getProperty:TargetFrameworks -p:Configuration=${{ matrix.configuration }} -nologo 2>/dev/null | tr -d '\r') + if [[ "$target_frameworks" == *"${{ matrix.targetFramework }}"* ]]; then + dotnet test -f ${{ matrix.targetFramework }} -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx --filter "Category!=IntegrationDisabled" + else + echo "Skipping $project - does not support target framework ${{ matrix.targetFramework }} (supports: $target_frameworks)" + fi + done + env: + COSMOSDB_ENDPOINT: https://localhost:8081 + COSMOSDB_KEY: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw== + OpenAI__ApiKey: ${{ secrets.OPENAI__APIKEY }} + OpenAI__ChatModelId: ${{ vars.OPENAI__CHATMODELID }} + OpenAI__ChatReasoningModelId: ${{ vars.OPENAI__CHATREASONINGMODELID }} + AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }} + AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} + AzureAI__Endpoint: ${{ secrets.AZUREAI__ENDPOINT }} + AzureAI__DeploymentName: ${{ vars.AZUREAI__DEPLOYMENTNAME }} + AzureAI__BingConnectionId: ${{ vars.AZUREAI__BINGCONECTIONID }} + FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }} + FOUNDRY_MEDIA_DEPLOYMENT_NAME: ${{ vars.FOUNDRY_MEDIA_DEPLOYMENT_NAME }} + FOUNDRY_MODEL_DEPLOYMENT_NAME: ${{ vars.FOUNDRY_MODEL_DEPLOYMENT_NAME }} + FOUNDRY_CONNECTION_GROUNDING_TOOL: ${{ vars.FOUNDRY_CONNECTION_GROUNDING_TOOL }} diff --git a/.github/workflows/integration-tests-manual.yml b/.github/workflows/integration-tests-manual.yml index 28866c39ff..d3d617fa68 100644 --- a/.github/workflows/integration-tests-manual.yml +++ b/.github/workflows/integration-tests-manual.yml @@ -2,7 +2,7 @@ # This workflow allows manually running integration tests against an open PR or a branch. # Go to Actions → "Integration Tests (Manual)" → Run workflow → enter a PR number or branch name. # -# It reuses the existing dotnet-build-and-test and python-merge-tests workflows, +# It calls dedicated integration-only workflows (dotnet-integration-tests and python-integration-tests), # passing a ref so they check out and test the correct code. # Changed paths are detected here so only the relevant test suites run. # @@ -119,18 +119,16 @@ jobs: name: .NET Integration Tests needs: resolve-ref if: needs.resolve-ref.outputs.dotnet-changes == 'true' - uses: ./.github/workflows/dotnet-build-and-test.yml + uses: ./.github/workflows/dotnet-integration-tests.yml with: checkout-ref: ${{ needs.resolve-ref.outputs.checkout-ref }} - integration-only: true secrets: inherit python-integration-tests: name: Python Integration Tests needs: resolve-ref if: needs.resolve-ref.outputs.python-changes == 'true' - uses: ./.github/workflows/python-merge-tests.yml + uses: ./.github/workflows/python-integration-tests.yml with: checkout-ref: ${{ needs.resolve-ref.outputs.checkout-ref }} - integration-only: true secrets: inherit diff --git a/.github/workflows/python-integration-tests.yml b/.github/workflows/python-integration-tests.yml new file mode 100644 index 0000000000..7897cb6fe6 --- /dev/null +++ b/.github/workflows/python-integration-tests.yml @@ -0,0 +1,112 @@ +# +# Dedicated Python integration tests workflow, called from the manual integration test orchestrator. +# Only runs integration tests (core + Azure AI). No sample tests, no paths filtering. +# + +name: python-integration-tests + +on: + workflow_call: + inputs: + checkout-ref: + description: "Git ref to checkout (e.g., refs/pull/123/head)" + required: true + type: string + +permissions: + contents: read + id-token: write + +env: + UV_CACHE_DIR: /tmp/.uv-cache + +jobs: + python-tests-core: + name: Python Integration Tests - Core + runs-on: ubuntu-latest + environment: integration + timeout-minutes: 60 + env: + UV_PYTHON: "3.10" + OPENAI_CHAT_MODEL_ID: ${{ vars.OPENAI__CHATMODELID }} + OPENAI_RESPONSES_MODEL_ID: ${{ vars.OPENAI__RESPONSESMODELID }} + OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + ANTHROPIC_CHAT_MODEL_ID: ${{ vars.ANTHROPIC_CHAT_MODEL_ID }} + AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }} + AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }} + AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }} + LOCAL_MCP_URL: ${{ vars.LOCAL_MCP__URL }} + FUNCTIONS_WORKER_RUNTIME: "python" + DURABLE_TASK_SCHEDULER_CONNECTION_STRING: "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None" + AzureWebJobsStorage: "UseDevelopmentStorage=true" + defaults: + run: + working-directory: python + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ inputs.checkout-ref }} + + - name: Set up python and install the project + id: python-setup + uses: ./.github/actions/python-setup + with: + python-version: "3.10" + os: ${{ runner.os }} + env: + UV_CACHE_DIR: /tmp/.uv-cache + + - name: Azure CLI Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: Set up Azure Functions Integration Test Emulators + uses: ./.github/actions/azure-functions-integration-setup + id: azure-functions-setup + + - name: Test with pytest + run: uv run poe all-tests -n logical --dist loadfile --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5 + working-directory: ./python + + python-tests-azure-ai: + name: Python Integration Tests - Azure AI + runs-on: ubuntu-latest + environment: integration + timeout-minutes: 60 + env: + UV_PYTHON: "3.10" + AZURE_AI_PROJECT_ENDPOINT: ${{ secrets.AZUREAI__ENDPOINT }} + AZURE_AI_MODEL_DEPLOYMENT_NAME: ${{ vars.AZUREAI__DEPLOYMENTNAME }} + LOCAL_MCP_URL: ${{ vars.LOCAL_MCP__URL }} + defaults: + run: + working-directory: python + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ inputs.checkout-ref }} + + - name: Set up python and install the project + id: python-setup + uses: ./.github/actions/python-setup + with: + python-version: "3.10" + os: ${{ runner.os }} + env: + UV_CACHE_DIR: /tmp/.uv-cache + + - name: Azure CLI Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: Test with pytest + timeout-minutes: 15 + run: uv run --directory packages/azure-ai poe integration-tests -n logical --dist loadfile --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5 + working-directory: ./python diff --git a/.github/workflows/python-merge-tests.yml b/.github/workflows/python-merge-tests.yml index 3ac5cf6846..8c0a0189c1 100644 --- a/.github/workflows/python-merge-tests.yml +++ b/.github/workflows/python-merge-tests.yml @@ -2,18 +2,6 @@ name: Python - Merge - Tests on: workflow_dispatch: - workflow_call: - inputs: - checkout-ref: - description: "Git ref to checkout (e.g., a commit SHA from a PR)" - required: false - type: string - default: "" - integration-only: - description: "Run only integration tests (skip sample tests)" - required: false - type: boolean - default: false pull_request: branches: ["main"] merge_group: @@ -38,12 +26,10 @@ jobs: contents: read pull-requests: read outputs: - pythonChanges: ${{ inputs.checkout-ref != '' && 'true' || steps.filter.outputs.python }} + pythonChanges: ${{ steps.filter.outputs.python }} steps: - uses: actions/checkout@v6 - if: ${{ inputs.checkout-ref == '' }} - uses: dorny/paths-filter@v3 - if: ${{ inputs.checkout-ref == '' }} id: filter with: filters: | @@ -90,8 +76,6 @@ jobs: working-directory: python steps: - uses: actions/checkout@v6 - with: - ref: ${{ inputs.checkout-ref }} - name: Set up python and install the project id: python-setup uses: ./.github/actions/python-setup @@ -116,7 +100,7 @@ jobs: working-directory: ./python - name: Test core samples timeout-minutes: 10 - if: inputs.integration-only != true && env.RUN_SAMPLES_TESTS == 'true' + if: env.RUN_SAMPLES_TESTS == 'true' run: uv run pytest tests/samples/ -m "openai" -m "azure" working-directory: ./python - name: Surface failing tests @@ -151,8 +135,6 @@ jobs: working-directory: python steps: - uses: actions/checkout@v6 - with: - ref: ${{ inputs.checkout-ref }} - name: Set up python and install the project id: python-setup uses: ./.github/actions/python-setup @@ -175,7 +157,7 @@ jobs: working-directory: ./python - name: Test Azure AI samples timeout-minutes: 10 - if: inputs.integration-only != true && env.RUN_SAMPLES_TESTS == 'true' + if: env.RUN_SAMPLES_TESTS == 'true' run: uv run pytest tests/samples/ -m "azure-ai" working-directory: ./python - name: Surface failing tests From b65f8f0312a19a2f64c7753c4440804c5c811189 Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Fri, 20 Feb 2026 18:35:23 -0800 Subject: [PATCH 08/12] Small fix for Python --- .github/workflows/python-integration-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/python-integration-tests.yml b/.github/workflows/python-integration-tests.yml index 7897cb6fe6..8689e7d0c0 100644 --- a/.github/workflows/python-integration-tests.yml +++ b/.github/workflows/python-integration-tests.yml @@ -19,6 +19,7 @@ permissions: env: UV_CACHE_DIR: /tmp/.uv-cache + RUN_INTEGRATION_TESTS: "true" jobs: python-tests-core: From fb9ff6291c5680030ce4dcc9585e6355a0f9fd48 Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Sat, 21 Feb 2026 11:22:28 -0800 Subject: [PATCH 09/12] Small fixes --- .github/workflows/python-integration-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-integration-tests.yml b/.github/workflows/python-integration-tests.yml index 8689e7d0c0..c323c4b7d6 100644 --- a/.github/workflows/python-integration-tests.yml +++ b/.github/workflows/python-integration-tests.yml @@ -48,6 +48,7 @@ jobs: - uses: actions/checkout@v6 with: ref: ${{ inputs.checkout-ref }} + persist-credentials: false - name: Set up python and install the project id: python-setup @@ -71,7 +72,6 @@ jobs: - name: Test with pytest run: uv run poe all-tests -n logical --dist loadfile --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5 - working-directory: ./python python-tests-azure-ai: name: Python Integration Tests - Azure AI @@ -90,6 +90,7 @@ jobs: - uses: actions/checkout@v6 with: ref: ${{ inputs.checkout-ref }} + persist-credentials: false - name: Set up python and install the project id: python-setup @@ -110,4 +111,3 @@ jobs: - name: Test with pytest timeout-minutes: 15 run: uv run --directory packages/azure-ai poe integration-tests -n logical --dist loadfile --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5 - working-directory: ./python From 95d3efd46d47540d718a49e8ddd9c46c86a2c0fb Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Sat, 21 Feb 2026 11:32:54 -0800 Subject: [PATCH 10/12] Small update --- .github/workflows/python-integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-integration-tests.yml b/.github/workflows/python-integration-tests.yml index c323c4b7d6..902c980794 100644 --- a/.github/workflows/python-integration-tests.yml +++ b/.github/workflows/python-integration-tests.yml @@ -1,6 +1,6 @@ # # Dedicated Python integration tests workflow, called from the manual integration test orchestrator. -# Only runs integration tests (core + Azure AI). No sample tests, no paths filtering. +# Runs all tests (unit + integration). # name: python-integration-tests From de1a7e77560aa70b59edcf160ea9dc73a4f83708 Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Sat, 21 Feb 2026 11:39:36 -0800 Subject: [PATCH 11/12] Small update --- .github/workflows/dotnet-integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet-integration-tests.yml b/.github/workflows/dotnet-integration-tests.yml index 364fb9732d..029ec5151d 100644 --- a/.github/workflows/dotnet-integration-tests.yml +++ b/.github/workflows/dotnet-integration-tests.yml @@ -1,6 +1,6 @@ # # Dedicated .NET integration tests workflow, called from the manual integration test orchestrator. -# Only runs integration test matrix entries (net10.0 and net472). No unit tests, no coverage. +# Only runs integration test matrix entries (net10.0 and net472). # name: dotnet-integration-tests From ac4aa7bfba34ad515439fccea2a1ddba69ce84db Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Sat, 21 Feb 2026 12:02:09 -0800 Subject: [PATCH 12/12] Added tests check for Python --- .../workflows/python-integration-tests.yml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/python-integration-tests.yml b/.github/workflows/python-integration-tests.yml index 902c980794..22af38d9c2 100644 --- a/.github/workflows/python-integration-tests.yml +++ b/.github/workflows/python-integration-tests.yml @@ -111,3 +111,24 @@ jobs: - name: Test with pytest timeout-minutes: 15 run: uv run --directory packages/azure-ai poe integration-tests -n logical --dist loadfile --dist worksteal --timeout=120 --session-timeout=900 --timeout_method thread --retries 2 --retry-delay 5 + + python-integration-tests-check: + if: always() + runs-on: ubuntu-latest + needs: + [ + python-tests-core, + python-tests-azure-ai + ] + steps: + - name: Fail workflow if tests failed + if: contains(join(needs.*.result, ','), 'failure') + uses: actions/github-script@v8 + with: + script: core.setFailed('Integration Tests Failed!') + + - name: Fail workflow if tests cancelled + if: contains(join(needs.*.result, ','), 'cancelled') + uses: actions/github-script@v8 + with: + script: core.setFailed('Integration Tests Cancelled!')