Skip to content

decrating: absorb shipper-git into shipper::ops::git#75

Merged
EffortlessSteven merged 1 commit into
mainfrom
feature/decrating-absorb-git
Apr 15, 2026
Merged

decrating: absorb shipper-git into shipper::ops::git#75
EffortlessSteven merged 1 commit into
mainfrom
feature/decrating-absorb-git

Conversation

@EffortlessSteven

Copy link
Copy Markdown
Member

Summary

Final microcrate absorption for decrating Phase 2. Collapses the standalone
shipper-git crate (2095 LOC) plus the in-tree crates/shipper/src/git.rs
shim (158 LOC) into crates/shipper/src/ops/git/ as crate-private modules,
bringing the workspace to the 13-crate target.

Layout

crates/shipper/src/ops/git/
├── CLAUDE.md
├── mod.rs            -- public-to-crate facade + collect_git_context
├── cleanliness.rs    -- is_git_clean / ensure_git_clean (CLI-compat phrasing)
├── bin_override.rs   -- SHIPPER_GIT_BIN-aware helpers
├── context.rs        -- commit/branch/tag/changed-files/remote queries (+170 tests)
└── snapshots/        -- 36 insta snapshots ported verbatim

Backward compatibility

  • Public shipper::git::* surface unchanged. src/git.rs is now a thin
    re-export of crate::ops::git::{collect_git_context, ensure_git_clean, is_git_clean}.
  • SHIPPER_GIT_BIN env override preserved (routes through bin_override.rs).
  • GitContext stays in shipper-types; its new/has_commit/is_dirty/
    short_commit methods are moved there (byte-for-byte port from the old
    shipper-git crate, including 7-byte short-commit slice).

Changes

  • crates/shipper/src/ops/{mod.rs,git/} — new module
  • crates/shipper/src/git.rs — now a facade (9 LOC, was 158)
  • crates/shipper/Cargo.toml — drops shipper-git dep
  • crates/shipper-types/src/lib.rs — adds GitContext accessor methods
  • crates/shipper-git/ — deleted (crate + snapshots)
  • Cargo.toml — workspace member removed
  • Cargo.lock — shipper-git entry dropped
  • fuzz/Cargo.toml, fuzz/fuzz_targets/git_context.rs — switches import to
    shipper_types::GitContext
  • docs/architecture.md — shipper-git marked absorbed

