2706 lines · 90.7 KB · Rust
RawDownload
// 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 std::io::Write as _; use indoc::indoc;use testutils::TestResult;use testutils::git; use crate::common::CommandOutput;use crate::common::TestEnvironment;use crate::common::TestWorkDir;use crate::common::create_commit; fn add_commit_to_branch(git_repo: &gix::Repository, branch: &str, message: &str) -> gix::ObjectId {    // Get current commit ID of the branch if it exists    let parents = git_repo        .find_reference(&format!("refs/heads/{branch}"))        .ok()        .and_then(|mut r| r.peel_to_commit().ok())        .map(|c| vec![c.id().detach()])        .unwrap_or_default();     git::add_commit(        git_repo,        &format!("refs/heads/{branch}"),        branch,            // filename        branch.as_bytes(), // content        message,        &parents,    )    .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, "message");     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_tag_output(work_dir: &TestWorkDir) -> CommandOutput {    work_dir.run_jj(["tag", "list", "--all-remotes"])} #[must_use]fn get_log_output(work_dir: &TestWorkDir) -> CommandOutput {    let template = indoc! {r#"        separate(" ",          commit_id.short(),          '"' ++ description.first_line() ++ '"',          bookmarks,          tags,        ) ++ "\n"    "#};    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()        .unwrap()        .detach();     fork_repo        .reference(            format!("refs/heads/{upstream}"),            upstream_head,            gix::refs::transaction::PreviousValue::MustNotExist,            "create tracking head",        )        .unwrap();     fork_repo} #[test]fn test_git_fetch_with_default_config() {    let test_env = TestEnvironment::default();    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");     // If supported, this should show fetched refs without actually updating    // refs on disk.    let output = work_dir.run_jj(["git", "fetch", "--no-integrate-operation"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Error: --no-integrate-operation is not respected    [EOF]    [exit status: 2]    ");     let output = work_dir.run_jj(["git", "fetch"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Fetching from Git remotes: origin    bookmark: origin@origin [new] untracked    [EOF]    ");    insta::assert_snapshot!(get_bookmark_output(&work_dir), @"    origin@origin: qmyrypzk ab8b299e message    [EOF]    ");} #[test]fn test_git_fetch_default_remote() {    let test_env = TestEnvironment::default();    test_env.add_config("remotes.origin.auto-track-bookmarks = '*'");    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::assert_snapshot!(get_bookmark_output(&work_dir), @"    origin: qmyrypzk ab8b299e message      @origin: qmyrypzk ab8b299e message    [EOF]    ");} #[test]fn test_git_fetch_single_remote() {    let test_env = TestEnvironment::default();    test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");    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::assert_snapshot!(output, @"    ------- stderr -------    Hint: Fetching from the only existing remote: rem1    Fetching from Git remotes: rem1    bookmark: rem1@rem1 [new] tracked    [EOF]    ");    insta::assert_snapshot!(get_bookmark_output(&work_dir), @"    rem1: ppspxspk 4acd0343 message      @rem1: ppspxspk 4acd0343 message    [EOF]    ");} #[test]fn test_git_fetch_single_remote_all_remotes_flag() {    let test_env = TestEnvironment::default();    test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");    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::assert_snapshot!(get_bookmark_output(&work_dir), @"    rem1: ppspxspk 4acd0343 message      @rem1: ppspxspk 4acd0343 message    [EOF]    ");} #[test]fn test_git_fetch_single_remote_from_arg() {    let test_env = TestEnvironment::default();    test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");    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::assert_snapshot!(get_bookmark_output(&work_dir), @"    rem1: ppspxspk 4acd0343 message      @rem1: ppspxspk 4acd0343 message    [EOF]    ");} #[test]fn test_git_fetch_single_remote_from_config() {    let test_env = TestEnvironment::default();    test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");    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::assert_snapshot!(get_bookmark_output(&work_dir), @"    rem1: ppspxspk 4acd0343 message      @rem1: ppspxspk 4acd0343 message    [EOF]    ");} #[test]fn test_git_fetch_multiple_remotes() {    let test_env = TestEnvironment::default();    test_env.add_config("remotes.rem1.auto-track-bookmarks = '*'");    test_env.add_config("remotes.rem2.auto-track-bookmarks = '*'");    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::assert_snapshot!(get_bookmark_output(&work_dir), @"    rem1: ppspxspk 4acd0343 message      @rem1: ppspxspk 4acd0343 message    rem2: pzqqpnpo 44c57802 message      @rem2: pzqqpnpo 44c57802 message    [EOF]    ");} #[test]fn test_git_fetch_default_bookmarks_and_tags() {    let test_env = TestEnvironment::default();    test_env.run_jj_in(".", ["git", "init", "repo"]).success();    let work_dir = test_env.work_dir("repo");     let rem1_repo = add_git_remote(&test_env, &work_dir, "rem1");    let rem2_repo = add_git_remote(&test_env, &work_dir, "rem2");    let setup_opid = work_dir.current_operation_id();     git::add_commit(&rem1_repo, "refs/tags/tag1", "file", b"", "1a", &[]);    git::add_commit(&rem1_repo, "refs/heads/branch1", "file", b"", "1b", &[]);    git::add_commit(&rem1_repo, "refs/tags/tag2", "file", b"", "1c", &[]);    git::add_commit(&rem1_repo, "refs/heads/branch2", "file", b"", "1d", &[]);    git::add_commit(&rem2_repo, "refs/tags/tag1", "file", b"", "2a", &[]);    git::add_commit(&rem2_repo, "refs/heads/branch1", "file", b"", "2b", &[]);    git::add_commit(&rem2_repo, "refs/tags/tag2", "file", b"", "2c", &[]);    git::add_commit(&rem2_repo, "refs/heads/branch2", "file", b"", "2d", &[]);     // Per-remote default config    test_env.add_config(indoc! {"        [remotes.rem1]        fetch-bookmarks = 'branch1'        fetch-tags = 'tag1'        [remotes.rem2]        fetch-bookmarks = 'branch2'        fetch-tags = 'tag2'    "});    let output = work_dir.run_jj(["git", "fetch", "--all-remotes"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Fetching from Git remotes: rem1, rem2    bookmark: branch1@rem1 [new] untracked    bookmark: branch2@rem2 [new] untracked    tag: tag1@rem1 [new] tracked    tag: tag2@rem2 [new] tracked    [EOF]    ");     // Default fetch-bookmarks/tags should be disabled by --branch    work_dir.run_jj(["op", "restore", &setup_opid]).success();    let output = work_dir.run_jj(["git", "fetch", "--all-remotes", "--branch=*"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Fetching from Git remotes: rem1, rem2    bookmark: branch1@rem1 [new] untracked    bookmark: branch1@rem2 [new] untracked    bookmark: branch2@rem1 [new] untracked    bookmark: branch2@rem2 [new] untracked    bookmark: rem1@rem1    [new] untracked    bookmark: rem2@rem2    [new] untracked    [EOF]    ");     // Default fetch-bookmarks/tags should be disabled by --tag    work_dir.run_jj(["op", "restore", &setup_opid]).success();    let output = work_dir.run_jj(["git", "fetch", "--all-remotes", "--tag=~*"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Fetching from Git remotes: rem1, rem2    Nothing changed.    [EOF]    ");} #[test]fn test_git_fetch_with_ignored_refspecs() {    let test_env = TestEnvironment::default();    test_env.run_jj_in(".", ["git", "init", "repo"]).success();    let source_repo = init_git_remote(&test_env, "origin");     for branch in [        "main", "foo", "foobar", "foobaz", "bar", "sub/yes", "sub/no",    ] {        add_commit_to_branch(&source_repo, branch, branch);    }     let work_dir = test_env.work_dir("repo");    std::fs::OpenOptions::new()        .append(true)        .open(work_dir.root().join(".jj/repo/store/git/config"))        .expect("failed to open config file")        .write_all(            br#"            [remote "origin"]            url = ../origin/.git            fetch = +refs/heads/main:refs/remotes/origin/main            fetch = +refs/heads/sub/*:refs/remotes/origin/sub/*            fetch = +refs/heads/foo*:refs/remotes/origin/baz*            fetch = +refs/heads/bar*:refs/tags/bar*            fetch = refs/heads/bar            fetch = ^refs/heads/sub/no            "#,        )        .expect("failed to update config file");     // Should fetch "main" and "sub/yes" by default    let output = work_dir.run_jj(["git", "fetch"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Warning: Ignored refspec `refs/heads/bar` from `origin`: fetch-only refspecs are not supported    Warning: Ignored refspec `+refs/heads/bar*:refs/tags/bar*` from `origin`: only refs/remotes/ is supported for fetch destinations    Warning: Ignored refspec `+refs/heads/foo*:refs/remotes/origin/baz*` from `origin`: renaming is not supported    Fetching from Git remotes: origin    bookmark: main@origin    [new] untracked    bookmark: sub/yes@origin [new] untracked    [EOF]    ");    insta::assert_snapshot!(get_bookmark_output(&work_dir), @"    main@origin: wlltxvop a437242b main    sub/yes@origin: xwxtqxvy 6b64b005 sub/yes    [EOF]    ");     // Can fetch ignored "sub/no" explicitly    let output = work_dir.run_jj(["git", "fetch", "--branch=sub/no"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Fetching from Git remotes: origin    bookmark: sub/no@origin [new] untracked    [EOF]    ");    insta::assert_snapshot!(get_bookmark_output(&work_dir), @"    main@origin: wlltxvop a437242b main    sub/no@origin: tknwmolt f7d8b914 sub/no    sub/yes@origin: xwxtqxvy 6b64b005 sub/yes    [EOF]    ");     // Forget "sub/no" without exporting the change to Git    work_dir        .run_jj(["bookmark", "forget", "--include-remotes", "sub/no"])        .success();    insta::assert_snapshot!(get_bookmark_output(&work_dir), @"    main@origin: wlltxvop a437242b main    sub/yes@origin: xwxtqxvy 6b64b005 sub/yes    [EOF]    ");     // Should not import "sub/no" because it is ignored by default    let output = work_dir.run_jj(["git", "fetch"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Warning: Ignored refspec `refs/heads/bar` from `origin`: fetch-only refspecs are not supported    Warning: Ignored refspec `+refs/heads/bar*:refs/tags/bar*` from `origin`: only refs/remotes/ is supported for fetch destinations    Warning: Ignored refspec `+refs/heads/foo*:refs/remotes/origin/baz*` from `origin`: renaming is not supported    Fetching from Git remotes: origin    Nothing changed.    [EOF]    ");    insta::assert_snapshot!(get_bookmark_output(&work_dir), @"    main@origin: wlltxvop a437242b main    sub/yes@origin: xwxtqxvy 6b64b005 sub/yes    [EOF]    ");} #[test]fn test_git_fetch_with_glob() {    let test_env = TestEnvironment::default();    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", "*"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Fetching from Git remotes: rem1, rem2    bookmark: rem1@rem1 [new] untracked    bookmark: rem2@rem2 [new] untracked    [EOF]    ");} #[test]fn test_git_fetch_with_glob_and_exact_match() {    let test_env = TestEnvironment::default();    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=rem*", "--remote=origin"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Fetching from Git remotes: origin, rem1, rem2    bookmark: origin@origin [new] untracked    bookmark: rem1@rem1     [new] untracked    bookmark: rem2@rem2     [new] untracked    [EOF]    ");} #[test]fn test_git_fetch_with_glob_from_config() {    let test_env = TestEnvironment::default();    test_env.add_config(r#"git.fetch = "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::assert_snapshot!(output, @"    ------- stderr -------    Fetching from Git remotes: rem1, rem2    bookmark: rem1@rem1 [new] untracked    bookmark: rem2@rem2 [new] untracked    [EOF]    ");} #[test]fn test_git_fetch_with_glob_with_no_matching_remotes() {    let test_env = TestEnvironment::default();    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=rem*"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Error: No git remotes to fetch from    [EOF]    [exit status: 1]    ");    // No remote should have been fetched as part of the failing transaction    insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");} #[test]fn test_git_fetch_all_remotes() {

Lines 1–500 of 2706.