Skip to content

Commit 16e6dfd

Browse files
committed
cargo-rail: improving the 'unify' process end to end; tested across 8x cloned repos including jj, datafusion, convex-backend, deno, ferros, helixdb, wasmtime, and rustpython. All green.
1 parent 604b821 commit 16e6dfd

File tree

19 files changed

+1040
-545
lines changed

19 files changed

+1040
-545
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ AGENTS.md
2323
# Documentation
2424
docs/*
2525
audit.md
26+
fixes.md
27+
fixes_split.md
28+
fixes_cdtwm.md
2629

2730
# Cargo-Rail (Testing)
2831
*rail.toml

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,35 @@
11
[package]
22
name = "cargo-rail"
3-
version = "0.1.0"
3+
version = "1.0.0"
44
edition = "2024"
55
rust-version = "1.89.0"
66
license = "MIT"
77
authors = ["loadingalias"]
8-
description = "Split Rust crates from Cargo workspaces into standalone repos with bidirectional sync"
8+
description = "Zero-waste Rust monorepo orchestration: graph-aware CI, dependency unification, release automation, and history-preserving crate distribution"
99
repository = "https://github.com/loadingalias/cargo-rail"
1010
homepage = "https://github.com/loadingalias/cargo-rail"
1111
documentation = "https://docs.rs/cargo-rail"
12-
categories = ["command-line-utilities", "development-tools", "git", "cargo", "monorepo-tools"]
13-
keywords = ["monorepo", "cargo", "workspace", "git", "split", "sync"]
12+
categories = [
13+
"command-line-utilities",
14+
"development-tools",
15+
"development-tools::cargo-plugins",
16+
"development-tools::build-utils",
17+
]
18+
keywords = ["monorepo", "cargo", "workspace", "ci", "release"]
1419
readme = "README.md"
1520

1621
[dependencies]
1722
clap = { version = "4.5.53", features = ["derive", "cargo"] }
18-
19-
# Workspace introspection
2023
cargo_metadata = "0.23.1"
21-
22-
# Graph analysis
2324
petgraph = "0.8.3"
24-
25-
# Lossless TOML editing (preserves formatting)
2625
toml_edit = { version = "0.23.7", features = ["serde"] }
27-
28-
# Error handling
2926
anyhow = "1.0.100"
30-
31-
# Serialization for config
3227
serde = { version = "1.0.228", features = ["derive"] }
3328
serde_json = "1.0.145"
3429
semver = "1.0.27"
35-
36-
# Parallelism and concurrency
3730
rayon = "1.11.0"
38-
39-
# Parsing (zero-copy, minimal deps)
4031
winnow = "0.7.13"
41-
42-
# Date/time handling for backup timestamps
43-
chrono = "0.4"
32+
chrono = "0.4.42"
4433

4534
[dev-dependencies]
4635
tempfile = "3.23.0"

README.md

Lines changed: 81 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
[![Crates.io](https://img.shields.io/crates/v/cargo-rail.svg)](https://crates.io/crates/cargo-rail)
66
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7-
[![Rust Version](https://img.shields.io/badge/rust-1.91%2B-orange.svg)](https://www.rust-lang.org)
7+
[![Rust Version](https://img.shields.io/badge/rust-1.89%2B-orange.svg)](https://www.rust-lang.org)
88

99
Stop wasting CI time. Stop fighting workspace dependencies. Stop copy-pasting git history.
1010

@@ -20,9 +20,19 @@ cargo install cargo-rail
2020

2121
| Problem | Solution | Impact |
2222
|---------|----------|--------|
23-
| 🔥 **Testing everything on every PR** | Graph-aware change detection | **10x faster CI** |
24-
| 💥 **Dependency fragmentation** | Resolution-based unification | **Zero workspace-hack crates** |
25-
| 🔨 **Distributing crates** | History-preserving split/sync | **One command, full git history** |
23+
| **Testing everything on every PR** | Graph-aware change detection | **10x faster CI** |
24+
| **Dependency fragmentation** | Resolution-based unification | **Zero workspace-hack crates** |
25+
| **Distributing crates** | History-preserving split/sync | **One command, full git history** |
26+
27+
### Replaces
28+
29+
| Tool | What cargo-rail does instead |
30+
|------|------------------------------|
31+
| **cargo-hakari** | Native `workspace.dependencies` unification—no workspace-hack crate |
32+
| **cargo-release / release-plz** | Dependency-ordered releases with native changelog generation |
33+
| **git-cliff** | Built-in conventional commit parsing (zero-copy, no external dep) |
34+
| **Copybara** | Deterministic split/sync with git-notes mapping |
35+
| **CI shell scripts** | Graph-aware `cargo rail affected` with nextest/bacon integration |
2636

2737
---
2838

@@ -156,7 +166,7 @@ def456 fix: critical bug # Same SHA!
156166

157167
- **System git only** – No libgit2/gitoxide dependency overhead
158168
- **Direct graph construction**`cargo_metadata` + `petgraph` (no guppy)
159-
- **8 core dependencies** – Minimal, auditable supply chain
169+
- **11 core dependencies** – Minimal, auditable supply chain
160170

161171
### Design Principles
162172

@@ -220,26 +230,80 @@ cargo rail sync my-crate # Bidirectional sync
220230
cargo rail status # Show sync status
221231
```
222232

223-
### Release Automation
233+
### Release Automation (replaces cargo-release + git-cliff)
224234

225235
```bash
226-
cargo rail release plan --all # Plan release
227-
cargo rail release publish --execute # Publish to crates.io
236+
# Plan releases with dependency-aware ordering
237+
cargo rail release --all --bump minor --dry-run
238+
239+
# Execute: bump versions, generate changelogs, tag, publish
240+
cargo rail release --all --bump patch --execute
241+
```
242+
243+
**What it does:**
244+
245+
- Native changelog generation from conventional commits (no git-cliff dependency)
246+
- Dependency-ordered publishing (deps before dependents)
247+
- Configurable delays between publishes (avoids registry race conditions)
248+
- GitHub release creation via `gh` CLI (optional)
249+
- GPG/SSH tag signing support
250+
251+
### Watch Mode (bacon/cargo-watch integration)
252+
253+
```bash
254+
# Auto-detect best watcher and run smart tests
255+
cargo rail test --watch
256+
257+
# Explicit watcher selection
258+
cargo rail test --watch --watch-mode bacon
228259
```
229260

230261
---
231262

232263
## Comparison
233264

234-
| Feature | cargo-rail | cargo-hakari | Copybara |
235-
|---------|-----------|-------------|----------|
236-
| Dependency unification | ✅ Resolution-based | ✅ Syntax-only ||
237-
| Workspace-hack crate | ❌ Not needed | ✅ Required ||
238-
| Git history preservation | ✅ Full || ⚠️ Partial |
239-
| Bidirectional sync ||||
240-
| Deterministic | ✅ Same SHAs | N/A ||
241-
| Smart testing | ✅ Graph-aware |||
242-
| Dependencies | 8 core | ~40+ (via guppy) | Go ecosystem |
265+
### vs Dependency Management
266+
267+
| Feature | cargo-rail | cargo-hakari |
268+
|---------|-----------|-------------|
269+
| Dependency unification | ✅ Resolution-based | ✅ Syntax-only |
270+
| Feature selection | Intersection (minimal) | Union (maximal) |
271+
| Workspace-hack crate | ❌ Not needed | ✅ Required |
272+
| TOML preservation | ✅ Lossless | ⚠️ Regenerates |
273+
| Dependencies | 10 core | ~40+ (via guppy) |
274+
275+
### vs Release Automation
276+
277+
| Feature | cargo-rail | cargo-release | release-plz |
278+
|---------|-----------|--------------|-------------|
279+
| Version bumping ||||
280+
| Changelog generation | ✅ Native | ❌ External ||
281+
| Dependency ordering | ✅ Graph-aware | ⚠️ Manual ||
282+
| GitHub releases | ✅ via gh |||
283+
| Publish delay | ✅ Configurable |||
284+
| Tag signing ||||
285+
| Dependencies | 90 |-| 600+|
286+
287+
### vs Monorepo Sync
288+
289+
| Feature | cargo-rail | Copybara | git-filter-repo |
290+
|---------|-----------|----------|-----------------|
291+
| Git history preservation | ✅ Full | ⚠️ Partial | ✅ Full |
292+
| Bidirectional sync ||| ❌ One-way |
293+
| Deterministic SHAs ||||
294+
| Conflict resolution | ✅ 3-way merge |||
295+
| Commit mapping | ✅ git-notes | Custom DB ||
296+
| Language | Rust | Go | Python |
297+
298+
### vs CI Optimization
299+
300+
| Feature | cargo-rail | Custom scripts | nx/turborepo |
301+
|---------|-----------|---------------|--------------|
302+
| Change detection | ✅ Graph-aware | ⚠️ Path-based | ✅ Graph-aware |
303+
| Rust-native || ⚠️ Shell | ❌ JS ecosystem |
304+
| Nextest integration | ✅ Auto-detect | Manual ||
305+
| Watch mode | ✅ bacon/cargo-watch | Manual ||
306+
| Dependency resolution | ✅ Cargo's resolver |||
243307

244308
---
245309

justfile

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,16 @@ pin-actions:
3636

3737
# Verify all GitHub Actions are properly pinned
3838
verify-actions:
39-
@scripts/ci/pin-actions.sh --verify-only
39+
@scripts/ci/pin-actions.sh --verify-only
40+
41+
# Create/update release PR via release-plz
42+
release-pr:
43+
@scripts/release/release_plz.sh release-pr
44+
45+
# Publish release (after PR merge)
46+
release:
47+
@scripts/release/release_plz.sh release
48+
49+
# Update changelog + versions locally (no PR)
50+
release-update:
51+
@scripts/release/release_plz.sh update

release-plz.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[workspace]
2+
changelog_update = true
3+
git_release_enable = true
4+
publish = true
5+
6+
[[package]]
7+
name = "cargo-rail"
8+
changelog_path = "CHANGELOG.md"
9+
git_tag_name = "v{{ version }}"

scripts/release/release_plz.sh

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
# release-plz wrapper for cargo-rail
5+
# Usage:
6+
# ./scripts/release/release_plz.sh release-pr # Create/update release PR
7+
# ./scripts/release/release_plz.sh release # Publish (after PR merge)
8+
# ./scripts/release/release_plz.sh update # Update changelog + versions locally
9+
10+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11+
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
12+
13+
check_release_plz() {
14+
if ! command -v release-plz &> /dev/null; then
15+
echo "release-plz not found. Install with:"
16+
echo " cargo install release-plz"
17+
exit 1
18+
fi
19+
}
20+
21+
main() {
22+
check_release_plz
23+
cd "$REPO_ROOT"
24+
25+
local cmd="${1:-release-pr}"
26+
shift || true
27+
28+
case "$cmd" in
29+
release-pr)
30+
echo "Creating/updating release PR..."
31+
release-plz release-pr "$@"
32+
;;
33+
release)
34+
echo "Publishing release..."
35+
release-plz release "$@"
36+
;;
37+
update)
38+
echo "Updating changelog and versions locally..."
39+
release-plz update "$@"
40+
;;
41+
*)
42+
echo "Usage: $0 {release-pr|release|update}"
43+
echo ""
44+
echo "Commands:"
45+
echo " release-pr Create or update a release PR on GitHub"
46+
echo " release Publish to crates.io (run after merging release PR)"
47+
echo " update Update changelog and versions locally (no PR/publish)"
48+
exit 1
49+
;;
50+
esac
51+
}
52+
53+
main "$@"

0 commit comments

Comments
 (0)