Skip to content

Commit 649a01c

Browse files
committed
feat(repo): 🎉 Add commit gpg support.
1 parent 1c15fa0 commit 649a01c

File tree

6 files changed

+133
-27
lines changed

6 files changed

+133
-27
lines changed

src/log.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,53 @@ use std::fmt::Display;
33
use console::Style;
44

55
/// GCR logger.
6-
pub fn grc_println(content: impl Display) {
6+
pub fn grc_log(content: impl Display) {
77
println!("{}", content)
88
}
99

1010
/// GCR error logger.
11-
pub fn grc_err_println(content: impl Display) {
11+
pub fn grc_err(content: impl Display) {
1212
let color = Style::new().red();
1313

1414
println!("{}", color.apply_to(content))
1515
}
1616

1717
/// GCR error logger.
18-
pub fn grc_warn_println(content: impl Display) {
18+
pub fn grc_warn(content: impl Display) {
1919
let color = Style::new().yellow();
2020

2121
println!("{}", color.apply_to(content))
2222
}
2323

24+
/// GCR success logger.
25+
pub fn grc_succ(content: impl Display) {
26+
let color = Style::new().green();
27+
28+
println!("{}", color.apply_to(content))
29+
}
30+
2431
#[cfg(test)]
2532
mod tests {
2633

2734
use super::*;
2835

2936
#[test]
3037
fn it_grc_println() {
31-
grc_println("TEST CONTENT.");
38+
grc_log("TEST CONTENT.");
3239
}
3340

3441
#[test]
3542
fn it_grc_err_println() {
36-
grc_err_println("TEST ERROR CONTENT.");
43+
grc_err("TEST ERROR CONTENT.");
3744
}
3845

3946
#[test]
4047
fn it_grc_warn_println() {
41-
grc_warn_println("TEST WARN CONTENT.");
48+
grc_warn("TEST WARN CONTENT.");
49+
}
50+
51+
#[test]
52+
fn it_grc_succ_println() {
53+
grc_succ("TEST SUCCESS CONTENT.");
4254
}
4355
}

src/main.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ fn main() {
2323
let arg = match Arguments::collect() {
2424
| Ok(a) => a,
2525
| Err(e) => {
26-
grc_err_println(e.message());
26+
grc_err(e.message());
2727
return;
2828
}
2929
};
@@ -38,7 +38,7 @@ fn main() {
3838
let extensions = match ext {
3939
| Ok(e) => e,
4040
| Err(e) => {
41-
grc_err_println(e.to_string());
41+
grc_err(e.to_string());
4242
return;
4343
}
4444
};
@@ -50,7 +50,7 @@ fn main() {
5050
let repo = match Repository::new(path, Rc::clone(&config)) {
5151
| Ok(r) => r,
5252
| Err(e) => {
53-
grc_err_println(e.message());
53+
grc_err(e.message());
5454
return;
5555
}
5656
};
@@ -62,10 +62,10 @@ fn main() {
6262
.ask()
6363
.build();
6464

65-
grc_println(&message);
65+
grc_log(&message);
6666

6767
// Git commit
6868
if let Err(e) = repo.commit(message.as_str()) {
69-
grc_err_println(e.message());
69+
grc_err(e.message());
7070
}
7171
}

src/message.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use dialoguer::{theme::ColorfulTheme, Input, Select};
22

3-
use crate::log::grc_err_println;
3+
use crate::log::grc_err;
44
use crate::metadata::*;
55
use crate::util::remove_pound_prefix;
66

@@ -69,7 +69,7 @@ impl Messager {
6969
.map(|typ: &String| -> CommitTD {
7070
let arr_td = typ.split(SEPARATOR_SYMBOL).collect::<Vec<&str>>();
7171
if arr_td.len() < 2 {
72-
grc_err_println(TYPE_PARSE_FAILED);
72+
grc_err(TYPE_PARSE_FAILED);
7373
std::process::exit(1);
7474
};
7575
CommitTD::from(arr_td[0].trim(), arr_td[1].trim())
@@ -87,7 +87,7 @@ impl Messager {
8787
emo.iter().for_each(|type_emo: &String| {
8888
let arr_emo = type_emo.split(SEPARATOR_SYMBOL).collect::<Vec<&str>>();
8989
if arr_emo.len() < 2 {
90-
grc_err_println(OVERWRITE_PARSE_FAILED);
90+
grc_err(OVERWRITE_PARSE_FAILED);
9191
std::process::exit(1);
9292
};
9393
if td.0 == arr_emo[0].trim() {

src/plugins/push.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{log::grc_warn_println, repo::Repository};
1+
use crate::{log::grc_warn, repo::Repository};
22
use console::Style;
33
use git2::{Cred, Error, PushOptions, RemoteCallbacks};
44
use std::env;
@@ -39,8 +39,8 @@ impl CommitPlugin for PushPlugin {
3939
let mut push_option: PushOptions = PushOptions::new();
4040
push_option.remote_callbacks(callbacks);
4141

42-
grc_warn_println(format!("Remote: {}", remote_name));
43-
grc_warn_println(format!("Branch: {}", branch_name));
42+
grc_warn(format!("Remote: {}", remote_name));
43+
grc_warn(format!("Branch: {}", branch_name));
4444

4545
remote.push(
4646
&[format!("refs/heads/{}:refs/heads/{}", branch_name, branch_name).as_str()],

src/repo.rs

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ use git2::{
77

88
use crate::{
99
config::Configuration,
10-
log::{grc_println, grc_warn_println},
10+
log::{grc_log, grc_warn},
1111
metadata::Mode,
12-
util::{author_sign_from_env, committer_sign_from_env, is_all_workspace},
12+
util::{author_sign_from_env, committer_sign_from_env, is_all_workspace, repo_gpg_available},
1313
};
1414

1515
/// Repository in GRC.
@@ -37,13 +37,23 @@ impl Repository {
3737
pub fn commit(&self, message: &str) -> Result<(), Error> {
3838
self.pre_commit()?;
3939

40+
let is_gpg_commit = self.gpg_sign_commit(message)?;
41+
if !is_gpg_commit {
42+
self.general_commit(message)?;
43+
}
44+
45+
self.after_commit()?;
46+
47+
Ok(())
48+
}
49+
50+
fn general_commit(&self, message: &str) -> Result<(), Error> {
4051
let tree_id = {
4152
let mut index = self.repo.index()?;
4253
index.write_tree()?
4354
};
4455

4556
let tree = self.repo.find_tree(tree_id)?;
46-
4757
let (author_sign, committer_sign) = self.generate_sign()?;
4858

4959
match self.find_last_commit() {
@@ -58,7 +68,7 @@ impl Repository {
5868
)?;
5969
}
6070
| Err(_) => {
61-
grc_warn_println("grc think this is the repo's first commit.");
71+
grc_warn("grc think this is the repo's first commit.");
6272
self.repo.commit(
6373
Some("HEAD"),
6474
&author_sign,
@@ -68,11 +78,54 @@ impl Repository {
6878
&[],
6979
)?;
7080
}
71-
};
81+
}
82+
Ok(())
83+
}
7284

73-
self.after_commit()?;
85+
/// check gpg is available, if true then using gpg sign commit.
86+
/// github.com/sdttttt/gcr/issues/52 Thinks @Enter-tainer @CoelacanthusHex
87+
fn gpg_sign_commit(&self, message: &str) -> Result<bool, Error> {
88+
match repo_gpg_available(&self.repo) {
89+
| Some(ref key) => {
90+
let tree_id = {
91+
let mut index = self.repo.index()?;
92+
index.write_tree()?
93+
};
7494

75-
Ok(())
95+
let tree = self.repo.find_tree(tree_id)?;
96+
let (author_sign, committer_sign) = self.generate_sign()?;
97+
98+
let buf = match self.find_last_commit() {
99+
| Ok(commit) => self.repo.commit_create_buffer(
100+
&author_sign,
101+
&committer_sign,
102+
message,
103+
&tree,
104+
&[&commit],
105+
)?,
106+
| Err(_) => {
107+
grc_warn("grc think this is the repo's first commit.");
108+
self.repo.commit_create_buffer(
109+
&author_sign,
110+
&committer_sign,
111+
message,
112+
&tree,
113+
&[],
114+
)?
115+
}
116+
};
117+
118+
// https://github.com/rust-lang/git2-rs/issues/507 Thinks @cole-h
119+
let commit_content = std::str::from_utf8(&buf).unwrap();
120+
let ret = self.repo.commit_signed(commit_content, key, Some(key))?;
121+
let commit = self.repo.find_commit(ret)?;
122+
self.repo.branch(&self.current_branch_name(), &commit, false)?;
123+
124+
Ok(true)
125+
}
126+
127+
| None => Ok(false),
128+
}
76129
}
77130

78131
fn pre_commit(&self) -> Result<(), Error> {
@@ -158,7 +211,7 @@ impl Repository {
158211
};
159212

160213
if use_env {
161-
grc_println("you are using environment variables to generate commit sign.");
214+
grc_log("you are using environment variables to generate commit sign.");
162215
}
163216

164217
Ok((author_sign, committer_sign))
@@ -170,6 +223,12 @@ impl Repository {
170223
obj.into_commit().map_err(|_| Error::from_str("not fonund Commit."))
171224
}
172225

226+
fn current_branch_name(&self) -> String {
227+
let head = &self.repo.head().unwrap();
228+
let branch_name = head.shorthand().unwrap_or_else(|| "");
229+
String::from(branch_name)
230+
}
231+
173232
/// Check to see if the repository commit index is empty.
174233
fn check_index(&self) -> Result<(), Error> {
175234
match self.status() {
@@ -185,3 +244,16 @@ impl Repository {
185244
}
186245
}
187246
}
247+
248+
//#[cfg(test)]
249+
//mod tests {
250+
251+
// use git2::Repository;
252+
253+
// #[test]
254+
// fn check_gpg() {
255+
// let repo = Repository::open(".").unwrap();
256+
// let config = repo.config().unwrap();
257+
// let gpg_enabled = config.get_bool("commit.gpgsign").unwrap_or_else(|_|
258+
// false); assert_eq!(gpg_enabled, true); }
259+
//}

src/util.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,35 @@
1-
use git2::{Signature, Status, Statuses};
1+
use git2::{Repository, Signature, Status, Statuses};
22
use std::{env, fs};
33

4-
use crate::metadata::{GIT_AUTHOR_EMAIL, GIT_AUTHOR_NAME, GIT_COMMITTER_EMAIL, GIT_COMMITTER_NAME};
4+
use crate::{
5+
log::grc_warn,
6+
metadata::{GIT_AUTHOR_EMAIL, GIT_AUTHOR_NAME, GIT_COMMITTER_EMAIL, GIT_COMMITTER_NAME},
7+
};
58

69
pub fn current_path() -> String {
710
let path = fs::canonicalize(".").unwrap();
811
String::from(path.to_str().unwrap())
912
}
1013

14+
/// if gpg available at repo. then return user.signingKey.
15+
pub fn repo_gpg_available(repo: &Repository) -> Option<String> {
16+
let config = repo.config().unwrap();
17+
let gpg_enabled = config.get_bool("commit.gpgsign").unwrap_or_else(|_| false);
18+
if gpg_enabled {
19+
let gpg_sign_key = config.get_str("user.signingkey").unwrap_or_else(|_| "");
20+
if gpg_sign_key.is_empty() {
21+
grc_warn(
22+
"It looks like you configured `gpgSign`, but grc did not find your `signingKey`.",
23+
);
24+
return None;
25+
} else {
26+
return Some(String::from(gpg_sign_key));
27+
}
28+
}
29+
None
30+
}
31+
32+
/// Check the workspace for file changes.
1133
pub fn is_all_workspace(statuses: &Statuses) -> bool {
1234
let mut tip = false;
1335
for state in statuses.iter() {

0 commit comments

Comments
 (0)