2318 lines · 76.3 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::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");     work_dir.run_jj(["git", "fetch"]).success();    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    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_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    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 -------    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    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 -------    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 -------    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 -------    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() {    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");     // 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::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_multiple_remotes_from_config() {    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");    test_env.add_config(r#"git.fetch = ["rem1", "rem2"]"#);     work_dir.run_jj(["git", "fetch"]).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_no_matching_remote() {    let test_env = TestEnvironment::default();    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::assert_snapshot!(output, @"    ------- stderr -------    Warning: No matching remotes for names: rem1    Error: No git remotes to fetch from    [EOF]    [exit status: 1]    ");     let output = work_dir.run_jj(["git", "fetch", "--remote=rem1", "--remote=rem2"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Warning: No matching remotes for names: rem1, rem2    Error: No git remotes to fetch from    [EOF]    [exit status: 1]    ");     insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");} #[test]fn test_git_fetch_nonexistent_remote() {    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");     let output = work_dir.run_jj(["git", "fetch", "--remote", "rem1", "--remote", "rem2"]);    insta::assert_snapshot!(output, @"    ------- stderr -------    Warning: No matching remotes for names: rem2    bookmark: rem1@rem1 [new] untracked    [EOF]    ");    insta::assert_snapshot!(get_bookmark_output(&work_dir), @"

Lines 1–500 of 2318.