Thank you for your interest in contributing to git-adr! This document provides guidelines and instructions for contributing.
- Rust 1.92 or higher
- Git
- Cargo (comes with Rust)
# Clone the repository
git clone https://github.com/zircote/git-adr.git
cd git-adr
# Build the project
cargo build
# Verify installation
cargo run -- --version# Run all tests
cargo test
# Run with verbose output
cargo test -- --nocapture
# Run specific test
cargo test test_name
# Run tests with all features
cargo test --all-features
# Run specific test module
cargo test core::adrBefore submitting a PR, ensure all checks pass:
# Format code
cargo fmt
# Check formatting without changes
cargo fmt -- --check
# Run clippy lints
cargo clippy --all-targets --all-features -- -D warnings
# Run security audit
cargo deny check
# Generate docs and check for warnings
RUSTDOCFLAGS="-D warnings" cargo doc --all-features --no-deps
# Run all checks (as CI does)
cargo fmt -- --check && \
cargo clippy --all-targets --all-features -- -D warnings && \
cargo test --all-featuressrc/
βββ lib.rs # Library entry point, Error types
βββ main.rs # Binary entry point
βββ cli/ # CLI command implementations
β βββ mod.rs # CLI definition and Commands enum
β βββ init.rs # Initialize command
β βββ new.rs # New ADR command
β βββ list.rs # List command
β βββ show.rs # Show command
β βββ edit.rs # Edit command
β βββ ... # Other commands
βββ core/ # Core business logic
β βββ mod.rs # Module exports
β βββ adr.rs # ADR struct and AdrStatus enum
β βββ config.rs # Configuration management
β βββ git.rs # Git operations wrapper
β βββ notes.rs # Git notes CRUD operations
β βββ index.rs # Search index management
β βββ templates.rs # ADR templates
βββ ai/ # AI service layer (optional)
β βββ mod.rs # Module exports
β βββ provider.rs # Provider abstraction
β βββ service.rs # AI service implementation
βββ wiki/ # Wiki providers (optional)
β βββ mod.rs # Module exports
β βββ github.rs # GitHub wiki
β βββ gitlab.rs # GitLab wiki
β βββ service.rs # Wiki service abstraction
βββ export/ # Format exporters (optional)
βββ mod.rs # Module exports
βββ docx.rs # DOCX export
βββ html.rs # HTML export
βββ json.rs # JSON export
- Git: Low-level git subprocess wrapper
- NotesManager: CRUD operations for ADRs stored in git notes
- IndexManager: Search index for fast full-text search
- ConfigManager: Git config-based configuration
- Adr: Struct representing an ADR with frontmatter metadata
Commands are implemented using Clap derive:
use clap::Args as ClapArgs;
use anyhow::Result;
#[derive(ClapArgs, Debug)]
pub struct Args {
/// ADR title
pub title: String,
/// ADR status
#[arg(long, short, default_value = "proposed")]
pub status: String,
}
pub fn run(args: Args) -> Result<()> {
let git = Git::new();
let config = ConfigManager::new(git.clone()).load()?;
let notes = NotesManager::new(git, config);
// ... implementation
Ok(())
}Abstracts LLM providers using langchain-rust:
- Anthropic (Claude)
- OpenAI (GPT-4)
- Google (Gemini)
- Ollama (local models)
- Fork and clone the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make changes following the coding standards
- Write tests for new functionality
- Run checks to ensure quality
- Commit with conventional commit messages
- Push and open a Pull Request
Use Conventional Commits:
feat: add wiki sync for GitLab
fix: handle empty ADR content gracefully
docs: update README with AI examples
test: add coverage for artifact operations
refactor: extract common validation logic
chore: update dependencies
- Follow Rust idioms and conventions
- Use
#[must_use]for functions that return values that shouldn't be ignored - Use
const fnwhere possible - Write doc comments for all public items
- Keep functions focused and small
- Prefer borrowing over ownership when possible
- Use
impl Into<String>for flexible string parameters
- Write tests for all new functionality
- Use inline
#[cfg(test)]modules for unit tests - Use
tests/directory for integration tests - Test both success and error cases
- Use meaningful test names:
test_<function>_<scenario>_<expected>
Example test structure:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_adr_from_markdown_parses_frontmatter() {
let content = r#"---
title: Test ADR
status: proposed
---
## Context
Test content.
"#;
let adr = Adr::from_markdown(
"ADR-0001".to_string(),
"abc123".to_string(),
content,
).unwrap();
assert_eq!(adr.title(), "Test ADR");
assert_eq!(*adr.status(), AdrStatus::Proposed);
}
}- Create a new file under
cli/:
// cli/mycommand.rs
use anyhow::Result;
use clap::Args as ClapArgs;
#[derive(ClapArgs, Debug)]
pub struct Args {
/// Description of argument
pub arg: String,
/// Description of option
#[arg(long, short, default_value = "default")]
pub option: String,
}
pub fn run(args: Args) -> Result<()> {
// Implementation
Ok(())
}- Register in
cli/mod.rs:
pub mod mycommand;
#[derive(Subcommand, Debug)]
pub enum Commands {
// ... existing commands
MyCommand(mycommand::Args),
}- Handle in
main.rs:
Commands::MyCommand(args) => git_adr::cli::mycommand::run(args),- Add tests
- Update README with documentation
- Update
ai/provider.rsto add the new provider variant - Update
ai/service.rsto handle the new provider - Add any required dependencies to
Cargo.tomlunder theaifeature - Add tests with mocked provider
- Create format module under
export/:
// export/newformat.rs
use crate::core::Adr;
use crate::Error;
use std::path::Path;
pub struct NewFormatExporter {
// configuration
}
impl NewFormatExporter {
pub fn export(&self, adr: &Adr, path: &Path) -> Result<(), Error> {
// Implementation
}
}- Register in
export/mod.rs - Add to
ExportFormatenum - Add dependencies to
Cargo.tomlif needed
- Ensure all checks pass locally
- Update documentation if needed
- Fill out the PR template completely
- Request review from maintainers
- Address feedback promptly
- Squash commits if requested
PRs should include:
- Description of changes
- Link to related issue (if any)
- Test coverage for new code
- Documentation updates
- Issues: For bugs and feature requests
- Discussions: For questions and ideas
- Code of Conduct: Be respectful and inclusive
By contributing, you agree that your contributions will be licensed under the MIT License.