diff --git a/asyncgit/src/sync/commit.rs b/asyncgit/src/sync/commit.rs index 171b375e..80f0b5db 100644 --- a/asyncgit/src/sync/commit.rs +++ b/asyncgit/src/sync/commit.rs @@ -1,5 +1,6 @@ -use super::{utils::repo, CommitId}; +use super::{get_head, utils::repo, CommitId}; use crate::error::Result; +use git2::{ErrorCode, Repository, Signature}; use scopetime::scope_time; /// @@ -29,13 +30,65 @@ pub fn amend( Ok(CommitId::new(new_id)) } +/// Wrap Repository::signature to allow unknown user.name. +/// +/// See . +fn signature_allow_undefined_name( + repo: &Repository, +) -> std::result::Result, git2::Error> { + match repo.signature() { + Err(e) if e.code() == ErrorCode::NotFound => { + let config = repo.config()?; + Signature::now( + config.get_str("user.name").unwrap_or("unknown"), + config.get_str("user.email")?, + ) + } + + v => v, + } +} + +/// this does not run any git hooks +pub fn commit(repo_path: &str, msg: &str) -> Result { + scope_time!("commit"); + + let repo = repo(repo_path)?; + + let signature = signature_allow_undefined_name(&repo)?; + let mut index = repo.index()?; + let tree_id = index.write_tree()?; + let tree = repo.find_tree(tree_id)?; + + let parents = if let Ok(id) = get_head(repo_path) { + vec![repo.find_commit(id.into())?] + } else { + Vec::new() + }; + + let parents = parents.iter().collect::>(); + + Ok(repo + .commit( + Some("HEAD"), + &signature, + &signature, + msg, + &tree, + parents.as_slice(), + )? + .into()) +} + #[cfg(test)] mod tests { use crate::error::Result; use crate::sync::{ commit, get_commit_details, get_commit_files, stage_add_file, - tests::repo_init_empty, utils::get_head, LogWalker, + tests::{get_statuses, repo_init, repo_init_empty}, + utils::get_head, + LogWalker, }; use commit::amend; use git2::Repository; @@ -48,6 +101,54 @@ mod tests { items.len() } + #[test] + fn test_commit() { + let file_path = Path::new("foo"); + let (_td, repo) = repo_init().unwrap(); + let root = repo.path().parent().unwrap(); + let repo_path = root.as_os_str().to_str().unwrap(); + + File::create(&root.join(file_path)) + .unwrap() + .write_all(b"test\nfoo") + .unwrap(); + + assert_eq!(get_statuses(repo_path), (1, 0)); + + stage_add_file(repo_path, file_path).unwrap(); + + assert_eq!(get_statuses(repo_path), (0, 1)); + + commit(repo_path, "commit msg").unwrap(); + + assert_eq!(get_statuses(repo_path), (0, 0)); + } + + #[test] + fn test_commit_in_empty_repo() { + let file_path = Path::new("foo"); + let (_td, repo) = repo_init_empty().unwrap(); + let root = repo.path().parent().unwrap(); + let repo_path = root.as_os_str().to_str().unwrap(); + + assert_eq!(get_statuses(repo_path), (0, 0)); + + File::create(&root.join(file_path)) + .unwrap() + .write_all(b"test\nfoo") + .unwrap(); + + assert_eq!(get_statuses(repo_path), (1, 0)); + + stage_add_file(repo_path, file_path).unwrap(); + + assert_eq!(get_statuses(repo_path), (0, 1)); + + commit(repo_path, "commit msg").unwrap(); + + assert_eq!(get_statuses(repo_path), (0, 0)); + } + #[test] fn test_amend() -> Result<()> { let file_path1 = Path::new("foo"); diff --git a/asyncgit/src/sync/mod.rs b/asyncgit/src/sync/mod.rs index 58b7f5f9..1120bcad 100644 --- a/asyncgit/src/sync/mod.rs +++ b/asyncgit/src/sync/mod.rs @@ -17,7 +17,7 @@ mod tags; pub mod utils; pub use branch::get_branch_name; -pub use commit::amend; +pub use commit::{amend, commit}; pub use commit_details::{get_commit_details, CommitDetails}; pub use commit_files::get_commit_files; pub use commits_info::{get_commits_info, CommitId, CommitInfo}; @@ -30,8 +30,8 @@ pub use reset::{reset_stage, reset_workdir}; pub use stash::{get_stashes, stash_apply, stash_drop, stash_save}; pub use tags::{get_tags, Tags}; pub use utils::{ - commit, get_head, is_bare_repo, is_repo, stage_add_all, - stage_add_file, stage_addremoved, + get_head, is_bare_repo, is_repo, stage_add_all, stage_add_file, + stage_addremoved, }; #[cfg(test)] diff --git a/asyncgit/src/sync/reset.rs b/asyncgit/src/sync/reset.rs index bfdd7980..93c6eb05 100644 --- a/asyncgit/src/sync/reset.rs +++ b/asyncgit/src/sync/reset.rs @@ -43,11 +43,12 @@ mod tests { use super::{reset_stage, reset_workdir}; use crate::error::Result; use crate::sync::{ + commit, status::{get_status, StatusType}, tests::{ debug_cmd_print, get_statuses, repo_init, repo_init_empty, }, - utils::{commit, stage_add_all, stage_add_file}, + utils::{stage_add_all, stage_add_file}, }; use std::{ fs::{self, File}, diff --git a/asyncgit/src/sync/utils.rs b/asyncgit/src/sync/utils.rs index fae81f97..6292a2a8 100644 --- a/asyncgit/src/sync/utils.rs +++ b/asyncgit/src/sync/utils.rs @@ -66,37 +66,6 @@ pub fn get_head_repo(repo: &Repository) -> Result { } } -/// this does not run any git hooks -pub fn commit(repo_path: &str, msg: &str) -> Result { - scope_time!("commit"); - - let repo = repo(repo_path)?; - - let signature = repo.signature()?; - let mut index = repo.index()?; - let tree_id = index.write_tree()?; - let tree = repo.find_tree(tree_id)?; - - let parents = if let Ok(id) = get_head(repo_path) { - vec![repo.find_commit(id.into())?] - } else { - Vec::new() - }; - - let parents = parents.iter().collect::>(); - - Ok(repo - .commit( - Some("HEAD"), - &signature, - &signature, - msg, - &tree, - parents.as_slice(), - )? - .into()) -} - /// add a file diff from workingdir to stage (will not add removed files see `stage_addremoved`) pub fn stage_add_file(repo_path: &str, path: &Path) -> Result<()> { scope_time!("stage_add_file"); @@ -143,6 +112,7 @@ pub fn stage_addremoved(repo_path: &str, path: &Path) -> Result<()> { mod tests { use super::*; use crate::sync::{ + commit, status::{get_status, StatusType}, tests::{ debug_cmd_print, get_statuses, repo_init, repo_init_empty, @@ -154,54 +124,6 @@ mod tests { path::Path, }; - #[test] - fn test_commit() { - let file_path = Path::new("foo"); - let (_td, repo) = repo_init().unwrap(); - let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); - - File::create(&root.join(file_path)) - .unwrap() - .write_all(b"test\nfoo") - .unwrap(); - - assert_eq!(get_statuses(repo_path), (1, 0)); - - stage_add_file(repo_path, file_path).unwrap(); - - assert_eq!(get_statuses(repo_path), (0, 1)); - - commit(repo_path, "commit msg").unwrap(); - - assert_eq!(get_statuses(repo_path), (0, 0)); - } - - #[test] - fn test_commit_in_empty_repo() { - let file_path = Path::new("foo"); - let (_td, repo) = repo_init_empty().unwrap(); - let root = repo.path().parent().unwrap(); - let repo_path = root.as_os_str().to_str().unwrap(); - - assert_eq!(get_statuses(repo_path), (0, 0)); - - File::create(&root.join(file_path)) - .unwrap() - .write_all(b"test\nfoo") - .unwrap(); - - assert_eq!(get_statuses(repo_path), (1, 0)); - - stage_add_file(repo_path, file_path).unwrap(); - - assert_eq!(get_statuses(repo_path), (0, 1)); - - commit(repo_path, "commit msg").unwrap(); - - assert_eq!(get_statuses(repo_path), (0, 0)); - } - #[test] fn test_stage_add_smoke() { let file_path = Path::new("foo");