From 1485c70181b47758f7e7139add6a80faff50d79d Mon Sep 17 00:00:00 2001 From: willbot Date: Wed, 12 Aug 2026 18:45:51 +0200 Subject: [PATCH 1/2] Attach the tarballs before the Release publishes, because published means frozen The first real next publish reached the Release step and failed there: this repo's releases are immutable, so gh release create published v8.0.0-rc.1 and the follow-up asset upload was refused with HTTP 422. The step now creates the Release as a draft with the smoked tarballs already attached, then publishes it through the API by the draft's id (a draft's tag does not exist yet, so gh cannot address it by tag). A rerun that finds the Release already published reports there is nothing to repair and succeeds, instead of failing the run after a complete npm publish. Co-Authored-By: Claude Fable 5 Signed-off-by: willbot Signed-off-by: Will Madden --- .github/workflows/publish.yml | 45 ++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2592bb63..97919a58 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -194,30 +194,43 @@ jobs: # changelog signal. The Release is created at $GITHUB_SHA so the # tag points at the same commit the publish ran from. # - # Idempotent on workflow rerun: if a Release for `v$VERSION` already - # exists (e.g. a previous run published to npm but failed before this - # step), edit it in place rather than re-creating it. + # This repo's releases are immutable: once published, neither the + # assets nor the tag can change (uploading to a published release + # answers HTTP 422). So the Release is created as a DRAFT with the + # smoked tarballs already attached, then published — assets first, + # publish second. On a rerun that finds the Release already + # published there is nothing left to repair; the step says so and + # succeeds. - name: Create GitHub Release if: ${{ steps.version.outputs.publish == 'true' && steps.version.outputs.release == 'true' && (github.event_name != 'workflow_dispatch' || github.event.inputs.dry-run != 'true') }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} VERSION: ${{ steps.version.outputs.version }} run: | + if gh release view "v$VERSION" >/dev/null 2>&1; then + echo "Release v$VERSION already exists and releases are immutable — nothing to repair." + exit 0 + fi PRERELEASE_FLAG="" case "$VERSION" in *-rc.*) PRERELEASE_FLAG="--prerelease" ;; esac - if gh release view "v$VERSION" >/dev/null 2>&1; then - gh release edit "v$VERSION" \ - --target "$GITHUB_SHA" \ - --title "v$VERSION" - else - gh release create "v$VERSION" \ - --target "$GITHUB_SHA" \ - --title "v$VERSION" \ - --generate-notes \ - $PRERELEASE_FLAG + gh release create "v$VERSION" \ + --draft \ + --target "$GITHUB_SHA" \ + --title "v$VERSION" \ + --generate-notes \ + $PRERELEASE_FLAG \ + artifacts/tarballs/*.tgz + # A draft's tag does not exist yet, so `gh release edit + # --draft=false` cannot address it; publish through the + # API by the draft's id. + release_id=$(gh api "repos/$GITHUB_REPOSITORY/releases" \ + --jq ".[] | select(.draft and .tag_name == \"v$VERSION\") | .id" | head -1) + if [ -z "$release_id" ]; then + echo "Could not find the draft release for v$VERSION" >&2 + exit 1 fi - # The exact tarballs the smoke verified, attached to the - # Release. --clobber keeps reruns idempotent. - gh release upload "v$VERSION" artifacts/tarballs/*.tgz --clobber + gh api -X PATCH "repos/$GITHUB_REPOSITORY/releases/$release_id" \ + -F draft=false >/dev/null + echo "Published release v$VERSION with $(ls artifacts/tarballs/*.tgz | wc -l | tr -d ' ') asset(s)." From 5c75a34402ddde7b87539aa6a9061db2bd7ff498 Mon Sep 17 00:00:00 2001 From: willbot Date: Wed, 12 Aug 2026 18:49:15 +0200 Subject: [PATCH 2/2] drive(prisma-cli-v8): record the assetless rc.1 Release and its repair path Operator ruling 2026-08-12: cosmetic, not immediate. npm is healthy; only the GitHub Release page is missing its tarballs, permanently, because it published before the upload and releases are immutable. The repair steps (merge #165, attempt deletion, re-dispatch) are in the entry for whoever picks it up. Co-Authored-By: Claude Fable 5 Signed-off-by: willbot Signed-off-by: Will Madden --- .drive/projects/prisma-cli-v8/deferred.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.drive/projects/prisma-cli-v8/deferred.md b/.drive/projects/prisma-cli-v8/deferred.md index c6f6cf5c..eb1c64df 100644 --- a/.drive/projects/prisma-cli-v8/deferred.md +++ b/.drive/projects/prisma-cli-v8/deferred.md @@ -4,6 +4,26 @@ Work identified during a slice that is not part of that slice's contract. Each entry: what, why it was deferred, where it lands. Nothing here is tracked outside this file. +## After S7's first real publish + +- **The `v8.0.0-rc.1` GitHub Release has no tarballs attached, and + none can be added.** The first real `next` publish (2026-08-12, run + 31618278670) published both packages to npm successfully, then the + Release step published the Release before uploading assets — and this + repo's releases are immutable, so the upload was refused (HTTP 422) + and the Release froze empty. npm is unaffected; the smoked tarballs + remain retrievable from that run's workflow artifacts (which expire + on the repo's retention schedule) and from npm itself. PR #165 fixes + the step for every future release (draft → attach assets → publish, + the order GitHub's own docs recommend). Repairing rc.1's Release + itself, if ever wanted: merge #165 first, try + `gh release delete v8.0.0-rc.1` (docs are silent on whether a + published immutable release can be deleted; the attempt is the test), + and if deletion works, re-dispatch the publish workflow — the + already-published npm versions are tolerated and the run recreates + the Release complete. Operator ruling (2026-08-12): cosmetic, not + immediate. + ## Still open after S3/D4 — mostly the composer repo, two items need both D4 landed the prisma-cli half (the mount, the node floor, the divergence