Skip to content

Commit 60aa7f4

Browse files
publish without pushing to protected master, derive version from npm registry
1 parent ee57517 commit 60aa7f4

1 file changed

Lines changed: 29 additions & 19 deletions

File tree

.github/workflows/publish.yml

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
publish:
1010
runs-on: ubuntu-latest
1111
permissions:
12-
contents: write
12+
contents: write # needed only to push the release tag
1313
steps:
1414
- uses: actions/checkout@v4
1515

@@ -28,30 +28,40 @@ jobs:
2828
- name: Build
2929
run: npm run build
3030

31-
# Fully automatic release: if the version in package.json is already on
32-
# npm, bump the patch version right here and push the bump back to
33-
# master. (Pushes made with GITHUB_TOKEN don't re-trigger workflows, so
34-
# this cannot loop; [skip ci] is extra insurance.)
35-
- name: Auto-bump version if already published
31+
# Master is a protected branch, so the workflow never commits or pushes
32+
# to it. The release version is derived from the npm registry instead:
33+
# if package.json already holds a NEW version (manual bump in a PR),
34+
# that wins; otherwise the published patch version is incremented. The
35+
# bump happens only inside this runner.
36+
- name: Resolve release version
37+
id: version
3638
run: |
3739
NAME=$(node -p "require('./package.json').name")
3840
LOCAL=$(node -p "require('./package.json').version")
3941
PUBLISHED=$(npm view "$NAME" version 2>/dev/null || echo "none")
40-
echo "local=$LOCAL published=$PUBLISHED"
41-
if [ "$LOCAL" = "$PUBLISHED" ]; then
42-
git config user.name "github-actions[bot]"
43-
git config user.email "github-actions[bot]@users.noreply.github.com"
44-
# Sync with master first — re-runs and racing pushes otherwise
45-
# operate on a stale checkout and get rejected.
46-
git pull --rebase origin master
47-
RESYNCED=$(node -p "require('./package.json').version")
48-
if [ "$RESYNCED" = "$PUBLISHED" ]; then
49-
npm version patch -m "release v%s [skip ci]"
50-
git push origin master --follow-tags
51-
fi
52-
fi
42+
NEXT=$(node -e "
43+
const local = '$LOCAL';
44+
const pub = '$PUBLISHED';
45+
const cmp = (a, b) => {
46+
const A = a.split('.').map(Number), B = b.split('.').map(Number);
47+
for (let i = 0; i < 3; i++) { if ((A[i] || 0) !== (B[i] || 0)) return (A[i] || 0) - (B[i] || 0); }
48+
return 0;
49+
};
50+
if (pub === 'none' || cmp(local, pub) > 0) { console.log(local); }
51+
else { const p = pub.split('.').map(Number); p[2] += 1; console.log(p.join('.')); }
52+
")
53+
echo "local=$LOCAL published=$PUBLISHED releasing=$NEXT"
54+
npm version "$NEXT" --no-git-tag-version --allow-same-version
55+
echo "next=$NEXT" >> "$GITHUB_OUTPUT"
5356
5457
- name: Publish
5558
run: npm publish
5659
env:
5760
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
61+
62+
# Tag pushes are allowed on protected branches, so releases stay
63+
# traceable in git even though no commit lands on master.
64+
- name: Tag release
65+
run: |
66+
git tag "v${{ steps.version.outputs.next }}" || exit 0
67+
git push origin "v${{ steps.version.outputs.next }}" || true

0 commit comments

Comments
 (0)