feat(packaging): shrink shipper to install façade (#95 PR 3)#142
Conversation
Third step of the #95 three-crate split. After PRs 1-2, `shipper`'s lib.rs was still blanket-re-exporting every `shipper-core` module; the README and CLAUDE.md still framed `shipper` as "the core library." This PR makes the façade framing real. ## Architecture (finalized after this PR) shipper (this crate — install handle + curated lib re-export) -> shipper-cli (real CLI adapter; pub fn run()) -> shipper-core (engine — stable embedding surface) ## Curated library re-export `crates/shipper/src/lib.rs` now re-exports only the six modules a programmatic driver would reach for as entry points: engine, plan, types, config, state, store Engine internals that used to be re-exported — `auth`, `cargo`, `cargo_failure`, `encryption`, `git`, `lock`, `registry`, `retry`, `runtime`, `webhook` — are **not** in the façade. Embedders who need them should depend on `shipper-core` directly. That's the point of the split: the `shipper` install crate shouldn't be both "the easy install path" and "the programmatic API surface for every internal." ## Tests migrated Four `crates/shipper/tests/*.rs` files reached into now-uncurated modules (`shipper::auth`, `shipper::lock`, `shipper::registry`). Their imports now read from `shipper_core::X` instead: - `cross_crate_integration.rs` - `facade_integration.rs` - `pipeline_integration.rs` - `execution_bdd.rs` (was already using `shipper::runtime`; now `shipper_core::runtime`) - plus incidental sed matches in other tests that happened to reference the same paths `shipper-core` is added as a dev-dep of `shipper` so the integration tests can import it directly. PR 4 will decide whether these tests belong in `crates/shipper-core/tests/` instead. ## README `crates/shipper/README.md` rewritten as the product landing page: - Opens with `cargo install shipper --locked`. - Names the five things Shipper does that raw `cargo publish` can't (resumable, backoff-aware, events-as-truth, prove, contain). - Shows the three-crate architecture diagram so users see where `shipper-core` and `shipper-cli` fit. - Quick-start section with preflight / publish / resume flow. - Scope section separates publishing concerns from versioning / tags / GitHub releases. The old README framed this crate as a library; it now frames it as the install handle and points embedders at `shipper-core`. ## CLAUDE.md `crates/shipper/CLAUDE.md` updated to describe the façade role: behavior changes belong in `shipper-core` or `shipper-cli`, not here; this crate's surface should move rarely; CLI dependencies stay out. ## Verification - `cargo check --workspace --all-targets` — clean - `cargo clippy --workspace --all-targets --all-features -- -D warnings` — clean - `cargo test --workspace --doc` — clean - `cargo test -p shipper` — 39 passed ## What this PR does not do - Does not physically move `crates/shipper/tests/` into `crates/shipper-core/tests/` (PR 4 decision). - Does not update workspace docs (`docs/how-to/*`, `docs/explanation/*`) that may still reference `shipper::X` paths for things that are no longer re-exported (PR 4 sweep). - Does not touch the architecture guard or CI topology.
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 0 minutes and 7 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (13)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Code Review
This pull request refactors the shipper crate to serve as a stable installation target and curated re-export layer, delegating core engine logic to shipper-core. Documentation across CLAUDE.md, README.md, and lib.rs has been updated to reflect this architectural shift, and integration tests have been adjusted to import internal modules directly from shipper-core. Feedback identifies a redundant dev-dependency in Cargo.toml and suggests removing unnecessary mut variable bindings in several test files to improve code cleanliness.
| # directly into `shipper-core` (for engine internals like `runtime::` | ||
| # that aren't part of the curated façade) and `shipper-types` (for | ||
| # constructing fixtures). | ||
| shipper-core.workspace = true |
|
|
||
| // Acquire lock | ||
| let mut lock = shipper::lock::LockFile::acquire(state_dir, None).expect("acquire lock"); | ||
| let mut lock = shipper_core::lock::LockFile::acquire(state_dir, None).expect("acquire lock"); |
There was a problem hiding this comment.
The mut keyword for the lock variable appears to be unnecessary as it is not mutated in a way that requires it. Removing mut would improve code cleanliness and allow for the removal of the #[allow(unused_mut)] attribute (which is present on line 1512 but not shown in this diff hunk).
| let mut lock = shipper_core::lock::LockFile::acquire(state_dir, None).expect("acquire lock"); | |
| let lock = shipper_core::lock::LockFile::acquire(state_dir, None).expect("acquire lock"); |
| let mut lock1 = | ||
| shipper_core::lock::LockFile::acquire(&state_dir, None).expect("acquire lock 1"); |
There was a problem hiding this comment.
The mut keyword for lock1 is unnecessary as it is not mutated before being released. Removing it improves code clarity and avoids the need for unused_mut lint suppressions.
| let mut lock1 = | |
| shipper_core::lock::LockFile::acquire(&state_dir, None).expect("acquire lock 1"); | |
| let lock1 = | |
| shipper_core::lock::LockFile::acquire(&state_dir, None).expect("acquire lock 1"); |
| let mut lock = shipper_core::lock::LockFile::acquire_with_timeout( | ||
| &state_dir, | ||
| None, | ||
| Duration::from_secs(60), | ||
| ) | ||
| .expect("acquire with timeout"); |
There was a problem hiding this comment.
The mut keyword for lock is unnecessary here as well. Removing it maintains consistency and follows Rust best practices for minimizing mutable bindings.
| let mut lock = shipper_core::lock::LockFile::acquire_with_timeout( | |
| &state_dir, | |
| None, | |
| Duration::from_secs(60), | |
| ) | |
| .expect("acquire with timeout"); | |
| let lock = shipper_core::lock::LockFile::acquire_with_timeout( | |
| &state_dir, | |
| None, | |
| Duration::from_secs(60), | |
| ) | |
| .expect("acquire with timeout"); |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d76e2e2dfb
ℹ️ 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".
| auth, cargo, cargo_failure, config, encryption, engine, git, lock, plan, registry, retry, | ||
| runtime, state, store, types, webhook, | ||
| }; | ||
| pub use shipper_core::{config, engine, plan, state, store, types}; |
There was a problem hiding this comment.
Keep parallel publish callable from the shipper facade
Dropping registry from the facade re-exports while still re-exporting engine makes shipper::engine::parallel::run_publish_parallel effectively unusable for shipper-only consumers, because that public function requires RegistryClient (shipper-core defines it as crate::registry::RegistryClient) and the corresponding shipper::registry::... path no longer exists. This is a compile-time regression for existing facade callers of the parallel entry point unless registry stays re-exported or the parallel API is no longer exposed through shipper::engine.
Useful? React with 👍 / 👎.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
After #95 PR 3 curated the `shipper` library re-exports, four fuzz targets broke on CI's Fuzz Smoke (PR) lane: - `resolve_token` + `auth_token_resolve` — imported `shipper::auth` - `encrypt_decrypt` — imported `shipper::encryption` - `execution_core` — imported `shipper::runtime` None of these modules are re-exported from the `shipper` façade anymore — they're engine internals. Updated each target to import from `shipper_core::X` directly, and added `shipper-core` as a dependency of the `shipper-fuzz` crate.
Summary
Third step of the #95 three-crate split. After PRs 1-2 (#140, #141) the code was in the right crates, but
crates/shipper/src/lib.rswas still blanket-re-exporting everyshipper-coremodule, and the README/CLAUDE.md still framedshipperas the core library. This PR makes the façade framing real.Architecture (finalized)
Curated library re-export
crates/shipper/src/lib.rsnow re-exports only the six modules a programmatic driver would reach for as entry points:Engine internals —
auth,cargo,cargo_failure,encryption,git,lock,registry,retry,runtime,webhook— are not in the façade. Embedders who need them depend onshipper-coredirectly. That's the point of the split: theshipperinstall crate shouldn't double as "the programmatic API surface for every engine internal."Tests migrated
Several
crates/shipper/tests/*.rsfiles reached into now-uncurated modules (shipper::auth,shipper::lock,shipper::registry,shipper::runtime). Their imports now read fromshipper_core::Xinstead.shipper-coreadded as a dev-dep ofshipper.PR 4 will decide whether these engine-internal integration tests belong in
crates/shipper-core/tests/instead.README
Rewritten as the product landing page:
cargo install shipper --lockedcargo publishcan't (resumable, backoff-aware, events-as-truth, prove, contain)shipper-coreandshipper-clifitCLAUDE.md
Updated to describe the façade role: behavior changes belong in
shipper-coreorshipper-cli; this crate's surface should move rarely; CLI dependencies stay out.Verification
cargo check --workspace --all-targets— cleancargo clippy --workspace --all-targets --all-features -- -D warnings— cleancargo test --workspace --doc— cleancargo test -p shipper— 39 passedWhat this PR does not do
crates/shipper/tests/intocrates/shipper-core/tests/(PR 4 decision)docs/how-to/*,docs/explanation/*) that may referenceshipper::Xpaths for no-longer-re-exported modules (PR 4 sweep)Test plan
cargo install shipper --lockedstill produces a working binaryPart of #95. PR 4 (docs/examples/workspace import sweep) to follow.