1use anyhow::{Context, Result};
2use std::process::Command;
3
4#[derive(Debug, thiserror::Error)]
6pub enum GitError {
7 #[error("Git command failed: {0}")]
8 CommandFailed(String),
9 #[error("Not in a Git repository")]
10 NotInRepository,
11 #[error("Git binary not found")]
12 GitNotFound,
13}
14
15pub struct GitCommit;
17
18impl GitCommit {
19 pub fn is_git_repository() -> Result<bool> {
21 let output = Command::new("git")
22 .args(["rev-parse", "--is-inside-work-tree"])
23 .output()
24 .context("Failed to execute git command")?;
25
26 Ok(output.status.success())
27 }
28
29 pub fn format_message(emoji_code: &str, message: &str) -> String {
31 format!("{emoji_code} {message}")
32 }
33
34 pub fn commit(message: &str, dry_run: bool) -> Result<String> {
36 if !Self::is_git_repository()? {
38 return Err(GitError::NotInRepository.into());
39 }
40
41 if dry_run {
42 return Ok(format!(
43 "DRY RUN: Would execute: git commit -m \"{message}\"",
44 ));
45 }
46
47 let output = Command::new("git")
48 .args(["commit", "-m", message])
49 .output()
50 .context("Failed to execute git commit")?;
51
52 if output.status.success() {
53 let stdout = String::from_utf8_lossy(&output.stdout);
54 Ok(format!("Git commit successful:\n{stdout}",))
55 } else {
56 let stderr = String::from_utf8_lossy(&output.stderr);
57 Err(GitError::CommandFailed(stderr.to_string()).into())
58 }
59 }
60
61 pub fn status() -> Result<String> {
63 let output = Command::new("git")
64 .args(["status", "--porcelain"])
65 .output()
66 .context("Failed to execute git status")?;
67
68 if output.status.success() {
69 let stdout = String::from_utf8_lossy(&output.stdout);
70 Ok(stdout.to_string())
71 } else {
72 let stderr = String::from_utf8_lossy(&output.stderr);
73 Err(GitError::CommandFailed(stderr.to_string()).into())
74 }
75 }
76
77 pub fn has_staged_changes() -> Result<bool> {
79 let status = Self::status()?;
80 Ok(status.lines().any(|line| {
82 if line.len() >= 2 {
83 matches!(line.chars().next(), Some('A' | 'M' | 'D' | 'R' | 'C'))
84 } else {
85 false
86 }
87 }))
88 }
89}