ci(coverage): drop --depth=1 base fetch (fix diff-cover 'no merge base') #209
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
| name: CI | |
| on: | |
| push: | |
| branches: [master] | |
| # CI-minute savings (2026-05-21): skip CI on docs-only commits. | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| - 'CLAUDE.md' | |
| - '.gitignore' | |
| - 'LICENSE' | |
| - 'BUGBASH-*/**' | |
| pull_request: | |
| branches: [master] | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| - 'CLAUDE.md' | |
| - '.gitignore' | |
| - 'LICENSE' | |
| - 'BUGBASH-*/**' | |
| concurrency: | |
| # CI-minute savings (2026-05-21): cancel prior in-flight CI for the same | |
| # branch/PR when a new commit lands. | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Stale-green guard. A PR can show a green CI run that was executed BEFORE a | |
| # breaking commit landed on the base branch — merging it would ship a broken | |
| # master. This job FAILS if the PR branch does not contain origin/<base> as | |
| # an ancestor, forcing an "Update branch" before the PR can merge. | |
| up-to-date-with-base: | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Fail if PR branch is behind its base branch | |
| run: | | |
| BASE="${{ github.event.pull_request.base.ref }}" | |
| git fetch origin "${BASE}" --depth=1 | |
| if git merge-base --is-ancestor "origin/${BASE}" HEAD; then | |
| echo "PR branch contains origin/${BASE} — up to date." | |
| else | |
| echo "::error::PR branch is behind origin/${BASE}. Update the branch (merge/rebase ${BASE}) and re-run CI so it validates against current base." | |
| exit 1 | |
| fi | |
| build-and-test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Checkout proto sibling (replace ../proto) | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: ${{ vars.PROTO_REPO || format('{0}/proto', github.repository_owner) }} | |
| # REPO_ACCESS_TOKEN is a fine-grained PAT with read on the private | |
| # sibling repos; GITHUB_TOKEN is scoped to THIS repo only and 404s. | |
| token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} | |
| path: _proto_ci | |
| - run: mv _proto_ci ../proto | |
| - name: Checkout common sibling (replace ../common) | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: ${{ vars.COMMON_REPO || format('{0}/common', github.repository_owner) }} | |
| token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} | |
| path: _common_ci | |
| - run: mv _common_ci ../common | |
| # Cross-repo registry-iterating tests (CLAUDE.md rule 18) text-walk | |
| # api/internal/models/audit_kinds.go and api/e2e/reliability_contract_test.go | |
| # to assert worker auditKind* wire values match the api source. Without | |
| # this checkout the tests SKIP in CI, leaving cross-repo drift detection | |
| # to developer machines only. INSTANT_API_REPO is set on the test step | |
| # below so findApiRepoRoot() locates the sibling deterministically. | |
| - name: Checkout api sibling (for cross-repo registry-iterating tests) | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: ${{ vars.API_REPO || format('{0}/api', github.repository_owner) }} | |
| token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} | |
| path: _api_ci | |
| fetch-depth: 1 | |
| - run: mv _api_ci ../api | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: '1.25' | |
| - run: go build ./... | |
| - run: go vet ./... | |
| - name: Run tests (with INSTANT_API_REPO for cross-repo gate) | |
| env: | |
| INSTANT_API_REPO: ${{ github.workspace }}/../api | |
| run: go test ./... -v -race -count=1 | |
| # Wave 5 — push the gated-test result to New Relic so a red run is | |
| # studyable from an NR dashboard, not just the GitHub Actions log. | |
| # if: always() records a FAILED `go test` as InstantCITestRun result=fail | |
| # + InstantCITestFailure. No-ops cleanly without the NR secret. | |
| - name: Emit CI result to New Relic | |
| if: always() | |
| uses: ./.github/actions/nr-ci-event | |
| with: | |
| license-key: ${{ secrets.NEW_RELIC_LICENSE_KEY }} | |
| account-id: ${{ secrets.NEW_RELIC_ACCOUNT_ID }} | |
| result: ${{ job.status == 'success' && 'pass' || 'fail' }} | |
| suite: build-and-test | |
| pr-number: ${{ github.event.pull_request.number }} | |
| failed-step: ${{ job.status != 'success' && 'go build / vet / test (-race)' || '' }} | |
| repo: ${{ github.repository }} | |
| workflow: ${{ github.workflow }} | |
| branch: ${{ github.ref_name }} | |
| commit-sha: ${{ github.sha }} | |
| log-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| event-name: ${{ github.event_name }} | |
| actor: ${{ github.actor }} | |
| # ------------------------------------------------------------------ | |
| # GATING integration job (W2-T1). | |
| # | |
| # WHY: the worker's real-DB integration tests | |
| # (internal/jobs/*_integration_test.go) skip under `-short` AND when | |
| # TEST_DATABASE_URL is unset. The fast `build-and-test` job above runs | |
| # `-race` with NO DB service and the deploy.yml test step runs | |
| # `-short` — so in BOTH the integration tests SKIP and gate NOTHING. | |
| # This job runs them WITHOUT `-short` against a real Postgres so the | |
| # trigger→DB round-trip is actually asserted in CI. It mirrors | |
| # coverage.yml's proven Postgres+Redis service block. Per the two-gate | |
| # rule (root CLAUDE.md rule 15 / project_api_two_test_gates_ci_and_deploy), | |
| # the same job is mirrored in deploy.yml — a worker test-infra change | |
| # must land in BOTH or the deploy wedges while PR CI stays green. | |
| integration: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| services: | |
| postgres: | |
| image: postgres:16-alpine | |
| env: | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_DB: instant_dev_test | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| redis: | |
| image: redis:7-alpine | |
| ports: | |
| - 6379:6379 | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| env: | |
| # Integration tests read TEST_DATABASE_URL and run the real-DB path | |
| # (they SKIP when it's unset). TEST_REDIS_URL is wired for parity | |
| # with coverage.yml and for the redis-touching jobs as they land. | |
| TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/instant_dev_test?sslmode=disable | |
| TEST_REDIS_URL: redis://localhost:6379/15 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Checkout proto sibling (replace ../proto) | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: ${{ vars.PROTO_REPO || format('{0}/proto', github.repository_owner) }} | |
| token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} | |
| path: _proto_ci | |
| - run: mv _proto_ci ../proto | |
| - name: Checkout common sibling (replace ../common) | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: ${{ vars.COMMON_REPO || format('{0}/common', github.repository_owner) }} | |
| token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} | |
| path: _common_ci | |
| - run: mv _common_ci ../common | |
| - name: Checkout api sibling (for migrations + cross-repo tests) | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: ${{ vars.API_REPO || format('{0}/api', github.repository_owner) }} | |
| token: ${{ secrets.REPO_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} | |
| path: _api_ci | |
| fetch-depth: 1 | |
| - run: mv _api_ci ../api | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: '1.25' | |
| - name: Apply DB migrations to the test database | |
| # Mirrors coverage.yml: api owns the platform_db schema | |
| # (teams / resources / deployments / pending_propagations / | |
| # audit_log) the integration tests round-trip against; apply those | |
| # first, then any worker-local SQL on top (IF NOT EXISTS-guarded). | |
| env: | |
| PGPASSWORD: postgres | |
| run: | | |
| if [ -d ../api/internal/db/migrations ]; then | |
| for f in $(ls ../api/internal/db/migrations/*.sql | sort); do | |
| echo "→ applying api migration $(basename "$f")" | |
| psql -h localhost -U postgres -d instant_dev_test -f "$f" >/dev/null | |
| done | |
| echo "all api migrations applied to instant_dev_test" | |
| else | |
| echo "::error::no api migrations directory found at ../api/internal/db/migrations — integration tests would skip" | |
| exit 1 | |
| fi | |
| if [ -d sql ]; then | |
| for f in $(ls sql/*.sql 2>/dev/null | sort); do | |
| echo "→ applying worker migration $(basename "$f")" | |
| psql -h localhost -U postgres -d instant_dev_test -f "$f" >/dev/null || echo "::warning::worker migration $(basename "$f") failed — likely overlap with api schema; continuing" | |
| done | |
| fi | |
| - name: Run real-DB integration tests (NO -short, so they do not skip) | |
| # `-run Integration` scopes the run to the _integration_test.go | |
| # funcs (all carry "Integration" in their name); `-p 1` because | |
| # every package shares the single instant_dev_test DB and default | |
| # parallelism corrupts shared state. Dropping `-short` is what | |
| # makes testhelpers.SetupTestDB's testing.Short() guard pass and | |
| # the real-DB path run instead of skipping. | |
| env: | |
| INSTANT_API_REPO: ${{ github.workspace }}/../api | |
| run: go test ./internal/... -run Integration -count=1 -p 1 -v | |
| # Wave 5 — record the real-DB integration-gate outcome in NR | |
| # (suite=integration) so a red here is visible alongside the unit gate on | |
| # the CI-health dashboard. No-ops without the NR secret. | |
| - name: Emit integration result to New Relic | |
| if: always() | |
| uses: ./.github/actions/nr-ci-event | |
| with: | |
| license-key: ${{ secrets.NEW_RELIC_LICENSE_KEY }} | |
| account-id: ${{ secrets.NEW_RELIC_ACCOUNT_ID }} | |
| result: ${{ job.status == 'success' && 'pass' || 'fail' }} | |
| suite: integration | |
| pr-number: ${{ github.event.pull_request.number }} | |
| failed-step: ${{ job.status != 'success' && 'real-DB integration tests' || '' }} | |
| repo: ${{ github.repository }} | |
| workflow: ${{ github.workflow }} | |
| branch: ${{ github.ref_name }} | |
| commit-sha: ${{ github.sha }} | |
| log-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| event-name: ${{ github.event_name }} | |
| actor: ${{ github.actor }} |