Skip to content

fix(release): make release tag idempotent so a failed publish can be retried#4466

Merged
matthew-dean merged 2 commits into
less:alphafrom
matthew-dean:fix/idempotent-release-tag
Jul 12, 2026
Merged

fix(release): make release tag idempotent so a failed publish can be retried#4466
matthew-dean merged 2 commits into
less:alphafrom
matthew-dean:fix/idempotent-release-tag

Conversation

@matthew-dean

Copy link
Copy Markdown
Member

Follow-up to #4464 addressing Greptile's P1 on scripts/bump-and-publish.js.

Problem: the script pushes the vX.Y.Z git tag before running the npm publish loop. If publish fails partway, the remote tag already exists, so a rerun fails on the existing tag before it can retry publishing — the release is stuck until the tag is manually deleted.

Fix: the tag step is now idempotent. Before creating/pushing the tag, it checks the remote: if vX.Y.Z already exists and points at the same release commit, it skips the tag step and proceeds to publish (so a rerun retries the publish); if it points at a different commit, it errors clearly; otherwise it creates+pushes the tag as before. DRY-RUN behavior preserved.

Note: bump-and-publish.js is byte-identical to master's, so the same fix applies there — happy to mirror it in a follow-up.

…retried

The tag vX.Y.Z was created and pushed before the npm publish loop. If publish
failed partway, the remote tag already existed and a rerun died on git tag/push
before it could retry publishing. Check the remote for the tag (dereferenced to
its commit) first: skip the tag step when it already marks this release commit,
error when it marks a different commit, otherwise create+push as before. Also
reconcile a stale local tag from a prior partial run. DRY-RUN preserved.
@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Jul 12, 2026
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 542dac9e-ee5b-4d7e-8ac9-27d83297ee7f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 12, 2026

Copy link
Copy Markdown

Greptile Summary

This PR makes the release tag step idempotent for retrying failed publishes. The main changes are:

  • Checks origin for an existing vX.Y.Z tag before creating one.
  • Skips tag creation when the remote tag already exists.
  • Deletes any local tag before creating a fresh annotated tag when the remote tag is absent.
  • Keeps the npm publish loop after the tag step.

Confidence Score: 4/5

This is close, but the tag conflict path should be fixed before merging.

  • The retry path now allows publishing when the remote release tag points at a different commit.
  • That can publish packages that do not match the git tag for the version.

scripts/bump-and-publish.js

Reviews (2): Last reviewed commit: "fix(release): simplify idempotent tag bl..." | Re-trigger Greptile

Comment thread scripts/bump-and-publish.js Outdated
Comment thread scripts/bump-and-publish.js Outdated
@matthew-dean
matthew-dean merged commit 81ce723 into less:alpha Jul 12, 2026
9 checks passed
Comment on lines +286 to +289
const headCommit = execSync('git rev-parse HEAD', { cwd: ROOT_DIR, encoding: 'utf8' }).trim();
if (remoteTagCommit !== headCommit) {
console.warn(`⚠️ Remote tag ${tagName} points at ${remoteTagCommit}, which differs from HEAD ${headCommit}. Proceeding to publish anyway.`);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Reject tag conflicts

When the remote tag exists but points at a different commit, this branch only warns and still runs the publish loop from the current checkout. That lets a real vX.Y.Z tag collision proceed as if it were a retry, so npm packages can be published for a checkout that is not represented by the release tag. The retry path should skip tag creation only when the existing remote tag is the intended release commit; otherwise it should stop before publishing.

Suggested change
const headCommit = execSync('git rev-parse HEAD', { cwd: ROOT_DIR, encoding: 'utf8' }).trim();
if (remoteTagCommit !== headCommit) {
console.warn(`⚠️ Remote tag ${tagName} points at ${remoteTagCommit}, which differs from HEAD ${headCommit}. Proceeding to publish anyway.`);
}
const headCommit = execSync('git rev-parse HEAD', { cwd: ROOT_DIR, encoding: 'utf8' }).trim();
if (remoteTagCommit !== headCommit) {
throw new Error(`Remote tag ${tagName} points at ${remoteTagCommit}, which differs from HEAD ${headCommit}. Refusing to publish.`);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant