// Copyright 2023 The Jujutsu Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License. use test_case::test_case;use testutils::git; use crate::common::create_commit;use crate::common::CommandOutput;use crate::common::TestEnvironment;use crate::common::TestWorkDir; fn add_commit_to_branch(git_repo: &gix::Repository, branch: &str) -> gix::ObjectId { git::add_commit( git_repo, &format!("refs/heads/{branch}"), branch, // filename branch.as_bytes(), // content "message", &[], ) .commit_id} /// Creates a remote Git repo containing a bookmark with the same namefn init_git_remote(test_env: &TestEnvironment, remote: &str) -> gix::Repository { let git_repo_path = test_env.env_root().join(remote); let git_repo = git::init(git_repo_path); add_commit_to_branch(&git_repo, remote); git_repo} /// Add a remote containing a bookmark with the same namefn add_git_remote( test_env: &TestEnvironment, work_dir: &TestWorkDir, remote: &str,) -> gix::Repository { let repo = init_git_remote(test_env, remote); work_dir .run_jj(["git", "remote", "add", remote, &format!("../{remote}")]) .success(); repo} #[must_use]fn get_bookmark_output(work_dir: &TestWorkDir) -> CommandOutput { // --quiet to suppress deleted bookmarks hint work_dir.run_jj(["bookmark", "list", "--all-remotes", "--quiet"])} #[must_use]fn get_log_output(work_dir: &TestWorkDir) -> CommandOutput { let template = r#"commit_id.short() ++ " \"" ++ description.first_line() ++ "\" " ++ bookmarks"#; work_dir.run_jj(["log", "-T", template, "-r", "all()"])} fn clone_git_remote_into( test_env: &TestEnvironment, upstream: &str, fork: &str,) -> gix::Repository { let upstream_path = test_env.env_root().join(upstream); let fork_path = test_env.env_root().join(fork); let fork_repo = git::clone(&fork_path, upstream_path.to_str().unwrap(), Some(upstream)); // create local branch mirroring the upstream let upstream_head = fork_repo .find_reference(&format!("refs/remotes/{upstream}/{upstream}")) .unwrap() .peel_to_id_in_place() .unwrap() .detach(); fork_repo .reference( format!("refs/heads/{upstream}"), upstream_head, gix::refs::transaction::PreviousValue::MustNotExist, "create tracking head", ) .unwrap(); fork_repo} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_with_default_config(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "origin"); work_dir.run_jj(["git", "fetch"]).success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" origin@origin: qmyrypzk ab8b299e message [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_default_remote(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "origin"); work_dir.run_jj(["git", "fetch"]).success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" origin: qmyrypzk ab8b299e message @origin: qmyrypzk ab8b299e message [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_single_remote(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); let output = work_dir.run_jj(["git", "fetch"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Hint: Fetching from the only existing remote: rem1 bookmark: rem1@rem1 [new] tracked [EOF] "); } insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_single_remote_all_remotes_flag(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); work_dir.run_jj(["git", "fetch", "--all-remotes"]).success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_single_remote_from_arg(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); work_dir .run_jj(["git", "fetch", "--remote", "rem1"]) .success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_single_remote_from_config(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); test_env.add_config(r#"git.fetch = "rem1""#); work_dir.run_jj(["git", "fetch"]).success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_multiple_remotes(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); work_dir .run_jj(["git", "fetch", "--remote", "rem1", "--remote", "rem2"]) .success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message rem2: pzqqpnpo 44c57802 message @rem2: pzqqpnpo 44c57802 message [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_with_glob(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); let output = work_dir.run_jj(["git", "fetch", "--remote", "glob:*"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- bookmark: rem1@rem1 [new] untracked bookmark: rem2@rem2 [new] untracked [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_with_glob_and_exact_match(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); add_git_remote(&test_env, &work_dir, "upstream1"); add_git_remote(&test_env, &work_dir, "upstream2"); add_git_remote(&test_env, &work_dir, "origin"); let output = work_dir.run_jj(["git", "fetch", "--remote=glob:rem*", "--remote=origin"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- bookmark: origin@origin [new] untracked bookmark: rem1@rem1 [new] untracked bookmark: rem2@rem2 [new] untracked [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_with_glob_from_config(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config(r#"git.fetch = "glob:rem*""#); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); add_git_remote(&test_env, &work_dir, "upstream"); let output = work_dir.run_jj(["git", "fetch"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- bookmark: rem1@rem1 [new] untracked bookmark: rem2@rem2 [new] untracked [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_with_glob_with_no_matching_remotes(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "upstream"); let output = work_dir.run_jj(["git", "fetch", "--remote=glob:rem*"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No git remotes matching 'rem*' Error: No git remotes to push [EOF] [exit status: 1] "); } // No remote should have been fetched as part of the failing transaction insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_all_remotes(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); // add empty [remote "rem3"] section to .git/config, which should be ignored work_dir .run_jj(["git", "remote", "add", "rem3", "../unknown"]) .success(); work_dir .run_jj(["git", "remote", "remove", "rem3"]) .success(); work_dir.run_jj(["git", "fetch", "--all-remotes"]).success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message rem2: pzqqpnpo 44c57802 message @rem2: pzqqpnpo 44c57802 message [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_multiple_remotes_from_config(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); test_env.add_config(r#"git.fetch = ["rem1", "rem2"]"#); work_dir.run_jj(["git", "fetch"]).success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message rem2: pzqqpnpo 44c57802 message @rem2: pzqqpnpo 44c57802 message [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_no_matching_remote(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let output = work_dir.run_jj(["git", "fetch", "--remote", "rem1"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No git remotes matching 'rem1' Error: No git remotes to push [EOF] [exit status: 1] "); } insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_nonexistent_remote(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); let output = work_dir.run_jj(["git", "fetch", "--remote", "rem1", "--remote", "rem2"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No git remotes matching 'rem2' bookmark: rem1@rem1 [new] untracked [EOF] "); } insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1@rem1: ppspxspk 4acd0343 message [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_nonexistent_remote_from_config(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); test_env.add_config(r#"git.fetch = ["rem1", "rem2"]"#); let output = work_dir.run_jj(["git", "fetch"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No git remotes matching 'rem2' bookmark: rem1@rem1 [new] untracked [EOF] "); } insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1@rem1: ppspxspk 4acd0343 message [EOF] "); }} #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]#[test_case(true; "spawn a git subprocess for remote calls")]fn test_git_fetch_from_remote_named_git(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); let work_dir = test_env.work_dir("repo"); init_git_remote(&test_env, "git"); git::init(work_dir.root()); git::add_remote(work_dir.root(), "git", "../git"); // Existing remote named 'git' shouldn't block the repo initialization. work_dir.run_jj(["git", "init", "--git-repo=."]).success(); // Try fetching from the remote named 'git'. let output = work_dir.run_jj(["git", "fetch", "--remote=git"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Error: Git remote named 'git' is reserved for local Git repository Hint: Run `jj git remote rename` to give a different name. [EOF] [exit status: 1] "); } // Fetch remote refs by using the git CLI. git::fetch(work_dir.root(), "git"); // Implicit import shouldn't fail because of the remote ref. let output = work_dir.run_jj(["bookmark", "list", "--all-remotes"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: Failed to import some Git refs: refs/remotes/git/git Hint: Git remote named 'git' is reserved for local Git repository. Use `jj git remote rename` to give a different name.Lines 1–500 of 2069. Load more
// Copyright 2023 The Jujutsu Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use test_case::test_case; use testutils::git; use crate::common::create_commit; use crate::common::CommandOutput; use crate::common::TestEnvironment; use crate::common::TestWorkDir; fn add_commit_to_branch(git_repo: &gix::Repository, branch: &str) -> gix::ObjectId { git::add_commit( git_repo, &format!("refs/heads/{branch}"), branch, // filename branch.as_bytes(), // content "message", &[], ) .commit_id } /// Creates a remote Git repo containing a bookmark with the same name fn init_git_remote(test_env: &TestEnvironment, remote: &str) -> gix::Repository { let git_repo_path = test_env.env_root().join(remote); let git_repo = git::init(git_repo_path); add_commit_to_branch(&git_repo, remote); git_repo } /// Add a remote containing a bookmark with the same name fn add_git_remote( test_env: &TestEnvironment, work_dir: &TestWorkDir, remote: &str, ) -> gix::Repository { let repo = init_git_remote(test_env, remote); work_dir .run_jj(["git", "remote", "add", remote, &format!("../{remote}")]) .success(); repo } #[must_use] fn get_bookmark_output(work_dir: &TestWorkDir) -> CommandOutput { // --quiet to suppress deleted bookmarks hint work_dir.run_jj(["bookmark", "list", "--all-remotes", "--quiet"]) } #[must_use] fn get_log_output(work_dir: &TestWorkDir) -> CommandOutput { let template = r#"commit_id.short() ++ " \"" ++ description.first_line() ++ "\" " ++ bookmarks"#; work_dir.run_jj(["log", "-T", template, "-r", "all()"]) } fn clone_git_remote_into( test_env: &TestEnvironment, upstream: &str, fork: &str, ) -> gix::Repository { let upstream_path = test_env.env_root().join(upstream); let fork_path = test_env.env_root().join(fork); let fork_repo = git::clone(&fork_path, upstream_path.to_str().unwrap(), Some(upstream)); // create local branch mirroring the upstream let upstream_head = fork_repo .find_reference(&format!("refs/remotes/{upstream}/{upstream}")) .unwrap() .peel_to_id_in_place() .unwrap() .detach(); fork_repo .reference( format!("refs/heads/{upstream}"), upstream_head, gix::refs::transaction::PreviousValue::MustNotExist, "create tracking head", ) .unwrap(); fork_repo } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_with_default_config(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "origin"); work_dir.run_jj(["git", "fetch"]).success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" origin@origin: qmyrypzk ab8b299e message [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_default_remote(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "origin"); work_dir.run_jj(["git", "fetch"]).success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" origin: qmyrypzk ab8b299e message @origin: qmyrypzk ab8b299e message [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_single_remote(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); let output = work_dir.run_jj(["git", "fetch"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Hint: Fetching from the only existing remote: rem1 bookmark: rem1@rem1 [new] tracked [EOF] "); } insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_single_remote_all_remotes_flag(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); work_dir.run_jj(["git", "fetch", "--all-remotes"]).success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_single_remote_from_arg(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); work_dir .run_jj(["git", "fetch", "--remote", "rem1"]) .success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_single_remote_from_config(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); test_env.add_config(r#"git.fetch = "rem1""#); work_dir.run_jj(["git", "fetch"]).success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_multiple_remotes(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); work_dir .run_jj(["git", "fetch", "--remote", "rem1", "--remote", "rem2"]) .success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message rem2: pzqqpnpo 44c57802 message @rem2: pzqqpnpo 44c57802 message [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_with_glob(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); let output = work_dir.run_jj(["git", "fetch", "--remote", "glob:*"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- bookmark: rem1@rem1 [new] untracked bookmark: rem2@rem2 [new] untracked [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_with_glob_and_exact_match(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); add_git_remote(&test_env, &work_dir, "upstream1"); add_git_remote(&test_env, &work_dir, "upstream2"); add_git_remote(&test_env, &work_dir, "origin"); let output = work_dir.run_jj(["git", "fetch", "--remote=glob:rem*", "--remote=origin"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- bookmark: origin@origin [new] untracked bookmark: rem1@rem1 [new] untracked bookmark: rem2@rem2 [new] untracked [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_with_glob_from_config(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config(r#"git.fetch = "glob:rem*""#); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); add_git_remote(&test_env, &work_dir, "upstream"); let output = work_dir.run_jj(["git", "fetch"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- bookmark: rem1@rem1 [new] untracked bookmark: rem2@rem2 [new] untracked [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_with_glob_with_no_matching_remotes(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "upstream"); let output = work_dir.run_jj(["git", "fetch", "--remote=glob:rem*"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No git remotes matching 'rem*' Error: No git remotes to push [EOF] [exit status: 1] "); } // No remote should have been fetched as part of the failing transaction insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_all_remotes(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); // add empty [remote "rem3"] section to .git/config, which should be ignored work_dir .run_jj(["git", "remote", "add", "rem3", "../unknown"]) .success(); work_dir .run_jj(["git", "remote", "remove", "rem3"]) .success(); work_dir.run_jj(["git", "fetch", "--all-remotes"]).success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message rem2: pzqqpnpo 44c57802 message @rem2: pzqqpnpo 44c57802 message [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_multiple_remotes_from_config(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); add_git_remote(&test_env, &work_dir, "rem2"); test_env.add_config(r#"git.fetch = ["rem1", "rem2"]"#); work_dir.run_jj(["git", "fetch"]).success(); insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1: ppspxspk 4acd0343 message @rem1: ppspxspk 4acd0343 message rem2: pzqqpnpo 44c57802 message @rem2: pzqqpnpo 44c57802 message [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_no_matching_remote(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let output = work_dir.run_jj(["git", "fetch", "--remote", "rem1"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No git remotes matching 'rem1' Error: No git remotes to push [EOF] [exit status: 1] "); } insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @""); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_nonexistent_remote(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); let output = work_dir.run_jj(["git", "fetch", "--remote", "rem1", "--remote", "rem2"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No git remotes matching 'rem2' bookmark: rem1@rem1 [new] untracked [EOF] "); } insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1@rem1: ppspxspk 4acd0343 message [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_nonexistent_remote_from_config(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); add_git_remote(&test_env, &work_dir, "rem1"); test_env.add_config(r#"git.fetch = ["rem1", "rem2"]"#); let output = work_dir.run_jj(["git", "fetch"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: No git remotes matching 'rem2' bookmark: rem1@rem1 [new] untracked [EOF] "); } insta::allow_duplicates! { insta::assert_snapshot!(get_bookmark_output(&work_dir), @r" rem1@rem1: ppspxspk 4acd0343 message [EOF] "); } } #[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))] #[test_case(true; "spawn a git subprocess for remote calls")] fn test_git_fetch_from_remote_named_git(subprocess: bool) { let test_env = TestEnvironment::default().with_git_subprocess(subprocess); test_env.add_config("git.auto-local-bookmark = true"); let work_dir = test_env.work_dir("repo"); init_git_remote(&test_env, "git"); git::init(work_dir.root()); git::add_remote(work_dir.root(), "git", "../git"); // Existing remote named 'git' shouldn't block the repo initialization. work_dir.run_jj(["git", "init", "--git-repo=."]).success(); // Try fetching from the remote named 'git'. let output = work_dir.run_jj(["git", "fetch", "--remote=git"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Error: Git remote named 'git' is reserved for local Git repository Hint: Run `jj git remote rename` to give a different name. [EOF] [exit status: 1] "); } // Fetch remote refs by using the git CLI. git::fetch(work_dir.root(), "git"); // Implicit import shouldn't fail because of the remote ref. let output = work_dir.run_jj(["bookmark", "list", "--all-remotes"]); insta::allow_duplicates! { insta::assert_snapshot!(output, @r" ------- stderr ------- Warning: Failed to import some Git refs: refs/remotes/git/git Hint: Git remote named 'git' is reserved for local Git repository. Use `jj git remote rename` to give a different name.