diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a055e7c0..3703389d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -96,18 +96,35 @@ 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. + - name: Publish the engine release + if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.dry-run != 'true' }} + env: + NPM_CONFIG_PROVENANCE: "true" + run: bash scripts/publish-packages.sh latest @prisma/cli-engine + - name: Publish the dev version if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.dry-run != 'true' }} env: NPM_CONFIG_PROVENANCE: "true" - run: bash scripts/publish-packages.sh dev @prisma/cli-engine @prisma/cli prisma + run: bash scripts/publish-packages.sh dev @prisma/cli prisma - name: Verify the dev version resolves if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.dry-run != 'true' }} env: DEV_VERSION: ${{ steps.version.outputs.devVersion }} run: | - node scripts/verify-published.mjs "@prisma/cli@$DEV_VERSION" "prisma@$DEV_VERSION" + engine=$(node -p "require('./packages/cli-engine/package.json').version") + node scripts/verify-published.mjs \ + "@prisma/cli-engine@$engine" \ + "@prisma/cli@$DEV_VERSION" \ + "prisma@$DEV_VERSION" # --- The release: only when the committed version changed. --- diff --git a/docs/oss/versioning.md b/docs/oss/versioning.md index 7a7d840b..9c1e889c 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; an already-published engine version is a no-op. 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 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. 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. + **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. 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.