|
| 1 | +# Package check: verify committed artifacts are in sync with `deploy/` |
| 2 | + |
| 3 | +`pgpm package --check` is a **read-only, no-DB** integrity check. It proves |
| 4 | +that each module's committed build artifact (`sql/<name>--<version>.bundle.tar.gz`) |
| 5 | +still matches the SQL in that module's `deploy/`, and fails fast when someone |
| 6 | +edited SQL without re-running `pgpm package`. Consult this when wiring a CI |
| 7 | +gate for pgpm workspaces, or when asked "how do we stop stale bundles from |
| 8 | +being merged". |
| 9 | + |
| 10 | +It is the verification half of the packaging story: |
| 11 | + |
| 12 | +- `pgpm package` — **build** the artifacts (`sql/<name>--<version>.sql` + |
| 13 | + `sql/<name>--<version>.bundle.tar.gz`). See `references/publishing.md`. |
| 14 | +- `pgpm package --check` — **verify** those committed artifacts (this file). |
| 15 | +- `pgpm deploy --fast` / `--bundled` — **consume** the verified bundle. See |
| 16 | + `references/deploy-lifecycle.md`. |
| 17 | +- Artifact internals (digests, AST) — the `pgpm-migration-bundle` skill. |
| 18 | + |
| 19 | +## Commands |
| 20 | + |
| 21 | +```bash |
| 22 | +pgpm package --check # verify only the modules that changed |
| 23 | +pgpm package --check --since origin/main # diff HEAD vs a branch, ref, or tag |
| 24 | +pgpm package --check --all # verify every module in the workspace |
| 25 | +pgpm package --check --dependents # also re-check modules that require a changed one |
| 26 | +pgpm package --check --no-fail-fast # list every drifted module instead of stopping at the first |
| 27 | +``` |
| 28 | + |
| 29 | +Exits non-zero and names each drifted module, e.g.: |
| 30 | + |
| 31 | +```text |
| 32 | +✖ my-second: committed bundle does not match deploy/ — run `pgpm package` |
| 33 | +1 module(s) out of sync. Run `pgpm package` in each and commit the artifacts. |
| 34 | +``` |
| 35 | + |
| 36 | +## How it decides what to check |
| 37 | + |
| 38 | +Change detection layers cheapest-source-first, then maps files to modules |
| 39 | +through the workspace graph: |
| 40 | + |
| 41 | +1. **Base ref** — explicit `--since <ref>` wins; otherwise the PR base in CI |
| 42 | + (`origin/$GITHUB_BASE_REF`); otherwise working-tree only. |
| 43 | +2. **Changed files** — union of `git diff --name-only <base>...HEAD` |
| 44 | + (three-dot, so branches/refs/tags all work) and `git status --porcelain` |
| 45 | + (uncommitted + untracked). It shells out to the `git` binary — no |
| 46 | + `simple-git`/Octokit dependency. |
| 47 | +3. **Files → modules** — each changed path is attributed to its owning module |
| 48 | + (longest-matching module directory). Only those modules are checked. |
| 49 | + `--all` skips detection; `--dependents` walks the reverse `requires` graph. |
| 50 | + |
| 51 | +> A module's artifact reflects **only its own** `deploy/` (`resolveWithPlan` |
| 52 | +> never inlines required modules), so a dependency change cannot drift a |
| 53 | +> dependent's artifact. `--dependents` is therefore off by default — enable it |
| 54 | +> only for extra-paranoid checks. |
| 55 | +
|
| 56 | +## What it verifies per module |
| 57 | + |
| 58 | +For each targeted module (`checkModuleArtifact` in |
| 59 | +`pgpm/core/src/packaging/check.ts`): |
| 60 | + |
| 61 | +1. `resolveBundleArtifactPath` — artifact exists → else `missing-artifact`. |
| 62 | +2. `readBundleArtifact` — archive is readable → else `unreadable-artifact`. |
| 63 | +3. `verifyBundle` — internal digests are self-consistent → else `integrity`. |
| 64 | +4. `bundleMatchesModule` — the artifact's stored per-change sha256 + plan bytes |
| 65 | + still match the current `deploy/` → else `out-of-sync`. |
| 66 | + |
| 67 | +No SQL is parsed or executed and no database is touched — it is read + sha256 |
| 68 | +only, so it is cheap enough to gate every PR. |
| 69 | + |
| 70 | +## CI usage |
| 71 | + |
| 72 | +Drop the one-liner into a PR workflow (works in any pgpm workspace with zero |
| 73 | +config — it auto-detects the PR base): |
| 74 | + |
| 75 | +```yaml |
| 76 | +- name: Verify pgpm bundles are in sync |
| 77 | + run: pgpm package --check --since origin/${{ github.base_ref }} |
| 78 | +``` |
| 79 | +
|
| 80 | +Fail-fast is the default, so the job stops at the first stale bundle. Use |
| 81 | +`--no-fail-fast` when you want the full list in one run. |
| 82 | + |
| 83 | +## Programmatic API |
| 84 | + |
| 85 | +```ts |
| 86 | +import { checkPackages } from '@pgpmjs/core'; |
| 87 | +
|
| 88 | +const result = await checkPackages({ since: 'origin/main' }); |
| 89 | +if (result.drifted.length) process.exit(1); |
| 90 | +// result: { targeted, checked, drifted, base, changedModules } |
| 91 | +``` |
0 commit comments