From 9e0abb109ef80480cd4576ca852b4461a68aa4b0 Mon Sep 17 00:00:00 2001 From: willbot Date: Thu, 24 Sep 2026 16:42:46 +0200 Subject: [PATCH] State the real reasons the engine has no dev builds The workflow and versioning.md said the engine has no dev builds because ADR 0004 forbids pre-releases. ADR 0004 says no such thing. The real reasons: the product CLI packages peer the engine at an exact release version, dev builds included, so a dev-stamped engine would make prisma@dev uninstallable; and CI makes every change to the engine's published contents bump its version, which publishes on merge, so a dev build would expose nothing. Co-Authored-By: Claude Opus 5.5 Signed-off-by: willbot Signed-off-by: Will Madden --- .github/workflows/publish.yml | 9 ++------- docs/oss/versioning.md | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3703389d..b06460c8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -96,13 +96,8 @@ jobs: pnpm test:scripts pnpm check:conformance - # The engine has no dev channel (ADR 0004: its line carries no - # pre-releases), so the dev stamp leaves its manifest alone and - # this run holds its committed version. Publishing it here, under - # `latest`, is the same rule the other packages follow — a merged - # version bump publishes that version under `latest` — applied at - # the engine's own bump, which is the first run to carry it. An - # already-published engine version is a no-op. + # Never a dev build of the engine: the families peer it at an exact + # release version, so a dev-stamped engine would satisfy none of them. - name: Publish the engine release if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.dry-run != 'true' }} env: diff --git a/docs/oss/versioning.md b/docs/oss/versioning.md index 9c1e889c..bdc38294 100644 --- a/docs/oss/versioning.md +++ b/docs/oss/versioning.md @@ -18,7 +18,7 @@ The transition onto the RC line is a one-time bump from the pre-8 base to `8.0.0 Every lockstep workspace package — publishable, private, and the workspace root — carries the same `version`. One read of root [`package.json`](../../package.json) answers "what version is this code?" for the repository. -**Exceptions:** `@prisma/compute` versions independently, pending extraction to another repository (operator ruling 2026-08-10), and keeps its own publish workflow ([`publish-compute.yml`](../../.github/workflows/publish-compute.yml)). `@prisma/cli-engine` also versions independently ([ADR 0004](../architecture/adrs/0004-engine-version-pinning.md), operator ruling 2026-08-13): an engine version means "the engine changed", not "the CLI released", which is what keeps the exact peer pins the product CLI packages hold on it cheap — they change only when the engine actually moves. The engine follows honest pre-1.0 semver (a breaking change bumps the minor); bumping it is one command — `pnpm bump-cli-engine-version ` — which edits `packages/cli-engine/package.json`, the `workspace:` pin in every consumer manifest (`packages/cli`, `packages/prisma`), and the lockfile together, landed as a reviewed commit like any other version change (run it in the PR that changes the engine). Both packages are hard-excluded in [`scripts/set-version.ts`](../../scripts/set-version.ts), which still sweeps their `workspace:` pins on lockstep siblings so those never go stale. At publish time the engine ships at its own manifest version **under `latest`**, on the first publish run that carries the bumped version — normally the merge of the PR that bumped it. That is the same rule every other package follows — a deliberately merged version-bump PR is what publishes a version under `latest` — applied at the engine's own bump instead of the root's. An already-published engine version is a no-op. The engine has no dev channel: its line carries no pre-releases (ADR 0004), so there is nothing to stamp and every published engine version is a release. (Before 2026-08-26 the workflow published the engine inside the dev-build half under `--tag dev`, so a new engine version reached the registry with its `latest` tag stuck on the previous version until an operator moved it by hand — `0.2.x` and `0.3.0` shipped that way.) The engine's own line continues from `0.1.0` (after the published `0.0.x` series); the `8.0.0-rc.N` engine versions that shipped while it was still in lockstep are burned values — they exist on the registry, nothing pins them, and version numbers are never reused. +**Exceptions:** `@prisma/compute` versions independently, pending extraction to another repository (operator ruling 2026-08-10), and keeps its own publish workflow ([`publish-compute.yml`](../../.github/workflows/publish-compute.yml)). `@prisma/cli-engine` also versions independently ([ADR 0004](../architecture/adrs/0004-engine-version-pinning.md), operator ruling 2026-08-13): an engine version means "the engine changed", not "the CLI released", which is what keeps the exact peer pins the product CLI packages hold on it cheap — they change only when the engine actually moves. The engine follows honest pre-1.0 semver (a breaking change bumps the minor); bumping it is one command — `pnpm bump-cli-engine-version ` — which edits `packages/cli-engine/package.json`, the `workspace:` pin in every consumer manifest (`packages/cli`, `packages/prisma`), and the lockfile together, landed as a reviewed commit like any other version change (run it in the PR that changes the engine). Both packages are hard-excluded in [`scripts/set-version.ts`](../../scripts/set-version.ts), which still sweeps their `workspace:` pins on lockstep siblings so those never go stale. At publish time the engine ships at its own manifest version **under `latest`**, on the first publish run that carries the bumped version — normally the merge of the PR that bumped it. That is the same rule every other package follows — a deliberately merged version-bump PR is what publishes a version under `latest` — applied at the engine's own bump instead of the root's. An already-published engine version is a no-op. The engine has no dev builds, for two reasons. First, the product CLI packages peer it at an exact release version, and so do their dev builds, so a dev-stamped engine would satisfy none of them and `npm install prisma@dev` would fail. Second, a dev build would expose nothing: CI refuses any change to the engine's published contents that does not bump its version, and that merge publishes the new version, so merged engine work is never unreleased. (Before 2026-08-26 the workflow published the engine inside the dev-build half under `--tag dev`, so a new engine version reached the registry with its `latest` tag stuck on the previous version until an operator moved it by hand — `0.2.x` and `0.3.0` shipped that way.) The engine's own line continues from `0.1.0` (after the published `0.0.x` series); the `8.0.0-rc.N` engine versions that shipped while it was still in lockstep are burned values — they exist on the registry, nothing pins them, and version numbers are never reused. The lockstep set is: the workspace root, `packages/cli`, `packages/cli-telemetry`, `packages/cli-conformance`, and `packages/tsconfig`. Private packages are never published (`pnpm publish` skips them), but they still version in lockstep so a contributor cloning the repo at any commit sees one consistent answer to "what version is this code?". Workspace-internal dependencies are pinned as `workspace:` (e.g. `workspace:8.0.0-rc.1`); pnpm resolves them locally during development and rewrites them to the exact version at publish time, so every published package carries an exact-version pin on its siblings. @@ -45,7 +45,7 @@ The npm registry exposes the CLI packages under these dist-tags: - **`dev`** — every routine push to `main` publishes `-dev.` here automatically (operator ruling 2026-08-13, superseding the earlier "no dev channel" ruling). The suffix derives from the workflow run number and is stamped ephemerally in CI, never committed, so release versions remain exactly what a commit says. The channel exists so a product's new version reaches a working CLI without a human: an auto-merging pull request moves the version, runs the full quality and conformance checks, and its merge ships the dev build. Today a daily scheduled run is what notices a product release; the immediate path needs a notification step in each product repository, which neither has yet. See [release automation](./release-automation.md). Only a real release — a merged `rc.N` bump publishing under `latest` — is a human act. - **Every** run of the publish workflow ships a dev build, including the one that cuts a release — the release publish is an additional half, not an alternative (operator ruling 2026-08-18). When they were alternatives, the release commit was the one merge to `main` that never reached the dev channel, so `dev` named an older version than the release until an unrelated commit landed. The dev build is published as its own version rather than by moving the `dev` tag, because OIDC trusted publishing authorises `npm publish` and nothing else. The dev channel covers `@prisma/cli` and `prisma` only: the engine's line carries no pre-releases (ADR 0004), so an engine version publishes once, under `latest`, on the run that first carries it. + **Every** run of the publish workflow ships a dev build, including the one that cuts a release — the release publish is an additional half, not an alternative (operator ruling 2026-08-18). When they were alternatives, the release commit was the one merge to `main` that never reached the dev channel, so `dev` named an older version than the release until an unrelated commit landed. The dev build is published as its own version rather than by moving the `dev` tag, because OIDC trusted publishing authorises `npm publish` and nothing else. The dev channel covers `@prisma/cli` and `prisma` only. The engine has no dev builds; [Lockstep across the workspace](#lockstep-across-the-workspace) gives the reasons. PR previews go through [`pkg.pr.new`](https://pkg.pr.new) ([`preview-cli-package.yml`](../../.github/workflows/preview-cli-package.yml)); they carry the committed base version and install via per-commit URLs, not dist-tags.