Thank you for your interest in contributing to Guisu! This document provides guidelines for contributing to the project.
Important: Guisu is currently in early development (pre-1.0). Expect significant changes and breaking API changes.
Prerequisites:
- Rust toolchain (edition 2024)
- Git
- Optional: mise for development environment management
Installation:
# Clone the repository
git clone https://github.com/yourusername/guisu.git
cd guisu
# Install Rust toolchain (if using mise)
mise install
# Build the project
cargo build
# Run tests
cargo test
# Run clippy (linter)
cargo clippy --all-targets --all-features
# Format code
cargo fmtRecommended Tools:
mise: Development environment manager (seemise.toml)pre-commit: Git hooks for code qualityrust-analyzer: IDE supportcargo-nextest: Faster test runner
Setting up pre-commit:
# Install pre-commit hooks
pre-commit install
# Run manually
pre-commit run --all-filesguisu/
├── crates/ # Workspace members
│ ├── core/ # Layer 0: Foundation types
│ ├── crypto/ # Layer 1: Age encryption
│ ├── vault/ # Layer 1: Password managers
│ ├── template/ # Layer 2: Template rendering
│ ├── config/ # Layer 2: Configuration
│ ├── engine/ # Layer 3: State management
│ └── cli/ # Layer 4: User interface
├── docs/ # Documentation
│ ├── architecture/ # Architecture docs
│ └── development/ # Development docs
├── Cargo.toml # Workspace configuration
├── CLAUDE.md # Development reference (chezmoi comparison)
├── README.md # Project README
└── rust-toolchain.toml # Rust edition specification
Key Files:
CLAUDE.md: Comprehensive reference comparing guisu to chezmoi, must-read for contributorsdocs/architecture/: Detailed architecture documentation.rust-analyzer.toml: IDE configuration.rustfmt.toml: Code formatting rules
Rust Style:
Follow standard Rust conventions with project-specific rules:
-
Naming:
- Types:
PascalCase(e.g.,SourceState,TargetEntry) - Functions:
snake_case(e.g.,read_source_state) - Constants:
SCREAMING_SNAKE_CASE(e.g.,CURRENT_PLATFORM) - Modules:
snake_case(e.g.,persistent_state)
- Types:
-
Formatting:
# Run before committing cargo fmt -
Linting:
# Fix auto-fixable issues cargo clippy --fix --allow-dirty # Check for issues cargo clippy --all-targets --all-features -- -D warnings
-
Documentation:
- All public items must have doc comments
- Use examples in doc comments where helpful
- Run
cargo doc --opento view documentation
Example:
/// Reads the source state from the repository directory.
///
/// This function walks the source directory in parallel using rayon,
/// parsing file attributes from filenames and creating `SourceEntry` objects.
///
/// # Arguments
///
/// * `root` - Absolute path to the source directory
///
/// # Returns
///
/// A `SourceState` containing all entries found in the directory.
///
/// # Errors
///
/// Returns an error if:
/// - The directory cannot be read
/// - File attributes cannot be parsed
/// - Any file has an unsupported type
///
/// # Example
///
/// ```no_run
/// # use guisu_core::AbsPath;
/// # use guisu_engine::SourceState;
/// let root = AbsPath::new("/home/user/.local/share/guisu")?;
/// let state = SourceState::read(root)?;
/// # Ok::<(), anyhow::Error>(())
/// ```
pub fn read(root: AbsPath) -> Result<Self> {
// Implementation
}Test Organization:
-
Unit Tests: In each crate
#[cfg(test)] mod tests { use super::*; #[test] fn test_parse_attributes() { let (attrs, name) = FileAttributes::parse_from_source(".bashrc.j2", None).unwrap(); assert!(attrs.is_template()); assert_eq!(name, ".bashrc"); } }
-
Integration Tests: In
crates/*/tests/// crates/engine/tests/integration.rs #[test] fn test_apply_workflow() { let temp = TempDir::new().unwrap(); // Setup test repository // Run apply // Verify results }
-
Doc Tests: In documentation
/// # Example /// ``` /// # use guisu_core::AbsPath; /// let path = AbsPath::new("/home/user")?; /// # Ok::<(), anyhow::Error>(()) /// ```
Running Tests:
# All tests
cargo test
# Specific crate
cargo test -p guisu-engine
# Specific test
cargo test test_parse_attributes
# With output
cargo test -- --nocapture
# Parallel test runner (faster)
cargo nextest runTest Coverage:
# Install tarpaulin
cargo install cargo-tarpaulin
# Generate coverage report
cargo tarpaulin --out Html --output-dir coverage-
Fork and Branch:
# Fork on GitHub, then: git clone https://github.com/yourusername/guisu.git cd guisu git checkout -b feature/my-feature
-
Make Changes:
- Follow code style guidelines
- Add tests for new functionality
- Update documentation if needed
- Run
cargo fmtandcargo clippy
-
Commit:
# Conventional commit format git commit -m "feat: add script execution system" git commit -m "fix: resolve template rendering bug" git commit -m "docs: update architecture diagrams"
Commit Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting)refactor: Code refactoringperf: Performance improvementstest: Adding or fixing testschore: Build process, tools, dependencies
-
Push and Create PR:
git push origin feature/my-feature # Create PR on GitHub -
PR Requirements:
- Clear description of changes
- Reference related issues
- All tests passing
- No clippy warnings
- Code formatted with
cargo fmt - Documentation updated if needed
PR Template:
## Description
Brief description of changes
## Motivation
Why is this change needed?
## Changes
- List of changes
- Another change
## Testing
How was this tested?
## Checklist
- [ ] Tests added/updated
- [ ] Documentation updated
- [ ] `cargo fmt` run
- [ ] `cargo clippy` passing
- [ ] All tests passingBefore Adding Features:
- Research chezmoi: Check
CLAUDE.mdand chezmoi's implementation - Design First: Discuss architecture in an issue before implementing
- Follow Patterns: Use existing patterns (NewType, trait-based, etc.)
- Consider Performance: Use rayon for parallelizable operations
Layered Architecture:
- Layer 0 (core): Only std dependencies
- Layer 1 (crypto, vault): Can depend on core
- Layer 2 (template, config): Can depend on Layer 0-1
- Layer 3 (engine): Can depend on Layer 0-2
- Layer 4 (cli): Can depend on all layers
No Circular Dependencies: Verify with cargo tree
Error Handling:
- Libraries: Use
thiserrorfor typed errors - CLI: Convert to
anyhow::Errorat boundaries - Add context with
.context()
Example:
// Library error (guisu-engine)
#[derive(Error, Debug)]
pub enum Error {
#[error("Failed to read source file {path}: {source}")]
ReadSource {
path: String,
#[source]
source: std::io::Error,
},
}
// CLI usage (guisu-cli)
engine.read_source(&path)
.context("Failed to read source state")?;感谢您对为 Guisu 做贡献的兴趣!本文档提供了为项目做贡献的指南。
重要:Guisu 目前处于早期开发阶段(1.0 版本之前)。预期会有重大变更和破坏性 API 变更。
前提条件:
- Rust 工具链(edition 2024)
- Git
- 可选:mise 用于开发环境管理
安装:
# 克隆仓库
git clone https://github.com/yourusername/guisu.git
cd guisu
# 安装 Rust 工具链(如果使用 mise)
mise install
# 构建项目
cargo build
# 运行测试
cargo test
# 运行 clippy(代码检查工具)
cargo clippy --all-targets --all-features
# 格式化代码
cargo fmt推荐工具:
mise:开发环境管理器(见mise.toml)pre-commit:代码质量的 Git hookrust-analyzer:IDE 支持cargo-nextest:更快的测试运行器
guisu/
├── crates/ # 工作空间成员
│ ├── core/ # 层级 0:基础类型
│ ├── crypto/ # 层级 1:Age 加密
│ ├── vault/ # 层级 1:密码管理器
│ ├── template/ # 层级 2:模板渲染
│ ├── config/ # 层级 2:配置
│ ├── engine/ # 层级 3:状态管理
│ └── cli/ # 层级 4:用户界面
├── docs/ # 文档
│ ├── architecture/ # 架构文档
│ └── development/ # 开发文档
├── Cargo.toml # 工作空间配置
├── CLAUDE.md # 开发参考(chezmoi 对比)
├── README.md # 项目 README
└── rust-toolchain.toml # Rust edition 规范
关键文件:
CLAUDE.md:比较 guisu 和 chezmoi 的综合参考,贡献者必读docs/architecture/:详细的架构文档.rust-analyzer.toml:IDE 配置.rustfmt.toml:代码格式化规则
Rust 风格:
遵循标准 Rust 约定和项目特定规则:
-
命名:
- 类型:
PascalCase(例如,SourceState、TargetEntry) - 函数:
snake_case(例如,read_source_state) - 常量:
SCREAMING_SNAKE_CASE(例如,CURRENT_PLATFORM) - 模块:
snake_case(例如,persistent_state)
- 类型:
-
格式化:
# 提交前运行 cargo fmt -
代码检查:
# 修复可自动修复的问题 cargo clippy --fix --allow-dirty # 检查问题 cargo clippy --all-targets --all-features -- -D warnings
-
文档:
- 所有公共项必须有文档注释
- 在文档注释中使用示例(如果有帮助)
- 运行
cargo doc --open查看文档
测试组织:
- 单元测试:在每个 crate 中
- 集成测试:在
crates/*/tests/中 - 文档测试:在文档中
运行测试:
# 所有测试
cargo test
# 特定 crate
cargo test -p guisu-engine
# 特定测试
cargo test test_parse_attributes
# 带输出
cargo test -- --nocapture
# 并行测试运行器(更快)
cargo nextest run-
Fork 和分支:
# 在 GitHub 上 fork,然后: git clone https://github.com/yourusername/guisu.git cd guisu git checkout -b feature/my-feature
-
进行更改:
- 遵循代码风格指南
- 为新功能添加测试
- 如需要更新文档
- 运行
cargo fmt和cargo clippy
-
提交:
# 约定式提交格式 git commit -m "feat: 添加脚本执行系统" git commit -m "fix: 解决模板渲染 bug" git commit -m "docs: 更新架构图"
提交类型:
feat:新功能fix:Bug 修复docs:文档更改style:代码风格更改(格式化)refactor:代码重构perf:性能改进test:添加或修复测试chore:构建过程、工具、依赖
-
推送并创建 PR:
git push origin feature/my-feature # 在 GitHub 上创建 PR -
PR 要求:
- 清晰的更改描述
- 引用相关 issue
- 所有测试通过
- 无 clippy 警告
- 使用
cargo fmt格式化代码 - 如需要更新文档
添加功能之前:
- 研究 chezmoi:检查
CLAUDE.md和 chezmoi 的实现 - 首先设计:在实现之前在 issue 中讨论架构
- 遵循模式:使用现有模式(NewType、基于 trait 等)
- 考虑性能:对可并行化的操作使用 rayon
分层架构:
- 层级 0(core):仅 std 依赖
- 层级 1(crypto、vault):可以依赖 core
- 层级 2(template、config):可以依赖层级 0-1
- 层级 3(engine):可以依赖层级 0-2
- 层级 4(cli):可以依赖所有层级
无循环依赖:使用 cargo tree 验证
错误处理:
- 库:使用
thiserror进行类型化错误 - CLI:在边界转换为
anyhow::Error - 使用
.context()添加上下文