From 8285e556599f0b92504a5ee6f97429c337c20805 Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Wed, 16 Sep 2026 10:37:49 +0200 Subject: [PATCH] ci(postgrest-typegen): drop the nightly parity job against postgres-meta postgres-meta deleted its own templates and consumes this package (supabase/postgres-meta#1084, postgres-meta v0.99.0), with its lockfile pinned to 0.2.0. The nightly "Parity vs. real postgres-meta" job was therefore diffing main against our own 0.2.0 release, and every intentional generator change since (Python fixes in 0.2.1, TypeScript collation in 0.2.2) failed it as "drift". There is no independent upstream left to compare against, so remove the job, its schedule and dispatch triggers, the three scripts that only served it, and rewrite the byte-parity docs to describe the post-cutover relationship. --- .../workflows/postgrest-typegen-validate.yml | 95 +------------------ CLAUDE.md | 2 +- packages/postgrest-typegen/CLAUDE.md | 32 ++++--- packages/postgrest-typegen/README.md | 16 ++-- packages/postgrest-typegen/knip.json | 8 +- .../scripts/canonicalize-typescript.ts | 33 ------- .../scripts/load-fixtures.ts | 30 ------ .../scripts/print-generated.ts | 53 ----------- .../test/parity/parity.test.ts | 32 +++---- 9 files changed, 40 insertions(+), 261 deletions(-) delete mode 100644 packages/postgrest-typegen/scripts/canonicalize-typescript.ts delete mode 100644 packages/postgrest-typegen/scripts/load-fixtures.ts delete mode 100644 packages/postgrest-typegen/scripts/print-generated.ts diff --git a/.github/workflows/postgrest-typegen-validate.yml b/.github/workflows/postgrest-typegen-validate.yml index a0c525ff..758f3661 100644 --- a/.github/workflows/postgrest-typegen-validate.yml +++ b/.github/workflows/postgrest-typegen-validate.yml @@ -10,9 +10,6 @@ on: paths: - "packages/postgrest-typegen/**" - ".github/workflows/postgrest-typegen-validate.yml" - schedule: - - cron: "0 6 * * *" # nightly drift check against real postgres-meta - workflow_dispatch: {} defaults: run: @@ -21,10 +18,9 @@ defaults: jobs: test: name: Types, lint, build, test - if: github.event_name == 'push' || github.event_name == 'pull_request' runs-on: ubuntu-latest steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Install bun run: curl -fsSL https://bun.sh/install | bash - name: Add bun to PATH @@ -35,92 +31,3 @@ jobs: - run: bun run knip - run: bun run build - run: bun run test - - parity-check: - name: Parity vs. real postgres-meta - # Nightly/manual only, never on push or pull_request: postgres-meta can - # drift for reasons unrelated to any change here, and that shouldn't - # block or flake unrelated PRs (same pattern as capability-matrix's - # "Tier 2" reference checks). - if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' - runs-on: ubuntu-latest - services: - postgres: - image: postgres:15-alpine - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: postgres - ports: - - 5432:5432 - options: >- - --health-cmd pg_isready - --health-interval 5s - --health-timeout 5s - --health-retries 10 - env: - DATABASE_URL: postgresql://postgres:postgres@localhost:5432/postgres - steps: - - name: Checkout supabase/sdk - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Checkout supabase/postgres-meta - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - repository: supabase/postgres-meta - path: postgres-meta - - name: Install bun - run: curl -fsSL https://bun.sh/install | bash - - name: Add bun to PATH - run: echo "$HOME/.bun/bin" >> "$GITHUB_PATH" - - run: bun install --frozen-lockfile - - name: Load shared fixture schema - run: bun scripts/load-fixtures.ts - - name: Generate postgrest-typegen output - run: | - mkdir -p /tmp/ours - for lang in typescript go python swift; do - bun scripts/print-generated.ts "$lang" > "/tmp/ours/$lang.txt" - done - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: "22" - - name: Install postgres-meta dependencies - working-directory: postgres-meta - run: npm ci - - name: Generate postgres-meta output - working-directory: postgres-meta - env: - PG_META_DB_URL: postgresql://postgres:postgres@localhost:5432/postgres - run: | - mkdir -p /tmp/theirs - for lang in typescript go python swift; do - PG_META_GENERATE_TYPES="$lang" node --loader ts-node/esm src/server/server.ts > "/tmp/theirs/$lang.txt" - done - - name: Canonicalize postgres-meta's TypeScript output - # postgres-meta formats with prettier; this package defaults to - # oxfmt, which has different line-wrap heuristics (e.g. printWidth is - # matched at 80, but wrapping decisions for nested object types can - # still differ). Reformatting postgres-meta's output through our own - # formatter first means the diff below reflects content, not which - # formatter produced it. - run: bun scripts/canonicalize-typescript.ts /tmp/theirs/typescript.txt > /tmp/theirs/typescript.canonical.txt - - name: Compare outputs - # Order-independent: sortGeneratorMetadata canonicalizes collection - # order (semantic schema+name, not postgres-meta's environment- and - # data-dependent heap order) across all four generators, which is a - # deliberate improvement over postgres-meta's real behavior, not a - # divergence to flag. Comparing declaration BLOCKS (paragraphs - # separated by a blank line) as a sorted set, rather than raw bytes, - # verifies the two agree on content without being sensitive to that - # reordering. - run: | - mv /tmp/theirs/typescript.canonical.txt /tmp/theirs/typescript.txt - normalize() { awk 'BEGIN{RS="";FS="\n"} {gsub(/\n/, "\\n"); print}' "$1" | sort; } - failed=0 - for lang in typescript go python swift; do - if ! diff -u <(normalize "/tmp/theirs/$lang.txt") <(normalize "/tmp/ours/$lang.txt"); then - echo "::error::$lang output diverges from real postgres-meta" - failed=1 - fi - done - exit "$failed" diff --git a/CLAUDE.md b/CLAUDE.md index 594a3a65..b609b702 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,7 +9,7 @@ This is a lightweight monorepo of shared tooling for the Supabase client SDKs. P - `packages/capability-matrix/` — the **canonical feature registry** for all Supabase client SDKs — not the SDKs themselves. It defines what features exist (name, description, grouping) across 7 client SDKs (JavaScript, Flutter, Python, Swift, C#, Go, Kotlin). SDKs declare compliance separately in their own repos via `sdk-compliance.yaml` files. The output is a static capability matrix website at https://supabase.github.io/sdk/ showing which features each SDK implements. - `packages/dart-symbol-extractor/` — Dart public API symbol extractor used by the Dart compliance workflow. - `packages/go-symbol-extractor/` — Go public API symbol extractor used by the Go compliance workflow. -- `packages/postgrest-typegen/` — introspects a PostgreSQL schema into the `GeneratorMetadata` contract and generates PostgREST types for TypeScript, Go, Python, and Swift. See its own `CLAUDE.md` for architecture and the byte-parity constraint with postgres-meta. +- `packages/postgrest-typegen/` — introspects a PostgreSQL schema into the `GeneratorMetadata` contract and generates PostgREST types for TypeScript, Go, Python, and Swift. See its own `CLAUDE.md` for architecture and how postgres-meta and the CLI consume it. ## Commands diff --git a/packages/postgrest-typegen/CLAUDE.md b/packages/postgrest-typegen/CLAUDE.md index 5aa422e6..99bc78de 100644 --- a/packages/postgrest-typegen/CLAUDE.md +++ b/packages/postgrest-typegen/CLAUDE.md @@ -65,21 +65,23 @@ bun run format-and-lint # oxfmt + oxlint check bun run knip # unused-code/deps check ``` -## Byte-Parity Constraint - -This package must produce **byte-identical** output to postgres-meta's -templates until parity is validated and released. Two consequences: - -- `prettier` is pinned **exact** to the version postgres-meta's own lockfile - currently resolves (not a caret range, and not just "latest"), since a - version mismatch reformats generator output and silently breaks parity with - the real upstream CLI, not just with this package's own snapshots. Check - postgres-meta's resolved version before bumping. Bumping means regenerating - every inline snapshot (`bun test --update-snapshots`) and the parity - fixtures under `test/parity/expected/`, and reviewing the diff. -- Don't "improve" template strings or SQL for existing generators without - regenerating snapshots/fixtures first. Byte parity first; behavior-changing - cleanups (e.g. oxfmt instead of prettier) come later. +## Relationship to postgres-meta + +postgres-meta deleted its own templates and consumes this package for all four +languages (supabase/postgres-meta#1084, shipped in postgres-meta v0.99.0 on +2026-08-31), and so does the CLI (supabase/cli#6404). This package is the +single source of truth for generator output: there is no upstream to stay +byte-identical with, and there is no cross-check against postgres-meta (its +output is whatever version of this package its lockfile pins, so such a check +only ever measured release lag). Consequences: + +- Every generator output change is a behavior change for every consumer. + Regenerate the inline snapshots (`bun test --update-snapshots`) and the + goldens under `test/parity/expected/` in the same PR, review that diff + deliberately, and describe the output change in the PR so it reaches the + release notes consumers read before bumping. +- Don't reformat or "clean up" template strings casually; a formatter-only + change still churns every consumer's generated files. SQL literal quoting: the introspection queries use `literal()` from `src/introspection/sql/pg-format.ts`, an inlined port of `pg-format@1.0.4` diff --git a/packages/postgrest-typegen/README.md b/packages/postgrest-typegen/README.md index 61808cb8..8fc5ee04 100644 --- a/packages/postgrest-typegen/README.md +++ b/packages/postgrest-typegen/README.md @@ -17,19 +17,19 @@ JSON output, not inside `postgrest-typegen`. The TypeScript, Go, Python, and Swift generators bundled here are a **deliberate transition**, not the target architecture for new languages. -They were ported byte-parity from postgres-meta's own templates so -`supabase gen types` keeps working unchanged while postgres-meta's copies get -deprecated in favor of this package. It's decided that all four eventually -move out to their own SDK repos too (tracked in SDK-1641), not yet scheduled -— sequenced after postgres-meta's cutover to this package settles. +They were ported byte-for-byte from postgres-meta's own templates so +`supabase gen types` kept working unchanged; postgres-meta has since deleted +its copies and consumes this package instead. It's decided that all four +eventually move out to their own SDK repos too (tracked in SDK-1641), not yet +scheduled — sequenced after postgres-meta's cutover to this package settles. > [!IMPORTANT] > **We are no longer accepting contributions that fix the bundled generators.** > Because each of the four is moving out to its own language's SDK repository, > a fix landed here would have to be made a second time in the destination -> repository, and it also breaks byte parity with postgres-meta until a release -> propagates. Please open an issue describing the bug instead, so it can be -> tracked and carried across the move. +> repository, and postgres-meta and the CLI only pick it up once they bump +> their pinned version of this package. Please open an issue describing the +> bug instead, so it can be tracked and carried across the move. ## Design diff --git a/packages/postgrest-typegen/knip.json b/packages/postgrest-typegen/knip.json index 120b6d19..4d23f829 100644 --- a/packages/postgrest-typegen/knip.json +++ b/packages/postgrest-typegen/knip.json @@ -1,11 +1,5 @@ { "$schema": "https://unpkg.com/knip@5/schema.json", - "entry": [ - "test/global-setup.ts", - "test/**/*.test.ts", - "scripts/load-fixtures.ts", - "scripts/print-generated.ts", - "scripts/canonicalize-typescript.ts" - ], + "entry": ["test/global-setup.ts", "test/**/*.test.ts"], "ignoreBinaries": ["oxfmt", "oxlint"] } diff --git a/packages/postgrest-typegen/scripts/canonicalize-typescript.ts b/packages/postgrest-typegen/scripts/canonicalize-typescript.ts deleted file mode 100644 index b9609322..00000000 --- a/packages/postgrest-typegen/scripts/canonicalize-typescript.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Reformats a TypeScript file through this package's default formatter - * (oxfmt, `semi: false`, `printWidth: 80`) and prints the result to stdout. - * - * Used by the "parity vs. real postgres-meta" CI job to canonicalize - * postgres-meta's prettier-formatted output before diffing it against ours, - * so a formatter-only difference (e.g. line-wrap heuristics) doesn't read as - * a content divergence. Content itself still fails the diff either way. - * - * Usage: bun scripts/canonicalize-typescript.ts - */ -import { readFileSync } from "node:fs"; -import { format } from "oxfmt"; - -const filePath = process.argv[2]; -if (!filePath) { - throw new Error("A file path is required"); -} - -const { code, errors } = await format( - "output.ts", - readFileSync(filePath, "utf8"), - { - semi: false, - printWidth: 80, - }, -); -if (errors.length > 0) { - throw new Error( - `oxfmt failed to format ${filePath}: ${errors.map((error) => error.message).join("; ")}`, - ); -} -process.stdout.write(code); diff --git a/packages/postgrest-typegen/scripts/load-fixtures.ts b/packages/postgrest-typegen/scripts/load-fixtures.ts deleted file mode 100644 index df2ed6f5..00000000 --- a/packages/postgrest-typegen/scripts/load-fixtures.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Loads the shared fixture schema (the same one `test/introspection/` and - * `test/parity/` use) into DATABASE_URL. Used by the "parity vs. real - * postgres-meta" CI job so both sides introspect the identical schema - * without depending on a system `psql` client being present on the runner. - */ -import { readFileSync } from "node:fs"; -import { join } from "node:path"; -import { Pool } from "pg"; - -const databaseUrl = process.env.DATABASE_URL; -if (!databaseUrl) { - throw new Error("DATABASE_URL is required"); -} - -const FIXTURE_DIR = join( - import.meta.dir, - "..", - "test", - "introspection", - "fixtures", -); - -const pool = new Pool({ connectionString: databaseUrl }); -try { - await pool.query(readFileSync(join(FIXTURE_DIR, "00-init.sql"), "utf8")); - await pool.query(readFileSync(join(FIXTURE_DIR, "01-memes.sql"), "utf8")); -} finally { - await pool.end(); -} diff --git a/packages/postgrest-typegen/scripts/print-generated.ts b/packages/postgrest-typegen/scripts/print-generated.ts deleted file mode 100644 index d075325e..00000000 --- a/packages/postgrest-typegen/scripts/print-generated.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Prints this package's generated output for one language against a live - * database, for the "parity vs. real postgres-meta" CI job to diff against - * postgres-meta's own `npm run gen:types:` output for the same schema. - * Not used by the test suite, which compares against committed goldens - * instead — this is the live-vs-live check the goldens can't provide, since - * they're maintained by regenerating from this package itself. - * - * Mirrors postgres-meta's `server.ts` CLI path: no generator options - * overridden, matching its defaults when no `PG_META_GENERATE_TYPES_*` env - * vars are set, and a single `console.log` so the trailing newline matches. - * - * Usage: bun scripts/print-generated.ts - */ -import { Pool } from "pg"; - -import { - generateGo, - generatePython, - generateSwift, - generateTypescript, - introspect, - sortGeneratorMetadata, -} from "../src/index.ts"; - -const language = process.argv[2]; -const databaseUrl = process.env.DATABASE_URL; -if (!databaseUrl) { - throw new Error("DATABASE_URL is required"); -} - -const pool = new Pool({ connectionString: databaseUrl }); -try { - const metadata = sortGeneratorMetadata(await introspect(pool)); - switch (language) { - case "typescript": - console.log(await generateTypescript(metadata)); - break; - case "go": - console.log(generateGo(metadata)); - break; - case "python": - console.log(generatePython(metadata)); - break; - case "swift": - console.log(generateSwift(metadata)); - break; - default: - throw new Error(`Unsupported language: ${language}`); - } -} finally { - await pool.end(); -} diff --git a/packages/postgrest-typegen/test/parity/parity.test.ts b/packages/postgrest-typegen/test/parity/parity.test.ts index 088f59d4..00e1e0a0 100644 --- a/packages/postgrest-typegen/test/parity/parity.test.ts +++ b/packages/postgrest-typegen/test/parity/parity.test.ts @@ -20,30 +20,22 @@ import { introspect } from "../../src/introspection/index.ts"; import type { GeneratorMetadata } from "../../src/types.ts"; /** - * End-to-end parity gate: introspect the shared postgres-meta fixture DB, run - * all four generators with their default options, and assert the output matches - * the committed golden files in `expected/`. + * End-to-end golden gate: introspect the shared fixture DB, run all four + * generators with their default options, and assert the output matches the + * committed golden files in `expected/`. * * The metadata is passed through `sortGeneratorMetadata` first (as every * consumer must), so the golden files reflect the canonical, deterministic - * ordering rather than the database's heap order. The goldens were originally - * captured from a real postgres-meta CLI run against this fixture DB; only the - * ordering of order-sensitive collections (Go/Python/Swift emit tables/views - * in metadata order) is canonicalized — and postgres-meta applies the same - * sort pass, so the two stay in lockstep. postgres-meta's CLI prints with - * `console.log`, which appends exactly one trailing newline to the - * generator's return value — hence the `+ "\n"` below. + * ordering rather than the database's heap order. Consumers print the + * generator's return value with `console.log`, which appends exactly one + * trailing newline, hence the `+ "\n"` below. * - * CAUTION — this only proves parity at the moment a golden was captured. The - * established workflow for an *intentional* generator change is to - * regenerate the goldens from this package itself and review the diff, which - * means a generator change and its golden update land in the same PR: the - * gate then only proves internal self-consistency (generator output matches - * its own golden), not agreement with postgres-meta's actual current output. - * It cannot catch a regression introduced by that same change. Re-verify - * against a real postgres-meta run periodically, and always whenever - * postgres-meta's own templates change (e.g. the upstream fixes ported into - * this package) rather than trusting a self-regenerated golden alone. + * The goldens were originally captured from postgres-meta's own templates + * before it cut over to this package; since then they are regenerated from + * this package whenever a generator changes on purpose. A generator change + * and its golden update land in the same PR, so this gate proves output does + * not change *unintentionally*, and the reviewed golden diff is where an + * intentional change gets scrutinized. */ const FIXTURE_DIR = join(import.meta.dir, "..", "introspection", "fixtures"); const EXPECTED_DIR = join(import.meta.dir, "expected");