Test plan

  • cargo check --workspace — clean
  • cargo check --workspace --all-targets — clean
  • cargo test -p shipper ops::git — 142/142 passing
  • cargo test -p shipper — 1830 lib tests passing
  • cargo test -p shipper-cli — only pre-existing flaky
    preflight_allow_dirty_snapshot fails (verified identical failure on
    main; network/mock-server timing, unrelated to this change)
  • cargo clippy --workspace --all-targets --all-features -- -D warnings — clean
  • cargo fmt --all -- --check — clean
  • Pre-flight R-PR-4: grep -l shipper-git crates/*/Cargo.toml fuzz/Cargo.toml — empty

Per docs/decrating-plan.md §3.2. Completes Phase 2.

Final microcrate absorption in Phase 2 — brings the workspace to the
13-crate target. The `shipper-git` microcrate (2095 LOC) and the in-tree
`crates/shipper/src/git.rs` shim (158 LOC) are collapsed into
`crates/shipper/src/ops/git/` as crate-private modules:

- `mod.rs` — public-to-crate facade + `collect_git_context`
- `cleanliness.rs` — canonical `is_git_clean` / `ensure_git_clean`
  (with CLI-compatible "not clean; commit/stash changes or use
  --allow-dirty" phrasing) plus the `SHIPPER_GIT_BIN` override routing
- `context.rs` — commit/branch/tag/changed-files/remote queries plus
  the `get_git_context` aggregator and all 170+ unit, snapshot, and
  property tests
- `bin_override.rs` — parallel `SHIPPER_GIT_BIN`-aware helpers that
  preserve the in-tree shim's env-var override behavior

`GitContext` already lived in `shipper-types`; its `new`, `has_commit`,
`is_dirty`, and `short_commit` methods are moved there (matching the
pre-absorption `shipper-git` implementation byte-for-byte, including
the 7-byte short-commit slice for ASCII hex).

Backward compatibility:
- `shipper::git::*` public surface unchanged — the new `src/git.rs`
  re-exports `crate::ops::git::{collect_git_context, ensure_git_clean,
  is_git_clean}`.
- `SHIPPER_GIT_BIN` env override preserved.
- All 36 original snapshot files renamed and ported verbatim under
  `src/ops/git/snapshots/` so the test matrix continues to pin
  GitContext serialization, error phrasing, and porcelain parsing.

Also updates:
- Workspace `Cargo.toml` (drops `crates/shipper-git` member)
- `crates/shipper/Cargo.toml` (drops `shipper-git` dep)
- `fuzz/Cargo.toml` + `fuzz/fuzz_targets/git_context.rs` (switch to
  `shipper_types::GitContext`)
- `docs/architecture.md` (shipper-git marked absorbed; leaf-crate list
  trimmed; `micro-git` mention removed)
- `crates/shipper/src/ops/mod.rs` (registers `pub(crate) mod git`)
- `Cargo.lock` (drops shipper-git entry)

Per `docs/decrating-plan.md` §3.2. Completes Phase 2.
@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@EffortlessSteven has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 56 seconds before requesting another review.

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 20 minutes and 56 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0440a117-aa7c-4092-87f8-8c13b954dfd1

📥 Commits

Reviewing files that changed from the base of the PR and between ce52098 and 80cd97c.

⛔ Files ignored due to path filters (37)
  • Cargo.lock is excluded by !**/*.lock
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__clean_result_err_not_git.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__clean_result_err_uncommitted.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__clean_result_ok.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__context_all_fields.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__context_detached_head.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__context_dirty_detached.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__context_dirty_with_tag.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__context_feature_branch_clean.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__context_no_commit_no_branch.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__context_tagged_detached.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__is_dirty_all_variants.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__porcelain_empty_output.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__porcelain_parsed_files.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__porcelain_renamed_and_copied.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__porcelain_spaces_in_names.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__short_commit_empty_string.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__edge_case_snapshots__short_commit_exactly_eight.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__clean_working_tree.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__dirty_default_behavior.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__dirty_working_tree.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__ensure_git_clean_error.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__git_context_commit_only.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__git_context_dirty_no_tag.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__git_context_empty.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__git_context_full.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__git_rev_parse_failed_error.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__git_status_failed_error.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__short_commit_full_hash.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__short_commit_none.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__short_commit_seven_chars.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__short_commit_short_hash.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__tag_absent.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__tag_dirty_tree.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__tag_prerelease.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__tag_semver.snap is excluded by !**/*.snap
  • crates/shipper/src/ops/git/snapshots/shipper__ops__git__context__snapshot_tests__unknown_dirty_state.snap is excluded by !**/*.snap
📒 Files selected for processing (16)
  • Cargo.toml
  • crates/shipper-git/CLAUDE.md
  • crates/shipper-git/Cargo.toml
  • crates/shipper-git/README.md
  • crates/shipper-types/src/lib.rs
  • crates/shipper/Cargo.toml
  • crates/shipper/src/git.rs
  • crates/shipper/src/ops/git/CLAUDE.md
  • crates/shipper/src/ops/git/bin_override.rs
  • crates/shipper/src/ops/git/cleanliness.rs
  • crates/shipper/src/ops/git/context.rs
  • crates/shipper/src/ops/git/mod.rs
  • crates/shipper/src/ops/mod.rs
  • docs/architecture.md
  • fuzz/Cargo.toml
  • fuzz/fuzz_targets/git_context.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/decrating-absorb-git

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 and usage tips.

@EffortlessSteven EffortlessSteven merged commit 0ec78d7 into main Apr 15, 2026
9 of 15 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request absorbs the shipper-git microcrate into the main shipper crate as the shipper::ops::git module. It relocates the GitContext struct to shipper-types and updates the workspace to reflect the removal of the standalone crate. A review comment suggests using anyhow::Context for improved error chaining in the git cleanliness check.

return bin_override::local_is_git_clean(repo_root, &git_program);
}

is_git_clean_default(repo_root).map_err(|err| anyhow::anyhow!("git status failed: {err}"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The error message construction here uses anyhow::anyhow!("git status failed: {err}"). While this is consistent with the existing code, it is generally better to use context from anyhow to chain errors properly, which preserves the error source and provides better debugging information.

Suggested change
is_git_clean_default(repo_root).map_err(|err| anyhow::anyhow!("git status failed: {err}"))
is_git_clean_default(repo_root).context("git status failed")

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