From 807bc10545501808ca319b65595848e8fba28c91 Mon Sep 17 00:00:00 2001 From: bsdinis Date: Thu, 2 Jan 2025 18:35:36 +0000 Subject: [PATCH] remove feature flag and enable CLI --shell arg and config option to activate shelling out to git --- Cargo.lock | 26 +++++ Cargo.toml | 1 + cli/Cargo.toml | 2 +- cli/src/commands/git/clone.rs | 10 +- cli/src/commands/git/fetch.rs | 7 +- cli/src/commands/git/push.rs | 15 ++- cli/src/git_util.rs | 31 ++++- cli/tests/cli-reference@.md.snap | 4 + cli/tests/test_git_clone.rs | 75 +++++++++++- cli/tests/test_git_fetch.rs | 151 ++++++++++++++++++++++++ cli/tests/test_git_push.rs | 194 +++++++++++++++++++++++++++++++ lib/Cargo.toml | 2 +- lib/src/config/misc.toml | 1 + lib/src/git.rs | 94 ++++++++++----- lib/tests/test_git.rs | 112 ++++++++++++++++++ 15 files changed, 675 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06757c0bf6..974fef236a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -685,6 +685,17 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "duplicate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97af9b5f014e228b33e77d75ee0e6e87960124f0f4b16337b586a6bec91867b1" +dependencies = [ + "heck", + "proc-macro2", + "proc-macro2-diagnostics", +] + [[package]] name = "either" version = "1.13.0" @@ -1960,6 +1971,7 @@ dependencies = [ "crossterm", "dirs", "dunce", + "duplicate", "futures 0.3.31", "git2", "gix", @@ -2013,6 +2025,7 @@ dependencies = [ "criterion", "digest", "dunce", + "duplicate", "either", "futures 0.3.31", "git2", @@ -2605,6 +2618,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "version_check", + "yansi", +] + [[package]] name = "prodash" version = "29.0.0" diff --git a/Cargo.toml b/Cargo.toml index da9322272d..da3a5d8fd2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ crossterm = { version = "0.27", default-features = false } digest = "0.10.7" dirs = "5.0.1" dunce = "1.0.5" +duplicate = "2.0.0" either = "1.13.0" futures = "0.3.31" git2 = { version = "0.19.0", features = [ diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 8f658bee06..209d5a85d1 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -101,6 +101,7 @@ anyhow = { workspace = true } assert_cmd = { workspace = true } assert_matches = { workspace = true } async-trait = { workspace = true } +duplicate = { workspace = true } insta = { workspace = true } test-case = { workspace = true } testutils = { workspace = true } @@ -115,7 +116,6 @@ packaging = ["gix-max-performance"] test-fakes = ["jj-lib/testing"] vendored-openssl = ["git2/vendored-openssl", "jj-lib/vendored-openssl"] watchman = ["jj-lib/watchman"] -shell = [] [package.metadata.binstall] # The archive name is jj, not jj-cli. Also, `cargo binstall` gets diff --git a/cli/src/commands/git/clone.rs b/cli/src/commands/git/clone.rs index a05cedafc5..d300e06f0d 100644 --- a/cli/src/commands/git/clone.rs +++ b/cli/src/commands/git/clone.rs @@ -34,6 +34,7 @@ use crate::command_error::user_error; use crate::command_error::user_error_with_message; use crate::command_error::CommandError; use crate::commands::git::maybe_add_gitignore; +use crate::git_util::get_config_git_shell; use crate::git_util::get_git_repo; use crate::git_util::map_git_error; use crate::git_util::print_git_import_stats; @@ -63,6 +64,9 @@ pub struct GitCloneArgs { /// Create a shallow clone of the given depth #[arg(long)] depth: Option, + /// Run git clone as a forked git process + #[arg(long)] + shell: bool, } fn absolute_git_source(cwd: &Path, source: &str) -> Result { @@ -129,6 +133,7 @@ pub fn cmd_git_clone( // `/some/path/.` let canonical_wc_path = dunce::canonicalize(&wc_path) .map_err(|err| user_error_with_message(format!("Failed to create {wc_path_str}"), err))?; + let shell = args.shell || get_config_git_shell(command)?; let clone_result = do_git_clone( ui, command, @@ -137,6 +142,7 @@ pub fn cmd_git_clone( remote_name, &source, &canonical_wc_path, + shell, ); if clone_result.is_err() { let clean_up_dirs = || -> io::Result<()> { @@ -196,6 +202,7 @@ fn do_git_clone( remote_name: &str, source: &str, wc_path: &Path, + shell: bool, ) -> Result<(WorkspaceCommandHelper, GitFetchStats), CommandError> { let (workspace, repo) = if colocate { Workspace::init_colocated_git(command.settings(), wc_path)? @@ -214,7 +221,7 @@ fn do_git_clone( let mut fetch_tx = workspace_command.start_transaction(); let git_settings = command.settings().git_settings()?; - let stats = with_remote_git_callbacks(ui, None, |cb| { + let stats = with_remote_git_callbacks(ui, None, shell, |cb| { git::fetch( fetch_tx.repo_mut(), &git_repo, @@ -223,6 +230,7 @@ fn do_git_clone( cb, &git_settings, depth, + shell, ) }) .map_err(|err| match err { diff --git a/cli/src/commands/git/fetch.rs b/cli/src/commands/git/fetch.rs index bf1226d436..0f115e8877 100644 --- a/cli/src/commands/git/fetch.rs +++ b/cli/src/commands/git/fetch.rs @@ -23,6 +23,7 @@ use crate::cli_util::CommandHelper; use crate::command_error::CommandError; use crate::commands::git::get_single_remote; use crate::complete; +use crate::git_util::get_config_git_shell; use crate::git_util::get_git_repo; use crate::git_util::git_fetch; use crate::ui::Ui; @@ -60,6 +61,9 @@ pub struct GitFetchArgs { /// Fetch from all remotes #[arg(long, conflicts_with = "remotes")] all_remotes: bool, + /// Run git fetch as a forked git process + #[arg(long)] + shell: bool, } #[tracing::instrument(skip(ui, command))] @@ -69,6 +73,7 @@ pub fn cmd_git_fetch( args: &GitFetchArgs, ) -> Result<(), CommandError> { let mut workspace_command = command.workspace_helper(ui)?; + let shell_flag = args.shell || get_config_git_shell(command)?; let git_repo = get_git_repo(workspace_command.repo().store())?; let remotes = if args.all_remotes { get_all_remotes(&git_repo)? @@ -78,7 +83,7 @@ pub fn cmd_git_fetch( args.remotes.clone() }; let mut tx = workspace_command.start_transaction(); - git_fetch(ui, &mut tx, &git_repo, &remotes, &args.branch)?; + git_fetch(ui, &mut tx, &git_repo, &remotes, &args.branch, shell_flag)?; tx.finish( ui, format!("fetch from git remote(s) {}", remotes.iter().join(",")), diff --git a/cli/src/commands/git/push.rs b/cli/src/commands/git/push.rs index 92e014f302..777ecb71e5 100644 --- a/cli/src/commands/git/push.rs +++ b/cli/src/commands/git/push.rs @@ -49,6 +49,7 @@ use crate::command_error::CommandError; use crate::commands::git::get_single_remote; use crate::complete; use crate::formatter::Formatter; +use crate::git_util::get_config_git_shell; use crate::git_util::get_git_repo; use crate::git_util::map_git_error; use crate::git_util::with_remote_git_callbacks; @@ -142,6 +143,9 @@ pub struct GitPushArgs { /// Only display what will change on the remote #[arg(long)] dry_run: bool, + /// Run git push as a forked git process + #[arg(long)] + shell: bool, } fn make_bookmark_term(bookmark_names: &[impl fmt::Display]) -> String { @@ -166,6 +170,7 @@ pub fn cmd_git_push( args: &GitPushArgs, ) -> Result<(), CommandError> { let mut workspace_command = command.workspace_helper(ui)?; + let shell_flag = args.shell || get_config_git_shell(command)?; let git_repo = get_git_repo(workspace_command.repo().store())?; let remote = if let Some(name) = &args.remote { @@ -313,9 +318,13 @@ pub fn cmd_git_push( let mut sideband_progress_callback = |progress_message: &[u8]| { _ = writer.write(ui, progress_message); }; - with_remote_git_callbacks(ui, Some(&mut sideband_progress_callback), |cb| { - git::push_branches(tx.repo_mut(), &git_repo, &remote, &targets, cb) - }) + + with_remote_git_callbacks( + ui, + Some(&mut sideband_progress_callback), + shell_flag, + |cb| git::push_branches(tx.repo_mut(), &git_repo, &remote, &targets, cb, shell_flag), + ) .map_err(|err| match err { GitPushError::InternalGitError(err) => map_git_error(err), GitPushError::RefInUnexpectedLocation(refs) => user_error_with_hint( diff --git a/cli/src/git_util.rs b/cli/src/git_util.rs index 702d0ad031..4fb9edd74c 100644 --- a/cli/src/git_util.rs +++ b/cli/src/git_util.rs @@ -24,6 +24,7 @@ use std::process::Stdio; use std::time::Instant; use itertools::Itertools; +use jj_lib::config::ConfigGetError; use jj_lib::git; use jj_lib::git::FailedRefExport; use jj_lib::git::FailedRefExportReason; @@ -40,6 +41,7 @@ use jj_lib::str_util::StringPattern; use jj_lib::workspace::Workspace; use unicode_width::UnicodeWidthStr; +use crate::cli_util::CommandHelper; use crate::cli_util::WorkspaceCommandTransaction; use crate::command_error::user_error; use crate::command_error::user_error_with_hint; @@ -257,11 +259,14 @@ type SidebandProgressCallback<'a> = &'a mut dyn FnMut(&[u8]); pub fn with_remote_git_callbacks( ui: &Ui, sideband_progress_callback: Option>, + shell: bool, f: impl FnOnce(git::RemoteCallbacks<'_>) -> T, ) -> T { - let mut callbacks = git::RemoteCallbacks::default(); - let mut progress_callback = None; - if !cfg!(feature = "shell") { + if shell { + f(git::RemoteCallbacks::default()) + } else { + let mut callbacks = git::RemoteCallbacks::default(); + let mut progress_callback = None; if let Some(mut output) = ui.progress_output() { let mut progress = Progress::new(Instant::now()); progress_callback = Some(move |x: &git::Progress| { @@ -282,8 +287,6 @@ pub fn with_remote_git_callbacks( |url: &str| Some((terminal_get_username(ui, url)?, terminal_get_pw(ui, url)?)); callbacks.get_username_password = Some(&mut get_user_pw); f(callbacks) - } else { - f(callbacks) } } @@ -467,11 +470,12 @@ pub fn git_fetch( git_repo: &git2::Repository, remotes: &[String], branch: &[StringPattern], + shell: bool, ) -> Result<(), CommandError> { let git_settings = tx.settings().git_settings()?; for remote in remotes { - let stats = with_remote_git_callbacks(ui, None, |cb| { + let stats = with_remote_git_callbacks(ui, None, shell, |cb| { git::fetch( tx.repo_mut(), git_repo, @@ -480,6 +484,7 @@ pub fn git_fetch( cb, &git_settings, None, + shell, ) }) .map_err(|err| match err { @@ -540,3 +545,17 @@ fn warn_if_branches_not_found( Ok(()) } + +pub(crate) fn get_config_git_shell(command: &CommandHelper) -> Result { + command + .config_env() + .resolve_config(command.raw_config())? + .get::("git.shell") + .or_else(|e| { + if matches!(e, ConfigGetError::NotFound { .. }) { + Ok(false) + } else { + Err(e) + } + }) +} diff --git a/cli/tests/cli-reference@.md.snap b/cli/tests/cli-reference@.md.snap index 49fe4c2156..95026eb3cc 100644 --- a/cli/tests/cli-reference@.md.snap +++ b/cli/tests/cli-reference@.md.snap @@ -1,6 +1,7 @@ --- source: cli/tests/test_generate_md_cli_help.rs description: "AUTO-GENERATED FILE, DO NOT EDIT. This cli reference is generated by a test as an `insta` snapshot. MkDocs includes this snapshot from docs/cli-reference.md." +snapshot_kind: text --- @@ -1073,6 +1074,7 @@ The Git repo will be a bare git repo stored inside the `.jj/` directory. Default value: `origin` * `--colocate` — Whether or not to colocate the Jujutsu repo with the git repo * `--depth ` — Create a shallow clone of the given depth +* `--shell` — Run git clone as a forked git process @@ -1103,6 +1105,7 @@ If a working-copy commit gets abandoned, it will be given a new, empty commit. T This defaults to the `git.fetch` setting. If that is not configured, and if there are multiple remotes, the remote named "origin" will be used. * `--all-remotes` — Fetch from all remotes +* `--shell` — Run git fetch as a forked git process @@ -1186,6 +1189,7 @@ Before the command actually moves, creates, or deletes a remote bookmark, it mak The created bookmark will be tracked automatically. Use the `git.push-bookmark-prefix` setting to change the prefix for generated names. * `--dry-run` — Only display what will change on the remote +* `--shell` — Run git push as a forked git process diff --git a/cli/tests/test_git_clone.rs b/cli/tests/test_git_clone.rs index 24b3fe3cff..b19826527a 100644 --- a/cli/tests/test_git_clone.rs +++ b/cli/tests/test_git_clone.rs @@ -20,6 +20,8 @@ use crate::common::get_stderr_string; use crate::common::get_stdout_string; use crate::common::TestEnvironment; +use duplicate::duplicate_item; + fn set_up_non_empty_git_repo(git_repo: &git2::Repository) { set_up_git_repo_with_file(git_repo, "file"); } @@ -47,10 +49,16 @@ fn set_up_git_repo_with_file(git_repo: &git2::Repository, filename: &str) { git_repo.set_head("refs/heads/main").unwrap(); } +#[duplicate_item( + test_git_clone shell_git_config; + [test_git_clone_shell] ["git.shell = true"]; + [test_git_clone_git2] [""]; +)] #[test] fn test_git_clone() { let test_env = TestEnvironment::default(); test_env.add_config("git.auto-local-bookmark = true"); + test_env.add_config(shell_git_config); let git_repo_path = test_env.env_root().join("source"); let git_repo = git2::Repository::init(git_repo_path).unwrap(); @@ -161,9 +169,15 @@ fn test_git_clone() { "###); } +#[duplicate_item( + test_git_clone_bad_source shell_git_config; + [test_git_clone_bad_source_shell] ["git.shell = true"]; + [test_git_clone_bad_source_git2] [""]; +)] #[test] fn test_git_clone_bad_source() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); let stderr = test_env.jj_cmd_cli_error(test_env.env_root(), &["git", "clone", "", "dest"]); insta::assert_snapshot!(stderr, @r#"Error: local path "" does not specify a path to a repository"#); @@ -179,10 +193,16 @@ fn test_git_clone_bad_source() { "#); } +#[duplicate_item( + test_git_clone_colocate shell_git_config; + [test_git_clone_colocate_shell] ["git.shell = true"]; + [test_git_clone_colocate_git2] [""]; +)] #[test] fn test_git_clone_colocate() { let test_env = TestEnvironment::default(); test_env.add_config("git.auto-local-bookmark = true"); + test_env.add_config(shell_git_config); let git_repo_path = test_env.env_root().join("source"); let git_repo = git2::Repository::init(git_repo_path).unwrap(); @@ -372,9 +392,15 @@ fn test_git_clone_colocate() { "###); } +#[duplicate_item( + test_git_clone_remote_default_bookmark shell_git_config; + [test_git_clone_remote_default_bookmark_shell] ["git.shell = true"]; + [test_git_clone_remote_default_bookmark_git2] [""]; +)] #[test] fn test_git_clone_remote_default_bookmark() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); let git_repo_path = test_env.env_root().join("source"); let git_repo = git2::Repository::init(git_repo_path).unwrap(); set_up_non_empty_git_repo(&git_repo); @@ -468,9 +494,15 @@ fn test_git_clone_remote_default_bookmark() { "###); } +#[duplicate_item( + test_git_clone_ignore_working_copy shell_git_config; + [test_git_clone_ignore_working_copy_shell] ["git.shell = true"]; + [test_git_clone_ignore_working_copy_git2] [""]; +)] #[test] fn test_git_clone_ignore_working_copy() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); let git_repo_path = test_env.env_root().join("source"); let git_repo = git2::Repository::init(git_repo_path).unwrap(); set_up_non_empty_git_repo(&git_repo); @@ -504,9 +536,15 @@ fn test_git_clone_ignore_working_copy() { "##); } +#[duplicate_item( + test_git_clone_at_operation shell_git_config; + [test_git_clone_at_operation_shell] ["git.shell = true"]; + [test_git_clone_at_operation_git2] [""]; +)] #[test] fn test_git_clone_at_operation() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); let git_repo_path = test_env.env_root().join("source"); let git_repo = git2::Repository::init(git_repo_path).unwrap(); set_up_non_empty_git_repo(&git_repo); @@ -520,10 +558,16 @@ fn test_git_clone_at_operation() { "###); } +#[duplicate_item( + test_git_clone_with_remote_name shell_git_config; + [test_git_clone_with_remote_name_shell] ["git.shell = true"]; + [test_git_clone_with_remote_name_git2] [""]; +)] #[test] fn test_git_clone_with_remote_name() { let test_env = TestEnvironment::default(); test_env.add_config("git.auto-local-bookmark = true"); + test_env.add_config(shell_git_config); let git_repo_path = test_env.env_root().join("source"); let git_repo = git2::Repository::init(git_repo_path).unwrap(); set_up_non_empty_git_repo(&git_repo); @@ -544,9 +588,15 @@ fn test_git_clone_with_remote_name() { "#); } +#[duplicate_item( + test_git_clone_trunk_deleted shell_git_config; + [test_git_clone_trunk_deleted_shell] ["git.shell = true"]; + [test_git_clone_trunk_deleted_git2] [""]; +)] #[test] fn test_git_clone_trunk_deleted() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); let git_repo_path = test_env.env_root().join("source"); let git_repo = git2::Repository::init(git_repo_path).unwrap(); set_up_non_empty_git_repo(&git_repo); @@ -586,9 +636,8 @@ fn test_git_clone_trunk_deleted() { "#); } -#[cfg(not(feature = "shell"))] #[test] -fn test_git_clone_with_depth() { +fn test_git_clone_with_depth_git2() { let test_env = TestEnvironment::default(); test_env.add_config("git.auto-local-bookmark = true"); let git_repo_path = test_env.env_root().join("source"); @@ -607,9 +656,13 @@ fn test_git_clone_with_depth() { "#); } -#[cfg(feature = "shell")] +// this test has slightly different behaviour from git2, because it doesn't support shallow clones +// on a local transport +// +// as a byproduct, it also tests shelling out via the cli flag `--shell`, whereas the others go +// through the config #[test] -fn test_git_clone_with_depth() { +fn test_git_clone_with_depth_shell() { let test_env = TestEnvironment::default(); test_env.add_config("git.auto-local-bookmark = true"); let git_repo_path = test_env.env_root().join("source"); @@ -621,7 +674,7 @@ fn test_git_clone_with_depth() { // we check everything works let (stdout, stderr) = test_env.jj_cmd_ok( test_env.env_root(), - &["git", "clone", "--depth", "1", "source", "clone"], + &["git", "clone", "--shell", "--depth", "1", "source", "clone"], ); insta::assert_snapshot!(stdout, @""); insta::assert_snapshot!(stderr, @r#" @@ -644,9 +697,15 @@ fn test_git_clone_with_depth() { insta::assert_snapshot!(stderr, @""); } +#[duplicate_item( + test_git_clone_invalid_immutable_heads shell_git_config; + [test_git_clone_invalid_immutable_heads_shell] ["git.shell = true"]; + [test_git_clone_invalid_immutable_heads_git2] [""]; +)] #[test] fn test_git_clone_invalid_immutable_heads() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); let git_repo_path = test_env.env_root().join("source"); let git_repo = git2::Repository::init(git_repo_path).unwrap(); set_up_non_empty_git_repo(&git_repo); @@ -667,9 +726,15 @@ fn test_git_clone_invalid_immutable_heads() { "#); } +#[duplicate_item( + test_git_clone_malformed shell_git_config; + [test_git_clone_malformed_shell] ["git.shell = true"]; + [test_git_clone_malformed_git2] [""]; +)] #[test] fn test_git_clone_malformed() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); let git_repo_path = test_env.env_root().join("source"); let git_repo = git2::Repository::init(git_repo_path).unwrap(); let clone_path = test_env.env_root().join("clone"); diff --git a/cli/tests/test_git_fetch.rs b/cli/tests/test_git_fetch.rs index b655f834f2..a4cf6ca60f 100644 --- a/cli/tests/test_git_fetch.rs +++ b/cli/tests/test_git_fetch.rs @@ -15,6 +15,8 @@ use std::path::Path; use crate::common::TestEnvironment; +use duplicate::duplicate_item; + /// Creates a remote Git repo containing a bookmark with the same name fn init_git_remote(test_env: &TestEnvironment, remote: &str) { let git_repo_path = test_env.env_root().join(remote); @@ -72,9 +74,15 @@ fn get_log_output(test_env: &TestEnvironment, workspace_root: &Path) -> String { test_env.jj_cmd_success(workspace_root, &["log", "-T", template, "-r", "all()"]) } +#[duplicate_item( + test_git_fetch_with_default_config shell_git_config; + [test_git_fetch_with_default_config_shell] ["git.shell = true"]; + [test_git_fetch_with_default_config_git2] [""]; +)] #[test] fn test_git_fetch_with_default_config() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); add_git_remote(&test_env, &repo_path, "origin"); @@ -85,9 +93,15 @@ fn test_git_fetch_with_default_config() { "###); } +#[duplicate_item( + test_git_fetch_default_remote shell_git_config; + [test_git_fetch_default_remote_shell] ["git.shell = true"]; + [test_git_fetch_default_remote_git2] [""]; +)] #[test] fn test_git_fetch_default_remote() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -100,9 +114,15 @@ fn test_git_fetch_default_remote() { "###); } +#[duplicate_item( + test_git_fetch_single_remote shell_git_config; + [test_git_fetch_single_remote_shell] ["git.shell = true"]; + [test_git_fetch_single_remote_git2] [""]; +)] #[test] fn test_git_fetch_single_remote() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -119,9 +139,15 @@ fn test_git_fetch_single_remote() { "###); } +#[duplicate_item( + test_git_fetch_single_remote_all_remotes_flag shell_git_config; + [test_git_fetch_single_remote_all_remotes_flag_shell] ["git.shell = true"]; + [test_git_fetch_single_remote_all_remotes_flag_git2] [""]; +)] #[test] fn test_git_fetch_single_remote_all_remotes_flag() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -137,9 +163,15 @@ fn test_git_fetch_single_remote_all_remotes_flag() { "###); } +#[duplicate_item( + test_git_fetch_single_remote_from_arg shell_git_config; + [test_git_fetch_single_remote_from_arg_shell] ["git.shell = true"]; + [test_git_fetch_single_remote_from_arg_git2] [""]; +)] #[test] fn test_git_fetch_single_remote_from_arg() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -152,9 +184,15 @@ fn test_git_fetch_single_remote_from_arg() { "###); } +#[duplicate_item( + test_git_fetch_single_remote_from_config shell_git_config; + [test_git_fetch_single_remote_from_config_shell] ["git.shell = true"]; + [test_git_fetch_single_remote_from_config_git2] [""]; + )] #[test] fn test_git_fetch_single_remote_from_config() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -168,9 +206,15 @@ fn test_git_fetch_single_remote_from_config() { "###); } +#[duplicate_item( + test_git_fetch_multiple_remotes shell_git_config; + [test_git_fetch_multiple_remotes_shell] ["git.shell = true"]; + [test_git_fetch_multiple_remotes_git2] [""]; +)] #[test] fn test_git_fetch_multiple_remotes() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -189,9 +233,15 @@ fn test_git_fetch_multiple_remotes() { "###); } +#[duplicate_item( + test_git_fetch_all_remotes shell_git_config; + [test_git_fetch_all_remotes_shell] ["git.shell = true"]; + [test_git_fetch_all_remotes_git2] [""]; +)] #[test] fn test_git_fetch_all_remotes() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -207,9 +257,15 @@ fn test_git_fetch_all_remotes() { "###); } +#[duplicate_item( + test_git_fetch_multiple_remotes_from_config shell_git_config; + [test_git_fetch_multiple_remotes_from_config_shell] ["git.shell = true"]; + [test_git_fetch_multiple_remotes_from_config_git2] [""]; +)] #[test] fn test_git_fetch_multiple_remotes_from_config() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -226,9 +282,15 @@ fn test_git_fetch_multiple_remotes_from_config() { "###); } +#[duplicate_item( + test_git_fetch_nonexistent_remote shell_git_config; + [test_git_fetch_nonexistent_remote_shell] ["git.shell = true"]; + [test_git_fetch_nonexistent_remote_git2] [""]; +)] #[test] fn test_git_fetch_nonexistent_remote() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); add_git_remote(&test_env, &repo_path, "rem1"); @@ -245,9 +307,15 @@ fn test_git_fetch_nonexistent_remote() { insta::assert_snapshot!(get_bookmark_output(&test_env, &repo_path), @""); } +#[duplicate_item( + test_git_fetch_nonexistent_remote_from_config shell_git_config; + [test_git_fetch_nonexistent_remote_from_config_shell] ["git.shell = true"]; + [test_git_fetch_nonexistent_remote_from_config_git2] [""]; +)] #[test] fn test_git_fetch_nonexistent_remote_from_config() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); add_git_remote(&test_env, &repo_path, "rem1"); @@ -262,9 +330,15 @@ fn test_git_fetch_nonexistent_remote_from_config() { insta::assert_snapshot!(get_bookmark_output(&test_env, &repo_path), @""); } +#[duplicate_item( + test_git_fetch_from_remote_named_git shell_git_config; + [test_git_fetch_from_remote_named_git_shell] ["git.shell = true"]; + [test_git_fetch_from_remote_named_git_git2] [""]; +)] #[test] fn test_git_fetch_from_remote_named_git() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); let repo_path = test_env.env_root().join("repo"); init_git_remote(&test_env, "git"); @@ -308,9 +382,15 @@ fn test_git_fetch_from_remote_named_git() { "###); } +#[duplicate_item( + test_git_fetch_prune_before_updating_tips shell_git_config; + [test_git_fetch_prune_before_updating_tips_shell] ["git.shell = true"]; + [test_git_fetch_prune_before_updating_tips_git2] [""]; +)] #[test] fn test_git_fetch_prune_before_updating_tips() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -336,9 +416,15 @@ fn test_git_fetch_prune_before_updating_tips() { "###); } +#[duplicate_item( + test_git_fetch_conflicting_bookmarks shell_git_config; + [test_git_fetch_conflicting_bookmarks_shell] ["git.shell = true"]; + [test_git_fetch_conflicting_bookmarks_git2] [""]; +)] #[test] fn test_git_fetch_conflicting_bookmarks() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -364,9 +450,15 @@ fn test_git_fetch_conflicting_bookmarks() { "###); } +#[duplicate_item( + test_git_fetch_conflicting_bookmarks_colocated shell_git_config; + [test_git_fetch_conflicting_bookmarks_colocated_shell] ["git.shell = true"]; + [test_git_fetch_conflicting_bookmarks_colocated_git2] [""]; +)] #[test] fn test_git_fetch_conflicting_bookmarks_colocated() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); let repo_path = test_env.env_root().join("repo"); let _git_repo = git2::Repository::init(&repo_path).unwrap(); @@ -427,9 +519,15 @@ fn create_trunk2_and_rebase_bookmarks(test_env: &TestEnvironment, repo_path: &Pa ) } +#[duplicate_item( + test_git_fetch_all shell_git_config; + [test_git_fetch_all_shell] ["git.shell = true"]; + [test_git_fetch_all_git2] [""]; +)] #[test] fn test_git_fetch_all() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#); let source_git_repo_path = test_env.env_root().join("source"); @@ -576,9 +674,15 @@ fn test_git_fetch_all() { "#); } +#[duplicate_item( + test_git_fetch_some_of_many_bookmarks shell_git_config; + [test_git_fetch_some_of_many_bookmarks_shell] ["git.shell = true"]; + [test_git_fetch_some_of_many_bookmarks_git2] [""]; +)] #[test] fn test_git_fetch_some_of_many_bookmarks() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#); let source_git_repo_path = test_env.env_root().join("source"); @@ -790,9 +894,15 @@ fn test_git_fetch_some_of_many_bookmarks() { "###); } +#[duplicate_item( + test_git_fetch_bookmarks_some_missing shell_git_config; + [test_git_fetch_bookmarks_some_missing_shell] ["git.shell = true"]; + [test_git_fetch_bookmarks_some_missing_git2] [""]; +)] #[test] fn test_git_fetch_bookmarks_some_missing() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -878,6 +988,11 @@ fn test_git_fetch_bookmarks_some_missing() { // See `test_undo_restore_commands.rs` for fetch-undo-push and fetch-undo-fetch // of the same bookmarks for various kinds of undo. +#[duplicate_item( + test_git_fetch_undo shell_git_config; + [test_git_fetch_undo_shell] ["git.shell = true"]; + [test_git_fetch_undo_git2] [""]; +)] #[test] fn test_git_fetch_undo() { let test_env = TestEnvironment::default(); @@ -955,9 +1070,15 @@ fn test_git_fetch_undo() { // Compare to `test_git_import_undo` in test_git_import_export // TODO: Explain why these behaviors are useful +#[duplicate_item( + test_fetch_undo_what shell_git_config; + [test_fetch_undo_what_shell] ["git.shell = true"]; + [test_fetch_undo_what_git2] [""]; +)] #[test] fn test_fetch_undo_what() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); let source_git_repo_path = test_env.env_root().join("source"); let _git_repo = git2::Repository::init(source_git_repo_path.clone()).unwrap(); @@ -1052,9 +1173,15 @@ fn test_fetch_undo_what() { "###); } +#[duplicate_item( + test_git_fetch_remove_fetch shell_git_config; + [test_git_fetch_remove_fetch_shell] ["git.shell = true"]; + [test_git_fetch_remove_fetch_git2] [""]; +)] #[test] fn test_git_fetch_remove_fetch() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -1096,9 +1223,15 @@ fn test_git_fetch_remove_fetch() { "###); } +#[duplicate_item( + test_git_fetch_rename_fetch shell_git_config; + [test_git_fetch_rename_fetch_shell] ["git.shell = true"]; + [test_git_fetch_rename_fetch_git2] [""]; +)] #[test] fn test_git_fetch_rename_fetch() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); @@ -1137,9 +1270,15 @@ fn test_git_fetch_rename_fetch() { "###); } +#[duplicate_item( + test_git_fetch_removed_bookmark shell_git_config; + [test_git_fetch_removed_bookmark_shell] ["git.shell = true"]; + [test_git_fetch_removed_bookmark_git2] [""]; +)] #[test] fn test_git_fetch_removed_bookmark() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); let source_git_repo_path = test_env.env_root().join("source"); let _git_repo = git2::Repository::init(source_git_repo_path.clone()).unwrap(); @@ -1229,9 +1368,15 @@ fn test_git_fetch_removed_bookmark() { "#); } +#[duplicate_item( + test_git_fetch_removed_parent_bookmark shell_git_config; + [test_git_fetch_removed_parent_bookmark_shell] ["git.shell = true"]; + [test_git_fetch_removed_parent_bookmark_git2] [""]; +)] #[test] fn test_git_fetch_removed_parent_bookmark() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); let source_git_repo_path = test_env.env_root().join("source"); let _git_repo = git2::Repository::init(source_git_repo_path.clone()).unwrap(); @@ -1310,9 +1455,15 @@ fn test_git_fetch_removed_parent_bookmark() { "#); } +#[duplicate_item( + test_git_fetch_remote_only_bookmark shell_git_config; + [test_git_fetch_remote_only_bookmark_shell] ["git.shell = true"]; + [test_git_fetch_remote_only_bookmark_git2] [""]; +)] #[test] fn test_git_fetch_remote_only_bookmark() { let test_env = TestEnvironment::default(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); diff --git a/cli/tests/test_git_push.rs b/cli/tests/test_git_push.rs index 3a868329d9..74d550e760 100644 --- a/cli/tests/test_git_push.rs +++ b/cli/tests/test_git_push.rs @@ -17,6 +17,8 @@ use std::path::PathBuf; use crate::common::TestEnvironment; +use duplicate::duplicate_item; + fn set_up() -> (TestEnvironment, PathBuf) { let test_env = TestEnvironment::default(); test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "origin"]); @@ -47,9 +49,15 @@ fn set_up() -> (TestEnvironment, PathBuf) { (test_env, workspace_root) } +#[duplicate_item( + test_git_push_nothing shell_git_config; + [test_git_push_nothing_shell] ["git.shell = true"]; + [test_git_push_nothing_git2] [""]; +)] #[test] fn test_git_push_nothing() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); // Show the setup. `insta` has trouble if this is done inside `set_up()` insta::assert_snapshot!(get_bookmark_output(&test_env, &workspace_root), @r###" bookmark1: xtvrqkyv d13ecdbd (empty) description 1 @@ -65,9 +73,15 @@ fn test_git_push_nothing() { "###); } +#[duplicate_item( + test_git_push_current_bookmark shell_git_config; + [test_git_push_current_bookmark_shell] ["git.shell = true"]; + [test_git_push_current_bookmark_git2] [""]; +)] #[test] fn test_git_push_current_bookmark() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#); // Update some bookmarks. `bookmark1` is not a current bookmark, but // `bookmark2` and `my-bookmark` are. @@ -143,9 +157,15 @@ fn test_git_push_current_bookmark() { "#); } +#[duplicate_item( + test_git_push_parent_bookmark shell_git_config; + [test_git_push_parent_bookmark_shell] ["git.shell = true"]; + [test_git_push_parent_bookmark_git2] [""]; +)] #[test] fn test_git_push_parent_bookmark() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#); test_env.jj_cmd_ok(&workspace_root, &["edit", "bookmark1"]); test_env.jj_cmd_ok( @@ -162,9 +182,15 @@ fn test_git_push_parent_bookmark() { "#); } +#[duplicate_item( + test_git_push_no_matching_bookmark shell_git_config; + [test_git_push_no_matching_bookmark_shell] ["git.shell = true"]; + [test_git_push_no_matching_bookmark_git2] [""]; +)] #[test] fn test_git_push_no_matching_bookmark() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["new"]); let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push"]); insta::assert_snapshot!(stdout, @""); @@ -174,9 +200,15 @@ fn test_git_push_no_matching_bookmark() { "###); } +#[duplicate_item( + test_git_push_matching_bookmark_unchanged shell_git_config; + [test_git_push_matching_bookmark_unchanged_shell] ["git.shell = true"]; + [test_git_push_matching_bookmark_unchanged_git2] [""]; +)] #[test] fn test_git_push_matching_bookmark_unchanged() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["new", "bookmark1"]); let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push"]); insta::assert_snapshot!(stdout, @""); @@ -189,9 +221,15 @@ fn test_git_push_matching_bookmark_unchanged() { /// Test that `jj git push` without arguments pushes a bookmark to the specified /// remote even if it's already up to date on another remote /// (`remote_bookmarks(remote=)..@` vs. `remote_bookmarks()..@`). +#[duplicate_item( + test_git_push_other_remote_has_bookmark shell_git_config; + [test_git_push_other_remote_has_bookmark_shell] ["git.shell = true"]; + [test_git_push_other_remote_has_bookmark_git2] [""]; +)] #[test] fn test_git_push_other_remote_has_bookmark() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#); // Create another remote (but actually the same) let other_remote_path = test_env @@ -246,9 +284,15 @@ fn test_git_push_other_remote_has_bookmark() { "#); } +#[duplicate_item( + test_git_push_forward_unexpectedly_moved shell_git_config; + [test_git_push_forward_unexpectedly_moved_shell] ["git.shell = true"]; + [test_git_push_forward_unexpectedly_moved_git2] [""]; +)] #[test] fn test_git_push_forward_unexpectedly_moved() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); // Move bookmark1 forward on the remote let origin_path = test_env.env_root().join("origin"); @@ -272,9 +316,15 @@ fn test_git_push_forward_unexpectedly_moved() { "#); } +#[duplicate_item( + test_git_push_sideways_unexpectedly_moved shell_git_config; + [test_git_push_sideways_unexpectedly_moved_shell] ["git.shell = true"]; + [test_git_push_sideways_unexpectedly_moved_git2] [""]; +)] #[test] fn test_git_push_sideways_unexpectedly_moved() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); // Move bookmark1 forward on the remote let origin_path = test_env.env_root().join("origin"); @@ -314,9 +364,15 @@ fn test_git_push_sideways_unexpectedly_moved() { // This tests whether the push checks that the remote bookmarks are in expected // positions. +#[duplicate_item( + test_git_push_deletion_unexpectedly_moved shell_git_config; + [test_git_push_deletion_unexpectedly_moved_shell] ["git.shell = true"]; + [test_git_push_deletion_unexpectedly_moved_git2] [""]; + )] #[test] fn test_git_push_deletion_unexpectedly_moved() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); // Move bookmark1 forward on the remote let origin_path = test_env.env_root().join("origin"); @@ -350,9 +406,15 @@ fn test_git_push_deletion_unexpectedly_moved() { "#); } +#[duplicate_item( + test_git_push_unexpectedly_deleted shell_git_config; + [test_git_push_unexpectedly_deleted_shell] ["git.shell = true"]; + [test_git_push_unexpectedly_deleted_git2] [""]; + )] #[test] fn test_git_push_unexpectedly_deleted() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); // Delete bookmark1 forward on the remote let origin_path = test_env.env_root().join("origin"); @@ -405,9 +467,15 @@ fn test_git_push_unexpectedly_deleted() { "#); } +#[duplicate_item( + test_git_push_creation_unexpectedly_already_exists shell_git_config; + [test_git_push_creation_unexpectedly_already_exists_shell] ["git.shell = true"]; + [test_git_push_creation_unexpectedly_already_exists_git2] [""]; + )] #[test] fn test_git_push_creation_unexpectedly_already_exists() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); // Forget bookmark1 locally test_env.jj_cmd_ok(&workspace_root, &["bookmark", "forget", "bookmark1"]); @@ -431,9 +499,15 @@ fn test_git_push_creation_unexpectedly_already_exists() { "#); } +#[duplicate_item( + test_git_push_locally_created_and_rewritten shell_git_config; + [test_git_push_locally_created_and_rewritten_shell] ["git.shell = true"]; + [test_git_push_locally_created_and_rewritten_git2] [""]; + )] #[test] fn test_git_push_locally_created_and_rewritten() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); // Ensure that remote bookmarks aren't tracked automatically test_env.add_config("git.auto-local-bookmark = false"); @@ -470,9 +544,15 @@ fn test_git_push_locally_created_and_rewritten() { "); } +#[duplicate_item( + test_git_push_multiple shell_git_config; + [test_git_push_multiple_shell] ["git.shell = true"]; + [test_git_push_multiple_git2] [""]; + )] #[test] fn test_git_push_multiple() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["bookmark", "delete", "bookmark1"]); test_env.jj_cmd_ok( &workspace_root, @@ -591,9 +671,15 @@ fn test_git_push_multiple() { "###); } +#[duplicate_item( + test_git_push_changes shell_git_config; + [test_git_push_changes_shell] ["git.shell = true"]; + [test_git_push_changes_git2] [""]; + )] #[test] fn test_git_push_changes() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["describe", "-m", "foo"]); std::fs::write(workspace_root.join("file"), "contents").unwrap(); test_env.jj_cmd_ok(&workspace_root, &["new", "-m", "bar"]); @@ -718,9 +804,15 @@ fn test_git_push_changes() { "#); } +#[duplicate_item( + test_git_push_revisions shell_git_config; + [test_git_push_revisions_shell] ["git.shell = true"]; + [test_git_push_revisions_git2] [""]; + )] #[test] fn test_git_push_revisions() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["describe", "-m", "foo"]); std::fs::write(workspace_root.join("file"), "contents").unwrap(); test_env.jj_cmd_ok(&workspace_root, &["new", "-m", "bar"]); @@ -796,9 +888,15 @@ fn test_git_push_revisions() { "#); } +#[duplicate_item( + test_git_push_mixed shell_git_config; + [test_git_push_mixed_shell] ["git.shell = true"]; + [test_git_push_mixed_git2] [""]; + )] #[test] fn test_git_push_mixed() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["describe", "-m", "foo"]); std::fs::write(workspace_root.join("file"), "contents").unwrap(); test_env.jj_cmd_ok(&workspace_root, &["new", "-m", "bar"]); @@ -848,9 +946,15 @@ fn test_git_push_mixed() { "#); } +#[duplicate_item( + test_git_push_existing_long_bookmark shell_git_config; + [test_git_push_existing_long_bookmark_shell] ["git.shell = true"]; + [test_git_push_existing_long_bookmark_git2] [""]; + )] #[test] fn test_git_push_existing_long_bookmark() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["describe", "-m", "foo"]); std::fs::write(workspace_root.join("file"), "contents").unwrap(); test_env.jj_cmd_ok( @@ -870,9 +974,15 @@ fn test_git_push_existing_long_bookmark() { "#); } +#[duplicate_item( + test_git_push_unsnapshotted_change shell_git_config; + [test_git_push_unsnapshotted_change_shell] ["git.shell = true"]; + [test_git_push_unsnapshotted_change_git2] [""]; + )] #[test] fn test_git_push_unsnapshotted_change() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["describe", "-m", "foo"]); std::fs::write(workspace_root.join("file"), "contents").unwrap(); test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--change", "@"]); @@ -880,9 +990,15 @@ fn test_git_push_unsnapshotted_change() { test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--change", "@"]); } +#[duplicate_item( + test_git_push_conflict shell_git_config; + [test_git_push_conflict_shell] ["git.shell = true"]; + [test_git_push_conflict_git2] [""]; + )] #[test] fn test_git_push_conflict() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); std::fs::write(workspace_root.join("file"), "first").unwrap(); test_env.jj_cmd_ok(&workspace_root, &["commit", "-m", "first"]); std::fs::write(workspace_root.join("file"), "second").unwrap(); @@ -898,9 +1014,15 @@ fn test_git_push_conflict() { "###); } +#[duplicate_item( + test_git_push_no_description shell_git_config; + [test_git_push_no_description_shell] ["git.shell = true"]; + [test_git_push_no_description_git2] [""]; + )] #[test] fn test_git_push_no_description() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["bookmark", "create", "my-bookmark"]); test_env.jj_cmd_ok(&workspace_root, &["describe", "-m="]); let stderr = test_env.jj_cmd_failure( @@ -924,9 +1046,15 @@ fn test_git_push_no_description() { ); } +#[duplicate_item( + test_git_push_no_description_in_immutable shell_git_config; + [test_git_push_no_description_in_immutable_shell] ["git.shell = true"]; + [test_git_push_no_description_in_immutable_git2] [""]; + )] #[test] fn test_git_push_no_description_in_immutable() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["bookmark", "create", "imm"]); test_env.jj_cmd_ok(&workspace_root, &["describe", "-m="]); test_env.jj_cmd_ok(&workspace_root, &["new", "-m", "foo"]); @@ -967,9 +1095,15 @@ fn test_git_push_no_description_in_immutable() { "#); } +#[duplicate_item( + test_git_push_missing_author shell_git_config; + [test_git_push_missing_author_shell] ["git.shell = true"]; + [test_git_push_missing_author_git2] [""]; + )] #[test] fn test_git_push_missing_author() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); let run_without_var = |var: &str, args: &[&str]| { test_env .jj_cmd(&workspace_root, args) @@ -999,9 +1133,15 @@ fn test_git_push_missing_author() { "); } +#[duplicate_item( + test_git_push_missing_author_in_immutable shell_git_config; + [test_git_push_missing_author_in_immutable_shell] ["git.shell = true"]; + [test_git_push_missing_author_in_immutable_git2] [""]; + )] #[test] fn test_git_push_missing_author_in_immutable() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); let run_without_var = |var: &str, args: &[&str]| { test_env .jj_cmd(&workspace_root, args) @@ -1050,9 +1190,15 @@ fn test_git_push_missing_author_in_immutable() { "#); } +#[duplicate_item( + test_git_push_missing_committer shell_git_config; + [test_git_push_missing_committer_shell] ["git.shell = true"]; + [test_git_push_missing_committer_git2] [""]; + )] #[test] fn test_git_push_missing_committer() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); let run_without_var = |var: &str, args: &[&str]| { test_env .jj_cmd(&workspace_root, args) @@ -1095,9 +1241,15 @@ fn test_git_push_missing_committer() { "); } +#[duplicate_item( + test_git_push_missing_committer_in_immutable shell_git_config; + [test_git_push_missing_committer_in_immutable_shell] ["git.shell = true"]; + [test_git_push_missing_committer_in_immutable_git2] [""]; + )] #[test] fn test_git_push_missing_committer_in_immutable() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); let run_without_var = |var: &str, args: &[&str]| { test_env .jj_cmd(&workspace_root, args) @@ -1147,9 +1299,15 @@ fn test_git_push_missing_committer_in_immutable() { "#); } +#[duplicate_item( + test_git_push_deleted shell_git_config; + [test_git_push_deleted_shell] ["git.shell = true"]; + [test_git_push_deleted_git2] [""]; + )] #[test] fn test_git_push_deleted() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["bookmark", "delete", "bookmark1"]); let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--deleted"]); @@ -1175,9 +1333,15 @@ fn test_git_push_deleted() { "###); } +#[duplicate_item( + test_git_push_conflicting_bookmarks shell_git_config; + [test_git_push_conflicting_bookmarks_shell] ["git.shell = true"]; + [test_git_push_conflicting_bookmarks_git2] [""]; + )] #[test] fn test_git_push_conflicting_bookmarks() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.add_config("git.auto-local-bookmark = true"); let git_repo = { let mut git_repo_path = workspace_root.clone(); @@ -1252,9 +1416,15 @@ fn test_git_push_conflicting_bookmarks() { "#); } +#[duplicate_item( + test_git_push_deleted_untracked shell_git_config; + [test_git_push_deleted_untracked_shell] ["git.shell = true"]; + [test_git_push_deleted_untracked_git2] [""]; + )] #[test] fn test_git_push_deleted_untracked() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); // Absent local bookmark shouldn't be considered "deleted" compared to // non-tracking remote bookmark. @@ -1273,9 +1443,15 @@ fn test_git_push_deleted_untracked() { "###); } +#[duplicate_item( + test_git_push_tracked_vs_all shell_git_config; + [test_git_push_tracked_vs_all_shell] ["git.shell = true"]; + [test_git_push_tracked_vs_all_git2] [""]; + )] #[test] fn test_git_push_tracked_vs_all() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["new", "bookmark1", "-mmoved bookmark1"]); test_env.jj_cmd_ok(&workspace_root, &["bookmark", "set", "bookmark1"]); test_env.jj_cmd_ok(&workspace_root, &["new", "bookmark2", "-mmoved bookmark2"]); @@ -1346,9 +1522,15 @@ fn test_git_push_tracked_vs_all() { "#); } +#[duplicate_item( + test_git_push_moved_forward_untracked shell_git_config; + [test_git_push_moved_forward_untracked_shell] ["git.shell = true"]; + [test_git_push_moved_forward_untracked_git2] [""]; +)] #[test] fn test_git_push_moved_forward_untracked() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["new", "bookmark1", "-mmoved bookmark1"]); test_env.jj_cmd_ok(&workspace_root, &["bookmark", "set", "bookmark1"]); @@ -1364,9 +1546,15 @@ fn test_git_push_moved_forward_untracked() { "###); } +#[duplicate_item( + test_git_push_moved_sideways_untracked shell_git_config; + [test_git_push_moved_sideways_untracked_shell] ["git.shell = true"]; + [test_git_push_moved_sideways_untracked_git2] [""]; +)] #[test] fn test_git_push_moved_sideways_untracked() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); test_env.jj_cmd_ok(&workspace_root, &["new", "root()", "-mmoved bookmark1"]); test_env.jj_cmd_ok( @@ -1385,9 +1573,15 @@ fn test_git_push_moved_sideways_untracked() { "###); } +#[duplicate_item( + test_git_push_to_remote_named_git shell_git_config; + [test_git_push_to_remote_named_git_shell] ["git.shell = true"]; + [test_git_push_to_remote_named_git_git2] [""]; +)] #[test] fn test_git_push_to_remote_named_git() { let (test_env, workspace_root) = set_up(); + test_env.add_config(shell_git_config); let git_repo = { let mut git_repo_path = workspace_root.clone(); git_repo_path.extend([".jj", "repo", "store", "git"]); diff --git a/lib/Cargo.toml b/lib/Cargo.toml index ed45da8278..130935eeb7 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -86,6 +86,7 @@ winreg = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } criterion = { workspace = true } +duplicate = { workspace = true } indoc = { workspace = true } insta = { workspace = true } num_cpus = { workspace = true } @@ -107,7 +108,6 @@ gix-max-performance = [ vendored-openssl = ["git2/vendored-openssl"] watchman = ["dep:tokio", "dep:watchman_client"] testing = ["git"] -shell = [] [lints] workspace = true diff --git a/lib/src/config/misc.toml b/lib/src/config/misc.toml index d432be25f9..a19b5a374d 100644 --- a/lib/src/config/misc.toml +++ b/lib/src/config/misc.toml @@ -12,6 +12,7 @@ register_snapshot_trigger = false [git] abandon-unreachable-commits = true # auto-local-bookmark = false +# shell = false [operation] # hostname = diff --git a/lib/src/git.rs b/lib/src/git.rs index 1d693a2212..bd0a4692cb 100644 --- a/lib/src/git.rs +++ b/lib/src/git.rs @@ -1286,8 +1286,7 @@ pub enum GitFetchError { PathConversionError(std::path::PathBuf), } -#[cfg(feature = "shell")] -fn fetch_options( +fn shell_fetch_options( callbacks: RemoteCallbacks<'_>, depth: Option, ) -> git2::FetchOptions<'_> { @@ -1304,8 +1303,7 @@ fn fetch_options( fetch_options } -#[cfg(not(feature = "shell"))] -fn fetch_options( +fn git2_fetch_options( callbacks: RemoteCallbacks<'_>, depth: Option, ) -> git2::FetchOptions<'_> { @@ -1334,6 +1332,7 @@ struct GitFetch<'a> { fetch_options: git2::FetchOptions<'a>, fetched: Vec, depth: Option, + shell: bool, } impl<'a> GitFetch<'a> { @@ -1343,6 +1342,7 @@ impl<'a> GitFetch<'a> { git_settings: &'a GitSettings, fetch_options: git2::FetchOptions<'a>, depth: Option, + shell: bool, ) -> Self { GitFetch { mut_repo, @@ -1351,6 +1351,7 @@ impl<'a> GitFetch<'a> { fetch_options, fetched: vec![], depth, + shell, } } @@ -1374,13 +1375,7 @@ impl<'a> GitFetch<'a> { .ok_or(GitFetchError::InvalidBranchPattern) } - /// Perform a `git fetch` on the local git repo, updating the - /// remote-tracking branches in the git repo. - /// - /// Keeps track of the {branch_names, remote_name} pair the refs can be - /// subsequently imported into the `jj` repo by calling `import_refs()`. - #[cfg(not(feature = "shell"))] - fn fetch( + fn git2_fetch( &mut self, branch_names: &[StringPattern], remote_name: &str, @@ -1443,13 +1438,7 @@ impl<'a> GitFetch<'a> { Ok(default_branch) } - /// Perform a `git fetch` on the local git repo, updating the - /// remote-tracking branches in the git repo. - /// - /// Keeps track of the {branch_names, remote_name} pair the refs can be - /// subsequently imported into the `jj` repo by calling `import_refs()`. - #[cfg(feature = "shell")] - fn fetch( + fn shell_fetch( &mut self, branch_names: &[StringPattern], remote_name: &str, @@ -1505,6 +1494,23 @@ impl<'a> GitFetch<'a> { Ok(default_branch) } + /// Perform a `git fetch` on the local git repo, updating the + /// remote-tracking branches in the git repo. + /// + /// Keeps track of the {branch_names, remote_name} pair the refs can be + /// subsequently imported into the `jj` repo by calling `import_refs()`. + fn fetch( + &mut self, + branch_names: &[StringPattern], + remote_name: &str, + ) -> Result, GitFetchError> { + if self.shell { + self.shell_fetch(branch_names, remote_name) + } else { + self.git2_fetch(branch_names, remote_name) + } + } + /// Import the previously fetched remote-tracking branches into the jj repo /// and update jj's local branches. We also import local tags since remote /// tags should have been merged by Git. @@ -1560,14 +1566,20 @@ pub fn fetch( callbacks: RemoteCallbacks<'_>, git_settings: &GitSettings, depth: Option, + shell: bool, ) -> Result { // git fetch remote_name branch_names let mut git_fetch = GitFetch::new( mut_repo, git_repo, git_settings, - fetch_options(callbacks, depth), + if shell { + shell_fetch_options(callbacks, depth) + } else { + git2_fetch_options(callbacks, depth) + }, depth, + shell, ); let default_branch = git_fetch.fetch(branch_names, remote_name)?; let import_stats = git_fetch.import_refs()?; @@ -1653,6 +1665,7 @@ pub fn push_branches( remote_name: &str, targets: &GitBranchPushTargets, callbacks: RemoteCallbacks<'_>, + shell: bool, ) -> Result<(), GitPushError> { let ref_updates = targets .branch_updates @@ -1663,7 +1676,14 @@ pub fn push_branches( new_target: update.new_target.clone(), }) .collect_vec(); - push_updates(mut_repo, git_repo, remote_name, &ref_updates, callbacks)?; + push_updates( + mut_repo, + git_repo, + remote_name, + &ref_updates, + callbacks, + shell, + )?; // TODO: add support for partially pushed refs? we could update the view // excluding rejected refs, but the transaction would be aborted anyway @@ -1688,6 +1708,7 @@ pub fn push_updates( remote_name: &str, updates: &[GitRefUpdate], callbacks: RemoteCallbacks<'_>, + shell: bool, ) -> Result<(), GitPushError> { let mut qualified_remote_refs_expected_locations = HashMap::new(); let mut refspecs = vec![]; @@ -1710,14 +1731,25 @@ pub fn push_updates( } // TODO(ilyagr): `push_refs`, or parts of it, should probably be inlined. This // requires adjusting some tests. - push_refs( - repo, - git_repo, - remote_name, - &qualified_remote_refs_expected_locations, - &refspecs, - callbacks, - ) + if shell { + shell_push_refs( + repo, + git_repo, + remote_name, + &qualified_remote_refs_expected_locations, + &refspecs, + callbacks, + ) + } else { + git2_push_refs( + repo, + git_repo, + remote_name, + &qualified_remote_refs_expected_locations, + &refspecs, + callbacks, + ) + } } fn check_allow_push( @@ -1771,8 +1803,7 @@ fn check_allow_push( true } -#[cfg(not(feature = "shell"))] -fn push_refs( +fn git2_push_refs( repo: &dyn Repo, git_repo: &git2::Repository, remote_name: &str, @@ -1866,8 +1897,7 @@ fn push_refs( } } -#[cfg(feature = "shell")] -fn push_refs( +fn shell_push_refs( repo: &dyn Repo, git_repo: &git2::Repository, remote_name: &str, diff --git a/lib/tests/test_git.rs b/lib/tests/test_git.rs index 558bc2982c..59439a59b5 100644 --- a/lib/tests/test_git.rs +++ b/lib/tests/test_git.rs @@ -25,6 +25,7 @@ use std::sync::Barrier; use std::thread; use assert_matches::assert_matches; +use duplicate::duplicate_item; use git2::Oid; use itertools::Itertools; use jj_lib::backend::BackendError; @@ -2232,6 +2233,11 @@ fn test_init() { assert!(!repo.view().heads().contains(&jj_id(&initial_git_commit))); } +#[duplicate_item ( + test_fetch_empty_repo shell_flag; + [test_fetch_empty_repo_shell] [ true ]; + [test_fetch_empty_repo_git2] [ false ]; +)] #[test] fn test_fetch_empty_repo() { let test_data = GitRepoData::create(); @@ -2246,6 +2252,7 @@ fn test_fetch_empty_repo() { git::RemoteCallbacks::default(), &git_settings, None, + shell_flag, ) .unwrap(); // No default bookmark and no refs @@ -2255,6 +2262,11 @@ fn test_fetch_empty_repo() { assert_eq!(tx.repo_mut().view().bookmarks().count(), 0); } +#[duplicate_item ( + test_fetch_initial_commit_head_is_not_set shell_flag; + [test_fetch_initial_commit_head_is_not_set_shell] [ true ]; + [test_fetch_initial_commit_head_is_not_set_git2] [ false ]; +)] #[test] fn test_fetch_initial_commit_head_is_not_set() { let test_data = GitRepoData::create(); @@ -2273,6 +2285,7 @@ fn test_fetch_initial_commit_head_is_not_set() { git::RemoteCallbacks::default(), &git_settings, None, + shell_flag, ) .unwrap(); // No default bookmark because the origin repo's HEAD wasn't set @@ -2306,6 +2319,11 @@ fn test_fetch_initial_commit_head_is_not_set() { ); } +#[duplicate_item ( + test_fetch_initial_commit_head_is_set shell_flag; + [test_fetch_initial_commit_head_is_set_shell] [ true ]; + [test_fetch_initial_commit_head_is_set_git2] [ false ]; +)] #[test] fn test_fetch_initial_commit_head_is_set() { let test_data = GitRepoData::create(); @@ -2334,6 +2352,7 @@ fn test_fetch_initial_commit_head_is_set() { git::RemoteCallbacks::default(), &git_settings, None, + shell_flag, ) .unwrap(); @@ -2341,6 +2360,11 @@ fn test_fetch_initial_commit_head_is_set() { assert!(stats.import_stats.abandoned_commits.is_empty()); } +#[duplicate_item ( + test_fetch_success shell_flag; + [test_fetch_success_shell] [ true ]; + [test_fetch_success_git2] [ false ]; +)] #[test] fn test_fetch_success() { let mut test_data = GitRepoData::create(); @@ -2359,6 +2383,7 @@ fn test_fetch_success() { git::RemoteCallbacks::default(), &git_settings, None, + shell_flag, ) .unwrap(); test_data.repo = tx.commit("test").unwrap(); @@ -2383,6 +2408,7 @@ fn test_fetch_success() { git::RemoteCallbacks::default(), &git_settings, None, + shell_flag, ) .unwrap(); // The default bookmark is "main" @@ -2423,6 +2449,11 @@ fn test_fetch_success() { ); } +#[duplicate_item ( + test_fetch_prune_deleted_ref shell_flag; + [test_fetch_prune_deleted_ref_shell] [ true ]; + [test_fetch_prune_deleted_ref_git2] [ false ]; +)] #[test] fn test_fetch_prune_deleted_ref() { let test_data = GitRepoData::create(); @@ -2441,6 +2472,7 @@ fn test_fetch_prune_deleted_ref() { git::RemoteCallbacks::default(), &git_settings, None, + shell_flag, ) .unwrap(); // Test the setup @@ -2465,6 +2497,7 @@ fn test_fetch_prune_deleted_ref() { git::RemoteCallbacks::default(), &git_settings, None, + shell_flag, ) .unwrap(); assert_eq!(stats.import_stats.abandoned_commits, vec![jj_id(&commit)]); @@ -2475,6 +2508,11 @@ fn test_fetch_prune_deleted_ref() { .is_absent()); } +#[duplicate_item ( + test_fetch_no_default_branch shell_flag; + [test_fetch_no_default_branch_shell] [ true ]; + [test_fetch_no_default_branch_git2] [ false ]; +)] #[test] fn test_fetch_no_default_branch() { let test_data = GitRepoData::create(); @@ -2493,6 +2531,7 @@ fn test_fetch_no_default_branch() { git::RemoteCallbacks::default(), &git_settings, None, + shell_flag, ) .unwrap(); @@ -2517,12 +2556,18 @@ fn test_fetch_no_default_branch() { git::RemoteCallbacks::default(), &git_settings, None, + shell_flag, ) .unwrap(); // There is no default bookmark assert_eq!(stats.default_branch, None); } +#[duplicate_item ( + test_fetch_empty_refspecs shell_flag; + [test_fetch_empty_refspecs_shell] [ true ]; + [test_fetch_empty_refspecs_git2] [ false ]; +)] #[test] fn test_fetch_empty_refspecs() { let test_data = GitRepoData::create(); @@ -2539,6 +2584,7 @@ fn test_fetch_empty_refspecs() { git::RemoteCallbacks::default(), &git_settings, None, + shell_flag, ) .unwrap(); assert!(tx @@ -2553,6 +2599,11 @@ fn test_fetch_empty_refspecs() { .is_absent()); } +#[duplicate_item ( + test_fetch_no_such_remote shell_flag; + [test_fetch_no_such_remote_shell] [ true ]; + [test_fetch_no_such_remote_git2] [ false ]; +)] #[test] fn test_fetch_no_such_remote() { let test_data = GitRepoData::create(); @@ -2566,6 +2617,7 @@ fn test_fetch_no_such_remote() { git::RemoteCallbacks::default(), &git_settings, None, + shell_flag, ); assert!(matches!(result, Err(GitFetchError::NoSuchRemote(_)))); } @@ -2663,6 +2715,11 @@ fn set_up_push_repos(settings: &UserSettings, temp_dir: &TempDir) -> PushTestSet } } +#[duplicate_item ( + test_push_bookmarks_success shell_flag; + [test_push_bookmarks_success_shell] [ true ]; + [test_push_bookmarks_success_git2] [ false ]; +)] #[test] fn test_push_bookmarks_success() { let settings = testutils::user_settings(); @@ -2686,6 +2743,7 @@ fn test_push_bookmarks_success() { "origin", &targets, git::RemoteCallbacks::default(), + shell_flag, ); assert_eq!(result, Ok(())); @@ -2728,6 +2786,11 @@ fn test_push_bookmarks_success() { assert!(!tx.repo_mut().has_changes()); } +#[duplicate_item ( + test_push_bookmarks_deletion shell_flag; + [test_push_bookmarks_deletion_shell] [ true ]; + [test_push_bookmarks_deletion_git2] [ false ]; +)] #[test] fn test_push_bookmarks_deletion() { let settings = testutils::user_settings(); @@ -2755,6 +2818,7 @@ fn test_push_bookmarks_deletion() { "origin", &targets, git::RemoteCallbacks::default(), + shell_flag, ); assert_eq!(result, Ok(())); @@ -2780,6 +2844,11 @@ fn test_push_bookmarks_deletion() { assert!(!tx.repo_mut().has_changes()); } +#[duplicate_item ( + test_push_bookmarks_mixed_deletion_and_addition shell_flag; + [test_push_bookmarks_mixed_deletion_and_addition_shell] [ true ]; + [test_push_bookmarks_mixed_deletion_and_addition_git2] [ false ]; +)] #[test] fn test_push_bookmarks_mixed_deletion_and_addition() { let settings = testutils::user_settings(); @@ -2812,6 +2881,7 @@ fn test_push_bookmarks_mixed_deletion_and_addition() { "origin", &targets, git::RemoteCallbacks::default(), + shell_flag, ); assert_eq!(result, Ok(())); @@ -2849,6 +2919,11 @@ fn test_push_bookmarks_mixed_deletion_and_addition() { assert!(!tx.repo_mut().has_changes()); } +#[duplicate_item ( + test_push_bookmarks_not_fast_forward shell_flag; + [test_push_bookmarks_not_fast_forward_shell] [ true ]; + [test_push_bookmarks_not_fast_forward_git2] [ false ]; +)] #[test] fn test_push_bookmarks_not_fast_forward() { let settings = testutils::user_settings(); @@ -2871,6 +2946,7 @@ fn test_push_bookmarks_not_fast_forward() { "origin", &targets, git::RemoteCallbacks::default(), + shell_flag, ); assert_eq!(result, Ok(())); @@ -2887,6 +2963,11 @@ fn test_push_bookmarks_not_fast_forward() { // may want to add tests for when a bookmark unexpectedly moved backwards or // unexpectedly does not exist for bookmark deletion. +#[duplicate_item ( + test_push_updates_unexpectedly_moved_sideways_on_remote shell_flag; + [test_push_updates_unexpectedly_moved_sideways_on_remote_shell] [ true ]; + [test_push_updates_unexpectedly_moved_sideways_on_remote_git2] [ false ]; +)] #[test] fn test_push_updates_unexpectedly_moved_sideways_on_remote() { let settings = testutils::user_settings(); @@ -2916,6 +2997,7 @@ fn test_push_updates_unexpectedly_moved_sideways_on_remote() { "origin", &targets, git::RemoteCallbacks::default(), + shell_flag, ) }; @@ -2952,6 +3034,11 @@ fn test_push_updates_unexpectedly_moved_sideways_on_remote() { ); } +#[duplicate_item ( + test_push_updates_unexpectedly_moved_forward_on_remote shell_flag; + [test_push_updates_unexpectedly_moved_forward_on_remote_shell] [ true ]; + [test_push_updates_unexpectedly_moved_forward_on_remote_git2] [ false ]; +)] #[test] fn test_push_updates_unexpectedly_moved_forward_on_remote() { let settings = testutils::user_settings(); @@ -2983,6 +3070,7 @@ fn test_push_updates_unexpectedly_moved_forward_on_remote() { "origin", &targets, git::RemoteCallbacks::default(), + shell_flag, ) }; @@ -3014,6 +3102,11 @@ fn test_push_updates_unexpectedly_moved_forward_on_remote() { ); } +#[duplicate_item ( + test_push_updates_unexpectedly_exists_on_remote shell_flag; + [test_push_updates_unexpectedly_exists_on_remote_shell] [ true ]; + [test_push_updates_unexpectedly_exists_on_remote_git2] [ false ]; +)] #[test] fn test_push_updates_unexpectedly_exists_on_remote() { let settings = testutils::user_settings(); @@ -3041,6 +3134,7 @@ fn test_push_updates_unexpectedly_exists_on_remote() { "origin", &targets, git::RemoteCallbacks::default(), + shell_flag, ) }; @@ -3056,6 +3150,11 @@ fn test_push_updates_unexpectedly_exists_on_remote() { ); } +#[duplicate_item ( + test_push_updates_success shell_flag; + [test_push_updates_success_shell] [ true ]; + [test_push_updates_success_git2] [ false ]; +)] #[test] fn test_push_updates_success() { let settings = testutils::user_settings(); @@ -3072,6 +3171,7 @@ fn test_push_updates_success() { new_target: Some(setup.child_of_main_commit.id().clone()), }], git::RemoteCallbacks::default(), + shell_flag, ); assert_eq!(result, Ok(())); @@ -3094,6 +3194,11 @@ fn test_push_updates_success() { assert_eq!(new_target, Some(new_oid)); } +#[duplicate_item ( + test_push_updates_no_such_remote shell_flag; + [test_push_updates_no_such_remote_shell] [ true ]; + [test_push_updates_no_such_remote_git2] [ false ]; +)] #[test] fn test_push_updates_no_such_remote() { let settings = testutils::user_settings(); @@ -3109,10 +3214,16 @@ fn test_push_updates_no_such_remote() { new_target: Some(setup.child_of_main_commit.id().clone()), }], git::RemoteCallbacks::default(), + shell_flag, ); assert!(matches!(result, Err(GitPushError::NoSuchRemote(_)))); } +#[duplicate_item ( + test_push_updates_invalid_remote shell_flag; + [test_push_updates_invalid_remote_shell] [ true ]; + [test_push_updates_invalid_remote_git2] [ false ]; +)] #[test] fn test_push_updates_invalid_remote() { let settings = testutils::user_settings(); @@ -3128,6 +3239,7 @@ fn test_push_updates_invalid_remote() { new_target: Some(setup.child_of_main_commit.id().clone()), }], git::RemoteCallbacks::default(), + shell_flag, ); assert!(matches!(result, Err(GitPushError::NoSuchRemote(_)))); }