From 102bcfdb32be9b848c2738c55989b42a543a92f6 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 13:11:57 +0000 Subject: [PATCH] =?UTF-8?q?ci(publish):=20=F0=9F=8F=B7=EF=B8=8F=20create?= =?UTF-8?q?=20a=20GitHub=20Release=20for=20each=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a third Publish job that creates a GitHub Release (tag `vX.Y.Z` plus auto-generated notes and an npm install line) for every version on npm that lacks one, so versions show under Releases on the repo page. Each release is tagged at the commit that released the version: the first commit on main (first-parent) whose package.json carries it. Because it works from the list of npm versions rather than only the current one, the first run backfills 0.1.0 through 0.3.1, and a missed or failed run heals on the next. It runs after the npm job, so only versions that reached npm get a release. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015XnPdQXFWDT6FTnQs1d1f1 --- .github/workflows/publish.yml | 43 ++++++++++++++++++++++++++++++++++- CLAUDE.md | 5 +++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0fd62db..827a468 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,7 +2,8 @@ name: Publish # Publishes on every push to main, but only a version that is not yet on the target registry — # so a commit that bumps the version releases it, and any other commit is a harmless no-op. -# Bump with `npm version patch|minor|major` and push. Two registries, one job each: +# Bump with `npm version patch|minor|major` and push. Two registries, one job each, plus a +# GitHub Release per version: # # - npm (`claudeleaf` on registry.npmjs.org) — the install source. Authenticates with npm # trusted publishing (OIDC): npm trades this job's GitHub identity token for a short-lived @@ -14,6 +15,9 @@ name: Publish # and its versions show on the repo page. GitHub Packages only accepts owner-scoped names, so # the job renames the package before publishing. It authenticates with GITHUB_TOKEN, and the # repository field links the package to this repo. +# - GitHub Releases (`vX.Y.Z`) — one per version on npm, tagged at the commit that released it +# (the first commit on main carrying that version) with auto-generated notes. Every npm +# version without a release gets one, so missed runs and older versions are backfilled. on: push: branches: [main] @@ -83,3 +87,40 @@ jobs: fi env: NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + github-release: + needs: publish # release only what reached npm + runs-on: ubuntu-latest + permissions: + contents: write # create tags and releases + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # full history, to find the commit each version was released from + + - name: Create a GitHub Release for each npm version that lacks one + run: | + NAME=$(node -p "require('./package.json').name") + VERSIONS=$(npm view "$NAME" versions --json | node -p '[].concat(JSON.parse(require("fs").readFileSync(0, "utf8"))).join(" ")') + + # A version's release commit is the first commit on main whose package.json carries it. + declare -A SHA_OF + for sha in $(git rev-list --first-parent --reverse HEAD -- package.json); do + v=$(git show "$sha:package.json" | node -p 'JSON.parse(require("fs").readFileSync(0, "utf8")).version' 2>/dev/null || true) + if [ -n "$v" ] && [ -z "${SHA_OF[$v]:-}" ]; then SHA_OF[$v]=$sha; fi + done + + for v in $VERSIONS; do # oldest first, so the newest ends up marked "Latest" + TAG="v$v" + if gh release view "$TAG" >/dev/null 2>&1; then continue; fi + SHA=${SHA_OF[$v]:-} + if [ -z "$SHA" ]; then + echo "::warning::No commit on main carries version $v — skipping $TAG." + continue + fi + echo "Creating release $TAG at $SHA…" + gh release create "$TAG" --target "$SHA" --title "$TAG" --generate-notes \ + --notes "Published to npm as [\`$NAME@$v\`](https://www.npmjs.com/package/$NAME/v/$v): \`npm install $NAME@$v\`" + done + env: + GH_TOKEN: ${{ github.token }} diff --git a/CLAUDE.md b/CLAUDE.md index ee378c3..93e8404 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -316,7 +316,10 @@ MCP server with `npx -y claudeleaf mcp`) without cloning. What makes that work: (GitHub Packages only accepts owner-scoped names, so the job renames the package before publishing) using `GITHUB_TOKEN` with `packages: write`; the `repository` field links it to the repo, so the package and its versions show on the repo page. npm stays the install - source — GitHub Packages requires auth even to install public packages. + source — GitHub Packages requires auth even to install public packages. A third job creates a + **GitHub Release** `vX.Y.Z` (tag + auto-generated notes) for every npm version that lacks + one, at the version's release commit — the first commit on `main` (first-parent) whose + `package.json` carries it — so it also backfills missed runs and older versions. - `.github/workflows/ci.yml` — typecheck + build + test on PRs and non-`main` pushes. - In CI the live integration/MCP tests auto-skip (no cached session → no network), so `npm test` runs the unit suite only.