Skip to content

Latest commit

Β 

History

History
338 lines (254 loc) Β· 7.7 KB

File metadata and controls

338 lines (254 loc) Β· 7.7 KB

Contributing to git-adr

Thank you for your interest in contributing to git-adr! This document provides guidelines and instructions for contributing.

Development Setup

Prerequisites

  • Rust 1.92 or higher
  • Git
  • Cargo (comes with Rust)

Setting Up Your Development Environment

# 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

Running Tests

# 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::adr

Code Quality Checks

Before 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-features

Project Architecture

Directory Structure

src/
β”œβ”€β”€ 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

Key Components

Core Layer (core/)

  • 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

Command Layer (cli/)

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(())
}

AI Layer (ai/)

Abstracts LLM providers using langchain-rust:

  • Anthropic (Claude)
  • OpenAI (GPT-4)
  • Google (Gemini)
  • Ollama (local models)

Making Changes

Workflow

  1. Fork and clone the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Make changes following the coding standards
  4. Write tests for new functionality
  5. Run checks to ensure quality
  6. Commit with conventional commit messages
  7. Push and open a Pull Request

Commit Messages

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

Code Style

  • Follow Rust idioms and conventions
  • Use #[must_use] for functions that return values that shouldn't be ignored
  • Use const fn where 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

Testing Guidelines

  • 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);
    }
}

Adding New Features

Adding a New Command

  1. 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(())
}
  1. Register in cli/mod.rs:
pub mod mycommand;

#[derive(Subcommand, Debug)]
pub enum Commands {
    // ... existing commands
    MyCommand(mycommand::Args),
}
  1. Handle in main.rs:
Commands::MyCommand(args) => git_adr::cli::mycommand::run(args),
  1. Add tests
  2. Update README with documentation

Adding a New AI Provider

  1. Update ai/provider.rs to add the new provider variant
  2. Update ai/service.rs to handle the new provider
  3. Add any required dependencies to Cargo.toml under the ai feature
  4. Add tests with mocked provider

Adding Export Format

  1. 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
    }
}
  1. Register in export/mod.rs
  2. Add to ExportFormat enum
  3. Add dependencies to Cargo.toml if needed

Pull Request Process

  1. Ensure all checks pass locally
  2. Update documentation if needed
  3. Fill out the PR template completely
  4. Request review from maintainers
  5. Address feedback promptly
  6. Squash commits if requested

PR Template

PRs should include:

  • Description of changes
  • Link to related issue (if any)
  • Test coverage for new code
  • Documentation updates

Getting Help

  • Issues: For bugs and feature requests
  • Discussions: For questions and ideas
  • Code of Conduct: Be respectful and inclusive

License

By contributing, you agree that your contributions will be licensed under the MIT License.