Files
jj-vcs-jj/cli/tests/test_gerrit_upload.rs
Gaëtan Lehmann bd036daa12 change-id: update tests
Note: we use longer short change-IDs in test_abandon_command to avoid
false codebook detection.
2026-06-27 15:29:00 +02:00

875 lines
29 KiB
Rust

// Copyright 2025 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 testutils::TestResult;
use crate::common::TestEnvironment;
use crate::common::create_commit;
use crate::common::create_commit_with_files;
#[test]
fn test_gerrit_upload_dryrun() {
let test_env = TestEnvironment::default();
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
let work_dir = test_env.work_dir("repo");
create_commit(&work_dir, "a", &[]);
create_commit(&work_dir, "b", &["a"]);
create_commit(&work_dir, "c", &["a"]);
let output = work_dir.run_jj(["gerrit", "upload", "-r", "b"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: No remote specified, and no 'gerrit' remote was found
[EOF]
[exit status: 1]
");
// With remote specified but.
test_env.add_config(r#"gerrit.default-remote="origin""#);
let output = work_dir.run_jj(["gerrit", "upload", "-r", "b"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: The remote 'origin' (configured via `gerrit.default-remote`) does not exist
[EOF]
[exit status: 1]
");
let output = work_dir.run_jj(["gerrit", "upload", "-r", "b", "--remote=origin"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: The remote 'origin' (specified via `--remote`) does not exist
[EOF]
[exit status: 1]
");
let output = work_dir.run_jj([
"git",
"remote",
"add",
"origin",
"http://example.com/repo/foo",
]);
insta::assert_snapshot!(output, @"");
let output = work_dir.run_jj(["gerrit", "upload", "-r", "b", "--remote=origin"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: No target branch specified via --remote-branch, and no 'gerrit.default-remote-branch' was found
[EOF]
[exit status: 1]
");
test_env.add_config(r#"gerrit.default-remote-branch="main""#);
let output = work_dir.run_jj(["gerrit", "upload", "-r", "b", "--dry-run"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Found 1 heads to push to Gerrit (remote 'origin'), target branch 'main'
Dry-run: Would push psuskuln dd148a1b b | b
[EOF]
");
let output = work_dir.run_jj(["gerrit", "upload", "-r", "b", "--dry-run", "-b", "other"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Found 1 heads to push to Gerrit (remote 'origin'), target branch 'other'
Dry-run: Would push psuskuln dd148a1b b | b
[EOF]
");
}
#[test]
fn test_gerrit_upload_default_revision() {
let test_env = TestEnvironment::default();
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
let work_dir = test_env.work_dir("repo");
work_dir
.run_jj([
"git",
"remote",
"add",
"origin",
"http://example.com/repo/foo",
])
.success();
test_env.add_config(r#"gerrit.default-remote="origin""#);
test_env.add_config(r#"gerrit.default-remote-branch="main""#);
work_dir
.run_jj(["new", "--message", "parent", "root()"])
.success();
work_dir.write_file("parent", "parent");
let output = work_dir.run_jj(["gerrit", "upload", "--dry-run"]);
insta::assert_snapshot!(output, @r"
------- stderr -------
No revision provided. Defaulting to @
Found 1 heads to push to Gerrit (remote 'origin'), target branch 'main'
Dry-run: Would push nkmpptxz f7f633c0 parent
[EOF]
");
work_dir.run_jj(["new"]).success();
let output = work_dir.run_jj(["gerrit", "upload", "--dry-run"]);
insta::assert_snapshot!(output, @r"
------- stderr -------
No revision provided and @ has no description. Defaulting to @-
Found 1 heads to push to Gerrit (remote 'origin'), target branch 'main'
Dry-run: Would push nkmpptxz f7f633c0 parent
[EOF]
");
work_dir.run_jj(["new", "@", "@-"]).success();
let output = work_dir.run_jj(["gerrit", "upload", "--dry-run"]);
insta::assert_snapshot!(output, @r"
------- stderr -------
Error: No revision provided, and @ is a merge commit with no description. Unable to determine a suitable default commit to upload.
Hint: Explicitly specify a revision to upload with `-r`
[EOF]
[exit status: 1]
");
work_dir.run_jj(["workspace", "forget"]).success();
let output = work_dir.run_jj(["gerrit", "upload", "--dry-run"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: No revision provided
Hint: Explicitly specify a revision to upload with `-r`
[EOF]
[exit status: 1]
");
}
#[test]
fn test_gerrit_upload_default_revision_already_in_trunk() {
let test_env = TestEnvironment::default();
test_env
.run_jj_in(".", ["git", "init", "--colocate", "remote"])
.success();
let remote_dir = test_env.work_dir("remote");
create_commit(&remote_dir, "main", &[]);
test_env
.run_jj_in(".", ["git", "clone", "remote", "local"])
.success();
let local_dir = test_env.work_dir("local");
test_env.add_config(r#"gerrit.default-remote="origin""#);
test_env.add_config(r#"gerrit.default-remote-branch="main""#);
test_env.add_config(r#"revset-aliases."trunk()" = "main@origin""#);
// Make @ an empty working-copy commit over immutable main@origin.
local_dir.run_jj(["new", "main@origin"]).success();
local_dir.run_jj(["describe", "-m="]).success();
let output = local_dir.run_jj(["gerrit", "upload", "--dry-run"]);
insta::assert_snapshot!(output, @r#"
------- stderr -------
No revision provided and @ has no description. Defaulting to @-
Error: Commit 86be1db760f2 is immutable
Hint: Could not modify commit: ylvkpnrz 86be1db7 main@origin | main
Hint: Immutable commits are used to protect shared history.
Hint: For more information, see:
- https://docs.jj-vcs.dev/latest/config/#set-of-immutable-commits
- `jj help -k config`, "Set of immutable commits"
Hint: This operation would rewrite 1 immutable commits.
[EOF]
[exit status: 1]
"#);
}
#[test]
fn test_gerrit_upload_option_failure() {
let test_env = TestEnvironment::default();
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
let work_dir = test_env.work_dir("repo");
// upload options are validated before anything else
// malformed custom option
let output = work_dir.run_jj(["gerrit", "upload", "--custom", "foo"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: Custom values must be of the form 'key:value'. Got foo
[EOF]
[exit status: 1]
");
// mutually exclusive flags
let output = work_dir.run_jj(["gerrit", "upload", "--wip", "--ready"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: --wip and --ready are mutually exclusive
[EOF]
[exit status: 1]
");
let output = work_dir.run_jj(["gerrit", "upload", "--private", "--remove-private"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: --private and --remove-private are mutually exclusive
[EOF]
[exit status: 1]
");
let output = work_dir.run_jj([
"gerrit",
"upload",
"--publish-comments",
"--no-publish-comments",
]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: --publish-comments and --no-publish-comments are mutually exclusive
[EOF]
[exit status: 1]
");
// cannot skip validation without submitting
let output = work_dir.run_jj(["gerrit", "upload", "--skip-validation"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: --skip-validation is only supported for --submit
[EOF]
[exit status: 1]
");
}
#[test]
fn test_gerrit_upload_failure() {
let test_env = TestEnvironment::default();
test_env
.run_jj_in(".", ["git", "init", "--colocate", "remote"])
.success();
let remote_dir = test_env.work_dir("remote");
create_commit(&remote_dir, "a", &[]);
test_env
.run_jj_in(".", ["git", "clone", "remote", "local"])
.success();
let local_dir = test_env.work_dir("local");
// construct test revisions
create_commit_with_files(&local_dir, "b", &["a@origin"], &[]);
create_commit(&local_dir, "c", &["a@origin"]);
local_dir.run_jj(["describe", "-m="]).success();
create_commit(&local_dir, "d", &["a@origin"]);
let output = local_dir.run_jj(["gerrit", "upload", "-r", "none()", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
No revisions to upload.
[EOF]
");
// empty revisions are not allowed
let output = local_dir.run_jj(["gerrit", "upload", "-r", "b", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: Refusing to upload revision pzvwutvlkqwt because it is empty
Hint: Perhaps you squashed then ran upload? Maybe you meant to upload the parent commit instead (eg. @-)
[EOF]
[exit status: 1]
");
// empty descriptions are not allowed
let output = local_dir.run_jj(["gerrit", "upload", "-r", "c", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: Refusing to upload revision nqosqzytrlsw because it is has no description
Hint: Maybe you meant to upload the parent commit instead (eg. @-)
[EOF]
[exit status: 1]
");
// upload failure
local_dir
.run_jj(["git", "remote", "set-url", "origin", "nonexistent"])
.success();
let output = local_dir.run_jj(["gerrit", "upload", "-r", "d", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Found 1 heads to push to Gerrit (remote 'origin'), target branch 'main'
Pushing qnkkpsqq 50f9c1c1 d | d
Error: Internal git error while pushing to gerrit
Caused by: Could not find repository at '$TEST_ENV/local/nonexistent'
[EOF]
[exit status: 1]
");
}
#[test]
fn test_gerrit_upload_local_implicit_change_ids() {
let test_env = TestEnvironment::default();
test_env
.run_jj_in(".", ["git", "init", "--colocate", "remote"])
.success();
let remote_dir = test_env.work_dir("remote");
create_commit(&remote_dir, "a", &[]);
test_env
.run_jj_in(".", ["git", "clone", "remote", "local"])
.success();
let local_dir = test_env.work_dir("local");
create_commit(&local_dir, "b", &["a@origin"]);
create_commit(&local_dir, "c", &["b"]);
// Ensure other trailers are preserved (no extra newlines)
local_dir
.run_jj([
"describe",
"c",
"-m",
"c\n\nSigned-off-by: Lucky K Maintainer <lucky@maintainer.example.org>\n",
])
.success();
// The output should only mention commit IDs from the log output above (no
// temporary commits)
let output = local_dir.run_jj(["log", "-r", "all()"]);
insta::assert_snapshot!(output, @"
@ nqosqzyt test.user@example.com 2001-02-03 08:05:15 c 06dc682a
│ c
○ pzvwutvl test.user@example.com 2001-02-03 08:05:12 b bd2773ca
│ b
◆ ylvkpnrz test.user@example.com 2001-02-03 08:05:09 a@origin a1afb583
│ a
◆ zzzzzzzz root() 00000000
[EOF]
");
let output = local_dir.run_jj(["gerrit", "upload", "-r", "c", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Found 1 heads to push to Gerrit (remote 'origin'), target branch 'main'
Pushing nqosqzyt 06dc682a c | c
[EOF]
");
// The output should be unchanged because we only add Change-Id trailers
// transiently
let output = local_dir.run_jj(["log", "-r", "all()"]);
insta::assert_snapshot!(output, @"
@ nqosqzyt test.user@example.com 2001-02-03 08:05:15 c 06dc682a
│ c
○ pzvwutvl test.user@example.com 2001-02-03 08:05:12 b bd2773ca
│ b
◆ ylvkpnrz test.user@example.com 2001-02-03 08:05:09 a@origin a1afb583
│ a
◆ zzzzzzzz root() 00000000
[EOF]
");
// There's no particular reason to run this with jj util exec, it's just that
// the infra makes it easier to run this way.
let output = remote_dir.run_jj(["util", "exec", "--", "git", "log", "refs/for/main"]);
insta::assert_snapshot!(output, @r"
commit d8b9cbe0b3ee36981d2d55050589d2d07fb05045
Author: Test User <test.user@example.com>
Date: Sat Feb 3 04:05:13 2001 +0700
c
Signed-off-by: Lucky K Maintainer <lucky@maintainer.example.org>
Change-Id: Ic9b790168e73f7a73a98deae21e807c06a6a6964
commit 166a6cec7b25f3206d67e661b5b354b60ae29998
Author: Test User <test.user@example.com>
Date: Sat Feb 3 04:05:11 2001 +0700
b
Change-Id: Ia043564ef93650b06a70f92f9d91912b6a6a6964
commit a1afb5834d8ee4dcb61b59db0f682c7a53f96f53
Author: Test User <test.user@example.com>
Date: Sat Feb 3 04:05:08 2001 +0700
a
[EOF]
");
}
#[test]
fn test_gerrit_upload_local_implicit_change_id_link() {
let test_env = TestEnvironment::default();
test_env.add_config(
r#"
[gerrit]
review-url = "https://gerrit.example.com/"
"#,
);
test_env
.run_jj_in(".", ["git", "init", "--colocate", "remote"])
.success();
let remote_dir = test_env.work_dir("remote");
create_commit(&remote_dir, "a", &[]);
test_env
.run_jj_in(".", ["git", "clone", "remote", "local"])
.success();
let local_dir = test_env.work_dir("local");
create_commit(&local_dir, "b", &["a@origin"]);
create_commit(&local_dir, "c", &["b"]);
// Ensure other trailers are preserved (no extra newlines)
local_dir
.run_jj([
"describe",
"c",
"-m",
"c\n\nSigned-off-by: Lucky K Maintainer <lucky@maintainer.example.org>\n",
])
.success();
// The output should only mention commit IDs from the log output above (no
// temporary commits)
let output = local_dir.run_jj(["log", "-r", "all()"]);
insta::assert_snapshot!(output, @"
@ nqosqzyt test.user@example.com 2001-02-03 08:05:15 c 06dc682a
│ c
○ pzvwutvl test.user@example.com 2001-02-03 08:05:12 b bd2773ca
│ b
◆ ylvkpnrz test.user@example.com 2001-02-03 08:05:09 a@origin a1afb583
│ a
◆ zzzzzzzz root() 00000000
[EOF]
");
let output = local_dir.run_jj(["gerrit", "upload", "-r", "c", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Found 1 heads to push to Gerrit (remote 'origin'), target branch 'main'
Pushing nqosqzyt 06dc682a c | c
[EOF]
");
// The output should be unchanged because we only add Link trailers
// transiently
let output = local_dir.run_jj(["log", "-r", "all()"]);
insta::assert_snapshot!(output, @"
@ nqosqzyt test.user@example.com 2001-02-03 08:05:15 c 06dc682a
│ c
○ pzvwutvl test.user@example.com 2001-02-03 08:05:12 b bd2773ca
│ b
◆ ylvkpnrz test.user@example.com 2001-02-03 08:05:09 a@origin a1afb583
│ a
◆ zzzzzzzz root() 00000000
[EOF]
");
// There's no particular reason to run this with jj util exec, it's just that
// the infra makes it easier to run this way.
let output = remote_dir.run_jj(["util", "exec", "--", "git", "log", "refs/for/main"]);
insta::assert_snapshot!(output, @r"
commit f4f2cd7de12a02296bbe8b2aeadf0abda9fc5e58
Author: Test User <test.user@example.com>
Date: Sat Feb 3 04:05:13 2001 +0700
c
Signed-off-by: Lucky K Maintainer <lucky@maintainer.example.org>
Link: https://gerrit.example.com/id/Ic9b790168e73f7a73a98deae21e807c06a6a6964
commit 0137efaa46414aac8f664eb33f5a7739b3372bda
Author: Test User <test.user@example.com>
Date: Sat Feb 3 04:05:11 2001 +0700
b
Link: https://gerrit.example.com/id/Ia043564ef93650b06a70f92f9d91912b6a6a6964
commit a1afb5834d8ee4dcb61b59db0f682c7a53f96f53
Author: Test User <test.user@example.com>
Date: Sat Feb 3 04:05:08 2001 +0700
a
[EOF]
");
}
#[test]
fn test_gerrit_upload_local_explicit_change_ids() {
let test_env = TestEnvironment::default();
test_env
.run_jj_in(".", ["git", "init", "--colocate", "remote"])
.success();
let remote_dir = test_env.work_dir("remote");
create_commit(&remote_dir, "a", &[]);
test_env
.run_jj_in(".", ["git", "clone", "remote", "local"])
.success();
let local_dir = test_env.work_dir("local");
create_commit(&local_dir, "b", &["a@origin"]);
// Add an explicit Change-Id footer to b
let output = local_dir.run_jj([
"describe",
"b",
"-m",
"b\n\nChange-Id: Id39b308212fe7e0b746d16c13355f3a90712d7f9\n",
]);
insta::assert_snapshot!(output, @"
------- stderr -------
Working copy (@) now at: pzvwutvl a92f28f1 b | b
Parent commit (@-) : ylvkpnrz a1afb583 a@origin | a
[EOF]
");
create_commit(&local_dir, "c", &["b"]);
// Add an explicit Link footer to c
let output = local_dir.run_jj([
"describe",
"c",
"-m",
"c\n\nLink: https://gerrit.example.com/id/Idfac1e8c149efddf5c7a286f787b43886a6a6964\n",
]);
insta::assert_snapshot!(output, @"
------- stderr -------
Working copy (@) now at: truxwmqv e5c39e2f c | c
Parent commit (@-) : pzvwutvl a92f28f1 b | b
[EOF]
");
// The output should only mention commit IDs from the log output above (no
// temporary commits)
let output = local_dir.run_jj(["log", "-r", "all()"]);
insta::assert_snapshot!(output, @"
@ truxwmqv test.user@example.com 2001-02-03 08:05:16 c e5c39e2f
│ c
○ pzvwutvl test.user@example.com 2001-02-03 08:05:13 b a92f28f1
│ b
◆ ylvkpnrz test.user@example.com 2001-02-03 08:05:09 a@origin a1afb583
│ a
◆ zzzzzzzz root() 00000000
[EOF]
");
let output = local_dir.run_jj(["gerrit", "upload", "-r", "c", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Found 1 heads to push to Gerrit (remote 'origin'), target branch 'main'
Pushing truxwmqv e5c39e2f c | c
[EOF]
");
// The output should be unchanged because no temporary commits should have
// been created
let output = local_dir.run_jj(["log", "-r", "all()"]);
insta::assert_snapshot!(output, @"
@ truxwmqv test.user@example.com 2001-02-03 08:05:16 c e5c39e2f
│ c
○ pzvwutvl test.user@example.com 2001-02-03 08:05:13 b a92f28f1
│ b
◆ ylvkpnrz test.user@example.com 2001-02-03 08:05:09 a@origin a1afb583
│ a
◆ zzzzzzzz root() 00000000
[EOF]
");
// There's no particular reason to run this with jj util exec, it's just that
// the infra makes it easier to run this way.
let output = remote_dir.run_jj(["util", "exec", "--", "git", "log", "refs/for/main"]);
insta::assert_snapshot!(output, @"
commit e5c39e2fe97d0c6db908e0bfe8487814cc04fa3d
Author: Test User <test.user@example.com>
Date: Sat Feb 3 04:05:14 2001 +0700
c
Link: https://gerrit.example.com/id/Idfac1e8c149efddf5c7a286f787b43886a6a6964
commit a92f28f1118f62b6b8c85eb7252e5a3c63720005
Author: Test User <test.user@example.com>
Date: Sat Feb 3 04:05:11 2001 +0700
b
Change-Id: Id39b308212fe7e0b746d16c13355f3a90712d7f9
commit a1afb5834d8ee4dcb61b59db0f682c7a53f96f53
Author: Test User <test.user@example.com>
Date: Sat Feb 3 04:05:08 2001 +0700
a
[EOF]
");
}
#[test]
fn test_gerrit_upload_local_mixed_change_ids() {
let test_env = TestEnvironment::default();
test_env
.run_jj_in(".", ["git", "init", "--colocate", "remote"])
.success();
let remote_dir = test_env.work_dir("remote");
create_commit(&remote_dir, "a", &[]);
test_env
.run_jj_in(".", ["git", "clone", "remote", "local"])
.success();
let local_dir = test_env.work_dir("local");
create_commit(&local_dir, "b", &["a@origin"]);
create_commit(&local_dir, "c", &["b"]);
// Add an explicit Change-Id footer to c but not b
let output = local_dir.run_jj([
"describe",
"c",
"-m",
"c\n\nChange-Id: Id39b308212fe7e0b746d16c13355f3a90712d7f9\n",
]);
insta::assert_snapshot!(output, @"
------- stderr -------
Working copy (@) now at: nqosqzyt a030199b c | c
Parent commit (@-) : pzvwutvl bd2773ca b | b
[EOF]
");
// The output should only mention commit IDs from the log output above (no
// temporary commits)
let output = local_dir.run_jj(["log", "-r", "all()"]);
insta::assert_snapshot!(output, @"
@ nqosqzyt test.user@example.com 2001-02-03 08:05:15 c a030199b
│ c
○ pzvwutvl test.user@example.com 2001-02-03 08:05:12 b bd2773ca
│ b
◆ ylvkpnrz test.user@example.com 2001-02-03 08:05:09 a@origin a1afb583
│ a
◆ zzzzzzzz root() 00000000
[EOF]
");
let output = local_dir.run_jj(["gerrit", "upload", "-r", "c", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Found 1 heads to push to Gerrit (remote 'origin'), target branch 'main'
Pushing nqosqzyt a030199b c | c
[EOF]
");
// The output should be unchanged because commits created within 'upload'
// should all be temporary
let output = local_dir.run_jj(["log", "-r", "all()"]);
insta::assert_snapshot!(output, @"
@ nqosqzyt test.user@example.com 2001-02-03 08:05:15 c a030199b
│ c
○ pzvwutvl test.user@example.com 2001-02-03 08:05:12 b bd2773ca
│ b
◆ ylvkpnrz test.user@example.com 2001-02-03 08:05:09 a@origin a1afb583
│ a
◆ zzzzzzzz root() 00000000
[EOF]
");
// There's no particular reason to run this with jj util exec, it's just that
// the infra makes it easier to run this way.
let output = remote_dir.run_jj(["util", "exec", "--", "git", "log", "refs/for/main"]);
insta::assert_snapshot!(output, @"
commit 1fad1dc37e6e6c0b2afc98f5103a7f912537110c
Author: Test User <test.user@example.com>
Date: Sat Feb 3 04:05:13 2001 +0700
c
Change-Id: Id39b308212fe7e0b746d16c13355f3a90712d7f9
commit 166a6cec7b25f3206d67e661b5b354b60ae29998
Author: Test User <test.user@example.com>
Date: Sat Feb 3 04:05:11 2001 +0700
b
Change-Id: Ia043564ef93650b06a70f92f9d91912b6a6a6964
commit a1afb5834d8ee4dcb61b59db0f682c7a53f96f53
Author: Test User <test.user@example.com>
Date: Sat Feb 3 04:05:08 2001 +0700
a
[EOF]
");
}
#[test]
fn test_gerrit_upload_bad_change_ids() {
let test_env = TestEnvironment::default();
test_env
.run_jj_in(".", ["git", "init", "--colocate", "remote"])
.success();
let remote_dir = test_env.work_dir("remote");
create_commit(&remote_dir, "a", &[]);
test_env
.run_jj_in(".", ["git", "clone", "remote", "local"])
.success();
let local_dir = test_env.work_dir("local");
create_commit(&local_dir, "b", &["a@origin"]);
create_commit(&local_dir, "b2", &["b"]);
create_commit(&local_dir, "b3", &["b2"]);
create_commit(&local_dir, "b4", &["b3"]);
create_commit(&local_dir, "c", &["a@origin"]);
create_commit(&local_dir, "d", &["a@origin"]);
create_commit(&local_dir, "e", &["a@origin"]);
local_dir
.run_jj(["describe", "-rb", "-m\n\nChange-Id: malformed\n"])
.success();
local_dir
.run_jj([
"describe",
"-rb2",
"-m\n\nChange-Id: i0000000000000000000000000000000000000000\n",
])
.success();
local_dir
.run_jj(["describe", "-rb3", "-m\n\nLink: malformed\n"])
.success();
local_dir
.run_jj([
"describe",
"-rb4",
"-m\n\nLink: https://gerrit.example.com/id/Imalformed\n",
])
.success();
local_dir
.run_jj([
"describe",
"-rc",
"-m",
concat!(
"\n\n",
"Change-Id: I1111111111111111111111111111111111111111\n",
"Change-Id: I2222222222222222222222222222222222222222\n",
),
])
.success();
local_dir
.run_jj([
"describe",
"-rd",
"-m",
concat!(
"\n\n",
"Link: https://gerrit.example.com/id/I1111111111111111111111111111111111111111\n",
"Change-Id: I2222222222222222222222222222222222222222\n",
),
])
.success();
local_dir
.run_jj([
"describe",
"-re",
"-m",
concat!(
"\n\n",
"Link: https://gerrit.example.com/id/I1111111111111111111111111111111111111111\n",
"Link: https://gerrit.example.com/id/I2222222222222222222222222222222222222222\n",
),
])
.success();
let output = local_dir.run_jj(["gerrit", "upload", "-rc", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: Multiple Change-Id footers in revision vqnwkozpkust
[EOF]
[exit status: 1]
");
let output = local_dir.run_jj(["gerrit", "upload", "-rd", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: Multiple Change-Id footers in revision uxryzmorwvtz
[EOF]
[exit status: 1]
");
let output = local_dir.run_jj(["gerrit", "upload", "-re", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Error: Multiple Change-Id footers in revision wyznsvlquzzm
[EOF]
[exit status: 1]
");
// check both badly and slightly malformed Change-Id / Link trailers
let output = local_dir.run_jj(["gerrit", "upload", "-rb4", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Warning: Invalid Change-Id footer in revision pzvwutvlkqwt
Warning: Invalid Change-Id footer in revision nqosqzytrlsw
Warning: Invalid Link footer in revision rostqsxwqrlt
Warning: Invalid Link footer in revision kpqxywonksrl
Found 1 heads to push to Gerrit (remote 'origin'), target branch 'main'
Pushing kpqxywon 45cdd32b b4
[EOF]
");
}
#[test]
fn test_gerrit_upload_rejected_by_remote() -> TestResult {
let test_env = TestEnvironment::default();
test_env
.run_jj_in(".", ["git", "init", "--colocate", "remote"])
.success();
let remote_dir = test_env.work_dir("remote");
create_commit(&remote_dir, "a", &[]);
// create a hook on the remote that prevents pushing
let hook_path = test_env
.env_root()
.join("remote")
.join(".git")
.join("hooks")
.join("update");
std::fs::write(&hook_path, "#!/bin/sh\nexit 1")?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt as _;
std::fs::set_permissions(&hook_path, std::fs::Permissions::from_mode(0o700))?;
}
test_env
.run_jj_in(".", ["git", "clone", "remote", "local"])
.success();
let local_dir = test_env.work_dir("local");
create_commit(&local_dir, "b", &["a@origin"]);
// Add an explicit Change-Id footer to b
let output = local_dir.run_jj([
"describe",
"b",
"-m",
"b\n\nChange-Id: Id39b308212fe7e0b746d16c13355f3a90712d7f9\n",
]);
insta::assert_snapshot!(output, @"
------- stderr -------
Working copy (@) now at: pzvwutvl a92f28f1 b | b
Parent commit (@-) : ylvkpnrz a1afb583 a@origin | a
[EOF]
");
let output = local_dir.run_jj(["gerrit", "upload", "-r", "b", "--remote-branch=main"]);
insta::assert_snapshot!(output, @"
------- stderr -------
Found 1 heads to push to Gerrit (remote 'origin'), target branch 'main'
Pushing pzvwutvl a92f28f1 b | b
remote: error: hook declined to update refs/for/main
Warning: The remote rejected the following updates:
refs/for/main (reason: hook declined)
Hint: Try checking if you have permission to push to all the bookmarks.
Error: Failed to push all changes to gerrit
[EOF]
[exit status: 1]
");
Ok(())
}