fix(signals): evict stale db connections in temporal activities #108390
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
| name: MCP CI | |
| on: | |
| push: | |
| branches: [master] | |
| pull_request: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| jobs: | |
| changes: | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| name: Determine need to run MCP checks | |
| outputs: | |
| mcp: ${{ steps.filter.outputs.mcp || 'true' }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| # MCP integration tests boot the full PostHog backend (Django web server, | |
| # Celery worker, migrations, demo data), so the filter mirrors the Dagster | |
| # approach: trigger on any Python change across the app. | |
| - uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 | |
| id: app-token | |
| if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository | |
| with: | |
| client-id: ${{ secrets.GH_APP_POSTHOG_PATHS_FILTER_APP_ID }} | |
| private-key: ${{ secrets.GH_APP_POSTHOG_PATHS_FILTER_PRIVATE_KEY }} | |
| - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 | |
| id: filter | |
| if: github.event_name != 'push' # Run all tests on master push | |
| with: | |
| token: ${{ steps.app-token.outputs.token || github.token }} | |
| filters: | | |
| mcp: | |
| # MCP service and per-product tool/UI-app configs | |
| - 'services/mcp/**' | |
| - 'products/*/mcp/**' | |
| # MCP integration tests exercise the full PostHog backend | |
| - 'posthog/**/*.py' | |
| - 'ee/**/*.py' | |
| - 'common/**/*.py' | |
| - 'products/*/backend/**/*.py' | |
| # Query schemas used by MCP analytics tools | |
| - 'frontend/src/queries/schema.json' | |
| # Shared UI component library (used by MCP UI apps) | |
| - 'common/mosaic/**' | |
| # Code generation tooling | |
| - 'tools/openapi-codegen/**' | |
| # Django entry point (manage.py migrate / generate_demo_data) | |
| - manage.py | |
| # Python dependencies (build + integration-tests run `uv sync --frozen`) | |
| - pyproject.toml | |
| - uv.lock | |
| # Node runtime + workspace dependencies | |
| - .nvmrc | |
| - pnpm-lock.yaml | |
| # Docker compose stack (dev.yml extends base.yml) | |
| - docker-compose.base.yml | |
| - docker-compose.dev.yml | |
| - docker-compose.profiles.yml | |
| # Docker helper scripts invoked in CI setup | |
| - bin/ci-wait-for-docker | |
| - bin/wait-for-docker | |
| # Database init scripts used by docker compose | |
| - 'docker/postgres-init-scripts/**' | |
| # Persons DB migrations (sqlx migrate run in integration tests) | |
| - 'rust/persons_migrations/**' | |
| # ClickHouse UDF copied in integration test setup | |
| - 'posthog/user_scripts/latest_user_defined_function.xml' | |
| # Composite actions used by the workflow | |
| - '.github/actions/commit-snapshots/**' | |
| # CI config | |
| - '.github/workflows/ci-mcp.yml' | |
| - '.github/workflows/mcp-publish.yml' | |
| build: | |
| name: Build Package | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| needs: changes | |
| if: needs.changes.outputs.mcp == 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Set up Python | |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | |
| with: | |
| python-version: 3.12.12 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0 | |
| with: | |
| version: '0.10.2' # pinned: unpinned setup-uv calls GH API on every job, exhausts rate limit | |
| enable-cache: true | |
| cache-dependency-glob: uv.lock | |
| save-cache: ${{ github.ref == 'refs/heads/master' }} | |
| - name: Install Python dependencies | |
| run: UV_PROJECT_ENVIRONMENT=$pythonLocation uv sync --frozen --dev | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 | |
| - name: Fix node-gyp permissions | |
| run: chmod +x ~/setup-pnpm/node_modules/.pnpm/pnpm@*/node_modules/pnpm/dist/node_modules/node-gyp/gyp/gyp_main.py | |
| - name: Setup Node.js | |
| uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: 'pnpm' | |
| - name: Install dependencies | |
| run: pnpm --filter=@posthog/mcp... --filter='./products/*' install --frozen-lockfile | |
| - name: Build package | |
| run: cd services/mcp && pnpm build | |
| - name: Type check | |
| run: cd services/mcp && pnpm typecheck | |
| - name: Check MCP schema is up to date | |
| run: | | |
| ./bin/hogli build:schema-mcp | |
| if ! git diff --exit-code services/mcp/schema/tool-inputs.json; then | |
| echo "" | |
| echo "::error::MCP tool-inputs.json is out of date. Run 'hogli build:schema-mcp' and commit the result." | |
| exit 1 | |
| fi | |
| - name: Check generated UI apps are up to date | |
| run: | | |
| cd services/mcp && pnpm run generate:ui-apps | |
| if ! git diff --exit-code -- src/ui-apps/apps/generated/ src/resources/ui-apps.generated.ts; then | |
| echo "" | |
| echo "::warning::The following generated files are out of date:" | |
| git diff --name-only -- src/ui-apps/apps/generated/ src/resources/ui-apps.generated.ts | |
| echo "" | |
| echo "::error::Generated UI app files are out of date. Run 'pnpm --filter=@posthog/mcp run generate:ui-apps' and commit the result." | |
| exit 1 | |
| fi | |
| - name: Lint tool names | |
| run: cd services/mcp && pnpm lint-tool-names | |
| unit-tests: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| needs: changes | |
| if: needs.changes.outputs.mcp == 'true' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 | |
| - name: Fix node-gyp permissions | |
| run: chmod +x ~/setup-pnpm/node_modules/.pnpm/pnpm@*/node_modules/pnpm/dist/node_modules/node-gyp/gyp/gyp_main.py | |
| - name: Setup Node.js | |
| uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: 'pnpm' | |
| - name: Install dependencies | |
| run: pnpm --filter=@posthog/mcp... --filter='./products/*' install --frozen-lockfile | |
| # The workers-pool project in vitest.config.mts parses wrangler.jsonc | |
| # up front and needs `assets.directory` (./public/) populated and | |
| # `shared/guidelines.md` (imported by src/mcp.ts) on disk. Both are | |
| # gitignored: public/ is produced by `pnpm build` (UI apps) and | |
| # guidelines.md by the wrangler build command. | |
| - name: Run wrangler pre-build steps | |
| working-directory: services/mcp | |
| run: | | |
| pnpm build | |
| pnpm exec tsx scripts/copy-instructions.ts | |
| - name: Run unit tests | |
| run: | | |
| pnpm --filter=@posthog/mcp run test -u | |
| if [ -n "$(git status --porcelain -- services/mcp/tests/unit)" ]; then | |
| echo "" | |
| git status --short -- services/mcp/tests/unit | |
| echo "::error::MCP unit test artifacts are out of date. Run 'pnpm --filter=@posthog/mcp run test -u' and commit the result." | |
| exit 1 | |
| fi | |
| - name: Create snapshot patch | |
| id: create-snapshot-patch | |
| if: ${{ always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && !contains(github.actor, '[bot]') && github.actor != 'posthog-bot' && !contains(github.actor, 'github-actions') }} | |
| run: | | |
| SNAPSHOT_PATH="services/mcp/tests/unit" | |
| if [ -z "$(git status --porcelain -- "$SNAPSHOT_PATH")" ]; then | |
| echo "No MCP unit test changes" | |
| echo "has-changes=false" >> $GITHUB_OUTPUT | |
| else | |
| echo "MCP unit test changes detected:" | |
| git status --short -- "$SNAPSHOT_PATH" | |
| git add -N "$SNAPSHOT_PATH" | |
| mkdir -p /tmp/patches | |
| git diff --binary --full-index "$SNAPSHOT_PATH" > /tmp/patches/mcp-unit-tests.patch | |
| echo "has-changes=true" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Upload snapshot patch | |
| if: ${{ steps.create-snapshot-patch.outputs.has-changes == 'true' && always() }} | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| with: | |
| name: mcp-snapshot-patch | |
| path: /tmp/patches/mcp-unit-tests.patch | |
| retention-days: 1 | |
| if-no-files-found: ignore | |
| integration-tests: | |
| name: Integration Tests (depot-ubuntu-latest-4) | |
| runs-on: depot-ubuntu-latest-4 | |
| needs: changes | |
| timeout-minutes: 30 | |
| if: needs.changes.outputs.mcp == 'true' | |
| env: | |
| OPT_OUT_CAPTURE: 1 | |
| SECRET_KEY: '6b01eee4f945ca25045b5aab440b953461faf08693a9abbf1166dc7c6b9772da' | |
| DATABASE_URL: 'postgres://posthog:posthog@localhost:5432/posthog' | |
| PERSONS_DB_WRITER_URL: 'postgres://posthog:posthog@localhost:5432/posthog_persons' | |
| REDIS_URL: 'redis://localhost' | |
| CLICKHOUSE_HOST: 'localhost' | |
| CLICKHOUSE_SECURE: 'False' | |
| CLICKHOUSE_VERIFY: 'False' | |
| OBJECT_STORAGE_ENABLED: 'True' | |
| OBJECT_STORAGE_ENDPOINT: 'http://localhost:19000' | |
| OBJECT_STORAGE_ACCESS_KEY_ID: 'object_storage_root_user' | |
| OBJECT_STORAGE_SECRET_ACCESS_KEY: 'object_storage_root_password' | |
| SKIP_SERVICE_VERSION_REQUIREMENTS: 1 | |
| NO_RESTART_LOOP: 1 | |
| DISABLE_SECURE_SSL_REDIRECT: 'True' | |
| CLICKHOUSE_LOGS_CLUSTER_SECURE: 'False' | |
| CELERY_METRICS_PORT: 8999 | |
| POSTHOG_FEATURE_FLAGS_FORCE_ENABLED: 'logs-alerting' | |
| # Required for the feature_flags test_evaluation endpoint, which authenticates | |
| # historical-flag override requests to the Rust flags service. Any non-empty | |
| # value is fine for CI — the Rust service in the test stack accepts it. | |
| INTERNAL_REQUEST_TOKEN: 'mcp-ci-internal-request-token' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 1 | |
| - name: Clean up data directories with container permissions | |
| run: | | |
| [ -d "data" ] && docker run --rm -v "$(pwd)/data:/data" alpine sh -c "rm -rf /data/seaweedfs /data/minio" || true | |
| continue-on-error: true | |
| - name: Stop/Start stack with Docker Compose | |
| shell: bash | |
| env: | |
| COMPOSE_PROFILES: temporal | |
| run: | | |
| cp posthog/user_scripts/latest_user_defined_function.xml docker/clickhouse/user_defined_function.xml | |
| ( | |
| max_attempts=3 | |
| attempt=1 | |
| delay=5 | |
| while [ $attempt -le $max_attempts ]; do | |
| echo "Attempt $attempt of $max_attempts to start stack..." | |
| if docker compose -f docker-compose.dev.yml down && \ | |
| docker compose -f docker-compose.dev.yml -f docker-compose.profiles.yml up -d; then | |
| echo "Stack started successfully" | |
| exit 0 | |
| fi | |
| echo "Failed to start stack on attempt $attempt" | |
| if [ $attempt -lt $max_attempts ]; then | |
| sleep_time=$((delay * 2 ** (attempt - 1))) | |
| echo "Waiting ${sleep_time} seconds before retry..." | |
| sleep $sleep_time | |
| fi | |
| attempt=$((attempt + 1)) | |
| done | |
| echo "Failed to start stack after $max_attempts attempts" | |
| exit 1 | |
| ) & | |
| - name: Add service hostnames to /etc/hosts | |
| shell: bash | |
| run: echo "127.0.0.1 db redis7 kafka clickhouse clickhouse-coordinator objectstorage seaweedfs temporal" | sudo tee -a /etc/hosts | |
| - name: Set up Python | |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | |
| with: | |
| python-version: 3.12.12 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0 | |
| with: | |
| version: '0.10.2' # pinned: unpinned setup-uv calls GH API on every job, exhausts rate limit | |
| enable-cache: true | |
| cache-dependency-glob: uv.lock | |
| save-cache: ${{ github.ref == 'refs/heads/master' }} | |
| - name: Install SAML (python3-saml) dependencies | |
| shell: bash | |
| run: | | |
| sudo apt-get update && sudo apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 | |
| - name: Fix node-gyp permissions | |
| run: chmod +x ~/setup-pnpm/node_modules/.pnpm/pnpm@*/node_modules/pnpm/dist/node_modules/node-gyp/gyp/gyp_main.py | |
| - name: Setup Node.js | |
| uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: 'pnpm' | |
| - name: Install Python dependencies | |
| shell: bash | |
| run: | | |
| UV_PROJECT_ENVIRONMENT=$pythonLocation uv sync --frozen --dev | |
| - name: Install Node dependencies | |
| run: pnpm --filter=@posthog/mcp... --filter='./products/*' install --frozen-lockfile | |
| - name: Set up needed files | |
| shell: bash | |
| run: | | |
| mkdir -p frontend/dist | |
| touch frontend/dist/index.html | |
| touch frontend/dist/layout.html | |
| touch frontend/dist/exporter.html | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@0b1efabc08b657293548b77fb76cc02d26091c7e | |
| with: | |
| toolchain: 1.91.1 | |
| components: cargo | |
| - name: Cache Rust dependencies | |
| uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 | |
| with: | |
| shared-key: 'v2-rust-mcp' | |
| workspaces: rust | |
| save-if: ${{ github.ref == 'refs/heads/master' }} | |
| - name: Install sqlx-cli | |
| run: | | |
| cargo install sqlx-cli --version 0.8.0 --features postgres --no-default-features --locked | |
| - name: Build Rust flags service | |
| working-directory: rust | |
| env: | |
| # Debug builds compile much faster than release (~4 min vs ~9 min). | |
| # We disable debug assertions because the codebase contains | |
| # debug_assert! checks that intentionally panic on data invariant | |
| # violations, which would crash the service mid-test-run. | |
| RUSTFLAGS: '-C debug-assertions=no' | |
| run: cargo build -p feature-flags | |
| - name: Download MaxMind Database | |
| run: ./bin/download-mmdb | |
| - name: Start Docker services | |
| shell: bash | |
| env: | |
| COMPOSE_FILE: docker-compose.dev.yml:docker-compose.profiles.yml | |
| COMPOSE_PROFILES: temporal | |
| run: bin/ci-wait-for-docker launch --down | |
| - name: Wait for Docker services | |
| shell: bash | |
| env: | |
| COMPOSE_FILE: docker-compose.dev.yml:docker-compose.profiles.yml | |
| COMPOSE_PROFILES: temporal | |
| run: bin/ci-wait-for-docker wait temporal | |
| - name: Run migrations | |
| run: | | |
| # Create persons database and run sqlx migrations first | |
| DATABASE_URL="postgres://posthog:posthog@localhost:5432/posthog_persons" \ | |
| sqlx database create | |
| DATABASE_URL="postgres://posthog:posthog@localhost:5432/posthog_persons" \ | |
| sqlx migrate run --source rust/persons_migrations/ | |
| # Then run Django migrations | |
| python manage.py migrate --noinput | |
| python manage.py migrate_clickhouse | |
| - name: Start Rust flags service | |
| working-directory: rust | |
| env: | |
| BIND_HOST: '127.0.0.1' | |
| BIND_PORT: '3001' | |
| READ_DATABASE_URL: postgres://posthog:posthog@localhost:5432/posthog | |
| WRITE_DATABASE_URL: postgres://posthog:posthog@localhost:5432/posthog | |
| PERSONS_READ_DATABASE_URL: postgres://posthog:posthog@localhost:5432/posthog_persons | |
| PERSONS_WRITE_DATABASE_URL: postgres://posthog:posthog@localhost:5432/posthog_persons | |
| REDIS_URL: redis://localhost:6379/ | |
| CACHE_TTL_SECONDS: '0' | |
| RUST_BACKTRACE: '1' | |
| run: | | |
| ./target/debug/feature-flags > /tmp/rust-flags.log 2>&1 & | |
| RUST_FLAGS_PID=$! | |
| echo "RUST_FLAGS_PID=$RUST_FLAGS_PID" >> $GITHUB_ENV | |
| for i in {1..30}; do | |
| if ! kill -0 "$RUST_FLAGS_PID" 2>/dev/null; then | |
| echo "ERROR: Rust flags service exited unexpectedly" | |
| cat /tmp/rust-flags.log || true | |
| exit 1 | |
| fi | |
| if curl -s http://127.0.0.1:3001/_readiness > /dev/null 2>&1; then | |
| echo "Rust flags service is ready" | |
| break | |
| fi | |
| echo "Waiting for Rust flags service... ($i/30)" | |
| sleep 2 | |
| done | |
| if ! curl -s http://127.0.0.1:3001/_readiness > /dev/null 2>&1; then | |
| echo "ERROR: Rust flags service failed to start after 30 attempts" | |
| cat /tmp/rust-flags.log || true | |
| exit 1 | |
| fi | |
| - name: Seed test data | |
| run: python manage.py generate_demo_data --n-clusters 10 --days-past 7 --days-future 0 --skip-materialization --skip-flag-sync --skip-user-product-list | |
| - name: Create API key and extract test IDs | |
| run: | | |
| python -c " | |
| import django, os | |
| os.environ['DJANGO_SETTINGS_MODULE'] = 'posthog.settings' | |
| django.setup() | |
| from posthog.models import Organization, Team, User, EventDefinition | |
| from posthog.models.personal_api_key import PersonalAPIKey | |
| from posthog.models.utils import hash_key_value | |
| org = Organization.objects.first() | |
| team = Team.objects.first() | |
| user = User.objects.first() | |
| PersonalAPIKey.objects.create( | |
| user=user, | |
| label='mcp_ci_api_key', | |
| secure_value=hash_key_value('e2e_demo_api_key'), | |
| scopes=['*'], | |
| ) | |
| # Ensure common event definitions exist for MCP integration tests | |
| for event_name in ['\$pageview', '\$pageleave', '\$autocapture', '\$screen']: | |
| EventDefinition.objects.get_or_create(name=event_name, team=team) | |
| print(f'TEST_ORG_ID={org.id}') | |
| print(f'TEST_PROJECT_ID={team.id}') | |
| " >> $GITHUB_ENV | |
| - name: Source celery queues | |
| run: | | |
| source ./bin/celery-queues.env | |
| echo "CELERY_WORKER_QUEUES=$CELERY_WORKER_QUEUES" >> $GITHUB_ENV | |
| - name: Start PostHog web & Celery worker | |
| run: | | |
| python manage.py run_autoreload_celery --type=worker &> /tmp/celery.log & | |
| python -m granian --interface asgi posthog.asgi:application --host 0.0.0.0 --port 8000 --workers 1 &> /tmp/server.log & | |
| - name: Wait for PostHog to be ready | |
| uses: iFaxity/wait-on-action@1fe019e0475491e9e8c4f421b6914ccc3ed8f99c # v1.2.1 | |
| with: | |
| resource: http://localhost:8000 | |
| timeout: 180000 | |
| interval: 2000 | |
| verbose: true | |
| - name: Run integration tests | |
| run: cd services/mcp && pnpm run test:integration | |
| env: | |
| TEST_POSTHOG_API_BASE_URL: http://localhost:8000 | |
| TEST_POSTHOG_PERSONAL_API_KEY: e2e_demo_api_key | |
| TEST_ORG_ID: ${{ env.TEST_ORG_ID }} | |
| TEST_PROJECT_ID: ${{ env.TEST_PROJECT_ID }} | |
| - name: Show server logs on failure | |
| if: failure() | |
| run: cat /tmp/server.log || true | |
| - name: Show celery logs on failure | |
| if: failure() | |
| run: cat /tmp/celery.log || true | |
| - name: Show Rust flags service logs on failure | |
| if: failure() | |
| run: cat /tmp/rust-flags.log || true | |
| - name: Show docker compose logs on failure | |
| if: failure() | |
| shell: bash | |
| run: docker compose -f docker-compose.dev.yml logs | |
| handle-snapshots: | |
| name: Commit snapshot changes | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| needs: [changes, unit-tests] | |
| if: ${{ always() && needs.changes.outputs.mcp == 'true' && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && !contains(github.actor, '[bot]') && github.actor != 'posthog-bot' && !contains(github.actor, 'github-actions') }} | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Get app token | |
| id: app-token | |
| uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 | |
| with: | |
| client-id: ${{ secrets.GH_APP_POSTHOG_TESTS_APP_ID }} | |
| private-key: ${{ secrets.GH_APP_POSTHOG_TESTS_PRIVATE_KEY }} | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| repository: ${{ github.event.pull_request.head.repo.full_name }} | |
| token: ${{ steps.app-token.outputs.token }} | |
| fetch-depth: 1 | |
| - name: Download snapshot patches | |
| id: download-patches | |
| continue-on-error: true | |
| uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 | |
| with: | |
| pattern: mcp-snapshot-patch | |
| path: /tmp/snapshot-patches | |
| merge-multiple: true | |
| - name: Check for patches | |
| id: check-patches | |
| run: | | |
| if [ "${{ steps.download-patches.outcome }}" == "failure" ] || [ ! -d /tmp/snapshot-patches ]; then | |
| echo "has-patches=false" >> $GITHUB_OUTPUT | |
| echo "No snapshot patches found" | |
| exit 0 | |
| fi | |
| if [ -n "$(find /tmp/snapshot-patches -name '*.patch' -type f -size +0c 2>/dev/null)" ]; then | |
| echo "has-patches=true" >> $GITHUB_OUTPUT | |
| echo "Found patches:" | |
| ls -la /tmp/snapshot-patches/ | |
| else | |
| echo "has-patches=false" >> $GITHUB_OUTPUT | |
| echo "Patch files empty or missing - no snapshot changes" | |
| fi | |
| - name: Commit snapshots | |
| if: steps.check-patches.outputs.has-patches == 'true' | |
| uses: ./.github/actions/commit-snapshots | |
| with: | |
| workflow-type: backend | |
| patch-path: /tmp/snapshot-patches | |
| snapshot-path: 'services/mcp/tests/unit/' | |
| commit-message: 'test(mcp): update unit test snapshots' | |
| pr-number: ${{ github.event.pull_request.number }} | |
| repository: ${{ github.repository }} | |
| commit-sha: ${{ github.event.pull_request.head.sha }} | |
| branch-name: ${{ github.event.pull_request.head.ref }} | |
| github-token: ${{ steps.app-token.outputs.token }} | |
| # Collation job for required status check | |
| mcp_tests: | |
| needs: [changes, build, unit-tests, integration-tests, handle-snapshots] | |
| name: MCP Tests Pass | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| if: always() | |
| steps: | |
| - name: Check all MCP jobs | |
| run: | | |
| # Fail if change detection itself failed | |
| if [[ "${{ needs.changes.result }}" == "failure" ]]; then | |
| echo "Change detection job failed." | |
| exit 1 | |
| fi | |
| # Pass if no MCP changes detected (jobs were skipped) | |
| if [[ "${{ needs.changes.outputs.mcp }}" != "true" ]]; then | |
| echo "MCP checks were skipped (no relevant changes)." | |
| exit 0 | |
| fi | |
| if [[ "${{ needs.build.result }}" != "success" && "${{ needs.build.result }}" != "skipped" ]]; then | |
| echo "MCP build failed." | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.unit-tests.result }}" != "success" && "${{ needs.unit-tests.result }}" != "skipped" ]]; then | |
| echo "MCP unit tests failed." | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.integration-tests.result }}" != "success" && "${{ needs.integration-tests.result }}" != "skipped" ]]; then | |
| echo "MCP integration tests failed." | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.handle-snapshots.result }}" == "failure" ]]; then | |
| echo "MCP snapshot commit job failed." | |
| exit 1 | |
| fi | |
| echo "All MCP checks passed." |