Skip to content

Commit f09c2f0

Browse files
committed
Use get_entry instead of get_str
1 parent 530e077 commit f09c2f0

File tree

3 files changed

+124
-9
lines changed

3 files changed

+124
-9
lines changed

asyncgit/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! asyncgit
22
3-
#![forbid(unsafe_code)]
43
#![forbid(missing_docs)]
4+
#![deny(unsafe_code)]
55
#![deny(unused_imports)]
66
#![deny(clippy::all)]
77
#![deny(clippy::unwrap_used)]

asyncgit/src/sync/commit.rs

+97-8
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,24 @@ pub fn amend(
3636
fn signature_allow_undefined_name(
3737
repo: &Repository,
3838
) -> std::result::Result<Signature<'_>, git2::Error> {
39-
match repo.signature() {
40-
Err(e) if e.code() == ErrorCode::NotFound => {
39+
let signature = repo.signature();
40+
41+
if let Err(ref e) = signature {
42+
if e.code() == ErrorCode::NotFound {
4143
let config = repo.config()?;
42-
Signature::now(
43-
config.get_str("user.name").unwrap_or("unknown"),
44-
config.get_str("user.email")?,
45-
)
46-
}
4744

48-
v => v,
45+
if let (Err(_), Ok(email_entry)) = (
46+
config.get_entry("user.name"),
47+
config.get_entry("user.email"),
48+
) {
49+
if let Some(email) = email_entry.value() {
50+
return Signature::now("unknown", email);
51+
}
52+
};
53+
}
4954
}
55+
56+
signature
5057
}
5158

5259
/// this does not run any git hooks
@@ -245,4 +252,86 @@ mod tests {
245252

246253
Ok(())
247254
}
255+
256+
/// Beware: this test has to be run with a `$HOME/.gitconfig` that has
257+
/// `user.email` not set. Otherwise, git falls back to the value of
258+
/// `user.email` in `$HOME/.gitconfig` and this test fails.
259+
///
260+
/// As of February 2021, `repo_init_empty` sets all git config locations
261+
/// to an empty temporary directory, so this constraint is met.
262+
#[test]
263+
fn test_empty_email() -> Result<()> {
264+
let file_path = Path::new("foo");
265+
let (_td, repo) = repo_init_empty().unwrap();
266+
let root = repo.path().parent().unwrap();
267+
let repo_path = root.as_os_str().to_str().unwrap();
268+
269+
File::create(&root.join(file_path))?
270+
.write_all(b"test\nfoo")?;
271+
272+
stage_add_file(repo_path, file_path)?;
273+
274+
repo.config()?.remove("user.email")?;
275+
276+
let error = commit(repo_path, "commit msg");
277+
278+
assert!(matches!(error, Err(_)));
279+
280+
repo.config()?.set_str("user.email", "email")?;
281+
282+
let success = commit(repo_path, "commit msg");
283+
284+
assert!(matches!(success, Ok(_)));
285+
assert_eq!(count_commits(&repo, 10), 1);
286+
287+
let details =
288+
get_commit_details(repo_path, success.unwrap()).unwrap();
289+
290+
assert_eq!(details.author.name, "name");
291+
assert_eq!(details.author.email, "email");
292+
293+
Ok(())
294+
}
295+
296+
/// See comment to `test_empty_email`.
297+
#[test]
298+
fn test_empty_name() -> Result<()> {
299+
let file_path = Path::new("foo");
300+
let (_td, repo) = repo_init_empty().unwrap();
301+
let root = repo.path().parent().unwrap();
302+
let repo_path = root.as_os_str().to_str().unwrap();
303+
304+
File::create(&root.join(file_path))?
305+
.write_all(b"test\nfoo")?;
306+
307+
stage_add_file(repo_path, file_path)?;
308+
309+
repo.config()?.remove("user.name")?;
310+
311+
let mut success = commit(repo_path, "commit msg");
312+
313+
assert!(matches!(success, Ok(_)));
314+
assert_eq!(count_commits(&repo, 10), 1);
315+
316+
let mut details =
317+
get_commit_details(repo_path, success.unwrap()).unwrap();
318+
319+
assert_eq!(details.author.name, "unknown");
320+
assert_eq!(details.author.email, "email");
321+
322+
repo.config()?.set_str("user.name", "name")?;
323+
324+
success = commit(repo_path, "commit msg");
325+
326+
assert!(matches!(success, Ok(_)));
327+
assert_eq!(count_commits(&repo, 10), 2);
328+
329+
details =
330+
get_commit_details(repo_path, success.unwrap()).unwrap();
331+
332+
assert_eq!(details.author.name, "name");
333+
assert_eq!(details.author.email, "email");
334+
335+
Ok(())
336+
}
248337
}

asyncgit/src/sync/mod.rs

+26
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,32 @@ mod tests {
6060
use std::process::Command;
6161
use tempfile::TempDir;
6262

63+
/// Calling `set_search_path` with an empty directory makes sure that there
64+
/// is no git config interfering with our tests (for example user-local
65+
/// `.gitconfig`).
66+
#[allow(unsafe_code)]
67+
fn sandbox_config_files() {
68+
use git2::{opts::set_search_path, ConfigLevel};
69+
use std::sync::Once;
70+
71+
static INIT: Once = Once::new();
72+
73+
// Adapted from https://github.com/rust-lang/cargo/pull/9035
74+
INIT.call_once(|| unsafe {
75+
let temp_dir = TempDir::new().unwrap();
76+
let path = temp_dir.path();
77+
78+
set_search_path(ConfigLevel::System, &path).unwrap();
79+
set_search_path(ConfigLevel::Global, &path).unwrap();
80+
set_search_path(ConfigLevel::XDG, &path).unwrap();
81+
set_search_path(ConfigLevel::ProgramData, &path).unwrap();
82+
});
83+
}
84+
6385
///
6486
pub fn repo_init_empty() -> Result<(TempDir, Repository)> {
87+
sandbox_config_files();
88+
6589
let td = TempDir::new()?;
6690
let repo = Repository::init(td.path())?;
6791
{
@@ -74,6 +98,8 @@ mod tests {
7498

7599
///
76100
pub fn repo_init() -> Result<(TempDir, Repository)> {
101+
sandbox_config_files();
102+
77103
let td = TempDir::new()?;
78104
let repo = Repository::init(td.path())?;
79105
{

0 commit comments

Comments
 (0)