From 31e33e82f637fcd1cd16c7b610ce6086a25bbcbf Mon Sep 17 00:00:00 2001 From: William Phetsinorath Date: Tue, 20 Aug 2024 17:15:52 +0200 Subject: [PATCH] cli: add support for push options --- cli/src/commands/git/push.rs | 12 +++++++++++- cli/tests/cli-reference@.md.snap | 1 + lib/src/git.rs | 14 +++++++++++++- lib/tests/test_git.rs | 10 ++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/cli/src/commands/git/push.rs b/cli/src/commands/git/push.rs index e0fbedb177f..589d4b813f1 100644 --- a/cli/src/commands/git/push.rs +++ b/cli/src/commands/git/push.rs @@ -106,6 +106,9 @@ pub struct GitPushArgs { /// Only display what will change on the remote #[arg(long)] dry_run: bool, + /// Git push options + #[arg(long, short)] + options: Vec, } fn make_branch_term(branch_names: &[impl fmt::Display]) -> String { @@ -322,7 +325,14 @@ pub fn cmd_git_push( _ = writer.write(ui, progress_message); }; with_remote_git_callbacks(ui, Some(&mut sideband_progress_callback), |cb| { - git::push_branches(tx.mut_repo(), &git_repo, &remote, &targets, cb) + git::push_branches( + tx.mut_repo(), + &git_repo, + &remote, + &targets, + &args.options.iter().map(|s| s.as_str()).collect::>(), + cb, + ) }) .map_err(|err| match err { GitPushError::InternalGitError(err) => map_git_error(err), diff --git a/cli/tests/cli-reference@.md.snap b/cli/tests/cli-reference@.md.snap index d749fead6f1..a0f497b4223 100644 --- a/cli/tests/cli-reference@.md.snap +++ b/cli/tests/cli-reference@.md.snap @@ -987,6 +987,7 @@ Before the command actually moves, creates, or deletes a remote branch, it makes * `-r`, `--revisions ` — Push branches pointing to these commits (can be repeated) * `-c`, `--change ` — Push this commit by creating a branch based on its change ID (can be repeated) * `--dry-run` — Only display what will change on the remote +* `-o`, `--options ` — Git push options diff --git a/lib/src/git.rs b/lib/src/git.rs index f4030a7ca2d..2d9a5ad0d25 100644 --- a/lib/src/git.rs +++ b/lib/src/git.rs @@ -1343,6 +1343,7 @@ pub fn push_branches( git_repo: &git2::Repository, remote_name: &str, targets: &GitBranchPushTargets, + remote_push_options: &[&str], callbacks: RemoteCallbacks<'_>, ) -> Result<(), GitPushError> { let ref_updates = targets @@ -1354,7 +1355,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, + remote_push_options, + callbacks, + )?; // TODO: add support for partially pushed refs? we could update the view // excluding rejected refs, but the transaction would be aborted anyway @@ -1378,6 +1386,7 @@ pub fn push_updates( git_repo: &git2::Repository, remote_name: &str, updates: &[GitRefUpdate], + remote_push_options: &[&str], callbacks: RemoteCallbacks<'_>, ) -> Result<(), GitPushError> { let mut qualified_remote_refs_expected_locations = HashMap::new(); @@ -1407,6 +1416,7 @@ pub fn push_updates( remote_name, &qualified_remote_refs_expected_locations, &refspecs, + remote_push_options, callbacks, ) } @@ -1417,6 +1427,7 @@ fn push_refs( remote_name: &str, qualified_remote_refs_expected_locations: &HashMap<&str, Option<&CommitId>>, refspecs: &[String], + remote_push_options: &[&str], callbacks: RemoteCallbacks<'_>, ) -> Result<(), GitPushError> { if remote_name == REMOTE_NAME_FOR_LOCAL_GIT_REPO { @@ -1436,6 +1447,7 @@ fn push_refs( let mut failed_push_negotiations = vec![]; let push_result = { let mut push_options = git2::PushOptions::new(); + push_options.remote_push_options(remote_push_options); let mut proxy_options = git2::ProxyOptions::new(); proxy_options.auto(); push_options.proxy_options(proxy_options); diff --git a/lib/tests/test_git.rs b/lib/tests/test_git.rs index 35fe45650e9..bb4d7cf9764 100644 --- a/lib/tests/test_git.rs +++ b/lib/tests/test_git.rs @@ -2618,6 +2618,7 @@ fn test_push_branches_success() { &clone_repo, "origin", &targets, + &[], git::RemoteCallbacks::default(), ); assert_eq!(result, Ok(())); @@ -2687,6 +2688,7 @@ fn test_push_branches_deletion() { &get_git_repo(&setup.jj_repo), "origin", &targets, + &[], git::RemoteCallbacks::default(), ); assert_eq!(result, Ok(())); @@ -2744,6 +2746,7 @@ fn test_push_branches_mixed_deletion_and_addition() { &clone_repo, "origin", &targets, + &[], git::RemoteCallbacks::default(), ); assert_eq!(result, Ok(())); @@ -2803,6 +2806,7 @@ fn test_push_branches_not_fast_forward() { &get_git_repo(&setup.jj_repo), "origin", &targets, + &[], git::RemoteCallbacks::default(), ); assert_eq!(result, Ok(())); @@ -2848,6 +2852,7 @@ fn test_push_updates_unexpectedly_moved_sideways_on_remote() { &get_git_repo(&setup.jj_repo), "origin", &targets, + &[], git::RemoteCallbacks::default(), ) }; @@ -2915,6 +2920,7 @@ fn test_push_updates_unexpectedly_moved_forward_on_remote() { &get_git_repo(&setup.jj_repo), "origin", &targets, + &[], git::RemoteCallbacks::default(), ) }; @@ -2973,6 +2979,7 @@ fn test_push_updates_unexpectedly_exists_on_remote() { &get_git_repo(&setup.jj_repo), "origin", &targets, + &[], git::RemoteCallbacks::default(), ) }; @@ -3004,6 +3011,7 @@ fn test_push_updates_success() { expected_current_target: Some(setup.main_commit.id().clone()), new_target: Some(setup.child_of_main_commit.id().clone()), }], + &[], git::RemoteCallbacks::default(), ); assert_eq!(result, Ok(())); @@ -3041,6 +3049,7 @@ fn test_push_updates_no_such_remote() { expected_current_target: Some(setup.main_commit.id().clone()), new_target: Some(setup.child_of_main_commit.id().clone()), }], + &[], git::RemoteCallbacks::default(), ); assert!(matches!(result, Err(GitPushError::NoSuchRemote(_)))); @@ -3060,6 +3069,7 @@ fn test_push_updates_invalid_remote() { expected_current_target: Some(setup.main_commit.id().clone()), new_target: Some(setup.child_of_main_commit.id().clone()), }], + &[], git::RemoteCallbacks::default(), ); assert!(matches!(result, Err(GitPushError::NoSuchRemote(_))));