cargo-delta
cargo-delta detects which crates in a Cargo workspace are impacted by changes in a Git feature branch. Build, test, and benchmark only the crates you need, saving time and resources in your CI/CD pipeline.
- Robust Detection: Uses code analysis, pattern matching and runtime heuristics to identify dependencies.
- Impact Categorization: Separates crates into Modified, Affected, and Required for precise targeting.
- Configurability: Highly customizable via config, with per-crate overrides for parsing and detection.
- Dual-branch Git Detection: Compares two branches or commits to find both modified and deleted files.
- File Control Mechanisms: Exclude files from analysis or trigger a full rebuild when critical files change.
Installation
Usage
-
Check out the baseline branch and analyze:
-
Check out your feature branch and analyze:
-
Compare analyses to find impacted crates:
Configuration
You can customize cargo-delta by providing a -c config.toml argument to the command.
Configuration options can be set globally and overridden per crate. For example:
[]
= true
= ["*.foo", "*.bar"]
[]
= ["*.baz"] # Override for a specific crate
Default settings are provided in config.toml.example.
Robust Detection
Module Traversal
Follows mod declarations and #[path] attributes to discover all Rust modules in the workspace.
Mod Macros
Discovers modules declared via custom macros (e.g., my_mod!), assuming first argument is the name of the module.
Config default:
[]
= []
Config example:
[]
= ["my_mod"] # my_mod!(foo)
Include Macros
Detects files included via macros such as include_str! and include_bytes!, assuming the first argument is the name of the file.
Config default:
[]
= true
= [
"include_str", # include_str!("file.txt")
"include_bytes" # include_bytes!("file.bin")
]
Pattern-based Assumptions
Assumes certain files are dependencies based on glob patterns (e.g., *.proto, *.snap).
Config default:
[]
= false
= []
Config example:
[]
= true
= [".proto"]
File Method Matching
Detects files loaded at runtime by matching method names (e.g., from_file, load, open), assuming the first argument is the name of the file.
Config default:
[]
= true
= [
"file", # ::file(path, ...)
"from_file", # ::from_file(path, ...)
"load", # ::load(path, ...)
"open", # ::open(path, ...)
"read", # ::read(path, ...)
"load_from" # ::load_from(path, ...)
]
File Control Mechanisms
File Exclusion
Exclude files and folders from analysis using glob patterns. Useful for ignoring build artifacts, temp files, etc.
Config default:
= ["target/**", "*.tmp"]
Trip Wire
If any changed or deleted file matches a configured trip wire pattern, all crates are considered impacted. Use this for critical files like top-level Cargo.toml, build scripts, or configuration files.
Config default:
= []
Config example:
= [
"Cargo.toml", # top-level Cargo.toml
"delta.toml" # Delta config file
]
Understanding Output
Analyze
Analyze phase produces JSON file that's intended to be consumed by run phase.
- files: Nested tree of file dependencies as detected by all the heuristics.
- crates: Dependency relationships between crates within the workspace.
Run
Run phase produces JSON file that's intended to be consumed by your CI/CD.
- Modified: Crates directly modified by Git changes.
- Affected: Modified crates plus all their dependents, direct and indirect.
- Required: Affected crates plus all their dependencies, direct and indirect.
Limitations
This tool is best-effort and may not detect all dependencies:
- Dynamic file paths computed at runtime
- Conditional compilation dependencies
- Other dependencies not captured by the heuristics
Example
{
}
)
)
)
)
Contributing
Contributions are welcome! Please feel free to fork the repository and submit a pull request.
License
This project is licensed under the MIT License - see the LICENSE file for details.