Thank you for your interest in contributing to Debtmap! This guide will help you get started with development, testing, and submitting contributions.
Before you begin, ensure you have the following installed:
- Rust (latest stable version): Install via rustup
- Just (command runner): Install with
cargo install just - Git: For version control
Optional but recommended:
- cargo-nextest: Faster test runner -
cargo install cargo-nextest - cargo-llvm-cov: Code coverage -
cargo install cargo-llvm-cov - cargo-watch: Auto-rebuild on file changes -
cargo install cargo-watch
# Clone the repository
git clone https://github.com/iepathos/debtmap.git
cd debtmap
# Build the project
cargo build
# Run tests to verify everything works
just test
# Try analyzing debtmap itself
cargo build --bin debtmap
./target/debug/debtmap analyze . --top 10Debtmap uses Just for common development tasks. Run just or just --list to see all available commands:
# Development
just dev # Run in development mode
just watch # Run with hot reloading
just build # Build the project
# Testing
just test # Run all tests with nextest
just test-verbose # Run tests with output
just coverage # Generate coverage report
just analyze-self # Analyze debtmap with coverage
# Code Quality
just fmt # Format code with rustfmt
just lint # Run clippy linter
just check # Quick syntax check
# CI Simulation
just ci # Run all CI checks locally
just pre-commit # Run pre-commit checks-
Create a feature branch from
master:git checkout -b feature/your-feature-name
-
Make your changes following the code style guidelines below
-
Run tests and linters:
just fmt just lint just test -
Commit your changes with clear, descriptive messages:
git add . git commit -m "Add feature: description of what changed"
-
Push to your fork and create a pull request
Debtmap follows functional programming principles and Rust best practices. Please review CLAUDE.md for detailed coding guidelines.
- Functional-first design: Prefer pure functions over stateful methods
- Immutable data structures: Use the
imcrate for persistent collections - Composable pipelines: Chain transformations using iterators
- Error handling: Use
Result<T>with the?operator andanyhow::Context - Maximum function length: 20 lines (prefer 5-10)
- Maximum cyclomatic complexity: 5
Before committing, always run:
just fmt # Auto-format code with rustfmt
just lint # Check for clippy warnings (must pass with -D warnings)Required standards:
- All code must be formatted with
cargo fmt - All clippy warnings must be addressed (no warnings allowed)
- Public APIs must have documentation comments
- Complex logic should have inline comments explaining "why"
// Good: Pure, composable, single responsibility
fn calculate_complexity_score(metrics: &FunctionMetrics) -> f64 {
let cyclomatic_weight = metrics.cyclomatic as f64 / 10.0;
let cognitive_weight = metrics.cognitive as f64 / 20.0;
(cyclomatic_weight + cognitive_weight) * 5.0
}
// Good: Clear error handling
fn parse_lcov_file(path: &Path) -> Result<CoverageData> {
let content = fs::read_to_string(path)
.context("Failed to read LCOV file")?;
parse_lcov_content(&content)
.context("Failed to parse LCOV content")
}
// Avoid: Long, complex functions with mixed concerns
fn bad_example(data: Vec<u8>) -> Option<String> {
// Don't do this - mixes parsing, validation, I/O, and error handling
// in one large function with unclear error handling
...
}All new features and bug fixes must include tests.
- Unit tests: Place in
#[cfg(test)]modules in the same file as the code - Integration tests: Add to
tests/directory - Test naming: Use descriptive names that explain what's being tested
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn complexity_score_increases_with_cyclomatic() {
let metrics = FunctionMetrics {
cyclomatic: 10,
cognitive: 5,
..Default::default()
};
let score = calculate_complexity_score(&metrics);
assert!(score > 0.0);
}
#[test]
fn lcov_parser_handles_empty_file() {
let result = parse_lcov_content("");
assert!(result.is_ok());
assert_eq!(result.unwrap().functions.len(), 0);
}
}# Run all tests
just test
# Run with verbose output
just test-verbose
# Run specific test pattern
just test-pattern "complexity"
# Run with coverage
just coverage
just coverage-open # Opens HTML report- Aim for 85%+ code coverage for new features
- Critical paths (scoring, analysis) should have 95%+ coverage
- Pure functions are easy to test - no excuses for low coverage
- Integration tests should cover end-to-end workflows
-
Ensure all tests pass:
just ci # Runs full CI suite locally -
Update documentation if you've changed APIs or added features
-
Add yourself to contributors (if this is your first PR)
-
Title: Clear, descriptive summary of changes
-
Description: Explain what changed and why
- Link to related issues:
Fixes #123orRelates to #456 - Describe the problem being solved
- Explain your approach
- Note any breaking changes
- Link to related issues:
-
Commits:
- Use clear, descriptive commit messages
- Follow conventional commits if possible:
feat:,fix:,docs:,test: - Each commit should be a logical, atomic change
- Maintainers will review your PR and may request changes
- Address feedback by pushing new commits (don't force-push)
- Once approved, a maintainer will merge your PR
- PRs require:
- All CI checks passing (tests, linting, formatting)
- At least one maintainer approval
- No merge conflicts with
master
Debtmap is organized into focused modules with clear responsibilities:
src/
├── analyzers/ # Language-specific AST parsers
├── core/ # Core data types and utilities
├── debt/ # Technical debt pattern detection
├── complexity/ # Complexity metrics calculation
├── risk/ # Risk analysis and coverage integration
├── io/ # File I/O and output formatting
└── testing/ # Test analysis and quality metrics
For detailed architecture documentation, see the Architecture Guide.
To contribute to Rust analysis depth:
- Add new analysis in
src/analyzers/rust.rsor related modules - Implement trait methods or extend existing analyzers
- Add comprehensive tests in
tests/rust_tests.rsor module-specific tests - Update documentation with examples
Example areas for improvement:
// Improving macro expansion analysis
pub fn analyze_macro_expansion(item: &syn::Item) -> Result<MacroMetrics> {
// Detect macro invocations and their complexity impact
}
// Better trait resolution
pub fn resolve_trait_impl(impl_item: &syn::ItemImpl) -> Result<TraitContext> {
// Track trait implementations and their relationships
}
// Lifetime analysis
pub fn analyze_lifetimes(sig: &syn::Signature) -> LifetimeComplexity {
// Measure complexity introduced by lifetime annotations
}New to Debtmap? Look for issues labeled:
good-first-issue- Beginner-friendly issueshelp-wanted- Issues where contributions are especially welcomedocumentation- Improve docs (great for first-time contributors)
- Documentation improvements: Fix typos, clarify confusing sections, add Rust examples
- Test coverage: Add tests for untested Rust analysis code paths
- Bug fixes: Start with issues tagged
bugandgood-first-issue - Rust analysis depth: Improve macro expansion, trait resolution, lifetime analysis
- New Rust metrics: Implement additional Rust-specific complexity or quality metrics
- Rust patterns: Detect more Rust idioms and anti-patterns
- Performance: Optimize Rust analysis algorithms
Note on multi-language support: Debtmap is currently focusing exclusively on Rust analysis. Multi-language support (Python, JavaScript/TypeScript, Go, etc.) will be considered once Rust analysis reaches maturity. If you're interested in contributing to multi-language support in the future, please open an issue to discuss the roadmap and timeline.
- GitHub Discussions: For general questions, ideas, and discussions
- GitHub Issues: For bug reports and feature requests
- Pull Requests: For code review and implementation discussions
Stuck? Don't hesitate to ask:
- Check the documentation
- Search existing issues and discussions
- Open a new discussion or issue with:
- What you're trying to do
- What you've tried so far
- Any error messages or unexpected behavior
# Build with debug symbols
cargo build --release --profile release-with-debug
# Profile with perf (Linux)
perf record --call-graph=dwarf ./target/release/debtmap analyze .
perf report
# Use cargo-flamegraph
cargo install flamegraph
cargo flamegraph -- analyze .# Run with debug logging
RUST_LOG=debug cargo run -- analyze .
# Run with backtrace
RUST_BACKTRACE=1 cargo run -- analyze .
# Use cargo-expand to debug macros
cargo expand# Check for unused dependencies
just unused-deps
# Find security vulnerabilities
just audit
# Check for duplicate dependencies
just duplicate-deps
# Generate and open documentation
just docDebtmap emphasizes functional programming patterns. When contributing, prefer:
// Good
let scores: Vec<f64> = functions
.iter()
.map(|f| calculate_score(f))
.collect();
// Avoid
let mut scores = Vec::new();
for func in &functions {
scores.push(calculate_score(func));
}// Good - returns new data
fn add_coverage(mut metrics: FileMetrics, coverage: f64) -> FileMetrics {
metrics.coverage = coverage;
metrics
}
// Avoid - mutates in place
fn add_coverage_mut(metrics: &mut FileMetrics, coverage: f64) {
metrics.coverage = coverage;
}// Good - pure function, easy to test
fn calculate_risk_score(complexity: u32, coverage: f64) -> f64 {
let complexity_factor = complexity as f64 / 10.0;
let coverage_factor = 1.0 - coverage;
complexity_factor * coverage_factor * 10.0
}
// Avoid - side effects, harder to test
fn calculate_risk_score_bad(func: &Function) -> f64 {
println!("Calculating for {}", func.name); // Side effect!
// ... calculation
}For complete guidelines, see CLAUDE.md in the repository root.
By contributing to Debtmap, you agree that your contributions will be licensed under the MIT License.
Please note that this project is released with a Code of Conduct. By participating in this project you agree to abide by its terms.
Your contributions make Debtmap better for everyone. Whether you're fixing bugs, adding features, improving documentation, or helping others in discussions - thank you for being part of the community!
If you have questions or need help getting started, don't hesitate to reach out through GitHub Discussions or Issues. We're here to help!