Skip to content

Commit e44623a

Browse files
aksOpsclaude
andcommitted
ci: idempotent publish — skip if version already on registry
Adds a 'Skip if already published' guard before each publish step in publish-npm and publish-gpr. Re-running the same tag (after a fix or partial failure downstream) is now a no-op for already-published versions, instead of erroring with E403/E409. Also: github-release tag_name now honors workflow_dispatch input so manual re-runs target the right tag (was using github.ref_name which is 'main' for dispatch). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6d04629 commit e44623a

1 file changed

Lines changed: 39 additions & 2 deletions

File tree

.github/workflows/release.yml

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,29 @@ jobs:
8888
registry-url: "https://registry.npmjs.org"
8989
scope: "@ossrandom"
9090

91+
- name: Skip if version already on npm
92+
id: npm-check
93+
# `npm view` against the configured registry returns 0 if the
94+
# version exists, non-zero otherwise. Lets re-running the same
95+
# tag (e.g. after a downstream failure) be a no-op instead of
96+
# erroring out the whole job.
97+
run: |
98+
PKG_NAME=$(node -p "require('./package.json').name")
99+
PKG_VER=$(node -p "require('./package.json').version")
100+
if npm view "$PKG_NAME@$PKG_VER" version > /dev/null 2>&1; then
101+
echo "already=true" >> "$GITHUB_OUTPUT"
102+
echo "::notice::$PKG_NAME@$PKG_VER is already published on npm — skipping."
103+
else
104+
echo "already=false" >> "$GITHUB_OUTPUT"
105+
fi
106+
env:
107+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
108+
91109
- name: Publish (with provenance)
92110
# --ignore-scripts: build was already done in the `build` job;
93111
# the prepublishOnly hook would otherwise try to invoke pnpm,
94112
# which isn't installed in this job.
113+
if: steps.npm-check.outputs.already != 'true'
95114
run: npm publish --provenance --access public --ignore-scripts
96115
env:
97116
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -129,7 +148,23 @@ jobs:
129148
fs.writeFileSync('package.json', JSON.stringify(p, null, 2));
130149
"
131150
151+
- name: Skip if version already on GHP
152+
id: gpr-check
153+
# Run AFTER the rewrite step so the lookup uses the GHP scope.
154+
run: |
155+
PKG_NAME=$(node -p "require('./package.json').name")
156+
PKG_VER=$(node -p "require('./package.json').version")
157+
if npm view "$PKG_NAME@$PKG_VER" version > /dev/null 2>&1; then
158+
echo "already=true" >> "$GITHUB_OUTPUT"
159+
echo "::notice::$PKG_NAME@$PKG_VER is already published on GHP — skipping."
160+
else
161+
echo "already=false" >> "$GITHUB_OUTPUT"
162+
fi
163+
env:
164+
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
165+
132166
- name: Publish to GitHub Packages
167+
if: steps.gpr-check.outputs.already != 'true'
133168
run: npm publish --ignore-scripts
134169
env:
135170
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -153,8 +188,10 @@ jobs:
153188
154189
- uses: softprops/action-gh-release@v3
155190
with:
156-
tag_name: ${{ github.ref_name }}
157-
name: ${{ github.ref_name }}
191+
# Honor the workflow_dispatch input; fall back to the tag the
192+
# tag-push trigger fired on (github.ref_name).
193+
tag_name: ${{ github.event.inputs.tag || github.ref_name }}
194+
name: ${{ github.event.inputs.tag || github.ref_name }}
158195
generate_release_notes: true
159196
files: |
160197
release-assets/*.tgz

0 commit comments

Comments
 (0)