Skip to content

Commit 9ba9e4f

Browse files
committed
feat: implement signoff feature for git commits ✍️
- Add support for signed-off-by line in commit messages with configurable option - Refactor commit function to accept signoff parameter in git.rs - Retrieve author name and email from repository config for signoff - Remove redundant signoff logic from main.rs and centralize in git.rs - Update commit call in main.rs to pass signoff requirement Signed-off-by: mingcheng <mingcheng@apache.org>
1 parent 4de240a commit 9ba9e4f

2 files changed

Lines changed: 35 additions & 44 deletions

File tree

src/git.rs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
* File Created: 2025-03-01 21:55:54
1010
*
1111
* Modified By: mingcheng (mingcheng@apache.org)
12-
* Last Modified: 2025-07-11 17:42:56
12+
* Last Modified: 2025-07-11 18:36:58
1313
*/
1414

15-
use git2::{Repository, RepositoryOpenFlags, StatusOptions};
15+
use git2::{Repository, RepositoryOpenFlags, Signature, StatusOptions};
1616
use log::trace;
1717
use std::error::Error;
1818
use std::path::Path;
@@ -37,8 +37,10 @@ impl Git {
3737
}
3838

3939
/// Commit the changes in the repository
40-
pub fn commit(&self, message: &str) -> Result<(), Box<dyn Error>> {
40+
pub fn commit(&self, message: &str, need_signoff: bool) -> Result<(), Box<dyn Error>> {
4141
// Get the current index (staged changes)
42+
43+
let mut message = message.to_string();
4244
let mut index = self.repository.index()?;
4345

4446
// Write the index to the repository
@@ -49,12 +51,29 @@ impl Git {
4951
let head = self.repository.head()?.peel_to_commit()?;
5052

5153
// Create a new commit
52-
let author = head.author();
53-
let committer = head.committer();
54-
match self
55-
.repository
56-
.commit(Some("HEAD"), &author, &committer, message, &tree, &[&head])
57-
{
54+
let author_name = self.get_author_name()?;
55+
let author_email = self.get_author_email()?;
56+
57+
// Create a signature for the author and committer
58+
let signature = Signature::now(&author_name, &author_email)?;
59+
60+
// If the --signoff option is enabled, add signoff to the commit message
61+
if need_signoff {
62+
trace!("signoff option is enabled, will add signoff to the commit message");
63+
64+
// Add signoff to the commit message
65+
let signoff = format!("\n\nSigned-off-by: {author_name} <{author_email}>");
66+
message.push_str(&signoff);
67+
}
68+
69+
match self.repository.commit(
70+
Some("HEAD"),
71+
&signature,
72+
&signature,
73+
&message,
74+
&tree,
75+
&[&head],
76+
) {
5877
Ok(_) => {
5978
trace!("commit created successfully");
6079
Ok(())
@@ -66,6 +85,7 @@ impl Git {
6685
}
6786
}
6887

88+
/// Get the author email and name from the repository configuration
6989
pub fn get_author_email(&self) -> Result<String, Box<dyn Error>> {
7090
// Get the configuration of the repository
7191
let config = self.repository.config()?;
@@ -102,6 +122,7 @@ impl Git {
102122
}
103123
}
104124

125+
/// Get the diff of the current repository
105126
pub fn get_diff(&self) -> Result<Vec<String>, Box<dyn Error>> {
106127
// Get the current index (staged changes)
107128
let index = self.repository.index()?;
@@ -149,6 +170,7 @@ impl Git {
149170
Ok(result)
150171
}
151172

173+
/// Get the latest `size` commit messages from the repository
152174
pub fn get_logs(&self, size: usize) -> Result<Vec<String>, Box<dyn Error>> {
153175
// Get the `size` latest commits starting from HEAD
154176
let mut revwalk = self.repository.revwalk()?;

src/main.rs

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* File Created: 2025-03-01 17:17:30
1010
*
1111
* Modified By: mingcheng (mingcheng@apache.org)
12-
* Last Modified: 2025-07-11 17:45:57
12+
* Last Modified: 2025-07-11 18:39:26
1313
*/
1414

1515
use aigitcommit::cli::Cli;
@@ -114,7 +114,7 @@ async fn main() -> std::result::Result<(), Box<dyn Error>> {
114114
];
115115

116116
// Send the request to OpenAI API and get the response
117-
let mut result = match client.chat(&model_name.to_string(), messages).await {
117+
let result = match client.chat(&model_name.to_string(), messages).await {
118118
Ok(s) => s,
119119
Err(e) => {
120120
let message = match e {
@@ -139,38 +139,7 @@ async fn main() -> std::result::Result<(), Box<dyn Error>> {
139139
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
140140
.unwrap_or(false);
141141

142-
// If the --signoff option is enabled, add signoff to the commit message
143-
if need_signoff {
144-
trace!("signoff option is enabled, will add signoff to the commit message");
145-
let (author_name, author_email) = (
146-
repository.get_author_name()?,
147-
repository.get_author_email()?,
148-
);
149-
150-
// Add signoff to the commit message
151-
let signoff = format!("\n\nSigned-off-by: {author_name} <{author_email}>");
152-
result.push_str(&signoff);
153-
}
154-
155-
// Detect auto signoff from environment variable
156-
let need_signoff = cli.signoff
157-
|| env::var("GIT_AUTO_SIGNOFF")
158-
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
159-
.unwrap_or(false);
160-
161-
// If the --signoff option is enabled, add signoff to the commit message
162-
if need_signoff {
163-
trace!("signoff option is enabled, will add signoff to the commit message");
164-
let (author_name, author_email) = (
165-
repository.get_author_name()?,
166-
repository.get_author_email()?,
167-
);
168-
169-
// Add signoff to the commit message
170-
let signoff = format!("\n\nSigned-off-by: {author_name} <{author_email}>");
171-
result.push_str(&signoff);
172-
}
173-
142+
// Write the commit message to stdout
174143
trace!("write to stdout, and finish the process");
175144
writeln!(std::io::stdout(), "{result}")?;
176145

@@ -194,7 +163,7 @@ async fn main() -> std::result::Result<(), Box<dyn Error>> {
194163

195164
// Prompt the user for confirmation if --yes option is not enabled
196165
if cli.yes || confirm.interact()? {
197-
match repository.commit(&result) {
166+
match repository.commit(&result, need_signoff) {
198167
Ok(_) => {
199168
writeln!(std::io::stdout(), "commit successful!")?;
200169
}

0 commit comments

Comments
 (0)