use rustic_git::{Hash, Repository, Result};
use std::{env, fs};
fn main() -> Result<()> {
println!("Rustic Git - Commit Workflows Example\n");
let repo_path = env::temp_dir().join("rustic_git_commit_example");
if repo_path.exists() {
fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
}
println!("Setting up repository for commit demonstrations...");
let repo = Repository::init(&repo_path, false)?;
println!("Repository initialized\n");
println!("=== Basic Commit Operations ===\n");
println!("Creating initial project files...");
fs::create_dir_all(repo_path.join("src"))?;
fs::write(
repo_path.join("README.md"),
"# Commit Demo Project\n\nThis project demonstrates commit workflows with rustic-git.\n",
)?;
fs::write(
repo_path.join("src/main.rs"),
r#"fn main() {
println!("Hello, Commit Demo!");
}
"#,
)?;
fs::write(
repo_path.join("Cargo.toml"),
r#"[package]
name = "commit-demo"
version = "0.1.0"
edition = "2021"
"#,
)?;
println!("Created README.md, src/main.rs, and Cargo.toml");
println!("\nStaging files for first commit...");
repo.add_all()?;
println!("Creating first commit with basic commit() method:");
let first_hash = repo.commit("Initial commit: Add project structure")?;
println!("First commit created!");
display_hash_info(&first_hash, "First commit");
println!();
println!("=== Hash Type Demonstrations ===\n");
println!("Hash type methods and usage:");
let hash_as_string: String = first_hash.to_string();
let hash_as_str: &str = first_hash.as_str();
let short_hash: &str = first_hash.short();
println!(" Hash conversions:");
println!(" as_str(): '{}'", hash_as_str);
println!(" short(): '{}'", short_hash);
println!(" to_string(): '{}'", hash_as_string);
println!(" Display: '{}'", first_hash);
let cloned_hash = first_hash.clone();
println!("\n Hash operations:");
println!(" Original == Clone: {}", first_hash == cloned_hash);
println!(
" Hash length: {} characters",
first_hash.as_str().len()
);
println!(
" Short hash length: {} characters",
first_hash.short().len()
);
let hash_from_string: Hash = "1234567890abcdef".to_string().into();
let hash_from_str: Hash = "fedcba0987654321".into();
println!(" Hash from String: {}", hash_from_string.short());
println!(" Hash from &str: {}", hash_from_str.short());
println!();
println!("=== Commits with Custom Authors ===\n");
println!("Adding features for custom author commit...");
fs::create_dir_all(repo_path.join("tests"))?;
fs::write(
repo_path.join("src/lib.rs"),
r#"//! Commit demo library
pub fn greet(name: &str) -> String {
format!("Hello, {}! This is a commit demo.", name)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_greet() {
assert_eq!(greet("Alice"), "Hello, Alice! This is a commit demo.");
}
}
"#,
)?;
fs::write(
repo_path.join("tests/integration_test.rs"),
r#"use commit_demo::greet;
#[test]
fn test_integration() {
let result = greet("Integration");
assert!(result.contains("Integration"));
assert!(result.contains("commit demo"));
}
"#,
)?;
println!("Created src/lib.rs and tests/integration_test.rs");
repo.add_all()?;
println!("\nCreating commit with custom author:");
let second_hash = repo.commit_with_author(
"Add library code and tests\n\n- Implement greet function with proper documentation\n- Add unit tests and integration tests\n- Prepare for version 0.2.0 release",
"Jane Developer <jane.dev@example.com>"
)?;
println!("Commit with custom author created!");
display_hash_info(&second_hash, "Second commit (custom author)");
println!();
println!("=== Multiple Commit Workflow ===\n");
let mut commit_hashes = vec![first_hash, second_hash];
println!("Step 1: Update version information...");
fs::write(
repo_path.join("Cargo.toml"),
r#"[package]
name = "commit-demo"
version = "0.2.0"
edition = "2021"
description = "A demo project for commit workflows"
"#,
)?;
repo.add(&["Cargo.toml"])?;
let third_hash = repo.commit("Bump version to 0.2.0 and add description")?;
commit_hashes.push(third_hash);
println!("Step 2: Add documentation...");
fs::write(
repo_path.join("CHANGELOG.md"),
r#"# Changelog
## [0.2.0] - 2024-01-01
### Added
- Library functionality with greet function
- Comprehensive test suite
- Project documentation
## [0.1.0] - 2024-01-01
### Added
- Initial project structure
- Basic Cargo configuration
"#,
)?;
repo.add(&["CHANGELOG.md"])?;
let fourth_hash = repo.commit_with_author(
"docs: Add CHANGELOG with version history",
"Doc Writer <docs@example.com>",
)?;
commit_hashes.push(fourth_hash);
println!("Step 3: Final polish...");
fs::write(
repo_path.join("README.md"),
r#"# Commit Demo Project
This project demonstrates commit workflows with rustic-git.
## Features
- Clean, type-safe Git operations
- Comprehensive commit history
- Multiple author support
- Hash management utilities
## Usage
```rust
use commit_demo::greet;
fn main() {
println!("{}", greet("World"));
}
```
## Version
Current version: 0.2.0
See CHANGELOG.md for version history.
"#,
)?;
repo.add(&["README.md"])?;
let fifth_hash = repo.commit("docs: Enhance README with usage examples and features")?;
commit_hashes.push(fifth_hash);
println!("\nComplete commit history created!");
println!("\n=== Commit History Summary ===\n");
for (i, hash) in commit_hashes.iter().enumerate() {
println!("{}. Commit {}", i + 1, i + 1);
display_hash_info(hash, &format!("Commit {}", i + 1));
println!();
}
println!("Hash comparisons:");
println!(
" First commit == Last commit: {}",
commit_hashes[0] == commit_hashes[4]
);
println!(" All hashes unique: {}", all_unique(&commit_hashes));
println!("\nAll commit short hashes:");
for (i, hash) in commit_hashes.iter().enumerate() {
println!(" {}: {}", i + 1, hash.short());
}
println!();
println!("=== Error Handling for Commits ===\n");
println!("Testing commit with no staged changes:");
match repo.commit("This should fail - no changes") {
Ok(_hash) => println!(" Unexpectedly succeeded with empty commit"),
Err(e) => {
println!(" Expected error for empty commit: {:?}", e);
println!(" This is normal behavior - Git requires changes to commit");
}
}
println!("\nTesting custom author commit with no changes:");
match repo.commit_with_author("This should also fail", "Test Author <test@example.com>") {
Ok(_hash) => println!(" Unexpectedly succeeded with empty custom author commit"),
Err(e) => {
println!(
" Expected error for empty commit with custom author: {:?}",
e
);
}
}
println!("\nTesting commit with empty message:");
fs::write(repo_path.join("temp_for_empty_message.txt"), "temp content")?;
repo.add(&["temp_for_empty_message.txt"])?;
match repo.commit("") {
Ok(hash) => {
println!(" Commit with empty message succeeded: {}", hash.short());
println!(" Some Git configurations allow empty commit messages");
}
Err(e) => {
println!(" Empty commit message rejected: {:?}", e);
}
}
println!();
println!("=== Final Repository State ===\n");
let final_status = repo.status()?;
if final_status.is_clean() {
println!("Repository is clean - all changes committed!");
} else {
println!(
"Repository has {} uncommitted changes",
final_status.entries.len()
);
}
println!("\nWorkflow summary:");
println!(" Total commits created: {}", commit_hashes.len());
println!(" Hash examples demonstrated: [OK]");
println!(" Custom author commits: [OK]");
println!(" Error handling tested: [OK]");
println!("\nCleaning up example repository...");
fs::remove_dir_all(&repo_path)?;
println!("Commit workflows example completed!");
Ok(())
}
fn display_hash_info(hash: &Hash, context: &str) {
println!(" {}:", context);
println!(" Full hash: {}", hash);
println!(" Short hash: {}", hash.short());
println!(" Hash length: {} chars", hash.as_str().len());
let full = hash.as_str();
if full.len() >= 10 {
println!(
" Pattern: {}...{}",
&full[..5],
&full[full.len() - 5..]
);
}
}
fn all_unique(hashes: &[Hash]) -> bool {
let mut seen = std::collections::HashSet::new();
for hash in hashes {
if !seen.insert(hash.as_str()) {
return false;
}
}
true
}