Skip to content

test(coverage): drive db/cache/nosql local providers to >=95% via sou… #125

test(coverage): drive db/cache/nosql local providers to >=95% via sou…

test(coverage): drive db/cache/nosql local providers to >=95% via sou… #125

Workflow file for this run

# instant.dev/api — CI
#
# Multi-repo note: go.mod uses `replace instant.dev/proto => ../proto`. The
# "Checkout proto sibling" step clones the proto repo next to this checkout.
# If your GitHub repo is not named `proto`, set the `PROTO_REPO` repository
# variable (e.g. `myorg/instant-proto`) or fork/rename to match
# `${{ github.repository_owner }}/proto`.
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-*/**'
schedule:
# Weekly — reserved for optional scheduled jobs (see e2e job).
- cron: '0 6 * * 1'
workflow_dispatch:
concurrency:
# CI-minute savings (2026-05-21): cancel prior in-flight CI run for the
# same branch/PR when a new commit lands. Different PRs/branches still
# run in parallel (group key includes github.ref).
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@v4
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
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:
TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/instant_dev_test?sslmode=disable
TEST_REDIS_URL: redis://localhost:6379/15
# db-provider admin target. internal/providers/db/local.go CREATEs a
# customer database per /db/new; in tests it connects to
# TEST_POSTGRES_CUSTOMERS_URL. testhelpers defaults this to an
# unreachable localhost:5434, so without this every postgres-
# provisioning test (TestDBNew_*, TestBulkTwin_*) 503'd. Points at an
# instant_customers DB created on the same service container below —
# exactly as deploy.yml's proven-green gate does.
TEST_POSTGRES_CUSTOMERS_URL: postgres://postgres:postgres@localhost:5432/instant_customers?sslmode=disable
steps:
- uses: actions/checkout@v4
- name: Checkout proto sibling (for go.mod replace ../proto)
uses: actions/checkout@v4
with:
repository: ${{ vars.PROTO_REPO || format('{0}/proto', github.repository_owner) }}
token: ${{ secrets.REPO_ACCESS_TOKEN }}
path: _proto_ci
- name: Place ../proto for Go replace directive
run: mv _proto_ci ../proto
- name: Checkout common sibling (for go.mod replace ../common)
uses: actions/checkout@v4
with:
repository: ${{ vars.COMMON_REPO || format('{0}/common', github.repository_owner) }}
token: ${{ secrets.REPO_ACCESS_TOKEN }}
path: _common_ci
- name: Place ../common for Go replace directive
run: mv _common_ci ../common
- uses: actions/setup-go@v5
with:
go-version: '1.25'
- name: Apply DB migrations to the test database
# Mirrors deploy.yml's proven-green gate. Before this step CI ran
# tests against a BARE Postgres whose schema came ONLY from
# testhelpers.runMigrations — a hand-maintained mirror. This step
# applies the REAL migration files (exactly like `make test-db-up`),
# then creates instant_customers — the db provider's local backend
# (internal/providers/db/local.go) CREATEs a customer database per
# /db/new and connects to TEST_POSTGRES_CUSTOMERS_URL for it. Without
# this DB every postgres provision (TestDBNew_*, TestBulkTwin_*) 503'd.
env:
PGPASSWORD: postgres
run: |
for f in $(ls internal/db/migrations/*.sql | sort); do
echo "→ applying $(basename "$f")"
psql -h localhost -U postgres -d instant_dev_test -f "$f" >/dev/null
done
echo "all migrations applied to instant_dev_test"
psql -h localhost -U postgres -d postgres -c "CREATE DATABASE instant_customers" >/dev/null
echo "created instant_customers (db-provider admin target)"
- run: go build ./...
- run: go vet ./...
# The gate. This MUST stay equal to deploy.yml's proven-green
# invocation (`go test ./... -short -count=1 -p 1`) PLUS `-race`:
# - `-p 1` is load-bearing: every package shares the single
# instant_dev_test DB + redis/15. Default parallelism runs ~25
# package binaries at once and they corrupt each other's DB/redis
# state mid-test. `-p 1` serialises package execution.
# - `-short` matches deploy.yml so the two gates run the identical
# hermetic suite (tests that genuinely need a live k8s/provisioner
# stack are tagged `e2e` and excluded from `./...` anyway).
# - `-race` is the extra rigor CI adds over deploy.yml — it caught
# the BillingHandler.ensureRazorpayFns data race.
- run: go test ./... -short -race -count=1 -p 1
# E2E requires a live Kubernetes stack (see repo CLAUDE.md). This job does not
# run on push/PR — only on schedule or manual dispatch — so default CI stays fast.
e2e:
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkout proto sibling
uses: actions/checkout@v4
with:
repository: ${{ vars.PROTO_REPO || format('{0}/proto', github.repository_owner) }}
token: ${{ secrets.REPO_ACCESS_TOKEN }}
path: _proto_ci
- run: mv _proto_ci ../proto
- name: Checkout common sibling
uses: actions/checkout@v4
with:
repository: ${{ vars.COMMON_REPO || format('{0}/common', github.repository_owner) }}
token: ${{ secrets.REPO_ACCESS_TOKEN }}
path: _common_ci
- run: mv _common_ci ../common
- uses: actions/setup-go@v5
with:
go-version: '1.25'
- name: E2E placeholder (wire to k8s / secrets)
run: |
echo "Configure services, secrets, and port-forwards, then run e.g.:"
echo " go test ./e2e/... -tags e2e -count=1 -timeout 180s"
echo "See CLAUDE.md (Full-stack E2E) for required env vars."