Repository navigation
sql-orm-client: run update and delete through a mutation graph #2988
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 (PR) | |
| on: | |
| pull_request: | |
| merge_group: | |
| # Least-privilege GITHUB_TOKEN: only repo checkout needs a scope here. The | |
| # pnpm/Turbo caches (actions/cache) use the runner's cache runtime token, not | |
| # GITHUB_TOKEN, so no `actions` scope is required. | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Classifies the PR diff as "inert" (touches only files that cannot affect | |
| # build/test/fixture results) so heavy jobs can skip their expensive steps. | |
| # Fail-safe: a diff is inert only if *every* changed file matches the | |
| # allow-list below; any unrecognized path forces a full run. Required jobs | |
| # still launch and report (Pattern 1), so the branch ruleset stays satisfied | |
| # on docs-only PRs while the Postgres-backed work is skipped. | |
| changes: | |
| name: Detect inert diff | |
| runs-on: ubuntu-latest | |
| outputs: | |
| inert: ${{ steps.detect.outputs.inert }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - id: detect | |
| uses: ./.github/actions/detect-inert-diff | |
| build: | |
| name: Build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: ./.github/actions/setup | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build | |
| run: pnpm build | |
| - name: Check working tree is clean | |
| run: pnpm check:clean-tree | |
| typecheck: | |
| name: Type Check | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: ./.github/actions/setup | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Generate Prisma client | |
| run: pnpm --filter prisma-orm-demo prisma:generate | |
| - name: Build packages (restored from Turbo cache) | |
| run: pnpm build | |
| - name: Type check packages | |
| run: pnpm typecheck:packages | |
| - name: Type check examples | |
| run: pnpm typecheck:examples | |
| lint: | |
| name: Lint | |
| # Depends on build only for cache coherence: build is the single writer of | |
| # the shared Turbo/pnpm caches, so every other job restores an exact-key | |
| # hit and skips saving. The build step below just restores that cache. | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| # The per-PR gates diff HEAD against the branch this PR targets; | |
| # needs enough history for `git diff origin/<base>..HEAD` to resolve. | |
| fetch-depth: 0 | |
| - name: Fetch the base branch this PR targets | |
| env: | |
| BASE: ${{ github.base_ref || 'main' }} | |
| run: git fetch --no-tags origin "$BASE:refs/remotes/origin/$BASE" | |
| - uses: ./.github/actions/setup | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build packages (restored from Turbo cache) | |
| run: pnpm build | |
| - name: Lint dependencies | |
| run: pnpm lint:deps | |
| - name: Lint code shape | |
| run: pnpm lint:code | |
| - name: Lint packages | |
| run: pnpm lint:packages | |
| - name: Lint examples | |
| run: pnpm lint:examples | |
| - name: Validate rules | |
| run: pnpm lint:rules | |
| - name: Validate rule symlinks | |
| run: pnpm lint:rules:symlinks | |
| - name: Validate skills | |
| run: pnpm lint:skills | |
| - name: Check rules footprint | |
| run: pnpm lint:rules:footprint | |
| - name: Validate package READMEs | |
| run: pnpm lint:docs | |
| - name: Validate package manifests (license declarations) | |
| run: pnpm lint:manifests | |
| - name: Lint workflow triggers (forbid Pwn Request pattern) | |
| run: pnpm lint:workflows | |
| - name: Test scripts/ | |
| run: pnpm test:scripts | |
| - name: Lint casts | |
| run: pnpm lint:casts | |
| - name: Lint throws | |
| run: pnpm lint:throws | |
| - name: Lint framework vocabulary | |
| run: pnpm lint:framework-vocabulary | |
| - name: Lint consumer internal imports | |
| run: pnpm lint:consumer-internal-imports | |
| - name: Lint the legacy product name | |
| run: pnpm lint:legacy-name | |
| - name: Lint vitest timeout budgets | |
| run: pnpm lint:vitest-timeouts | |
| - name: Lint publishability matches the directory layout | |
| run: pnpm lint:publishability | |
| - name: Check upgrade-instruction coverage | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }} | |
| HEAD_SHA: ${{ github.event.merge_group.head_sha || github.sha }} | |
| run: pnpm check:upgrade-coverage --mode pr --prev "$BASE_SHA" --head "$HEAD_SHA" | |
| - name: Check error-reference completeness | |
| run: pnpm check:error-reference | |
| - name: Check release notes | |
| env: | |
| BASE: ${{ github.base_ref || 'main' }} | |
| run: pnpm check:release-notes --mode pr --prev "origin/$BASE" | |
| fixtures: | |
| name: Fixtures | |
| needs: [build, changes] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: ./.github/actions/setup | |
| - name: Install dependencies | |
| if: needs.changes.outputs.inert != 'true' | |
| run: pnpm install --frozen-lockfile | |
| - name: Build (restored from Turbo cache) | |
| if: needs.changes.outputs.inert != 'true' | |
| run: pnpm build | |
| - name: Link built binaries | |
| if: needs.changes.outputs.inert != 'true' | |
| run: pnpm install --frozen-lockfile | |
| - name: Check fixtures are up to date | |
| if: needs.changes.outputs.inert != 'true' | |
| run: pnpm fixtures:check | |
| test-packages: | |
| name: Package Tests (${{ matrix.index }}/4) | |
| needs: [build, changes] | |
| if: needs.changes.outputs.inert != 'true' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| index: [1, 2, 3, 4] | |
| env: | |
| TEST_TIMEOUT_MULTIPLIER: 2 | |
| services: | |
| postgres: | |
| image: postgres:15 | |
| env: | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_DB: postgres | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd="pg_isready -U postgres" | |
| --health-interval=10s | |
| --health-timeout=5s | |
| --health-retries=5 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: ./.github/actions/setup | |
| - name: Install dependencies (skip bin linking) | |
| run: pnpm install --frozen-lockfile --ignore-scripts | |
| - name: Build packages (restored from Turbo cache; needed for bin linking) | |
| run: pnpm build | |
| - name: Link bins | |
| run: pnpm install --frozen-lockfile | |
| - name: Run package tests with coverage | |
| id: package-tests | |
| continue-on-error: true | |
| env: | |
| VITEST_COVERAGE_SHARD: ${{ matrix.index }} | |
| run: pnpm coverage:packages --reporter=default --reporter=github-actions --reporter=blob --shard=${{ matrix.index }}/4 | |
| - name: Upload package coverage shard | |
| if: ${{ !cancelled() }} | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: package-coverage-${{ matrix.index }} | |
| path: .vitest/blob/blob-${{ matrix.index }}-4.json | |
| if-no-files-found: error | |
| include-hidden-files: true | |
| retention-days: 1 | |
| - name: Propagate package test failure | |
| if: steps.package-tests.outcome == 'failure' | |
| run: exit 1 | |
| test-examples: | |
| name: Test Examples | |
| needs: [build, changes] | |
| if: needs.changes.outputs.inert != 'true' | |
| runs-on: ubuntu-latest | |
| env: | |
| TEST_TIMEOUT_MULTIPLIER: 2 | |
| # Used by examples/prisma-8-cloudflare-worker's vitest-pool-workers | |
| # integration test. Mirrors the .env.example pattern; the container is | |
| # brought up by `pnpm db:up` below (docker-compose, not a service | |
| # container, because GitHub Actions service containers can't override | |
| # the postgres CMD to enable shared_preload_libraries=pg_stat_statements). | |
| WRANGLER_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE: postgres://postgres:postgres@127.0.0.1:5433/prisma_8_cloudflare_worker | |
| services: | |
| postgres: | |
| image: postgres:15 | |
| env: | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_DB: postgres | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd="pg_isready -U postgres" | |
| --health-interval=10s | |
| --health-timeout=5s | |
| --health-retries=5 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: ./.github/actions/setup | |
| - name: Install dependencies (skip bin linking) | |
| run: pnpm install --frozen-lockfile --ignore-scripts | |
| - name: Build packages (restored from Turbo cache; needed for bin linking) | |
| run: pnpm build | |
| - name: Link bins | |
| run: pnpm install --frozen-lockfile | |
| - name: Start cloudflare-worker Postgres (5433, pg_stat_statements) | |
| run: pnpm --filter prisma-8-cloudflare-worker db:up | |
| # Fetch Prisma 7's schema engine, which the install does not download, | |
| # so a slow or unreachable binary host fails this step within 5 minutes | |
| # instead of timing out inside the example test. | |
| - name: Fetch the Prisma 7 schema engine (prisma7-adoption) | |
| timeout-minutes: 5 | |
| run: pnpm --filter prisma7-adoption exec prisma7 --version --config prisma7.config.ts | |
| - name: Test examples | |
| run: pnpm test:examples | |
| - name: Check working tree is clean | |
| run: pnpm check:clean-tree | |
| coverage: | |
| name: Coverage | |
| needs: [build, changes, test-packages] | |
| if: ${{ !cancelled() && needs.build.result == 'success' && needs.changes.result == 'success' && needs.changes.outputs.inert != 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: ./.github/actions/setup | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile --ignore-scripts | |
| - name: Build packages (restored from Turbo cache) | |
| run: pnpm build | |
| - name: Download package coverage shards | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| pattern: package-coverage-* | |
| path: .vitest/blob | |
| merge-multiple: true | |
| - name: Verify package coverage shards | |
| run: | | |
| test -f .vitest/blob/blob-1-4.json | |
| test -f .vitest/blob/blob-2-4.json | |
| test -f .vitest/blob/blob-3-4.json | |
| test -f .vitest/blob/blob-4-4.json | |
| - name: Merge package tests and coverage | |
| run: pnpm coverage:packages:merge | |
| - name: Report package coverage | |
| if: ${{ !cancelled() }} | |
| run: pnpm coverage:report | |
| - name: Check working tree is clean | |
| if: ${{ !cancelled() }} | |
| run: pnpm check:clean-tree | |
| test: | |
| name: Test | |
| needs: [build, changes, test-packages, test-examples, coverage, test-integration] | |
| if: ${{ !cancelled() }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Propagate test failures | |
| if: ${{ needs.build.result != 'success' || needs.changes.result != 'success' || (needs.changes.outputs.inert != 'true' && (needs.test-packages.result != 'success' || needs.test-examples.result != 'success' || needs.coverage.result != 'success')) }} | |
| run: exit 1 | |
| - name: Require integration tests in the merge queue | |
| if: ${{ github.event_name == 'merge_group' && needs.changes.outputs.inert != 'true' && needs.test-integration.result != 'success' }} | |
| run: exit 1 | |
| test-e2e: | |
| name: E2E Tests | |
| needs: [build, changes] | |
| runs-on: ubuntu-latest | |
| env: | |
| TEST_TIMEOUT_MULTIPLIER: 2 | |
| services: | |
| postgres: | |
| image: postgres:15 | |
| env: | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_DB: postgres | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd="pg_isready -U postgres" | |
| --health-interval=10s | |
| --health-timeout=5s | |
| --health-retries=5 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: ./.github/actions/setup | |
| - name: Install dependencies | |
| if: needs.changes.outputs.inert != 'true' | |
| run: pnpm install --frozen-lockfile | |
| - name: Build (restored from Turbo cache) | |
| if: needs.changes.outputs.inert != 'true' | |
| run: pnpm build | |
| - name: Run E2E tests | |
| if: needs.changes.outputs.inert != 'true' | |
| run: pnpm test:e2e | |
| - name: Check working tree is clean | |
| if: needs.changes.outputs.inert != 'true' | |
| run: pnpm check:clean-tree | |
| test-integration: | |
| name: Integration Tests (${{ matrix.shard }}) | |
| needs: [build, changes] | |
| # Runs only in the merge queue, where `Test` requires it. The suite is | |
| # slow, so pull requests do not run it; run it on a branch with | |
| # `gh workflow run integration.yml --ref <branch>`. | |
| if: github.event_name == 'merge_group' && needs.changes.outputs.inert != 'true' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| shard: ['1/4', '2/4', '3/4', '4/4'] | |
| env: | |
| TEST_TIMEOUT_MULTIPLIER: 2 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: ./.github/actions/integration-tests | |
| with: | |
| shard: ${{ matrix.shard }} | |
| # Runs the real-Supabase acceptance harness against a live local Supabase | |
| # stack (`supabase start`), so the extension's role/grant/JWT behaviour is | |
| # proven against real platform defaults on every PR — the hermetic shim | |
| # alone let fidelity bugs ship (TML-3035 findings §5/§6/§8). Skips its | |
| # steps only on inert (docs-only) diffs; any change under packages/** or | |
| # examples/** is non-inert, so extension-supabase, examples/supabase, and | |
| # postgres target/adapter changes always run it. The stack's Docker images | |
| # are loaded from a cache that supabase-images.yml writes on main, because | |
| # public.ecr.aws rate-limits anonymous pulls; on a cache miss | |
| # `supabase start` pulls them from the registry. | |
| supabase-acceptance: | |
| name: Supabase Acceptance | |
| needs: [build, changes] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| env: | |
| TEST_TIMEOUT_MULTIPLIER: 2 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: ./.github/actions/setup | |
| - name: Install Supabase CLI | |
| id: supabase-cli | |
| if: needs.changes.outputs.inert != 'true' | |
| uses: ./.github/actions/supabase-cli | |
| - name: Restore Supabase Docker images | |
| id: supabase-images | |
| if: needs.changes.outputs.inert != 'true' | |
| uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 | |
| with: | |
| path: ${{ steps.supabase-cli.outputs.images-archive }} | |
| key: ${{ steps.supabase-cli.outputs.images-cache-key }} | |
| # Deleting the archive after loading frees its disk space for the build. | |
| - name: Load Supabase Docker images | |
| if: needs.changes.outputs.inert != 'true' && steps.supabase-images.outputs.cache-hit == 'true' | |
| env: | |
| ARCHIVE: ${{ steps.supabase-cli.outputs.images-archive }} | |
| run: | | |
| docker load --input "$ARCHIVE" | |
| rm "$ARCHIVE" | |
| - name: Install dependencies | |
| if: needs.changes.outputs.inert != 'true' | |
| run: pnpm install --frozen-lockfile | |
| - name: Build (restored from Turbo cache) | |
| if: needs.changes.outputs.inert != 'true' | |
| run: pnpm build | |
| - name: Start local Supabase stack | |
| if: needs.changes.outputs.inert != 'true' | |
| working-directory: examples/supabase | |
| run: supabase start | |
| - name: Export stack credentials for the acceptance harness | |
| if: needs.changes.outputs.inert != 'true' | |
| working-directory: examples/supabase | |
| run: | | |
| set -euo pipefail | |
| supabase status -o env > "$RUNNER_TEMP/supabase-status.env" | |
| set -a | |
| # shellcheck disable=SC1091 | |
| . "$RUNNER_TEMP/supabase-status.env" | |
| set +a | |
| { | |
| echo "DATABASE_URL=$DB_URL" | |
| echo "SUPABASE_JWT_SECRET=$JWT_SECRET" | |
| echo "SUPABASE_URL=$API_URL" | |
| echo "SUPABASE_ANON_KEY=$ANON_KEY" | |
| } >> "$GITHUB_ENV" | |
| - name: Run the real-Supabase acceptance harness | |
| if: needs.changes.outputs.inert != 'true' | |
| run: pnpm --filter supabase-example test test/real-supabase.acceptance.test.ts |