commit_workflows/
commit_workflows.rs1use rustic_git::{Hash, Repository, Result};
13use std::{env, fs};
14
15fn main() -> Result<()> {
16 println!("Rustic Git - Commit Workflows Example\n");
17
18 let repo_path = env::temp_dir().join("rustic_git_commit_example");
19
20 if repo_path.exists() {
22 fs::remove_dir_all(&repo_path).expect("Failed to clean up previous example");
23 }
24
25 println!("Setting up repository for commit demonstrations...");
27 let repo = Repository::init(&repo_path, false)?;
28 println!("Repository initialized\n");
29
30 println!("=== Basic Commit Operations ===\n");
31
32 println!("Creating initial project files...");
34 fs::create_dir_all(repo_path.join("src"))?;
35
36 fs::write(
37 repo_path.join("README.md"),
38 "# Commit Demo Project\n\nThis project demonstrates commit workflows with rustic-git.\n",
39 )?;
40
41 fs::write(
42 repo_path.join("src/main.rs"),
43 r#"fn main() {
44 println!("Hello, Commit Demo!");
45}
46"#,
47 )?;
48
49 fs::write(
50 repo_path.join("Cargo.toml"),
51 r#"[package]
52name = "commit-demo"
53version = "0.1.0"
54edition = "2021"
55"#,
56 )?;
57
58 println!("Created README.md, src/main.rs, and Cargo.toml");
59
60 println!("\nStaging files for first commit...");
62 repo.add_all()?;
63
64 println!("Creating first commit with basic commit() method:");
65 let first_hash = repo.commit("Initial commit: Add project structure")?;
66
67 println!("First commit created!");
68 display_hash_info(&first_hash, "First commit");
69 println!();
70
71 println!("=== Hash Type Demonstrations ===\n");
72
73 println!("Hash type methods and usage:");
74
75 let hash_as_string: String = first_hash.to_string();
77 let hash_as_str: &str = first_hash.as_str();
78 let short_hash: &str = first_hash.short();
79
80 println!(" Hash conversions:");
81 println!(" as_str(): '{}'", hash_as_str);
82 println!(" short(): '{}'", short_hash);
83 println!(" to_string(): '{}'", hash_as_string);
84 println!(" Display: '{}'", first_hash);
85
86 let cloned_hash = first_hash.clone();
88 println!("\n Hash operations:");
89 println!(" Original == Clone: {}", first_hash == cloned_hash);
90 println!(
91 " Hash length: {} characters",
92 first_hash.as_str().len()
93 );
94 println!(
95 " Short hash length: {} characters",
96 first_hash.short().len()
97 );
98
99 let hash_from_string: Hash = "1234567890abcdef".to_string().into();
101 let hash_from_str: Hash = "fedcba0987654321".into();
102
103 println!(" Hash from String: {}", hash_from_string.short());
104 println!(" Hash from &str: {}", hash_from_str.short());
105 println!();
106
107 println!("=== Commits with Custom Authors ===\n");
108
109 println!("Adding features for custom author commit...");
111 fs::create_dir_all(repo_path.join("tests"))?;
112
113 fs::write(
114 repo_path.join("src/lib.rs"),
115 r#"//! Commit demo library
116
117pub fn greet(name: &str) -> String {
118 format!("Hello, {}! This is a commit demo.", name)
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn test_greet() {
127 assert_eq!(greet("Alice"), "Hello, Alice! This is a commit demo.");
128 }
129}
130"#,
131 )?;
132
133 fs::write(
134 repo_path.join("tests/integration_test.rs"),
135 r#"use commit_demo::greet;
136
137#[test]
138fn test_integration() {
139 let result = greet("Integration");
140 assert!(result.contains("Integration"));
141 assert!(result.contains("commit demo"));
142}
143"#,
144 )?;
145
146 println!("Created src/lib.rs and tests/integration_test.rs");
147
148 repo.add_all()?;
150 println!("\nCreating commit with custom author:");
151 let second_hash = repo.commit_with_author(
152 "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",
153 "Jane Developer <jane.dev@example.com>"
154 )?;
155
156 println!("Commit with custom author created!");
157 display_hash_info(&second_hash, "Second commit (custom author)");
158 println!();
159
160 println!("=== Multiple Commit Workflow ===\n");
161
162 let mut commit_hashes = vec![first_hash, second_hash];
164
165 println!("Step 1: Update version information...");
167 fs::write(
168 repo_path.join("Cargo.toml"),
169 r#"[package]
170name = "commit-demo"
171version = "0.2.0"
172edition = "2021"
173description = "A demo project for commit workflows"
174"#,
175 )?;
176
177 repo.add(&["Cargo.toml"])?;
178 let third_hash = repo.commit("Bump version to 0.2.0 and add description")?;
179 commit_hashes.push(third_hash);
180
181 println!("Step 2: Add documentation...");
183 fs::write(
184 repo_path.join("CHANGELOG.md"),
185 r#"# Changelog
186
187## [0.2.0] - 2024-01-01
188
189### Added
190- Library functionality with greet function
191- Comprehensive test suite
192- Project documentation
193
194## [0.1.0] - 2024-01-01
195
196### Added
197- Initial project structure
198- Basic Cargo configuration
199"#,
200 )?;
201
202 repo.add(&["CHANGELOG.md"])?;
203 let fourth_hash = repo.commit_with_author(
204 "docs: Add CHANGELOG with version history",
205 "Doc Writer <docs@example.com>",
206 )?;
207 commit_hashes.push(fourth_hash);
208
209 println!("Step 3: Final polish...");
211 fs::write(
212 repo_path.join("README.md"),
213 r#"# Commit Demo Project
214
215This project demonstrates commit workflows with rustic-git.
216
217## Features
218
219- Clean, type-safe Git operations
220- Comprehensive commit history
221- Multiple author support
222- Hash management utilities
223
224## Usage
225
226```rust
227use commit_demo::greet;
228
229fn main() {
230 println!("{}", greet("World"));
231}
232```
233
234## Version
235
236Current version: 0.2.0
237
238See CHANGELOG.md for version history.
239"#,
240 )?;
241
242 repo.add(&["README.md"])?;
243 let fifth_hash = repo.commit("docs: Enhance README with usage examples and features")?;
244 commit_hashes.push(fifth_hash);
245
246 println!("\nComplete commit history created!");
247
248 println!("\n=== Commit History Summary ===\n");
250
251 for (i, hash) in commit_hashes.iter().enumerate() {
252 println!("{}. Commit {}", i + 1, i + 1);
253 display_hash_info(hash, &format!("Commit {}", i + 1));
254 println!();
255 }
256
257 println!("Hash comparisons:");
259 println!(
260 " First commit == Last commit: {}",
261 commit_hashes[0] == commit_hashes[4]
262 );
263 println!(" All hashes unique: {}", all_unique(&commit_hashes));
264
265 println!("\nAll commit short hashes:");
267 for (i, hash) in commit_hashes.iter().enumerate() {
268 println!(" {}: {}", i + 1, hash.short());
269 }
270 println!();
271
272 println!("=== Error Handling for Commits ===\n");
273
274 println!("Testing commit with no staged changes:");
276 match repo.commit("This should fail - no changes") {
277 Ok(_hash) => println!(" Unexpectedly succeeded with empty commit"),
278 Err(e) => {
279 println!(" Expected error for empty commit: {:?}", e);
280 println!(" This is normal behavior - Git requires changes to commit");
281 }
282 }
283
284 println!("\nTesting custom author commit with no changes:");
286 match repo.commit_with_author("This should also fail", "Test Author <test@example.com>") {
287 Ok(_hash) => println!(" Unexpectedly succeeded with empty custom author commit"),
288 Err(e) => {
289 println!(
290 " Expected error for empty commit with custom author: {:?}",
291 e
292 );
293 }
294 }
295
296 println!("\nTesting commit with empty message:");
298
299 fs::write(repo_path.join("temp_for_empty_message.txt"), "temp content")?;
301 repo.add(&["temp_for_empty_message.txt"])?;
302
303 match repo.commit("") {
304 Ok(hash) => {
305 println!(" Commit with empty message succeeded: {}", hash.short());
306 println!(" Some Git configurations allow empty commit messages");
307 }
308 Err(e) => {
309 println!(" Empty commit message rejected: {:?}", e);
310 }
311 }
312
313 println!();
314
315 println!("=== Final Repository State ===\n");
316
317 let final_status = repo.status()?;
318 if final_status.is_clean() {
319 println!("Repository is clean - all changes committed!");
320 } else {
321 println!(
322 "Repository has {} uncommitted changes",
323 final_status.entries.len()
324 );
325 }
326
327 println!("\nWorkflow summary:");
328 println!(" Total commits created: {}", commit_hashes.len());
329 println!(" Hash examples demonstrated: [OK]");
330 println!(" Custom author commits: [OK]");
331 println!(" Error handling tested: [OK]");
332
333 println!("\nCleaning up example repository...");
335 fs::remove_dir_all(&repo_path)?;
336 println!("Commit workflows example completed!");
337
338 Ok(())
339}
340
341fn display_hash_info(hash: &Hash, context: &str) {
343 println!(" {}:", context);
344 println!(" Full hash: {}", hash);
345 println!(" Short hash: {}", hash.short());
346 println!(" Hash length: {} chars", hash.as_str().len());
347
348 let full = hash.as_str();
350 if full.len() >= 10 {
351 println!(
352 " Pattern: {}...{}",
353 &full[..5],
354 &full[full.len() - 5..]
355 );
356 }
357}
358
359fn all_unique(hashes: &[Hash]) -> bool {
361 let mut seen = std::collections::HashSet::new();
362 for hash in hashes {
363 if !seen.insert(hash.as_str()) {
364 return false;
365 }
366 }
367 true
368}