Skip to content

ci: auto-publish relayburn-sdk + relayburn-cli to crates.io in lockstep with npm#353

Merged
willwashburn merged 2 commits intomainfrom
add-crates-io-publish
May 7, 2026
Merged

ci: auto-publish relayburn-sdk + relayburn-cli to crates.io in lockstep with npm#353
willwashburn merged 2 commits intomainfrom
add-crates-io-publish

Conversation

@willwashburn
Copy link
Copy Markdown
Member

Summary

  • Extends .github/workflows/publish.yml so each workflow_dispatch publish run also ships relayburn-sdk and relayburn-cli to crates.io, using OIDC trusted publishing (no long-lived CARGO_REGISTRY_TOKEN).
  • Lockstep-versioned with the eight npm packages: bump step rewrites [workspace.package].version and the cli/sdk-node relayburn-sdk MAJOR.MINOR dep pin, refreshes Cargo.lock, and stages all Rust files alongside the npm version commit.
  • Cargo publishes before npm so a crate-side failure aborts before any tarball, tag, or commit goes out. Both cargo steps are idempotent (skip if the version is already on crates.io), so a partial failure can be retried with version: none.
  • Adds annotated relayburn-sdk-v<ver> / relayburn-cli-v<ver> tags (the relayburn- prefix disambiguates them from the existing npm sdk-v… / cli-v… tags).

Pre-bump bootstrap (one-time alignment)

This PR aligns the Rust workspace with the current npm lockstep version:

  • Cargo.toml: workspace version 0.0.01.10.0.
  • crates/relayburn-cli/Cargo.toml + crates/relayburn-sdk-node/Cargo.toml: relayburn-sdk dep version constraint 0.01.10 (caret = >=1.10.0, <2.0.0).
  • Cargo.lock refreshed.

Required maintainer steps before the first auto-publish run

The workflow can't mint OIDC tokens until trusted publishing is configured on crates.io. After this PR merges:

  1. Manually publish at 1.10.0 from a workstation using a personal API token:
    • cargo publish -p relayburn-sdk
    • Wait for sparse-index propagation (poll https://index.crates.io/re/la/relayburn-sdk for 1.10.0).
    • cargo publish -p relayburn-cli
  2. Configure trusted publishing on crates.io for both crates (Settings → Trusted Publishing → GitHub):
    • Repo: AgentWorkforce/burn, workflow filename: publish.yml, environment: empty.
  3. Revoke the personal API token used in step 1.

After bootstrap, the next workflow_dispatch run with version: patch will land 1.10.1 everywhere in lockstep.

Risks + mitigations

Risk Mitigation
Index propagation race between sdk and cli publish Poll index.crates.io/re/la/relayburn-sdk for the new version with timeout
Partial failure (cargo OK, npm fails) Cargo idempotent gate skips already-published versions; re-run picks up where it left off
Trusted-publisher misconfigured First production run with dry_run: true validates the OIDC exchange without publishing
Rust port broken at release time New cargo build/test step gates the whole job; npm doesn't ship if Rust is red

Test plan

  • Local: cargo build --workspace && cargo test --workspace passes on the bumped workspace.
  • After merge, run workflow_dispatch with dry_run: true, version: patch to verify:
    • Rust toolchain installs and cargo build/test pass on the runner.
    • Bump step rewrites Cargo.toml workspace version + crates/relayburn-{cli,sdk-node}/Cargo.toml SDK constraints (visible in step log).
    • rust-lang/crates-io-auth-action@v1 exchanges OIDC successfully.
    • cargo publish --dry-run -p relayburn-sdk and -p relayburn-cli succeed.
    • No git commit, no tags pushed, no npm publish.
  • First real publish run (after bootstrap): verify 1.10.1 ships to both crates.io and npm; tags relayburn-sdk-v1.10.1 and relayburn-cli-v1.10.1 appear; cargo install relayburn-cli from a clean machine works.

🤖 Generated with Claude Code

…ep with npm

Extends `.github/workflows/publish.yml` to ship the two Rust crates
alongside the eight npm packages on every workflow_dispatch publish
run, using crates.io OIDC trusted publishing (no long-lived token,
mirrors the existing npm flow).

Workflow changes:
- Adds a `cargo build --workspace --all-targets` + `cargo test
  --workspace` gate after the npm build/test so a Rust regression
  aborts the run before any publish side-effects.
- Bump step rewrites `[workspace.package].version` and the
  `relayburn-sdk` MAJOR.MINOR pin in the cli + sdk-node Cargo.toml
  files to the new lockstep version, then `cargo update --workspace`
  refreshes Cargo.lock.
- Inserts an OIDC token mint (`rust-lang/crates-io-auth-action@v1`)
  and `cargo publish` for sdk → cli before the npm pack+publish, with
  sparse-index polling between them and idempotent gates that skip
  versions already on crates.io so partial-failure re-runs work.
- Tag step adds annotated `relayburn-sdk-v<ver>` / `relayburn-cli-v<ver>`
  tags alongside the existing npm package tags.
- Summary step lists the cargo crates published.

Pre-bump bootstrap (one-time alignment):
- Workspace `Cargo.toml` version 0.0.0 → 1.10.0 to match current npm
  lockstep.
- relayburn-cli + relayburn-sdk-node `relayburn-sdk` dep version
  constraint 0.0 → 1.10 (caret = >=1.10.0, <2.0.0).
- Cargo.lock refreshed accordingly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6eb50cb1-3084-4c48-8675-b998cbcf523b

📥 Commits

Reviewing files that changed from the base of the PR and between 239794d and 0d319ec.

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

📝 Walkthrough

Walkthrough

Adds Rust workspace version bump and updates internal crate dependency versions; integrates Rust build/test gating, Rust version sync during npm bump, crates.io publishing via GitHub OIDC (with sparse-index checks and polling), crate-specific git tags, and workflow summary updates — all in the publish GitHub Actions workflow.

Changes

Rust Package Publishing Integration

Layer / File(s) Summary
Workspace Version
Cargo.toml
Workspace [workspace.package].version changed from 0.0.01.10.0.
Dependent Crate Versions
crates/relayburn-cli/Cargo.toml, crates/relayburn-sdk-node/Cargo.toml
relayburn-sdk path dependency version constraints bumped from 0.01.10 (path retained).
Rust Build & Test Gating
.github/workflows/publish.yml (lines ~84–98)
After JS tests, workflow installs Rust toolchain and runs cargo build --workspace --all-targets and cargo test --workspace to fail early on Rust errors.
Version Bump Sync
.github/workflows/publish.yml (lines ~224–240)
Bump flow reads bumped npm version, updates Rust workspace Cargo.toml.version, rewrites the two crate dependency version fields to the minor-pinned value, and runs cargo update --workspace.
Commit Staging
.github/workflows/publish.yml (lines ~566–568)
Version-bump commit now stages Cargo.toml, Cargo.lock, and the two modified crate Cargo.toml files.
Crates.io Publish (OIDC)
.github/workflows/publish.yml (lines ~582–662)
Mints short-lived CARGO_REGISTRY_TOKEN via GitHub OIDC; conditionally runs cargo publish for relayburn-sdk and relayburn-cli if version absent from crates.io sparse index; polls for SDK index visibility before CLI publish; supports --dry-run.
Tags & Summary
.github/workflows/publish.yml (lines ~720–748)
Creates crate-specific tags (relayburn-sdk-v$version, relayburn-cli-v$version) for SDK/CLI packages and adds a crates.io section to the workflow summary listing published crate versions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Poem

🐰 From zero to one-ten I hop with glee,
Cargo checks and tokens set us free,
SDK first then CLI takes flight,
Tags and npm join the night,
A tiny rabbit celebrates the spree!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: extending CI to auto-publish Rust crates to crates.io in lockstep with npm releases.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering workflow modifications, version alignment, bootstrap requirements, risks, and test plans.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-crates-io-publish

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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 (1)
.github/workflows/publish.yml (1)

88-95: 💤 Low value

clippy component is installed but never executed.

The workflow adds clippy as a component but only runs cargo build and cargo test. If lint gates are intended, add cargo clippy --workspace --all-targets -- -D warnings. If clippy isn't needed, remove it from the component list to reduce setup time.

Option A: Run clippy (if lint gates are intended)
       - name: Cargo build + test
         run: |
           cargo build --workspace --all-targets
+          cargo clippy --workspace --all-targets -- -D warnings
           cargo test --workspace
Option B: Remove unused component
       - name: Setup Rust toolchain
         run: |
           rustup toolchain install
-          rustup component add rustfmt clippy
+          rustup component add rustfmt
🤖 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/publish.yml around lines 88 - 95, The workflow installs
the "clippy" component but never runs it; either run Clippy as part of the job
by adding a step that invokes "cargo clippy --workspace --all-targets -- -D
warnings" (so lint failures fail the job) after the existing "cargo build +
test" steps, or remove "clippy" from the "rustup component add rustfmt clippy"
line to avoid installing an unused component; update the job to reference the
same workspace invocation style as "cargo build" and "cargo test".
🤖 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/publish.yml:
- Around line 595-608: The workflow mints the crates.io token only when dry_run
!= 'true', but the subsequent "Cargo publish (sdk → cli)" step requires
CARGO_REGISTRY_TOKEN even for --dry-run; update the workflow so the OIDC token
minting step (id: cargo-auth, uses: rust-lang/crates-io-auth-action@v1) runs
unconditionally (remove the if: condition) or ensure a token is supplied for dry
runs (set CARGO_REGISTRY_TOKEN from a repo/secret or a conditional step) so the
"Cargo publish (sdk → cli)" step always has CARGO_REGISTRY_TOKEN available.
- Around line 623-635: The polling loop that checks the crates.io sparse index
for relayburn-sdk@$VER can silently time out and allow the publish to continue;
modify the block around the for loop (the code that uses DRY, sdk_published, VER
and the for i in $(seq 1 30) loop) to detect whether the grep ever succeeded
and, if not, print a clear error like "relayburn-sdk@$VER not visible in index
after 30 attempts" and exit non‑zero (exit 1) so the workflow fails fast;
implement this by setting a local flag (e.g., found=0 set to 1 when grep
matches) or by checking the loop exit status and then echoing the message and
exiting when the version was not found.

---

Nitpick comments:
In @.github/workflows/publish.yml:
- Around line 88-95: The workflow installs the "clippy" component but never runs
it; either run Clippy as part of the job by adding a step that invokes "cargo
clippy --workspace --all-targets -- -D warnings" (so lint failures fail the job)
after the existing "cargo build + test" steps, or remove "clippy" from the
"rustup component add rustfmt clippy" line to avoid installing an unused
component; update the job to reference the same workspace invocation style as
"cargo build" and "cargo test".
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b614fd5-e8a4-406d-89c4-495b60adfdb2

📥 Commits

Reviewing files that changed from the base of the PR and between e5e5b99 and 239794d.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • .github/workflows/publish.yml
  • Cargo.toml
  • crates/relayburn-cli/Cargo.toml
  • crates/relayburn-sdk-node/Cargo.toml

Comment thread .github/workflows/publish.yml
Comment thread .github/workflows/publish.yml
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 239794d85f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/publish.yml Outdated
Comment on lines +596 to +598
if: ${{ github.event.inputs.dry_run != 'true' }}
id: cargo-auth
uses: rust-lang/crates-io-auth-action@v1
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 Badge Mint crates token for dry-run publish checks

The workflow skips Mint crates.io token via OIDC when dry_run=true, but the next step still executes cargo publish --dry-run in Cargo publish (sdk → cli). In this context, dry-run releases will fail in the Rust publish phase because cargo publish requires registry authentication even when running checks only, so the advertised dry-run preflight path cannot complete. Gate the publish step consistently or mint the token for dry-runs as well.

Useful? React with 👍 / 👎.

- Drop the redundant `rustup component add rustfmt clippy` line —
  rust-toolchain.toml already lists those components, so `rustup
  toolchain install` installs them on its own. Saves setup time and
  removes the false signal that publish.yml was going to run clippy
  (it doesn't; ci.yml doesn't either).

- Always mint the crates.io OIDC token, including on `dry_run: true`.
  Two reasons:
    1. `cargo publish --dry-run` requires registry auth on some cargo
       versions, so passing a real token avoids version-dependent
       surprises on the runner.
    2. Running the OIDC exchange on every dry run validates that the
       crates.io trusted-publisher registration is healthy — the whole
       point of running a dry run before a real release.

- Make the sparse-index polling loop fail loudly on timeout. If
  relayburn-sdk@$VER never appears within 30 attempts (5 min), exit
  non-zero with a clear error annotation instead of falling through
  to the CLI publish — a "missing dep" cargo error there is harder
  to diagnose than an explicit timeout.

Flagged by CodeRabbit + Codex on PR #353.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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