From f2c26759530d3b007385fb4338a89a17cfab1f96 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 16:33:13 +0000 Subject: [PATCH] Publish the workspace in one cargo invocation, not crate by crate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The verify job cannot rehearse imcp2's package for any new release. It runs cargo publish --locked --dry-run -p imcp2-core cargo package --locked --no-verify -p imcp2 and the second command fails, because packaging imcp2 resolves `imcp2-core = "="` against crates.io — where only the PREVIOUS release exists. The version being released is uploaded by the publish job, which verify gates, so the requirement cannot be satisfied at the moment it is checked: error: failed to select a version for the requirement `imcp2-core = "^0.3.0"` candidate versions found which didn't match: 0.2.0 `--no-verify` is not the escape hatch it looks like: it skips the compile, not the dependency resolution that packaging performs. The step's comment anticipated the verify-build half of this and dropped the build; the resolution half was left, and it is the half that fails. This has never fired because imcp2-core has never been released through this workflow — 0.2.0 was hand-published, and the lockstep pin has named an already-published version ever since. It fires on the first real lockstep release. Publish the workspace in one invocation instead. Cargo then resolves the two crates together: it packages imcp2-core first and verifies imcp2 against a temporary local registry holding it, so the rehearsal covers the same crates in the same order as the upload, and imcp2 gets a verify build again rather than being packaged sight-unseen. The publish job takes the matching `--workspace` form, which sequences the uploads in dependency order itself — one step instead of two that could drift apart. The job split that keeps dependency code away from the credential is unchanged, and the rewritten comments say why it still holds: `--no-verify` on a workspace publish emits no Compiling or Verifying step at all, so the credential-holding job still compiles nothing. Verified against a 0.3.0 tree, where the current commands fail and these succeed. Also correct the header's one-time-setup note, which still said imcp2-core's first release was pending; 0.2.0 is on crates.io. Whether its trusted publisher is configured is a crates.io-side setting this file cannot assert, so the note now says each crate needs its own or its upload 403s. Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01GqhkbpCwxs67F5E2EzyDwh --- .github/workflows/publish-crate.yml | 64 ++++++++++++++++------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/.github/workflows/publish-crate.yml b/.github/workflows/publish-crate.yml index 97d72bea..4e7fd93d 100644 --- a/.github/workflows/publish-crate.yml +++ b/.github/workflows/publish-crate.yml @@ -32,9 +32,10 @@ # or be left blank to accept any # A trusted publisher can only be configured on a crate that already exists, so the # FIRST release of each crate has to be published by hand — `cargo publish --locked` -# with a personal token (imcp2's 0.1.0 was; imcp2-core's first release must be, and -# its trusted publisher configured with this same repository/workflow/environment) -# — and every release after it goes through this workflow. +# with a personal token — and every release after it goes through this workflow. +# imcp2's 0.1.0 and imcp2-core's 0.2.0 were both published that way, so both crates +# now exist; each still needs its OWN trusted publisher configured against this same +# repository/workflow/environment, or its upload below 403s. # # REQUIRED REPOSITORY SETTINGS, to be in place BEFORE the trusted publisher is # enabled. Neither can be expressed in this file, and without them the guards below @@ -143,19 +144,28 @@ jobs: - name: Test run: cargo test --locked --workspace --all-targets - # Rehearses the real thing — packages each crate, and compiles imcp2-core's - # package in isolation — but stops short of uploading, so a package that only - # builds because of something untracked in the working tree fails here rather - # than after the upload is already permanent. imcp2's package cannot be - # compile-verified before this release's imcp2-core exists on crates.io (it - # depends on it by version), so its rehearsal is `cargo package` without the - # verify build: the workspace test above already compiled exactly these - # sources. This is also the verify work that lets the publish job skip its - # own; see `--no-verify` below. + # Rehearses the real thing — packages both crates and compiles each package in + # isolation — but stops short of uploading, so a package that only builds + # because of something untracked in the working tree fails here rather than + # after the upload is already permanent. + # + # `--workspace` is what makes rehearsing imcp2 possible at all. Packaged one + # at a time, imcp2 cannot even be PACKAGED before this release's imcp2-core + # exists on crates.io: it depends on it by version, and packaging resolves + # that requirement against the registry, where only the PREVIOUS release + # exists — the new one is uploaded by the publish job below, which this job + # gates. (`--no-verify` does not help: it skips the compile, not the + # resolution.) A workspace publish resolves the two together — cargo packages + # imcp2-core first and verifies imcp2 against a temporary local registry + # holding it — so the rehearsal covers the same crates, in the same order, as + # the upload. It also restores the verify build for imcp2, which the previous + # per-crate form had to give up. + # + # This is also the verify work that lets the publish job skip its own; see + # `--no-verify` below. imcp2-local is `publish = false`, so `--workspace` + # leaves it out on its own. - name: Package - run: | - cargo publish --locked --dry-run -p imcp2-core - cargo package --locked --no-verify -p imcp2 + run: cargo publish --locked --dry-run --workspace # Holds the credential, and compiles nothing. publish: @@ -189,19 +199,17 @@ jobs: # it `cargo publish` compiles the package — running the dependency tree's build # scripts and proc macros — while CARGO_REGISTRY_TOKEN sits in their # environment. The verify build is not skipped, only moved: the `verify` job - # packaged both crates (and compiled imcp2-core's package) over this same - # commit, and the workspace test suite compiled exactly these sources. What - # remains in this job is reading files into a .crate and an HTTPS upload. + # packaged and compiled both crates over this same commit, and the workspace + # test suite compiled exactly these sources. What remains in this job is + # reading files into a .crate and an HTTPS upload — with `--no-verify` a + # workspace publish emits no Compiling/Verifying step at all, so no dependency + # code runs anywhere near the credential. # - # Order matters: imcp2 depends on imcp2-core by version, so core publishes - # first; `cargo publish` waits for the just-published crate to appear in the - # index before returning, so the second publish resolves the first. - - name: Publish imcp2-core - run: cargo publish --locked --no-verify -p imcp2-core - env: - CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} - - - name: Publish imcp2 - run: cargo publish --locked --no-verify -p imcp2 + # Order matters: imcp2 depends on imcp2-core by version, so core must be + # uploaded first. `--workspace` sequences that itself, publishing in dependency + # order and waiting for each crate to appear in the index before the next, so + # the two uploads no longer have to be spelled out (and cannot drift apart). + - name: Publish imcp2-core and imcp2 + run: cargo publish --locked --no-verify --workspace env: CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}