From 1bc093017ae0021cbbf49855d723d1f798ff1e36 Mon Sep 17 00:00:00 2001 From: willbot Date: Mon, 17 Aug 2026 09:47:50 +0200 Subject: [PATCH 1/4] Plain names: update-product-versions, and a secret called what it contains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The workflow formerly named auto-repin updates the shell's pinned product CLI versions when the products publish; it is now named for that. The secret it authenticates with is the wmadden-electric bot's GitHub token, so it is now called BOT_GITHUB_TOKEN — a secret's name should say what it holds, not compress what one workflow does with it. Invented shorthand ('repin') is gone from the code, the workflow, the tests and the docs. Co-Authored-By: Claude Opus 5 Signed-off-by: willbot Signed-off-by: Will Madden --- ...-repin.yml => update-product-versions.yml} | 42 +++++++++---------- docs/oss/versioning.md | 4 +- package.json | 2 +- ...-repin.mjs => update-product-versions.mjs} | 12 +++--- ...t.mjs => update-product-versions.test.mjs} | 14 +++---- 5 files changed, 37 insertions(+), 37 deletions(-) rename .github/workflows/{auto-repin.yml => update-product-versions.yml} (59%) rename scripts/{auto-repin.mjs => update-product-versions.mjs} (90%) rename scripts/{auto-repin.test.mjs => update-product-versions.test.mjs} (78%) diff --git a/.github/workflows/auto-repin.yml b/.github/workflows/update-product-versions.yml similarity index 59% rename from .github/workflows/auto-repin.yml rename to .github/workflows/update-product-versions.yml index e21738d4..53fa2a0f 100644 --- a/.github/workflows/auto-repin.yml +++ b/.github/workflows/update-product-versions.yml @@ -1,7 +1,7 @@ -name: Auto-repin product CLI packages +name: Update product CLI versions # When composer or prisma/prisma publish a family package, this repo -# repins automatically and the merged repin ships as a dev version of +# updates its pinned version automatically, and the merged update ships as a dev version of # the CLI (operator ruling 2026-08-13; docs/oss/versioning.md). Only a # real CLI release needs a human. # @@ -9,11 +9,11 @@ name: Auto-repin product CLI packages # - repository_dispatch `family-published`: sent by the product # repos' publish workflows the moment they ship. # - schedule (daily): the backstop for a missed dispatch — the same -# comparison against the registry, so a lost event delays a repin +# comparison against the registry, so a lost event delays an update # by at most a day. # - workflow_dispatch: run it by hand. # -# The PR is opened with REPIN_PAT, not GITHUB_TOKEN, for two reasons: +# The PR is opened with BOT_GITHUB_TOKEN, not GITHUB_TOKEN, for two reasons: # pull requests created with the workflow token never trigger CI, and # without CI the required checks never report, so auto-merge would hang # forever. The PAT is the wmadden-electric bot's. @@ -26,12 +26,12 @@ on: workflow_dispatch: concurrency: - group: auto-repin + group: update-product-versions cancel-in-progress: false jobs: - repin: - name: Repin against the registry + update: + name: Update pinned versions against the registry runs-on: ubuntu-latest permissions: contents: write @@ -52,40 +52,40 @@ jobs: node-version-file: .node-version - name: Compare pins against the registry - id: repin - run: node scripts/auto-repin.mjs + id: compare + run: node scripts/update-product-versions.mjs # `pnpm install --no-frozen-lockfile` scoped to the lockfile - # refresh: the repin edits one manifest, and the PR must carry the + # refresh: the version update edits one manifest, and the PR must carry the # matching lockfile or every CI job fails on --frozen-lockfile. - name: Refresh the lockfile - if: ${{ steps.repin.outputs.changed == 'true' }} + if: ${{ steps.compare.outputs.changed == 'true' }} run: | corepack enable pnpm install --lockfile-only --no-frozen-lockfile - - name: Open the repin PR with auto-merge - if: ${{ steps.repin.outputs.changed == 'true' }} + - name: Open the version-update PR with auto-merge + if: ${{ steps.compare.outputs.changed == 'true' }} env: - GH_TOKEN: ${{ secrets.REPIN_PAT }} - SUMMARY: ${{ steps.repin.outputs.summary }} + GH_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} + SUMMARY: ${{ steps.compare.outputs.summary }} run: | if [ -z "$GH_TOKEN" ]; then - echo "::error::REPIN_PAT is not configured; cannot open a CI-triggering PR. Add the bot PAT as the REPIN_PAT repository secret." + echo "::error::BOT_GITHUB_TOKEN is not configured; cannot open a CI-triggering PR. Add the bot PAT as the BOT_GITHUB_TOKEN repository secret." exit 1 fi - BRANCH="auto/repin-$(date -u +%Y%m%d%H%M%S)" + BRANCH="auto/update-product-versions-$(date -u +%Y%m%d%H%M%S)" git config user.name "willbot" git config user.email "w.a.madden+machine@gmail.com" git checkout -b "$BRANCH" git add packages/cli/package.json pnpm-lock.yaml git commit -s --trailer "Signed-off-by: Will Madden " \ - -m "Repin product CLI packages to the registry: $SUMMARY" \ - -m "Opened automatically (auto-repin.yml); merging ships a dev version of the CLI. A real release stays a human act." + -m "Update product CLI packages to their latest published versions: $SUMMARY" \ + -m "Opened automatically (update-product-versions.yml); merging ships a dev version of the CLI. A real release stays a human act." git push "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "$BRANCH" PR_URL=$(gh pr create \ - --title "Repin product CLI packages: $SUMMARY" \ - --body "Automated repin from the registry ($SUMMARY). Merging publishes a \`dev\` version of the CLI automatically; the conformance checks on this PR are what stand between a family publish and that dev build. Opened by auto-repin.yml." \ + --title "Update product CLI packages: $SUMMARY" \ + --body "Automated version update from the registry ($SUMMARY). Merging publishes a \`dev\` version of the CLI automatically; the conformance checks on this PR are what stand between a family publish and that dev build. Opened by update-product-versions.yml." \ --base main --head "$BRANCH") gh pr merge --auto --squash "$PR_URL" echo "Opened $PR_URL with auto-merge armed." diff --git a/docs/oss/versioning.md b/docs/oss/versioning.md index d700b765..ecb8146f 100644 --- a/docs/oss/versioning.md +++ b/docs/oss/versioning.md @@ -16,7 +16,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 repin only when the engine actually moves. The engine follows honest pre-1.0 semver (a breaking change bumps the minor); bumping it is a deliberate edit to `packages/cli-engine/package.json` plus the shell's `workspace:` pin, landed as a reviewed commit like any other version change. 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 update that pin only when the engine actually moves. The engine follows honest pre-1.0 semver (a breaking change bumps the minor); bumping it is a deliberate edit to `packages/cli-engine/package.json` plus the shell's `workspace:` pin, landed as a reviewed commit like any other version change. 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. 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. @@ -30,7 +30,7 @@ The npm registry exposes the CLI packages under these dist-tags: - **`next`** — the Prisma 8 RC line (`8.0.0-rc.N`). A merged release PR on the RC line publishes here automatically. - **`beta`** — reserved for hand-cut previews ahead of significant changes, published by dispatching the workflow with that dist-tag. Routine releases do not use this tag. -- **`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 automated family repins ([`auto-repin.yml`](../../.github/workflows/auto-repin.yml)) deploy without a human: composer's and prisma/prisma's publish workflows dispatch to this repo, an auto-merge repin PR runs the full quality and conformance checks, and its merge ships the dev build. Only a real release — an `rc.N` bump under `next`, or moving `latest` — is a human act. +- **`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 automated product-version updates ([`update-product-versions.yml`](../../.github/workflows/update-product-versions.yml)) deploy without a human: composer's and prisma/prisma's publish workflows dispatch to this repo, an auto-merge repin PR runs the full quality and conformance checks, and its merge ships the dev build. Only a real release — an `rc.N` bump under `next`, or moving `latest` — is a human act. 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. diff --git a/package.json b/package.json index 695ffd68..31b0df2f 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "lint:fix": "biome check . --write", "bump-version": "node scripts/bump-version.ts", "test": "turbo run test", - "test:scripts": "node --test scripts/determine-version-utils.test.ts scripts/set-version-utils.test.ts scripts/resolve-package-version.test.mjs scripts/auto-repin.test.mjs", + "test:scripts": "node --test scripts/determine-version-utils.test.ts scripts/set-version-utils.test.ts scripts/resolve-package-version.test.mjs scripts/update-product-versions.test.mjs", "typecheck": "turbo run typecheck", "prisma-cli": "tsx packages/cli/src/bin.ts", "prisma": "tsx packages/cli/src/bin.ts", diff --git a/scripts/auto-repin.mjs b/scripts/update-product-versions.mjs similarity index 90% rename from scripts/auto-repin.mjs rename to scripts/update-product-versions.mjs index fb093755..d4e8b551 100644 --- a/scripts/auto-repin.mjs +++ b/scripts/update-product-versions.mjs @@ -1,10 +1,10 @@ #!/usr/bin/env node -// Repins the shell's exact dependencies on the product CLI packages to +// Updates the shell's exact dependencies on the product CLI packages to // what their repos last published (operator ruling 2026-08-13: family // publishes flow into this repo automatically and deploy as dev // versions; only a real CLI release needs a human). Run by -// `.github/workflows/auto-repin.yml` on a repository_dispatch from a +// `.github/workflows/update-product-versions.yml` on a repository_dispatch from a // product repo's publish workflow, on a daily schedule as the backstop // for missed dispatches, and by hand via workflow_dispatch. // @@ -34,14 +34,14 @@ const rootDir = dirname(dirname(fileURLToPath(import.meta.url))); const manifestPath = join(rootDir, "packages", "cli", "package.json"); /** - * Computes the repin edits for a manifest given the registry's current + * Computes the version-update edits for a manifest given the registry's current * versions. Pure; exported for tests. * * @param {{ dependencies?: Record }} manifest * @param {ReadonlyMap} published name → version at its watched tag * @returns {Array<{ name: string; from: string; to: string }>} */ -export function computeRepins(manifest, published) { +export function computeVersionUpdates(manifest, published) { const changes = []; const deps = manifest.dependencies ?? {}; for (const { name } of WATCHED) { @@ -61,7 +61,7 @@ function publishedVersion(name, tag) { }).trim(); return out.length > 0 ? out : undefined; } catch { - // Not published yet (or the tag does not exist) — nothing to repin to. + // Not published yet (or the tag does not exist) — nothing to update to. return undefined; } } @@ -71,7 +71,7 @@ function main() { const published = new Map( WATCHED.map(({ name, tag }) => [name, publishedVersion(name, tag)]), ); - const changes = computeRepins(manifest, published); + const changes = computeVersionUpdates(manifest, published); for (const { name, from, to } of changes) { manifest.dependencies[name] = to; diff --git a/scripts/auto-repin.test.mjs b/scripts/update-product-versions.test.mjs similarity index 78% rename from scripts/auto-repin.test.mjs rename to scripts/update-product-versions.test.mjs index 91320d6a..ae29565b 100644 --- a/scripts/auto-repin.test.mjs +++ b/scripts/update-product-versions.test.mjs @@ -1,10 +1,10 @@ import assert from "node:assert/strict"; import { describe, it } from "node:test"; -import { computeRepins } from "./auto-repin.mjs"; +import { computeVersionUpdates } from "./update-product-versions.mjs"; -describe("computeRepins", () => { - it("repins a watched dependency whose registry version moved", () => { - const changes = computeRepins( +describe("computeVersionUpdates", () => { + it("updates a watched dependency whose registry version moved", () => { + const changes = computeVersionUpdates( { dependencies: { "@prisma/composer": "0.6.0-dev.16", left: "1.0.0" } }, new Map([["@prisma/composer", "0.7.0"]]), ); @@ -14,7 +14,7 @@ describe("computeRepins", () => { }); it("skips watched packages the shell does not depend on — candidates, not requirements", () => { - const changes = computeRepins( + const changes = computeVersionUpdates( { dependencies: { "@prisma/composer": "0.6.0-dev.16" } }, new Map([ ["@prisma/composer", "0.6.0-dev.16"], @@ -25,7 +25,7 @@ describe("computeRepins", () => { }); it("skips a package the registry has never seen at its watched tag", () => { - const changes = computeRepins( + const changes = computeVersionUpdates( { dependencies: { "@prisma/orm-toolchain": "8.0.0-rc.1-dev.40" } }, new Map([["@prisma/orm-toolchain", undefined]]), ); @@ -33,7 +33,7 @@ describe("computeRepins", () => { }); it("reports every drifted pin in one run", () => { - const changes = computeRepins( + const changes = computeVersionUpdates( { dependencies: { "@prisma/composer": "0.6.0", From 74090768eaf9e8f83f13570dde2e5eaee36ed25d Mon Sep 17 00:00:00 2001 From: willbot Date: Mon, 17 Aug 2026 09:48:09 +0200 Subject: [PATCH 2/4] Two more 'repin' stragglers in comments Co-Authored-By: Claude Opus 5 Signed-off-by: willbot Signed-off-by: Will Madden --- .github/workflows/publish.yml | 2 +- scripts/determine-version-utils.ts | 2 +- scripts/determine-version.ts | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f6ddb9a9..275b5299 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,7 +11,7 @@ name: Publish to npm # Trigger model: # - push to `main` with the root `version` unchanged → publish # `-dev.` under the `dev` dist-tag (operator ruling -# 2026-08-13: automated family repins deploy automatically; only a +# 2026-08-13: automated product-version updates deploy automatically; only a # real release needs a human). The dev suffix is stamped # ephemerally below and never committed. # - push to `main` with the root `version` changed → publish `` diff --git a/scripts/determine-version-utils.ts b/scripts/determine-version-utils.ts index bc7f25f4..bc5ff335 100644 --- a/scripts/determine-version-utils.ts +++ b/scripts/determine-version-utils.ts @@ -68,7 +68,7 @@ export interface VersionResult { /** * The version a routine main push publishes under the `dev` dist-tag - * (operator ruling 2026-08-13: automatic repins deploy automatic dev + * (operator ruling 2026-08-13: automatic product-version updates deploy dev * versions; only a real release needs a human). The run number makes * the suffix monotonic per workflow run without reading the registry. */ diff --git a/scripts/determine-version.ts b/scripts/determine-version.ts index 5fec59a4..8e9f23c9 100644 --- a/scripts/determine-version.ts +++ b/scripts/determine-version.ts @@ -17,7 +17,7 @@ * operator deliberately moves it. * Otherwise `-dev.` under the `dev` * dist-tag: every routine main push — an - * automated family repin above all — ships an + * automated product-version update above all — ships an * installable dev build automatically * (operator ruling 2026-08-13). * - `workflow_dispatch` → `` (no suffix), dist-tag from @@ -160,8 +160,8 @@ switch (eventName) { result = { version: baseVersion, tag: releaseDistTag(baseVersion) }; } else if (previous.available) { // Routine push: publish `-dev.` under `dev` (operator - // ruling 2026-08-13 — automatic repins from the product repos - // deploy automatically; only a real release needs a human). The + // ruling 2026-08-13 — automatic product-version updates deploy + // automatically; only a real release needs a human). The // suffix is derived here and stamped ephemerally in CI; it is // never committed, so releases remain committed-at-HEAD. const runNumber = process.env.GITHUB_RUN_NUMBER ?? ""; From b986f9e1039eb2b3511469bf24907cfd7e0a3429 Mon Sep 17 00:00:00 2001 From: willbot Date: Mon, 17 Aug 2026 09:48:25 +0200 Subject: [PATCH 3/4] And the last two, in the ADR and the versioning doc Co-Authored-By: Claude Opus 5 Signed-off-by: willbot Signed-off-by: Will Madden --- docs/architecture/adrs/0004-engine-version-pinning.md | 2 +- docs/oss/versioning.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/architecture/adrs/0004-engine-version-pinning.md b/docs/architecture/adrs/0004-engine-version-pinning.md index 84879eec..1dfec85a 100644 --- a/docs/architecture/adrs/0004-engine-version-pinning.md +++ b/docs/architecture/adrs/0004-engine-version-pinning.md @@ -37,7 +37,7 @@ Per edge: **Exact now, range later.** During the rc line the engine breaks its consumers deliberately, slice by slice, so a version range would be fiction. Post-GA, the recorded destination is widening the peers to a range under a written engine compatibility contract, so a non-breaking engine release ships in the next shell release with zero family republishes. Widening is a deliberate future decision against that contract, not a drift. -**Engine versioning — RULED (operator, 2026-08-13): the engine versions independently.** Under the shell lockstep it previously shared, every CLI release manufactured a new engine version — and with it a family-repin obligation — whether or not the engine changed. Decoupled, an engine version means "the engine changed", the exact peers stay valid between real engine changes, and the repin train runs only when there is something to repin for. Mechanically: the engine is excluded from `set-version.ts`'s lockstep (alongside `@prisma/compute`), follows honest pre-1.0 semver (breaking bumps the minor), and publishes at its own manifest version, with an already-published version treated as a no-op by the publish workflow. +**Engine versioning — RULED (operator, 2026-08-13): the engine versions independently.** Under the shell lockstep it previously shared, every CLI release manufactured a new engine version — and with it an obligation for every family to update its pin — whether or not the engine changed. Decoupled, an engine version means "the engine changed", the exact peers stay valid between real engine changes, and the cross-repo update train runs only when there is something to update for. Mechanically: the engine is excluded from `set-version.ts`'s lockstep (alongside `@prisma/compute`), follows honest pre-1.0 semver (breaking bumps the minor), and publishes at its own manifest version, with an already-published version treated as a no-op by the publish workflow. ## Enforcement diff --git a/docs/oss/versioning.md b/docs/oss/versioning.md index ecb8146f..d36ab064 100644 --- a/docs/oss/versioning.md +++ b/docs/oss/versioning.md @@ -30,7 +30,7 @@ The npm registry exposes the CLI packages under these dist-tags: - **`next`** — the Prisma 8 RC line (`8.0.0-rc.N`). A merged release PR on the RC line publishes here automatically. - **`beta`** — reserved for hand-cut previews ahead of significant changes, published by dispatching the workflow with that dist-tag. Routine releases do not use this tag. -- **`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 automated product-version updates ([`update-product-versions.yml`](../../.github/workflows/update-product-versions.yml)) deploy without a human: composer's and prisma/prisma's publish workflows dispatch to this repo, an auto-merge repin PR runs the full quality and conformance checks, and its merge ships the dev build. Only a real release — an `rc.N` bump under `next`, or moving `latest` — is a human act. +- **`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 automated product-version updates ([`update-product-versions.yml`](../../.github/workflows/update-product-versions.yml)) deploy without a human: composer's and prisma/prisma's publish workflows dispatch to this repo, an auto-merge version-update PR runs the full quality and conformance checks, and its merge ships the dev build. Only a real release — an `rc.N` bump under `next`, or moving `latest` — is a human act. 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. From 1be9b65d5c4f59f3ffc5e43fcff0d889b4bd713b Mon Sep 17 00:00:00 2001 From: willbot Date: Mon, 17 Aug 2026 12:40:14 +0200 Subject: [PATCH 4/4] From review: a second publish does not open a duplicate update PR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dispatch's 204 only means GitHub accepted the event. Two publishes landing before the first update PR merges would each have opened one. Since the comparison is against the registry rather than against the event, an already-open PR carries whatever the registry now says — so the run leaves it alone and its merge picks up both publishes. Co-Authored-By: Claude Opus 5 Signed-off-by: willbot Signed-off-by: Will Madden --- .github/workflows/update-product-versions.yml | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-product-versions.yml b/.github/workflows/update-product-versions.yml index defbf6f7..41f3c414 100644 --- a/.github/workflows/update-product-versions.yml +++ b/.github/workflows/update-product-versions.yml @@ -65,8 +65,30 @@ jobs: corepack enable pnpm install --lockfile-only --no-frozen-lockfile - - name: Open the version-update PR with auto-merge + # A second publish arriving before the first update PR merges must + # not open a duplicate: the dispatch's 204 only says GitHub accepted + # the event, not that anything was processed. An open PR from this + # workflow already carries whatever the registry now says (the + # comparison is against the registry, not against the event), so the + # right move is to leave it alone and let its own merge pick up both + # publishes. + - name: Skip if an update PR is already open + id: existing if: ${{ steps.compare.outputs.changed == 'true' }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + OPEN=$(gh pr list --state open --json headRefName \ + --jq '[.[] | select(.headRefName | startswith("auto/update-product-versions-"))] | length') + if [ "$OPEN" != "0" ]; then + echo "An update PR is already open; leaving it to pick up this publish too." + echo "skip=true" >> "$GITHUB_OUTPUT" + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi + + - name: Open the version-update PR with auto-merge + if: ${{ steps.compare.outputs.changed == 'true' && steps.existing.outputs.skip == 'false' }} env: GH_TOKEN: ${{ secrets.DEPLOY_GITHUB_TOKEN }} SUMMARY: ${{ steps.compare.outputs.summary }}