Skip to content

Lockstep release tooling for the three packages - #2296

Merged
ttypic merged 2 commits into
integration/v3from
lockstep-release
Sep 15, 2026
Merged

ttypic merged 2 commits into
integration/v3from
lockstep-release

Conversation

@umair-ably

@umair-ably umair-ably commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Stacked on #2294 (base: uts-per-side) — implements the rollout plan's release-tooling step: "One command releases core + device + server at the same version. Partial release is impossible or fails reversibly."

What

scripts/release.js, one command per release step, replacing the manual checklist's three hand-edited version sites and three separate publishes:

  • npm run check:versions — verifies all seven version sites agree (root + three workspace package.jsons, both wrappers' exact @ably/pubsub-core peer pins, and the react-hooks agent version constant). Now runs in the lint CI job, so a drifted site cannot merge.
  • npm run release:bump <version> — moves every site at once and refreshes the lockfile. It rewrites the package.json files directly rather than using npm version --workspaces --include-workspace-root, which was observed (npm 11) to rewrite the files and still exit non-zero, then fail on re-run with Version not changed — exactly the partial state this tooling exists to prevent. bump is deterministic and re-runnable at any version.
  • npm run release:publish [-- --dry-run] [-- --otp <code>] — the lockstep publish:
    • refuses to start unless every version site agrees and every build artifact the packages' files globs reference exists on disk (npm pack silently omits missing files, so a stale checkout would otherwise ship broken tarballs);
    • dry-run packs everything before publishing anything;
    • publishes in dependency order (core before the wrappers that pin it exactly), so no wrapper is ever visible on the registry before its core;
    • consults the registry first and skips already-published versions, so a run that fails partway is completed by simply re-running it;
    • prints rollback guidance (npm unpublish within 72h) if a release is abandoned instead.

Also fixes a first-release landmine found while building this: none of the three scoped packages set publishConfig.access, and npm publishes scoped packages as restricted by default on first publish — so the first release would have shipped them private (or failed, depending on org plan). All three now declare access: public.

CONTRIBUTING's release process shrinks accordingly (steps 4–6 → one bump command; 10–11 → one publish command).

Verification

  • check passes at 2.28.0 and correctly reports a deliberately drifted site with the full table.
  • bump round-tripped 2.28.0 → 2.99.0 → 2.28.0 with all seven sites moving together.
  • publish --dry-run runs the full preflight against the real registry (all three names correctly detected as not yet published), dry-run packs all three, and reports the publish order.
  • The missing-artifact guard verified by deleting packages/server/dist/index.mjs: publish refuses with the exact path.

Out of scope, flagged

First-time npm provisioning: trusted publishing can only be configured per package after its first publish, so release one of the new packages is necessarily an authenticated manual publish (OTP) — this tooling supports exactly that; the trusted-publishing binding (and its later re-binding for the repo rename) is registry-side configuration outside this repo.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added automated version consistency checks for all related packages and release metadata.
    • Added commands to update versions, validate release readiness, and publish packages in the correct order.
    • Added support for dry-run publishing, OTP authentication, resumable releases, and skipping already-published packages.
    • Configured packages for public npm publication.
  • Documentation

    • Updated release instructions to describe the streamlined lockstep release process.

@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: e7551a3d-352e-4e24-a304-de6c572ec7a2

📥 Commits

Reviewing files that changed from the base of the PR and between 0657fec and 19c4595.

📒 Files selected for processing (7)
  • .github/workflows/check.yml
  • CONTRIBUTING.md
  • package.json
  • packages/core/package.json
  • packages/device/package.json
  • packages/server/package.json
  • scripts/release.js

Disabled knowledge base sources:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.


Walkthrough

The pull request adds centralized lockstep release automation for three packages. It validates version sites, updates release metadata, publishes packages in dependency order, exposes npm commands, enables public access, and adds CI and contributor documentation.

Changes

Lockstep release workflow

Layer / File(s) Summary
Release command implementation
scripts/release.js
Adds check, bump, and publish commands. The script validates versions, updates package and React Hooks metadata, refreshes the lockfile, checks artifacts, supports dry runs and OTP, skips published packages, and publishes in dependency order.
Release scripts and package metadata
package.json, packages/*/package.json
Adds root npm commands and sets public npm access for all three packages.
CI and release procedure
.github/workflows/check.yml, CONTRIBUTING.md
Runs version checks in CI and documents the centralized bump and publish process.

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

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Maintainer
  participant ReleaseScript as scripts/release.js
  participant PackageFiles
  participant NpmRegistry
  Maintainer->>ReleaseScript: run release:bump VERSION
  ReleaseScript->>PackageFiles: update versions and peer pins
  ReleaseScript->>PackageFiles: update React Hooks constant and lockfile
  ReleaseScript->>ReleaseScript: re-check version sites
  Maintainer->>ReleaseScript: run release:publish
  ReleaseScript->>NpmRegistry: check published package versions
  ReleaseScript->>NpmRegistry: pack and publish remaining packages
Loading

Suggested reviewers: ttypic

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lockstep-release

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

A rabbit checks each version line,
Then bumps three packages in time.
The lockfile hops, the pins align,
CI guards the release sign.
Core leads the publish trail,
While ears applaud a tidy fail.

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

@ttypic ttypic 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.

LGTM

Base automatically changed from uts-per-side to integration/v3 September 15, 2026 10:45
umair-ably and others added 2 commits September 15, 2026 11:45
None of the three package.json files set publishConfig.access, and npm
publishes a scoped package as restricted by default on its first
publish. The first lockstep release would therefore have published
@ably/pubsub-core, @ably/pubsub-device and @ably/pubsub-server as
private packages (or failed outright, depending on the org's plan).
Declare access: public explicitly in all three.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rollout plan requires that one command releases core + device +
server at the same version, with partial release impossible or failing
reversibly. The release process was a manual checklist with three
hand-edited version sites and three separate npm publish invocations —
plenty of room for a drifted peer pin or a half-published release.

scripts/release.js owns the mechanics, one command per step:

- check: verifies all seven version sites agree (root and workspace
  package.json files, the wrappers' exact @ably/pubsub-core peer pins,
  and the react-hooks agent version constant). Wired into the lint CI
  job, so a drifted site cannot merge.
- bump <version>: moves every site at once and refreshes the lockfile.
  The package.json files are rewritten directly rather than via
  npm version --workspaces, which was observed (npm 11) to rewrite the
  files and still exit non-zero, and then to fail on re-run with
  'Version not changed' — exactly the partial state this tool exists
  to prevent. bump is deterministic and safely re-runnable.
- publish [--dry-run] [--otp]: refuses to start unless the sites agree
  and every build artifact the packages' files globs reference exists
  (npm pack silently omits missing files, so a stale checkout would
  otherwise ship broken tarballs). Dry-run packs everything before
  publishing anything, publishes in dependency order (core before the
  wrappers that pin it), skips versions already on the registry so a
  failed run resumes by re-running, and prints rollback guidance
  (unpublish within 72 hours) if a release is abandoned partway.

CONTRIBUTING's release process shrinks accordingly (three version
steps become one, two publish steps become one).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ttypic
ttypic marked this pull request as ready for review September 15, 2026 10:45
@ttypic
ttypic merged commit 2e811c3 into integration/v3 Sep 15, 2026
15 of 20 checks passed
@ttypic
ttypic deleted the lockstep-release branch September 15, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants