Skip to content

Fix npm release recovery - #2830

Open
findolor wants to merge 2 commits into
mainfrom
arda/fix-npm-release-recovery
Open

Fix npm release recovery#2830
findolor wants to merge 2 commits into
mainfrom
arda/fix-npm-release-recovery

Conversation

@findolor

@findolor findolor commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Motivation

The npm release workflow can leave Git and npm permanently out of sync. Run 31486644553 published raindex 0.0.1-alpha.244 and UI components 0.0.1-alpha.243, then failed to push its version commit because main advanced. Run 31487015421 consequently derived raindex 0.0.1-alpha.244 from the stale manifest and npm rejected the duplicate version.

This is not isolated to one run: #2815 previously had to synchronize package manifests after another partial two-package release.

Solution

  • Serialize npm release runs and skip a source commit once a newer main head supersedes it.
  • Reconcile each workspace independently against npm versions and exact tarball hashes before selecting a release version.
  • Preserve a Git-reserved version when npm is behind, adopt npm when the registry is ahead, and bump only when the selected published artifact differs.
  • Commit and push version reservations before changing npm, so a non-fast-forward failure cannot leave npm ahead of Git.
  • Allow the version-commit workflow run to recover automatically when neither, one, or both package publishes completed.
  • Publish only packages whose selected artifact is missing, while still rebuilding both release assets.
  • Create the tag only after required publishes succeed and recover a missing tag or GitHub release without republishing immutable versions.

Checks

  • nix run nixpkgs#actionlint -- .github/workflows/npm-package-release.yml
  • npx --no-install prettier --check .github/workflows/npm-package-release.yml
  • git diff --check
  • Simulated the live npm-ahead state: repository .243/.242, npm .244/.243; selected .245/.244.
  • Simulated a retry after committing .245/.244 with npm still behind; preserved both reserved versions without another bump.
  • Commit hooks passed, including no-consumer-prettier and yamlfmt.

Summary by CodeRabbit

  • Improvements
    • Release runs are now coordinated to prevent overlapping releases.
    • Release state is validated before publishing begins.
    • Package changes are detected more accurately before publishing.
    • Version updates are reserved before publication to reduce conflicting releases.
    • Release workflows can recover from partially completed runs.
    • Tags and release records are created only after successful package publication.
    • Unchanged packages can skip unnecessary versioning and publishing.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ef8924e6-0084-406e-b5d5-5cd62b6b8a64

📥 Commits

Reviewing files that changed from the base of the PR and between df1fd1b and 4b9521e.

📒 Files selected for processing (1)
  • .github/workflows/npm-package-release.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/npm-package-release.yml

📝 Walkthrough

Walkthrough

The npm release workflow now serializes runs, validates the current main head, reconciles package and registry state, commits required versions before publishing, and creates tags and GitHub releases after successful publication.

Changes

npm Release Workflow

Layer / File(s) Summary
Run serialization and head validation
.github/workflows/npm-package-release.yml
Concurrent release runs are serialized. The workflow identifies superseded commits and skips later release actions for them.
Package release-state reconciliation
.github/workflows/npm-package-release.yml
The workflow compares repository and npm package versions and tarball hashes. It handles first publishes, prerelease selection, dependency and lockfile updates, package-specific publish flags, and existing release state.
Version reservation and package publishing
.github/workflows/npm-package-release.yml
The workflow commits required package and lockfile version reservations before publishing. Tarball creation and publication use package-specific release flags.
Post-publish tag and GitHub release
.github/workflows/npm-package-release.yml
The workflow creates release tags after successful publication. It retains existing tags and creates GitHub releases only when required and absent.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions
  participant MainBranch
  participant NpmRegistry
  participant GitHub
  GitHubActions->>MainBranch: validate current main head
  GitHubActions->>NpmRegistry: resolve package versions and tarball hashes
  NpmRegistry-->>GitHubActions: return registry state
  GitHubActions->>MainBranch: commit required version reservations
  GitHubActions->>NpmRegistry: publish selected package tarballs
  GitHubActions->>GitHub: create release tag after publishing
  GitHubActions->>GitHub: create GitHub release when required
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: improving npm release recovery in the workflow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch arda/fix-npm-release-recovery

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
.github/workflows/npm-package-release.yml (2)

