forked from GitoxideLabs/gitoxide
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: make certain git-credential helper implementations work from cmd…
…-prompts on Windows (GitoxideLabs#1103) On prompts, typically only `git.exe` is available, but no shell (i.e. `sh`). Thus, we have to prefer going through `git.exe` to launch credential helpers and possibly split simple arguments ourselves.
- Loading branch information
Showing
4 changed files
with
134 additions
and
38 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,102 @@ | ||
use gix_credentials::{program::Kind, Program}; | ||
use gix_credentials::{helper, program::Kind, Program}; | ||
|
||
#[cfg(windows)] | ||
const GIT: &str = "git.exe"; | ||
#[cfg(not(windows))] | ||
const GIT: &str = "git"; | ||
|
||
#[cfg(windows)] | ||
const SH: &str = "sh"; | ||
#[cfg(not(windows))] | ||
const SH: &str = "/bin/sh"; | ||
|
||
#[test] | ||
fn script() { | ||
assert!( | ||
matches!(Program::from_custom_definition("!exe").kind, Kind::ExternalShellScript(script) if script == "exe") | ||
fn empty() { | ||
let prog = Program::from_custom_definition(""); | ||
assert!(matches!(&prog.kind, Kind::ExternalName { name_and_args } if name_and_args == "")); | ||
assert_eq!( | ||
format!("{:?}", prog.to_command(&helper::Action::Store("egal".into()))), | ||
format!(r#""{GIT}" "credential-" "store""#), | ||
"not useful, but allowed, would have to be caught elsewhere" | ||
); | ||
} | ||
|
||
#[test] | ||
fn simple_script_in_path() { | ||
let prog = Program::from_custom_definition("!exe"); | ||
assert!(matches!(&prog.kind, Kind::ExternalShellScript(script) if script == "exe")); | ||
assert_eq!( | ||
format!("{:?}", prog.to_command(&helper::Action::Store("egal".into()))), | ||
r#""exe" "store""#, | ||
"it didn't detect anything shell-scripty, and thus doesn't use a shell" | ||
); | ||
} | ||
|
||
#[test] | ||
fn name_with_args() { | ||
let input = "name --arg --bar=\"a b\""; | ||
let expected = "git credential-name --arg --bar=\"a b\""; | ||
assert!( | ||
matches!(Program::from_custom_definition(input).kind, Kind::ExternalName{name_and_args} if name_and_args == expected) | ||
let prog = Program::from_custom_definition(input); | ||
assert!(matches!(&prog.kind, Kind::ExternalName{name_and_args} if name_and_args == input)); | ||
assert_eq!( | ||
format!("{:?}", prog.to_command(&helper::Action::Store("egal".into()))), | ||
format!(r#""{GIT}" "credential-name" "--arg" "--bar=a b" "store""#) | ||
); | ||
} | ||
|
||
#[test] | ||
fn name_with_special_args() { | ||
let input = "name --arg --bar=~/folder/in/home"; | ||
let prog = Program::from_custom_definition(input); | ||
assert!(matches!(&prog.kind, Kind::ExternalName{name_and_args} if name_and_args == input)); | ||
assert_eq!( | ||
format!("{:?}", prog.to_command(&helper::Action::Store("egal".into()))), | ||
format!(r#""{SH}" "-c" "{GIT} credential-name --arg --bar=~/folder/in/home \"$@\"" "--" "store""#) | ||
); | ||
} | ||
|
||
#[test] | ||
fn name() { | ||
let input = "name"; | ||
let expected = "git credential-name"; | ||
assert!( | ||
matches!(Program::from_custom_definition(input).kind, Kind::ExternalName{name_and_args} if name_and_args == expected) | ||
let prog = Program::from_custom_definition(input); | ||
assert!(matches!(&prog.kind, Kind::ExternalName{name_and_args} if name_and_args == input)); | ||
assert_eq!( | ||
format!("{:?}", prog.to_command(&helper::Action::Store("egal".into()))), | ||
format!(r#""{GIT}" "credential-name" "store""#), | ||
"we detect that this can run without shell, which is also more portable on windows" | ||
); | ||
} | ||
|
||
#[test] | ||
fn path_with_args() { | ||
fn path_with_args_that_definitely_need_shell() { | ||
let input = "/abs/name --arg --bar=\"a b\""; | ||
assert!( | ||
matches!(Program::from_custom_definition(input).kind, Kind::ExternalPath{path_and_args} if path_and_args == input) | ||
let prog = Program::from_custom_definition(input); | ||
assert!(matches!(&prog.kind, Kind::ExternalPath{path_and_args} if path_and_args == input)); | ||
assert_eq!( | ||
format!("{:?}", prog.to_command(&helper::Action::Store("egal".into()))), | ||
format!(r#""{SH}" "-c" "/abs/name --arg --bar=\"a b\" \"$@\"" "--" "store""#) | ||
); | ||
} | ||
|
||
#[test] | ||
fn path() { | ||
fn path_without_args() { | ||
let input = "/abs/name"; | ||
assert!( | ||
matches!(Program::from_custom_definition(input).kind, Kind::ExternalPath{path_and_args} if path_and_args == input) | ||
let prog = Program::from_custom_definition(input); | ||
assert!(matches!(&prog.kind, Kind::ExternalPath{path_and_args} if path_and_args == input)); | ||
assert_eq!( | ||
format!("{:?}", prog.to_command(&helper::Action::Store("egal".into()))), | ||
r#""/abs/name" "store""#, | ||
"no shell is used" | ||
); | ||
} | ||
|
||
#[test] | ||
fn path_with_simple_args() { | ||
let input = "/abs/name a b"; | ||
let prog = Program::from_custom_definition(input); | ||
assert!(matches!(&prog.kind, Kind::ExternalPath{path_and_args} if path_and_args == input)); | ||
assert_eq!( | ||
format!("{:?}", prog.to_command(&helper::Action::Store("egal".into()))), | ||
format!(r#""{SH}" "-c" "/abs/name a b \"$@\"" "--" "store""#), | ||
"a shell is used as well because there are arguments, and we don't do splitting ourselves. On windows, this can be a problem." | ||
); | ||
} |