Cargo Copter
Test downstream impact of Rust crate changes before publishing. Spot and locate regressions and API breakages.
Test any versions of your crate and/or a local WIP version X any versions of any specified dependents (defaults to top 10 most popular dependents).
Let natural version resolution take place --test-versions "0.8.50 0.8.51" (to simulate publishing to crates.io)
OR use --force-versions "0.8.52 0.8.53" to simulate them upgrading to a new version of your crate with an edit of their cargo.toml.
⚠️ Security: Executes arbitrary code from crates.io. Always run in sandboxed environments.
Why did you name it cargo-copter? To make it absolutely impossible to find via google.
Quick Start
# Clone and build
# Test your crate
Example Output
Testing 2 reverse dependencies of rgb
Dependents: ansi_colours, resvg
rgb versions: baseline, 0.8.91-alpha.3 [!], 0.8.52
2 × 3 = 6 tests
this = 0.8.52 bd35c97* (your work-in-progress version)
┌─────────────────────────────┬────────────┬──────────────────┬──────────────────────────────┬─────────────────────────┐
│ Offered │ Spec │ Resolved │ Dependent │ Result Time │
├─────────────────────────────┼────────────┼──────────────────┼──────────────────────────────┼─────────────────────────┤
│ - baseline │ 0.8 │ 0.8.52 📦 │ ansi_colours 1.2.3 │ passed ✓✓✓ 8.3s │
│ ✗ ≠0.8.91-alpha.3 [≠→!] │ → =0.8.... │ 0.8.91-alpha.... │ ansi_colours 1.2.3 │ test failed ✓✓✗ 1.7s │
│ ┌────────────────────────┴────────────┘ └──────────────────────────────┘ │
│ │ cargo test failed on ansi_colours │
│ │ error[E0277]: the trait bound `Gray<u8>: ToLab` is not satisfied │
│ │ --> src/test.rs:45:47 │
│ └────────────────────────┬────────────┬──────────────────┬──────────────────────────────┬─────────────────────────┤
│ ✓ =0.8.52 │ 0.8 │ 0.8.52 📦 │ ansi_colours 1.2.3 │ passed ✓✓✓ 3.1s │
├─────────────────────────────┼────────────┼──────────────────┼──────────────────────────────┼─────────────────────────┤
│ - baseline │ 0.8 │ 0.8.52 📦 │ resvg 0.45.1 │ passed ✓✓✓ 8.4s │
│ ✓ ≠0.8.91-alpha.3 [≠→!] │ → =0.8.... │ 0.8.91-alpha.... │ resvg 0.45.1 │ passed ✓✓✓ 4.9s │
│ ✓ =0.8.52 │ 0.8 │ 0.8.52 📦 │ resvg 0.45.1 │ passed ✓✓✓ 2.1s │
└─────────────────────────────┴────────────┴──────────────────┴──────────────────────────────┴─────────────────────────┘
Version Comparison:
Default 0.8.52 0.8.91-alpha.3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Total tested 2 2 2
Already broken 0 - -
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Passed fetch 2 2 2
Passed check 2 2 2
Passed test 2 2 -1 → 1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Fully passing 2 2 -1 → 1
Markdown report: copter-report.md
Detailed failure logs: copter-failures.log
💡 To analyze API changes that may have caused regressions:
Install: cargo install cargo-public-api
cargo public-api diff .copter/staging/rgb-baseline .copter/staging/rgb-0.8.91-alpha.3
Common Usage
# Test top dependents
# Test specific dependents
# Test specific dependent versions
# Test multiple versions (includes baseline automatically)
# Force incompatible versions (bypasses semver)
# Test published crate without local source
# Clean cache and retest
CLI Options
-p, --path <PATH> Path to crate (directory or Cargo.toml)
-c, --crate <NAME> Test published crate by name
--top-dependents <N> Test top N by downloads [default: 5]
--dependents <CRATE[:VER]> Test specific crates (space-separated)
--dependent-paths <PATH> Test local crate paths
--test-versions <VER>... Test multiple versions
--force-versions <VER>... Force versions (bypass semver)
--staging-dir <PATH> Cache directory [default: .copter/staging]
--output <PATH> HTML report [default: copter-report.html]
--only-fetch Only fetch dependencies (skip check and test)
--only-check Only fetch and check (skip tests)
--clean Clean cache before testing
--error-lines <N> Error lines to show [default: 10]
--skip-normal-testing Skip auto-patch mode for forced versions
--json JSON output
How It Works
- Baseline test: Tests each dependent with currently published version
- Offered version tests: Tests with specified versions (--test-versions, --force-versions, or local WIP)
- Three-step ICT: Install (fetch) → Check → Test (stops early on failure)
- Classification:
- ✓ passed: Baseline and offered both passed
- ✗ regressed: Baseline passed, offered failed
- ✗ broken: Baseline already failed
- ⊘ skipped: Version offered but not used by cargo
Version Testing Modes
Patch Mode (default with --test-versions)
- Uses
[patch.crates-io]in Cargo.toml - Respects semver requirements
- Cargo can ignore if version doesn't satisfy spec
Force Mode (--force-versions)
- Directly modifies dependency in Cargo.toml
- Bypasses semver requirements
- Always tests the exact version specified
- Auto-adds patch mode test unless --skip-normal-testing
Caching
Cache location: .copter/staging/{crate}-{version}/
- Unpacked sources
- Build artifacts (target/)
- 10x speedup on subsequent runs
Downloaded .crate files: .copter/crate-cache/
Reports
- Console: Live streaming table output
- HTML:
copter-report.htmlwith visual summaries - Markdown:
copter-report.mdoptimized for LLM analysis - Failure log:
copter-failures.logwith deduplicated errors
Table Symbols
Offered column:
-= Baseline row✓= Test passed✗= Test failed⊘= Version skipped== Exact version match↑= Upgraded to newer version≠= Version mismatch[≠→!]= Forced version
Resolved column:
📦= Published from crates.io📁= Local path
Result column:
✓✓✓= Install + Check + Test passed✓✓✗= Install + Check passed, Test failed✓✗-= Install passed, Check failed, Test skipped
Development
# Build and test
# Run with debug logging
RUST_LOG=debug
License
MIT/Apache-2.0 (standard Rust dual-license)
Links
- GitHub: https://github.com/imazen/cargo-copter
- Rust API Evolution RFC: https://github.com/rust-lang/rfcs/blob/master/text/1105-api-evolution.md
- Inspired by: cargo-crusader