352-357: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Create GitHub Release runs even when the release already exists.

The step condition uses only RELEASE_REQUIRED. GITHUB_RELEASE_EXISTS is computed at line 265 but never used in a step condition. softprops/action-gh-release@v2 updates an existing release by default, so this is not a failure, but it re-uploads the tarball assets on every recovery run. Gate the step on the existing-release state if you want the recovery path to be a no-op.

Note also that the tarball assets at lines 360-361 are only produced when RELEASE_REQUIRED is true, which matches this condition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/npm-package-release.yml around lines 352 - 357, Update the
Create GitHub Release step’s if condition to require both RELEASE_REQUIRED to be
true and GITHUB_RELEASE_EXISTS to indicate that no release already exists.
Preserve the existing tarball production condition and release configuration.

296-299: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Move ${{ ... }} expansions into env: blocks to satisfy zizmor.

zizmor flags template expansion inside run: bodies at lines 298, 306, 321, 331, 336, and 345-349. The values come from this workflow's own step, so the practical risk is low. The values still originate from repository files (package.json versions) and from npm pack output. Referencing them as shell variables removes the injection surface and clears the warnings.

♻️ Example for the tag step
       - name: Push release tag
         if: ${{ env.RELEASE_REQUIRED == 'true' }}
+        env:
+          RELEASE_TAG: ${{ env.RELEASE_TAG }}
+          RELEASE_TAG_EXISTS: ${{ env.RELEASE_TAG_EXISTS }}
         run: |
-          if [ "${{ env.RELEASE_TAG_EXISTS }}" = false ]; then
-            git tag "${{ env.RELEASE_TAG }}"
-            git push origin "${{ env.RELEASE_TAG }}"
+          if [ "$RELEASE_TAG_EXISTS" = false ]; then
+            git tag "$RELEASE_TAG"
+            git push origin "$RELEASE_TAG"
           else
-            echo "Tag ${{ env.RELEASE_TAG }} already exists"
+            echo "Tag $RELEASE_TAG already exists"
           fi

Also applies to: 304-306, 320-324, 329-331, 335-339, 344-350

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/npm-package-release.yml around lines 296 - 299, Move all
GitHub Actions expression expansions currently embedded in the run scripts
around the release commit, tag, publish, and packaging steps into step-level env
entries. Update the affected shell commands to reference those environment
variables instead, including values derived from RAINDEX_NEW_VERSION,
UC_NEW_VERSION, and npm pack output, while preserving the existing release
behavior.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/npm-package-release.yml:
- Around line 181-196: Update resolve_baseline_version to determine the highest
published semver rather than relying on npm view "$package_name@latest" version.
Compare the maximum registry version against repository_version and return the
higher baseline, preserving the repository fallback when no published versions
are available.
- Around line 198-224: Update the RAINDEX publish decision flow around
package_hash and the prerelease npm version step to verify each generated alpha
candidate with npm before publishing. After npm version prerelease selects a
candidate, query npm for that exact package version and continue incrementing
until the candidate is unused, while preserving the existing hash comparison and
publish behavior.

---

Nitpick comments:
In @.github/workflows/npm-package-release.yml:
- Around line 352-357: Update the Create GitHub Release step’s if condition to
require both RELEASE_REQUIRED to be true and GITHUB_RELEASE_EXISTS to indicate
that no release already exists. Preserve the existing tarball production
condition and release configuration.
- Around line 296-299: Move all GitHub Actions expression expansions currently
embedded in the run scripts around the release commit, tag, publish, and
packaging steps into step-level env entries. Update the affected shell commands
to reference those environment variables instead, including values derived from
RAINDEX_NEW_VERSION, UC_NEW_VERSION, and npm pack output, while preserving the
existing release behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fd2e4f2a-6844-4a5f-b4fe-ac246867df8b

📥 Commits

Reviewing files that changed from the base of the PR and between 16049a3 and df1fd1b.

📒 Files selected for processing (1)
  • .github/workflows/npm-package-release.yml

Comment thread .github/workflows/npm-package-release.yml Outdated
Comment thread .github/workflows/npm-package-release.yml
@findolor findolor self-assigned this Aug 12, 2026
@findolor
findolor requested a review from rouzwelt August 13, 2026 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant