From 9cc5bb32e878a5334a7e3afc50350205c7f5a80a Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Wed, 12 Jul 2023 21:56:43 +0200 Subject: [PATCH 01/13] feat: add signoff key to commit editor --- src/components/commit.rs | 25 +++++++++++++++++++++++++ src/keys/key_list.rs | 2 ++ src/strings.rs | 15 +++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/src/components/commit.rs b/src/components/commit.rs index 875d0a35e9..92a2fd777e 100644 --- a/src/components/commit.rs +++ b/src/components/commit.rs @@ -43,6 +43,7 @@ enum Mode { Merge(Vec<CommitId>), Revert, Reword(CommitId), + Signoff, } pub struct CommitComponent { @@ -301,6 +302,7 @@ impl CommitComponent { commit } + Mode::Signoff => sync::commit(&self.repo.borrow(), msg)?, }; Ok(()) } @@ -341,6 +343,18 @@ impl CommitComponent { Ok(()) } + fn toggle_signoff(&mut self) { + match self.mode { + Mode::Normal => { + self.mode = Mode::Signoff; + self.input.set_title(strings::commit_title_signoff()); + } + _ => { + self.mode = Mode::Normal; + self.input.set_title(strings::commit_title()); + } + } + } fn toggle_verify(&mut self) { self.verify = !self.verify; } @@ -464,6 +478,12 @@ impl Component for CommitComponent { true, )); + out.push(CommandInfo::new( + strings::commands::commit_signoff(&self.key_config), + true, + true, + )); + out.push(CommandInfo::new( strings::commands::commit_open_editor( &self.key_config, @@ -531,6 +551,11 @@ impl Component for CommitComponent { self.input.set_text(msg); self.commit_msg_history_idx += 1; } + } else if key_match( + e, + self.key_config.keys.commit_signoff, + ) { + self.toggle_signoff(); } // stop key event propagation return Ok(EventState::Consumed); diff --git a/src/keys/key_list.rs b/src/keys/key_list.rs index 134d992d87..3912a9c388 100644 --- a/src/keys/key_list.rs +++ b/src/keys/key_list.rs @@ -88,6 +88,7 @@ pub struct KeysList { pub log_reset_comit: GituiKeyEvent, pub log_reword_comit: GituiKeyEvent, pub commit_amend: GituiKeyEvent, + pub commit_signoff: GituiKeyEvent, pub toggle_verify: GituiKeyEvent, pub copy: GituiKeyEvent, pub create_branch: GituiKeyEvent, @@ -174,6 +175,7 @@ impl Default for KeysList { log_reset_comit: GituiKeyEvent { code: KeyCode::Char('R'), modifiers: KeyModifiers::SHIFT }, log_reword_comit: GituiKeyEvent { code: KeyCode::Char('r'), modifiers: KeyModifiers::empty() }, commit_amend: GituiKeyEvent::new(KeyCode::Char('a'), KeyModifiers::CONTROL), + commit_signoff: GituiKeyEvent::new(KeyCode::Char('s'), KeyModifiers::CONTROL), toggle_verify: GituiKeyEvent::new(KeyCode::Char('f'), KeyModifiers::CONTROL), copy: GituiKeyEvent::new(KeyCode::Char('y'), KeyModifiers::empty()), create_branch: GituiKeyEvent::new(KeyCode::Char('c'), KeyModifiers::empty()), diff --git a/src/strings.rs b/src/strings.rs index 3e1ff80633..cf8d3bb109 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -117,6 +117,9 @@ pub fn commit_title_revert() -> String { pub fn commit_title_amend() -> String { "Commit (Amend)".to_string() } +pub fn commit_title_signoff() -> String { + "Commit (Sign-off)".to_string() +} pub fn commit_msg(_key_config: &SharedKeyConfig) -> String { "type commit message..".to_string() } @@ -980,6 +983,18 @@ pub mod commands { CMD_GROUP_COMMIT_POPUP, ) } + pub fn commit_signoff( + key_config: &SharedKeyConfig, + ) -> CommandText { + CommandText::new( + format!( + "Sing-off [{}]", + key_config.get_hint(key_config.keys.commit_signoff), + ), + "sign-off commit (-s option)", + CMD_GROUP_COMMIT_POPUP, + ) + } pub fn edit_item(key_config: &SharedKeyConfig) -> CommandText { CommandText::new( format!( From 4dcb5a75df588995f93be479c69c853329554c7d Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Wed, 12 Jul 2023 22:50:18 +0200 Subject: [PATCH 02/13] feat: Adding sign off string manually Signed-off-by Dominik Tacke <tacdom+github@gmail.com> --- asyncgit/src/sync/commit.rs | 40 ++++++++++++++++++++++++------ asyncgit/src/sync/commit_revert.rs | 2 +- src/components/commit.rs | 10 +++++--- src/keys/key_list.rs | 4 +-- src/strings.rs | 2 +- 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/asyncgit/src/sync/commit.rs b/asyncgit/src/sync/commit.rs index d1af74d85d..dd9d83d73f 100644 --- a/asyncgit/src/sync/commit.rs +++ b/asyncgit/src/sync/commit.rs @@ -60,8 +60,28 @@ pub(crate) fn signature_allow_undefined_name( signature } +fn add_sign_off<'a>( + msg: &'a str, + signature: &'a Signature, +) -> &'a str { + match (signature.name(), signature.email()) { + (Some(name), Some(mail)) => { + msg.to_owned().push_str(&format!( + "Signed-off-by {} <{}>", + name, mail + )); + msg + } + _ => msg, + } +} + /// this does not run any git hooks, git-hooks have to be executed manually, checkout `hooks_commit_msg` for example -pub fn commit(repo_path: &RepoPath, msg: &str) -> Result<CommitId> { +pub fn commit( + repo_path: &RepoPath, + msg: &str, + sign_off: bool, +) -> Result<CommitId> { scope_time!("commit"); let repo = repo(repo_path)?; @@ -79,12 +99,18 @@ pub fn commit(repo_path: &RepoPath, msg: &str) -> Result<CommitId> { let parents = parents.iter().collect::<Vec<_>>(); + let msg = if sign_off { + add_sign_off(&msg, &signature) + } else { + msg + }; + Ok(repo .commit( Some("HEAD"), &signature, &signature, - msg, + &msg, &tree, parents.as_slice(), )? @@ -162,7 +188,7 @@ mod tests { assert_eq!(get_statuses(repo_path), (0, 1)); - commit(repo_path, "commit msg").unwrap(); + commit(repo_path, "commit msg", false).unwrap(); assert_eq!(get_statuses(repo_path), (0, 0)); } @@ -188,7 +214,7 @@ mod tests { assert_eq!(get_statuses(repo_path), (0, 1)); - commit(repo_path, "commit msg").unwrap(); + commit(repo_path, "commit msg", false).unwrap(); assert_eq!(get_statuses(repo_path), (0, 0)); } @@ -322,13 +348,13 @@ mod tests { repo.config()?.remove("user.email")?; - let error = commit(repo_path, "commit msg"); + let error = commit(repo_path, "commit msg", false); assert!(matches!(error, Err(_))); repo.config()?.set_str("user.email", "email")?; - let success = commit(repo_path, "commit msg"); + let success = commit(repo_path, "commit msg", false); assert!(matches!(success, Ok(_))); assert_eq!(count_commits(&repo, 10), 1); @@ -358,7 +384,7 @@ mod tests { repo.config()?.remove("user.name")?; - let mut success = commit(repo_path, "commit msg"); + let mut success = commit(repo_path, "commit msg", false); assert!(matches!(success, Ok(_))); assert_eq!(count_commits(&repo, 10), 1); diff --git a/asyncgit/src/sync/commit_revert.rs b/asyncgit/src/sync/commit_revert.rs index 2d66a2a1d4..326525d8dd 100644 --- a/asyncgit/src/sync/commit_revert.rs +++ b/asyncgit/src/sync/commit_revert.rs @@ -43,7 +43,7 @@ pub fn commit_revert( ) -> Result<CommitId> { scope_time!("commit_revert"); - let id = crate::sync::commit(repo_path, msg)?; + let id = crate::sync::commit(repo_path, msg, false)?; repo(repo_path)?.cleanup_state()?; diff --git a/src/components/commit.rs b/src/components/commit.rs index 92a2fd777e..fb240b909a 100644 --- a/src/components/commit.rs +++ b/src/components/commit.rs @@ -285,7 +285,9 @@ impl CommitComponent { fn do_commit(&self, msg: &str) -> Result<()> { match &self.mode { - Mode::Normal => sync::commit(&self.repo.borrow(), msg)?, + Mode::Normal => { + sync::commit(&self.repo.borrow(), msg, false)? + } Mode::Amend(amend) => { sync::amend(&self.repo.borrow(), *amend, msg)? } @@ -302,7 +304,9 @@ impl CommitComponent { commit } - Mode::Signoff => sync::commit(&self.repo.borrow(), msg)?, + Mode::Signoff => { + sync::commit(&self.repo.borrow(), msg, true)? + } }; Ok(()) } @@ -553,7 +557,7 @@ impl Component for CommitComponent { } } else if key_match( e, - self.key_config.keys.commit_signoff, + self.key_config.keys.toggle_signoff, ) { self.toggle_signoff(); } diff --git a/src/keys/key_list.rs b/src/keys/key_list.rs index 3912a9c388..619dde5ee1 100644 --- a/src/keys/key_list.rs +++ b/src/keys/key_list.rs @@ -88,7 +88,7 @@ pub struct KeysList { pub log_reset_comit: GituiKeyEvent, pub log_reword_comit: GituiKeyEvent, pub commit_amend: GituiKeyEvent, - pub commit_signoff: GituiKeyEvent, + pub toggle_signoff: GituiKeyEvent, pub toggle_verify: GituiKeyEvent, pub copy: GituiKeyEvent, pub create_branch: GituiKeyEvent, @@ -175,7 +175,7 @@ impl Default for KeysList { log_reset_comit: GituiKeyEvent { code: KeyCode::Char('R'), modifiers: KeyModifiers::SHIFT }, log_reword_comit: GituiKeyEvent { code: KeyCode::Char('r'), modifiers: KeyModifiers::empty() }, commit_amend: GituiKeyEvent::new(KeyCode::Char('a'), KeyModifiers::CONTROL), - commit_signoff: GituiKeyEvent::new(KeyCode::Char('s'), KeyModifiers::CONTROL), + toggle_signoff: GituiKeyEvent::new(KeyCode::Char('s'), KeyModifiers::CONTROL), toggle_verify: GituiKeyEvent::new(KeyCode::Char('f'), KeyModifiers::CONTROL), copy: GituiKeyEvent::new(KeyCode::Char('y'), KeyModifiers::empty()), create_branch: GituiKeyEvent::new(KeyCode::Char('c'), KeyModifiers::empty()), diff --git a/src/strings.rs b/src/strings.rs index cf8d3bb109..6477906d31 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -989,7 +989,7 @@ pub mod commands { CommandText::new( format!( "Sing-off [{}]", - key_config.get_hint(key_config.keys.commit_signoff), + key_config.get_hint(key_config.keys.toggle_signoff), ), "sign-off commit (-s option)", CMD_GROUP_COMMIT_POPUP, From 4d421bb1ccfaf2901545e572e8c353d67e8ede00 Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Thu, 13 Jul 2023 10:23:55 +0200 Subject: [PATCH 03/13] chore: refactores sync::commit to keep function's signature stable Signed-off-by: Dominik Tacke <tacdom+github@gmail.com> --- asyncgit/src/sync/commit.rs | 38 ++++++++++++++++++++---------- asyncgit/src/sync/commit_revert.rs | 2 +- asyncgit/src/sync/mod.rs | 2 +- src/components/commit.rs | 21 +++++++---------- 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/asyncgit/src/sync/commit.rs b/asyncgit/src/sync/commit.rs index dd9d83d73f..10e20c347a 100644 --- a/asyncgit/src/sync/commit.rs +++ b/asyncgit/src/sync/commit.rs @@ -66,18 +66,15 @@ fn add_sign_off<'a>( ) -> &'a str { match (signature.name(), signature.email()) { (Some(name), Some(mail)) => { - msg.to_owned().push_str(&format!( - "Signed-off-by {} <{}>", - name, mail - )); + msg.to_owned() + .push_str(&format!("Signed-off-by {name} <{mail}>")); msg } _ => msg, } } -/// this does not run any git hooks, git-hooks have to be executed manually, checkout `hooks_commit_msg` for example -pub fn commit( +fn do_commit( repo_path: &RepoPath, msg: &str, sign_off: bool, @@ -100,7 +97,7 @@ pub fn commit( let parents = parents.iter().collect::<Vec<_>>(); let msg = if sign_off { - add_sign_off(&msg, &signature) + add_sign_off(msg, &signature) } else { msg }; @@ -110,13 +107,28 @@ pub fn commit( Some("HEAD"), &signature, &signature, - &msg, + msg, &tree, parents.as_slice(), )? .into()) } +/// this does not run any git hooks, git-hooks have to be executed manually, checkout `hooks_commit_msg` for example +pub fn commit(repo_path: &RepoPath, msg: &str) -> Result<CommitId> { + do_commit(repo_path, msg, false) +} + +/// Do a commit including the sign-off option +/// +/// Refer to [git documentation](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--s) +pub fn commit_with_singoff( + repo_path: &RepoPath, + msg: &str, +) -> Result<CommitId> { + do_commit(repo_path, msg, true) +} + /// Tag a commit. /// /// This function will return an `Err(…)` variant if the tag’s name is refused @@ -188,7 +200,7 @@ mod tests { assert_eq!(get_statuses(repo_path), (0, 1)); - commit(repo_path, "commit msg", false).unwrap(); + commit(repo_path, "commit msg").unwrap(); assert_eq!(get_statuses(repo_path), (0, 0)); } @@ -214,7 +226,7 @@ mod tests { assert_eq!(get_statuses(repo_path), (0, 1)); - commit(repo_path, "commit msg", false).unwrap(); + commit(repo_path, "commit msg").unwrap(); assert_eq!(get_statuses(repo_path), (0, 0)); } @@ -348,13 +360,13 @@ mod tests { repo.config()?.remove("user.email")?; - let error = commit(repo_path, "commit msg", false); + let error = commit(repo_path, "commit msg"); assert!(matches!(error, Err(_))); repo.config()?.set_str("user.email", "email")?; - let success = commit(repo_path, "commit msg", false); + let success = commit(repo_path, "commit msg"); assert!(matches!(success, Ok(_))); assert_eq!(count_commits(&repo, 10), 1); @@ -384,7 +396,7 @@ mod tests { repo.config()?.remove("user.name")?; - let mut success = commit(repo_path, "commit msg", false); + let mut success = commit(repo_path, "commit msg"); assert!(matches!(success, Ok(_))); assert_eq!(count_commits(&repo, 10), 1); diff --git a/asyncgit/src/sync/commit_revert.rs b/asyncgit/src/sync/commit_revert.rs index 326525d8dd..2d66a2a1d4 100644 --- a/asyncgit/src/sync/commit_revert.rs +++ b/asyncgit/src/sync/commit_revert.rs @@ -43,7 +43,7 @@ pub fn commit_revert( ) -> Result<CommitId> { scope_time!("commit_revert"); - let id = crate::sync::commit(repo_path, msg, false)?; + let id = crate::sync::commit(repo_path, msg)?; repo(repo_path)?.cleanup_state()?; diff --git a/asyncgit/src/sync/mod.rs b/asyncgit/src/sync/mod.rs index a7bf7d64ed..2c67df0c00 100644 --- a/asyncgit/src/sync/mod.rs +++ b/asyncgit/src/sync/mod.rs @@ -43,7 +43,7 @@ pub use branch::{ merge_rebase::merge_upstream_rebase, rename::rename_branch, validate_branch_name, BranchCompare, BranchDetails, BranchInfo, }; -pub use commit::{amend, commit, tag_commit}; +pub use commit::{amend, commit, commit_with_singoff, tag_commit}; pub use commit_details::{ get_commit_details, CommitDetails, CommitMessage, CommitSignature, }; diff --git a/src/components/commit.rs b/src/components/commit.rs index fb240b909a..c52ce5a249 100644 --- a/src/components/commit.rs +++ b/src/components/commit.rs @@ -285,9 +285,7 @@ impl CommitComponent { fn do_commit(&self, msg: &str) -> Result<()> { match &self.mode { - Mode::Normal => { - sync::commit(&self.repo.borrow(), msg, false)? - } + Mode::Normal => sync::commit(&self.repo.borrow(), msg)?, Mode::Amend(amend) => { sync::amend(&self.repo.borrow(), *amend, msg)? } @@ -305,7 +303,7 @@ impl CommitComponent { commit } Mode::Signoff => { - sync::commit(&self.repo.borrow(), msg, true)? + sync::commit_with_singoff(&self.repo.borrow(), msg)? } }; Ok(()) @@ -348,15 +346,12 @@ impl CommitComponent { Ok(()) } fn toggle_signoff(&mut self) { - match self.mode { - Mode::Normal => { - self.mode = Mode::Signoff; - self.input.set_title(strings::commit_title_signoff()); - } - _ => { - self.mode = Mode::Normal; - self.input.set_title(strings::commit_title()); - } + if matches!(self.mode, Mode::Normal) { + self.mode = Mode::Signoff; + self.input.set_title(strings::commit_title_signoff()); + } else { + self.mode = Mode::Normal; + self.input.set_title(strings::commit_title()); } } fn toggle_verify(&mut self) { From 60d181cfb3ffa3f16450eb2a93656c6a0ecc93a4 Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Thu, 13 Jul 2023 13:26:34 +0200 Subject: [PATCH 04/13] fix: typo in function name --- asyncgit/src/sync/commit.rs | 2 +- asyncgit/src/sync/mod.rs | 2 +- src/components/commit.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/asyncgit/src/sync/commit.rs b/asyncgit/src/sync/commit.rs index 10e20c347a..79d3acf8bd 100644 --- a/asyncgit/src/sync/commit.rs +++ b/asyncgit/src/sync/commit.rs @@ -122,7 +122,7 @@ pub fn commit(repo_path: &RepoPath, msg: &str) -> Result<CommitId> { /// Do a commit including the sign-off option /// /// Refer to [git documentation](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--s) -pub fn commit_with_singoff( +pub fn commit_with_signoff( repo_path: &RepoPath, msg: &str, ) -> Result<CommitId> { diff --git a/asyncgit/src/sync/mod.rs b/asyncgit/src/sync/mod.rs index 2c67df0c00..a626bfec2e 100644 --- a/asyncgit/src/sync/mod.rs +++ b/asyncgit/src/sync/mod.rs @@ -43,7 +43,7 @@ pub use branch::{ merge_rebase::merge_upstream_rebase, rename::rename_branch, validate_branch_name, BranchCompare, BranchDetails, BranchInfo, }; -pub use commit::{amend, commit, commit_with_singoff, tag_commit}; +pub use commit::{amend, commit, commit_with_signoff, tag_commit}; pub use commit_details::{ get_commit_details, CommitDetails, CommitMessage, CommitSignature, }; diff --git a/src/components/commit.rs b/src/components/commit.rs index c52ce5a249..58f06787e3 100644 --- a/src/components/commit.rs +++ b/src/components/commit.rs @@ -303,7 +303,7 @@ impl CommitComponent { commit } Mode::Signoff => { - sync::commit_with_singoff(&self.repo.borrow(), msg)? + sync::commit_with_signoff(&self.repo.borrow(), msg)? } }; Ok(()) From 0e5be1ab09ff12a110621f43b98f99ca5ab47e8b Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Thu, 13 Jul 2023 13:42:07 +0200 Subject: [PATCH 05/13] fix: add sign-off to message Signed-off-by Dominik Tacke <tacdom+github@gmail.com> --- asyncgit/src/sync/commit.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/asyncgit/src/sync/commit.rs b/asyncgit/src/sync/commit.rs index 79d3acf8bd..92b06e9454 100644 --- a/asyncgit/src/sync/commit.rs +++ b/asyncgit/src/sync/commit.rs @@ -60,17 +60,14 @@ pub(crate) fn signature_allow_undefined_name( signature } -fn add_sign_off<'a>( - msg: &'a str, - signature: &'a Signature, -) -> &'a str { +fn add_sign_off(msg: &str, signature: &Signature) -> String { match (signature.name(), signature.email()) { (Some(name), Some(mail)) => { - msg.to_owned() - .push_str(&format!("Signed-off-by {name} <{mail}>")); + let mut msg = msg.to_owned(); + msg.push_str(&format!("\nSigned-off-by {name} <{mail}>")); msg } - _ => msg, + _ => msg.to_owned(), } } @@ -99,7 +96,7 @@ fn do_commit( let msg = if sign_off { add_sign_off(msg, &signature) } else { - msg + msg.to_owned() }; Ok(repo @@ -107,7 +104,7 @@ fn do_commit( Some("HEAD"), &signature, &signature, - msg, + &msg, &tree, parents.as_slice(), )? From 3a656f2c0d9b4dc684f2a06976624b902062792e Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Thu, 13 Jul 2023 15:20:11 +0200 Subject: [PATCH 06/13] test: add unit test for creating the signed-off commit message Signed-off-by Dominik Tacke <tacdom+github@gmail.com> --- asyncgit/src/sync/commit.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/asyncgit/src/sync/commit.rs b/asyncgit/src/sync/commit.rs index 92b06e9454..e5cebc94e1 100644 --- a/asyncgit/src/sync/commit.rs +++ b/asyncgit/src/sync/commit.rs @@ -168,9 +168,11 @@ mod tests { LogWalker, }; use commit::{amend, tag_commit}; - use git2::Repository; + use git2::{Repository, Signature}; use std::{fs::File, io::Write, path::Path}; + use super::add_sign_off; + fn count_commits(repo: &Repository, max: usize) -> usize { let mut items = Vec::new(); let mut walk = LogWalker::new(repo, max).unwrap(); @@ -419,4 +421,16 @@ mod tests { Ok(()) } + + #[test] + fn test_add_sign_off_to_commit_msg() { + let in_msg = "test commit"; + let signature = + Signature::now("MyName", "my@mail.com").unwrap(); + + let expected = + format!("{in_msg}\nSigned-off-by MyName <my@mail.com>"); + let result = add_sign_off(in_msg, &signature); + assert_eq!(expected, result); + } } From 0cf23f274637ce6a6c26ae829d7418bd75087031 Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Thu, 13 Jul 2023 15:20:32 +0200 Subject: [PATCH 07/13] docs: added sign off feature to changelog Signed-off-by Dominik Tacke <tacdom+github@gmail.com> --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bceb31185c..f5dcab69d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added * support 'n'/'p' key to move to the next/prev hunk in diff component [[@hamflx](https://github.com/hamflx)] ([#1523](https://github.com/extrawurst/gitui/issues/1523)) * simplify theme overrides [[@cruessler](https://github.com/cruessler)] ([#1367](https://github.com/extrawurst/gitui/issues/1367)) +* Support for sign-off of commits [#1757]https://github.com/extrawurst/gitui/issues/1757 ### Fixes * fix commit dialog char count for multibyte characters ([#1726](https://github.com/extrawurst/gitui/issues/1726)) From 34dacf0a8316916356c4d54a8230df3b98b1c221 Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Fri, 14 Jul 2023 08:16:56 +0200 Subject: [PATCH 08/13] fix(CHANGELOG): formatting Signed-off-by Dominik Tacke <tacdom+github@gmail.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5dcab69d5..4c25dc867f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added * support 'n'/'p' key to move to the next/prev hunk in diff component [[@hamflx](https://github.com/hamflx)] ([#1523](https://github.com/extrawurst/gitui/issues/1523)) * simplify theme overrides [[@cruessler](https://github.com/cruessler)] ([#1367](https://github.com/extrawurst/gitui/issues/1367)) -* Support for sign-off of commits [#1757]https://github.com/extrawurst/gitui/issues/1757 +* support for sign-off of commits [#1757](https://github.com/extrawurst/gitui/issues/1757) ### Fixes * fix commit dialog char count for multibyte characters ([#1726](https://github.com/extrawurst/gitui/issues/1726)) From 176bc8266ed91550aa9682385ab3279709ec4b43 Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Tue, 25 Jul 2023 21:02:25 +0200 Subject: [PATCH 09/13] refactor: sign-off is not a state, just adds signature to message --- src/components/commit.rs | 44 ++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/components/commit.rs b/src/components/commit.rs index 58f06787e3..d1da3d2e2e 100644 --- a/src/components/commit.rs +++ b/src/components/commit.rs @@ -7,7 +7,8 @@ use crate::{ keys::{key_match, SharedKeyConfig}, options::SharedOptions, queue::{InternalEvent, NeedsUpdate, Queue}, - strings, try_or_popup, + strings::{self, commit_title_signoff}, + try_or_popup, ui::style::SharedTheme, }; use anyhow::{bail, Ok, Result}; @@ -43,7 +44,6 @@ enum Mode { Merge(Vec<CommitId>), Revert, Reword(CommitId), - Signoff, } pub struct CommitComponent { @@ -58,6 +58,7 @@ pub struct CommitComponent { commit_msg_history_idx: usize, options: SharedOptions, verify: bool, + sign_off: bool, } const FIRST_LINE_LIMIT: usize = 50; @@ -89,6 +90,7 @@ impl CommitComponent { commit_msg_history_idx: 0, options, verify: true, + sign_off: false, } } @@ -256,7 +258,13 @@ impl CommitComponent { return Ok(CommitResult::Aborted); } } + let mut msg = message_prettify(msg, Some(b'#'))?; + + if self.sign_off { + msg = self.add_sign_off(&msg)?; + } + if verify { // run commit message check hook - can reject commit if let HookResult::NotOk(e) = @@ -302,9 +310,6 @@ impl CommitComponent { commit } - Mode::Signoff => { - sync::commit_with_signoff(&self.repo.borrow(), msg)? - } }; Ok(()) } @@ -346,11 +351,10 @@ impl CommitComponent { Ok(()) } fn toggle_signoff(&mut self) { - if matches!(self.mode, Mode::Normal) { - self.mode = Mode::Signoff; - self.input.set_title(strings::commit_title_signoff()); + self.sign_off = !self.sign_off; + if self.sign_off { + self.input.set_title(commit_title_signoff()); } else { - self.mode = Mode::Normal; self.input.set_title(strings::commit_title()); } } @@ -429,6 +433,28 @@ impl CommitComponent { Ok(()) } + + fn add_sign_off(&self, msg: &str) -> Result<String> { + const CONFIG_KEY_USER_NAME: &str = "user.name"; + const CONFIG_KEY_USER_MAIL: &str = "user.email"; + + let user = get_config_string( + &self.repo.borrow(), + CONFIG_KEY_USER_NAME, + )?; + + let mail = get_config_string( + &self.repo.borrow(), + CONFIG_KEY_USER_MAIL, + )?; + + if let (Some(user), Some(mail)) = (user, mail) { + let mut msg = msg.to_owned(); + msg.push_str(&format!("\nSigned-off-by {user} <{mail}>")); + } + + Ok(msg.to_string()) + } } impl DrawableComponent for CommitComponent { From 24acc64be4c96c694e830a2eee8e85ffe3bd15d7 Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Tue, 25 Jul 2023 21:07:33 +0200 Subject: [PATCH 10/13] fix: message creation Signed-off-by Dominik Tacke <tacdom+github@gmail.com> --- src/components/commit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/commit.rs b/src/components/commit.rs index d1da3d2e2e..bb77eee2e6 100644 --- a/src/components/commit.rs +++ b/src/components/commit.rs @@ -448,12 +448,12 @@ impl CommitComponent { CONFIG_KEY_USER_MAIL, )?; + let mut msg = msg.to_owned(); if let (Some(user), Some(mail)) = (user, mail) { - let mut msg = msg.to_owned(); msg.push_str(&format!("\nSigned-off-by {user} <{mail}>")); } - Ok(msg.to_string()) + Ok(msg) } } From f411c9cdfd2f8895c29ec7f54f2c47a998b07f04 Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Tue, 25 Jul 2023 21:15:25 +0200 Subject: [PATCH 11/13] refactor: undid changes to asyncgit Signed-off-by Dominik Tacke <tacdom+github@gmail.com> --- asyncgit/src/sync/commit.rs | 57 +++---------------------------------- asyncgit/src/sync/mod.rs | 2 +- 2 files changed, 5 insertions(+), 54 deletions(-) diff --git a/asyncgit/src/sync/commit.rs b/asyncgit/src/sync/commit.rs index e5cebc94e1..d1af74d85d 100644 --- a/asyncgit/src/sync/commit.rs +++ b/asyncgit/src/sync/commit.rs @@ -60,22 +60,8 @@ pub(crate) fn signature_allow_undefined_name( signature } -fn add_sign_off(msg: &str, signature: &Signature) -> String { - match (signature.name(), signature.email()) { - (Some(name), Some(mail)) => { - let mut msg = msg.to_owned(); - msg.push_str(&format!("\nSigned-off-by {name} <{mail}>")); - msg - } - _ => msg.to_owned(), - } -} - -fn do_commit( - repo_path: &RepoPath, - msg: &str, - sign_off: bool, -) -> Result<CommitId> { +/// this does not run any git hooks, git-hooks have to be executed manually, checkout `hooks_commit_msg` for example +pub fn commit(repo_path: &RepoPath, msg: &str) -> Result<CommitId> { scope_time!("commit"); let repo = repo(repo_path)?; @@ -93,39 +79,18 @@ fn do_commit( let parents = parents.iter().collect::<Vec<_>>(); - let msg = if sign_off { - add_sign_off(msg, &signature) - } else { - msg.to_owned() - }; - Ok(repo .commit( Some("HEAD"), &signature, &signature, - &msg, + msg, &tree, parents.as_slice(), )? .into()) } -/// this does not run any git hooks, git-hooks have to be executed manually, checkout `hooks_commit_msg` for example -pub fn commit(repo_path: &RepoPath, msg: &str) -> Result<CommitId> { - do_commit(repo_path, msg, false) -} - -/// Do a commit including the sign-off option -/// -/// Refer to [git documentation](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--s) -pub fn commit_with_signoff( - repo_path: &RepoPath, - msg: &str, -) -> Result<CommitId> { - do_commit(repo_path, msg, true) -} - /// Tag a commit. /// /// This function will return an `Err(…)` variant if the tag’s name is refused @@ -168,11 +133,9 @@ mod tests { LogWalker, }; use commit::{amend, tag_commit}; - use git2::{Repository, Signature}; + use git2::Repository; use std::{fs::File, io::Write, path::Path}; - use super::add_sign_off; - fn count_commits(repo: &Repository, max: usize) -> usize { let mut items = Vec::new(); let mut walk = LogWalker::new(repo, max).unwrap(); @@ -421,16 +384,4 @@ mod tests { Ok(()) } - - #[test] - fn test_add_sign_off_to_commit_msg() { - let in_msg = "test commit"; - let signature = - Signature::now("MyName", "my@mail.com").unwrap(); - - let expected = - format!("{in_msg}\nSigned-off-by MyName <my@mail.com>"); - let result = add_sign_off(in_msg, &signature); - assert_eq!(expected, result); - } } diff --git a/asyncgit/src/sync/mod.rs b/asyncgit/src/sync/mod.rs index a626bfec2e..a7bf7d64ed 100644 --- a/asyncgit/src/sync/mod.rs +++ b/asyncgit/src/sync/mod.rs @@ -43,7 +43,7 @@ pub use branch::{ merge_rebase::merge_upstream_rebase, rename::rename_branch, validate_branch_name, BranchCompare, BranchDetails, BranchInfo, }; -pub use commit::{amend, commit, commit_with_signoff, tag_commit}; +pub use commit::{amend, commit, tag_commit}; pub use commit_details::{ get_commit_details, CommitDetails, CommitMessage, CommitSignature, }; From ec0b5955d38b4db52333a071606f4e41311301cc Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Tue, 25 Jul 2023 22:09:13 +0200 Subject: [PATCH 12/13] fix(changelog): format Signed-off-by Dominik Tacke <tacdom+github@gmail.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c25dc867f..f9005d557c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added * support 'n'/'p' key to move to the next/prev hunk in diff component [[@hamflx](https://github.com/hamflx)] ([#1523](https://github.com/extrawurst/gitui/issues/1523)) * simplify theme overrides [[@cruessler](https://github.com/cruessler)] ([#1367](https://github.com/extrawurst/gitui/issues/1367)) -* support for sign-off of commits [#1757](https://github.com/extrawurst/gitui/issues/1757) +* support for sign-off of commits [[@domtac](https://github.com/domtac)]([#1757](https://github.com/extrawurst/gitui/issues/1757)) ### Fixes * fix commit dialog char count for multibyte characters ([#1726](https://github.com/extrawurst/gitui/issues/1726)) From 0d2d578304f78d68d62ec161fdeb7fb0c09efa66 Mon Sep 17 00:00:00 2001 From: Dominik Tacke <tacdom+github@gmail.com> Date: Tue, 25 Jul 2023 22:11:13 +0200 Subject: [PATCH 13/13] refactor: build in proposed changes Signed-off-by Dominik Tacke <tacdom+github@gmail.com> --- src/components/commit.rs | 26 ++++++++++---------------- src/strings.rs | 3 --- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/components/commit.rs b/src/components/commit.rs index bb77eee2e6..586dbb2569 100644 --- a/src/components/commit.rs +++ b/src/components/commit.rs @@ -7,8 +7,7 @@ use crate::{ keys::{key_match, SharedKeyConfig}, options::SharedOptions, queue::{InternalEvent, NeedsUpdate, Queue}, - strings::{self, commit_title_signoff}, - try_or_popup, + strings, try_or_popup, ui::style::SharedTheme, }; use anyhow::{bail, Ok, Result}; @@ -58,7 +57,6 @@ pub struct CommitComponent { commit_msg_history_idx: usize, options: SharedOptions, verify: bool, - sign_off: bool, } const FIRST_LINE_LIMIT: usize = 50; @@ -90,7 +88,6 @@ impl CommitComponent { commit_msg_history_idx: 0, options, verify: true, - sign_off: false, } } @@ -261,10 +258,6 @@ impl CommitComponent { let mut msg = message_prettify(msg, Some(b'#'))?; - if self.sign_off { - msg = self.add_sign_off(&msg)?; - } - if verify { // run commit message check hook - can reject commit if let HookResult::NotOk(e) = @@ -350,12 +343,11 @@ impl CommitComponent { Ok(()) } - fn toggle_signoff(&mut self) { - self.sign_off = !self.sign_off; - if self.sign_off { - self.input.set_title(commit_title_signoff()); - } else { - self.input.set_title(strings::commit_title()); + fn signoff_commit(&mut self) { + let msg = self.input.get_text(); + let signed_msg = self.add_sign_off(msg); + if let std::result::Result::Ok(signed_msg) = signed_msg { + self.input.set_text(signed_msg); } } fn toggle_verify(&mut self) { @@ -450,7 +442,9 @@ impl CommitComponent { let mut msg = msg.to_owned(); if let (Some(user), Some(mail)) = (user, mail) { - msg.push_str(&format!("\nSigned-off-by {user} <{mail}>")); + msg.push_str(&format!( + "\n\nSigned-off-by {user} <{mail}>" + )); } Ok(msg) @@ -580,7 +574,7 @@ impl Component for CommitComponent { e, self.key_config.keys.toggle_signoff, ) { - self.toggle_signoff(); + self.signoff_commit(); } // stop key event propagation return Ok(EventState::Consumed); diff --git a/src/strings.rs b/src/strings.rs index 6477906d31..1f856b9c5d 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -117,9 +117,6 @@ pub fn commit_title_revert() -> String { pub fn commit_title_amend() -> String { "Commit (Amend)".to_string() } -pub fn commit_title_signoff() -> String { - "Commit (Sign-off)".to_string() -} pub fn commit_msg(_key_config: &SharedKeyConfig) -> String { "type commit message..".to_string() }