2655 lines · 90.8 KB · Rust
RawDownload
// Copyright 2022 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::CommandOutput;use crate::common::TestEnvironment;use crate::common::TestWorkDir; fn git_repo_dir_for_jj_repo(work_dir: &TestWorkDir<'_>) -> std::path::PathBuf {    work_dir        .root()        .join(".jj")        .join("repo")        .join("store")        .join("git")} fn set_up(test_env: &TestEnvironment) {    test_env.run_jj_in(".", ["git", "init", "origin"]).success();    let origin_dir = test_env.work_dir("origin");    let origin_git_repo_path = git_repo_dir_for_jj_repo(&origin_dir);     origin_dir        .run_jj(["describe", "-m=description 1"])        .success();    origin_dir        .run_jj(["bookmark", "create", "-r@", "bookmark1"])        .success();    origin_dir        .run_jj(["new", "root()", "-m=description 2"])        .success();    origin_dir        .run_jj(["bookmark", "create", "-r@", "bookmark2"])        .success();    origin_dir.run_jj(["git", "export"]).success();     test_env        .run_jj_in(            ".",            [                "git",                "clone",                "--config=git.auto-local-bookmark=true",                origin_git_repo_path.to_str().unwrap(),                "local",            ],        )        .success();} #[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_push_nothing(subprocess: bool) {    let test_env = TestEnvironment::default();    set_up(&test_env);    let work_dir = test_env.work_dir("local");    if !subprocess {        test_env.add_config("git.subprocess = false");    }    // Show the setup. `insta` has trouble if this is done inside `set_up()`    insta::allow_duplicates! {    insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"    bookmark1: xtvrqkyv d13ecdbd (empty) description 1      @origin: xtvrqkyv d13ecdbd (empty) description 1    bookmark2: rlzusymt 8476341e (empty) description 2      @origin: rlzusymt 8476341e (empty) description 2    [EOF]    ");    }    // No bookmarks to push yet    let output = work_dir.run_jj(["git", "push", "--all"]);    insta::allow_duplicates! {    insta::assert_snapshot!(output, @r"    ------- stderr -------    Nothing changed.    [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_push_current_bookmark(subprocess: bool) {    let test_env = TestEnvironment::default();    set_up(&test_env);    let work_dir = test_env.work_dir("local");    if !subprocess {        test_env.add_config("git.subprocess = false");    }    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.    work_dir        .run_jj(["describe", "bookmark1", "-m", "modified bookmark1 commit"])        .success();    work_dir.run_jj(["new", "bookmark2"]).success();    work_dir        .run_jj(["bookmark", "set", "bookmark2", "-r@"])        .success();    work_dir        .run_jj(["bookmark", "create", "-r@", "my-bookmark"])        .success();    work_dir.run_jj(["describe", "-m", "foo"]).success();    // Check the setup    insta::allow_duplicates! {    insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"    bookmark1: xtvrqkyv 0f8dc656 (empty) modified bookmark1 commit      @origin (ahead by 1 commits, behind by 1 commits): xtvrqkyv hidden d13ecdbd (empty) description 1    bookmark2: yostqsxw bc7610b6 (empty) foo      @origin (behind by 1 commits): rlzusymt 8476341e (empty) description 2    my-bookmark: yostqsxw bc7610b6 (empty) foo    [EOF]    ");    }    // First dry-run. `bookmark1` should not get pushed.    let output = work_dir.run_jj(["git", "push", "--allow-new", "--dry-run"]);    insta::allow_duplicates! {    insta::assert_snapshot!(output, @r"    ------- stderr -------    Changes to push to origin:      Move forward bookmark bookmark2 from 8476341eb395 to bc7610b65a91      Add bookmark my-bookmark to bc7610b65a91    Dry-run requested, not pushing.    [EOF]    ");    }    let output = work_dir.run_jj(["git", "push", "--allow-new"]);    insta::allow_duplicates! {    insta::assert_snapshot!(output, @r"    ------- stderr -------    Changes to push to origin:      Move forward bookmark bookmark2 from 8476341eb395 to bc7610b65a91      Add bookmark my-bookmark to bc7610b65a91    [EOF]    ");    }    insta::allow_duplicates! {    insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"    bookmark1: xtvrqkyv 0f8dc656 (empty) modified bookmark1 commit      @origin (ahead by 1 commits, behind by 1 commits): xtvrqkyv hidden d13ecdbd (empty) description 1    bookmark2: yostqsxw bc7610b6 (empty) foo      @origin: yostqsxw bc7610b6 (empty) foo    my-bookmark: yostqsxw bc7610b6 (empty) foo      @origin: yostqsxw bc7610b6 (empty) foo    [EOF]    ");    }     // Try pushing backwards    work_dir        .run_jj([            "bookmark",            "set",            "bookmark2",            "-rbookmark2-",            "--allow-backwards",        ])        .success();    // This behavior is a strangeness of our definition of the default push revset.    // We could consider changing it.    let output = work_dir.run_jj(["git", "push"]);    insta::allow_duplicates! {    insta::assert_snapshot!(output, @r"    ------- stderr -------    Warning: No bookmarks found in the default push revset: remote_bookmarks(remote=origin)..@    Nothing changed.    [EOF]    ");    }    // We can move a bookmark backwards    let output = work_dir.run_jj(["git", "push", "-bbookmark2"]);    insta::allow_duplicates! {    insta::assert_snapshot!(output, @r"    ------- stderr -------    Changes to push to origin:      Move backward bookmark bookmark2 from bc7610b65a91 to 8476341eb395    [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_push_parent_bookmark(subprocess: bool) {    let test_env = TestEnvironment::default();    set_up(&test_env);    let work_dir = test_env.work_dir("local");    if !subprocess {        test_env.add_config("git.subprocess = false");    }    test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#);    work_dir.run_jj(["edit", "bookmark1"]).success();    work_dir        .run_jj(["describe", "-m", "modified bookmark1 commit"])        .success();    work_dir        .run_jj(["new", "-m", "non-empty description"])        .success();    work_dir.write_file("file", "file");    let output = work_dir.run_jj(["git", "push"]);    insta::allow_duplicates! {    insta::assert_snapshot!(output, @r"    ------- stderr -------    Changes to push to origin:      Move sideways bookmark bookmark1 from d13ecdbda2a2 to e612d524a5c6    [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_push_no_matching_bookmark(subprocess: bool) {    let test_env = TestEnvironment::default();    set_up(&test_env);    let work_dir = test_env.work_dir("local");    if !subprocess {        test_env.add_config("git.subprocess = false");    }    work_dir.run_jj(["new"]).success();    let output = work_dir.run_jj(["git", "push"]);    insta::allow_duplicates! {    insta::assert_snapshot!(output, @r"    ------- stderr -------    Warning: No bookmarks found in the default push revset: remote_bookmarks(remote=origin)..@    Nothing changed.    [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_push_matching_bookmark_unchanged(subprocess: bool) {    let test_env = TestEnvironment::default();    set_up(&test_env);    let work_dir = test_env.work_dir("local");    if !subprocess {        test_env.add_config("git.subprocess = false");    }    work_dir.run_jj(["new", "bookmark1"]).success();    let output = work_dir.run_jj(["git", "push"]);    insta::allow_duplicates! {    insta::assert_snapshot!(output, @r"    ------- stderr -------    Warning: No bookmarks found in the default push revset: remote_bookmarks(remote=origin)..@    Nothing changed.    [EOF]    ");    }} /// 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=<remote>)..@` vs. `remote_bookmarks()..@`).#[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_push_other_remote_has_bookmark(subprocess: bool) {    let test_env = TestEnvironment::default();    set_up(&test_env);    let work_dir = test_env.work_dir("local");    if !subprocess {        test_env.add_config("git.subprocess = false");    }    test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#);    // Create another remote (but actually the same)    let other_remote_path = test_env        .env_root()        .join("origin")        .join(".jj")        .join("repo")        .join("store")        .join("git");    work_dir        .run_jj([            "git",            "remote",            "add",            "other",            other_remote_path.to_str().unwrap(),        ])        .success();    // Modify bookmark1 and push it to `origin`    work_dir.run_jj(["edit", "bookmark1"]).success();    work_dir.run_jj(["describe", "-m=modified"]).success();    let output = work_dir.run_jj(["git", "push"]);    insta::allow_duplicates! {    insta::assert_snapshot!(output, @r"    ------- stderr -------    Changes to push to origin:      Move sideways bookmark bookmark1 from d13ecdbda2a2 to a657f1b61b94    [EOF]    ");    }    // Since it's already pushed to origin, nothing will happen if push again    let output = work_dir.run_jj(["git", "push"]);    insta::allow_duplicates! {    insta::assert_snapshot!(output, @r"    ------- stderr -------    Warning: No bookmarks found in the default push revset: remote_bookmarks(remote=origin)..@    Nothing changed.    [EOF]    ");    }    // The bookmark was moved on the "other" remote as well (since it's actually the    // same remote), but `jj` is not aware of that since it thinks this is a    // different remote. So, the push should fail.    //    // But it succeeds! That's because the bookmark is created at the same location    // as it is on the remote. This would also work for a descendant.    //    // TODO: Saner test?    let output = work_dir.run_jj(["git", "push", "--allow-new", "--remote=other"]);    insta::allow_duplicates! {    insta::assert_snapshot!(output, @r"    ------- stderr -------    Changes to push to other:      Add bookmark bookmark1 to a657f1b61b94    [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_push_forward_unexpectedly_moved(subprocess: bool) {    let test_env = TestEnvironment::default();    set_up(&test_env);    let work_dir = test_env.work_dir("local");    if !subprocess {        test_env.add_config("git.subprocess = false");    }     // Move bookmark1 forward on the remote    let origin_dir = test_env.work_dir("origin");    origin_dir        .run_jj(["new", "bookmark1", "-m=remote"])        .success();    origin_dir.write_file("remote", "remote");    origin_dir        .run_jj(["bookmark", "set", "bookmark1", "-r@"])        .success();    origin_dir.run_jj(["git", "export"]).success();     // Move bookmark1 forward to another commit locally    work_dir.run_jj(["new", "bookmark1", "-m=local"]).success();    work_dir.write_file("local", "local");    work_dir        .run_jj(["bookmark", "set", "bookmark1", "-r@"])        .success();     // Pushing should fail    let output = work_dir.run_jj(["git", "push"]);    if subprocess {        insta::assert_snapshot!(output, @r"        ------- stderr -------        Changes to push to origin:          Move forward bookmark bookmark1 from d13ecdbda2a2 to 6750425ff51c        Error: Failed to push some bookmarks        Hint: The following references unexpectedly moved on the remote:          refs/heads/bookmark1 (reason: stale info)        Hint: Try fetching from the remote, then make the bookmark point to where you want it to be, and push again.        [EOF]        [exit status: 1]        ");    } else {        insta::assert_snapshot!(output, @r"        ------- stderr -------        Changes to push to origin:          Move forward bookmark bookmark1 from d13ecdbda2a2 to 6750425ff51c        Error: Failed to push some bookmarks        Hint: The following references unexpectedly moved on the remote:          refs/heads/bookmark1        Hint: Try fetching from the remote, then make the bookmark point to where you want it to be, and push again.        [EOF]        [exit status: 1]        ");    }} #[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_push_sideways_unexpectedly_moved(subprocess: bool) {    let test_env = TestEnvironment::default();    set_up(&test_env);    let work_dir = test_env.work_dir("local");    if !subprocess {        test_env.add_config("git.subprocess = false");    }     // Move bookmark1 forward on the remote    let origin_dir = test_env.work_dir("origin");    origin_dir        .run_jj(["new", "bookmark1", "-m=remote"])        .success();    origin_dir.write_file("remote", "remote");    origin_dir        .run_jj(["bookmark", "set", "bookmark1", "-r@"])        .success();    insta::allow_duplicates! {    insta::assert_snapshot!(get_bookmark_output(&origin_dir), @r"    bookmark1: vruxwmqv 80284bec remote      @git (behind by 1 commits): qpvuntsm d13ecdbd (empty) description 1    bookmark2: zsuskuln 8476341e (empty) description 2      @git: zsuskuln 8476341e (empty) description 2    [EOF]    ");    }    origin_dir.run_jj(["git", "export"]).success();     // Move bookmark1 sideways to another commit locally    work_dir.run_jj(["new", "root()", "-m=local"]).success();    work_dir.write_file("local", "local");    work_dir        .run_jj(["bookmark", "set", "bookmark1", "--allow-backwards", "-r@"])        .success();    insta::allow_duplicates! {    insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"    bookmark1: kmkuslsw 0f8bf988 local      @origin (ahead by 1 commits, behind by 1 commits): xtvrqkyv d13ecdbd (empty) description 1    bookmark2: rlzusymt 8476341e (empty) description 2      @origin: rlzusymt 8476341e (empty) description 2    [EOF]    ");    }     let output = work_dir.run_jj(["git", "push"]);    if subprocess {        insta::assert_snapshot!(output, @r"        ------- stderr -------        Changes to push to origin:          Move sideways bookmark bookmark1 from d13ecdbda2a2 to 0f8bf988588e        Error: Failed to push some bookmarks        Hint: The following references unexpectedly moved on the remote:          refs/heads/bookmark1 (reason: stale info)        Hint: Try fetching from the remote, then make the bookmark point to where you want it to be, and push again.        [EOF]        [exit status: 1]        ");    } else {        insta::assert_snapshot!(output, @r"        ------- stderr -------        Changes to push to origin:          Move sideways bookmark bookmark1 from d13ecdbda2a2 to 0f8bf988588e        Error: Failed to push some bookmarks        Hint: The following references unexpectedly moved on the remote:          refs/heads/bookmark1        Hint: Try fetching from the remote, then make the bookmark point to where you want it to be, and push again.        [EOF]        [exit status: 1]        ");    }} // This tests whether the push checks that the remote bookmarks are in expected// positions.#[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_push_deletion_unexpectedly_moved(subprocess: bool) {    let test_env = TestEnvironment::default();    set_up(&test_env);    let work_dir = test_env.work_dir("local");    if !subprocess {        test_env.add_config("git.subprocess = false");    }     // Move bookmark1 forward on the remote    let origin_dir = test_env.work_dir("origin");    origin_dir        .run_jj(["new", "bookmark1", "-m=remote"])        .success();    origin_dir.write_file("remote", "remote");    origin_dir        .run_jj(["bookmark", "set", "bookmark1", "-r@"])        .success();    insta::allow_duplicates! {    insta::assert_snapshot!(get_bookmark_output(&origin_dir), @r"    bookmark1: vruxwmqv 80284bec remote      @git (behind by 1 commits): qpvuntsm d13ecdbd (empty) description 1    bookmark2: zsuskuln 8476341e (empty) description 2      @git: zsuskuln 8476341e (empty) description 2    [EOF]    ");    }    origin_dir.run_jj(["git", "export"]).success();     // Delete bookmark1 locally

Lines 1–500 of 2655.