ok/jj
1
0
Fork 0
forked from mirrors/jj
jj/cli/tests/test_commit_template.rs
tinger d0a29a831d cli: add ui.color = "debug"
When using `ui.color = "debug"`, changes in the output style
additionally include delimiters << and >>, as well as all active labels
at this point separated by ::. The output is otherwise unformatted and
the delimiters and labels inherit the style of the content they apply
to.
2024-05-11 10:16:09 +02:00

873 lines
38 KiB
Rust
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 regex::Regex;
use crate::common::TestEnvironment;
#[test]
fn test_log_parents() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["new"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@-"]);
test_env.jj_cmd_ok(&repo_path, &["new", "@", "@-"]);
let template =
r#"commit_id ++ "\nP: " ++ parents.len() ++ " " ++ parents.map(|c| c.commit_id()) ++ "\n""#;
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", template]);
insta::assert_snapshot!(stdout, @r###"
@ c067170d4ca1bc6162b64f7550617ec809647f84
├─╮ P: 2 4db490c88528133d579540b6900b8098f0c17701 230dd059e1b059aefc0da06a2e5a7dbf22362f22
◉ │ 4db490c88528133d579540b6900b8098f0c17701
├─╯ P: 1 230dd059e1b059aefc0da06a2e5a7dbf22362f22
◉ 230dd059e1b059aefc0da06a2e5a7dbf22362f22
│ P: 1 0000000000000000000000000000000000000000
◉ 0000000000000000000000000000000000000000
P: 0
"###);
let template = r#"parents.map(|c| c.commit_id().shortest(4))"#;
let stdout = test_env.jj_cmd_success(
&repo_path,
&["log", "-T", template, "-r@", "--color=always"],
);
insta::assert_snapshot!(stdout, @r###"
@ 4db4 230d
~
"###);
// Commit object isn't printable
let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-T", "parents"]);
insta::assert_snapshot!(stderr, @r###"
Error: Failed to parse template: Expected expression of type "Template", but actual type is "List<Commit>"
Caused by: --> 1:1
|
1 | parents
| ^-----^
|
= Expected expression of type "Template", but actual type is "List<Commit>"
"###);
// Redundant argument passed to keyword method
let template = r#"parents.map(|c| c.commit_id(""))"#;
let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-T", template]);
insta::assert_snapshot!(stderr, @r###"
Error: Failed to parse template: Function "commit_id": Expected 0 arguments
Caused by: --> 1:29
|
1 | parents.map(|c| c.commit_id(""))
| ^^
|
= Function "commit_id": Expected 0 arguments
"###);
}
#[test]
fn test_log_author_timestamp() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-m", "second"]);
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", "author.timestamp()"]);
insta::assert_snapshot!(stdout, @r###"
@ 2001-02-03 04:05:09.000 +07:00
◉ 2001-02-03 04:05:07.000 +07:00
◉ 1970-01-01 00:00:00.000 +00:00
"###);
}
#[test]
fn test_log_author_timestamp_ago() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "first"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-m", "second"]);
let template = r#"author.timestamp().ago() ++ "\n""#;
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "--no-graph", "-T", template]);
let line_re = Regex::new(r"[0-9]+ years ago").unwrap();
assert!(
stdout.lines().all(|x| line_re.is_match(x)),
"expected every line to match regex"
);
}
#[test]
fn test_log_author_timestamp_utc() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", "author.timestamp().utc()"]);
insta::assert_snapshot!(stdout, @r###"
@ 2001-02-02 21:05:07.000 +00:00
◉ 1970-01-01 00:00:00.000 +00:00
"###);
}
#[cfg(unix)]
#[test]
fn test_log_author_timestamp_local() {
let mut test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
test_env.add_env_var("TZ", "UTC-05:30");
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", "author.timestamp().local()"]);
insta::assert_snapshot!(stdout, @r###"
@ 2001-02-03 08:05:07.000 +11:00
◉ 1970-01-01 11:00:00.000 +11:00
"###);
test_env.add_env_var("TZ", "UTC+10:00");
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", "author.timestamp().local()"]);
insta::assert_snapshot!(stdout, @r###"
@ 2001-02-03 08:05:07.000 +11:00
◉ 1970-01-01 11:00:00.000 +11:00
"###);
}
#[test]
fn test_mine_is_true_when_author_is_user() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(
&repo_path,
&[
"--config-toml=user.email='johndoe@example.com'",
"--config-toml=user.name='John Doe'",
"new",
],
);
let stdout = test_env.jj_cmd_success(
&repo_path,
&[
"log",
"-T",
r#"coalesce(if(mine, "mine"), author.email(), email_placeholder)"#,
],
);
insta::assert_snapshot!(stdout, @r###"
@ johndoe@example.com
◉ mine
◉ (no email set)
"###);
}
#[test]
fn test_log_default() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
std::fs::write(repo_path.join("file1"), "foo\n").unwrap();
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "add a file"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-m", "description 1"]);
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "my-branch"]);
// Test default log output format
let stdout = test_env.jj_cmd_success(&repo_path, &["log"]);
insta::assert_snapshot!(stdout, @r###"
@ kkmpptxz test.user@example.com 2001-02-03 08:05:09 my-branch 9de54178
│ (empty) description 1
◉ qpvuntsm test.user@example.com 2001-02-03 08:05:08 4291e264
│ add a file
◉ zzzzzzzz root() 00000000
"###);
// Color
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "--color=always"]);
insta::assert_snapshot!(stdout, @r###"
@ kkmpptxz test.user@example.com 2001-02-03 08:05:09 my-branch 9de54178
(empty) description 1
qpvuntsm test.user@example.com 2001-02-03 08:05:08 4291e264
│ add a file
zzzzzzzz root() 00000000
"###);
// Color without graph
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "--color=always", "--no-graph"]);
insta::assert_snapshot!(stdout, @r###"
kkmpptxz test.user@example.com 2001-02-03 08:05:09 my-branch 9de54178
(empty) description 1
qpvuntsm test.user@example.com 2001-02-03 08:05:08 4291e264
add a file
zzzzzzzz root() 00000000
"###);
}
#[test]
fn test_log_builtin_templates() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
// Render without graph and append "[EOF]" marker to test line ending
let render = |template| {
test_env.jj_cmd_success(&repo_path, &["log", "-T", template, "--no-graph"]) + "[EOF]\n"
};
test_env.jj_cmd_ok(
&repo_path,
&[
"--config-toml=user.email=''",
"--config-toml=user.name=''",
"new",
],
);
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "my-branch"]);
insta::assert_snapshot!(render(r#"builtin_log_oneline"#), @r###"
rlvkpnrz (no email set) 2001-02-03 08:05:08 my-branch dc315397 (empty) (no description set)
qpvuntsm test.user 2001-02-03 08:05:07 230dd059 (empty) (no description set)
zzzzzzzz root() 00000000
[EOF]
"###);
insta::assert_snapshot!(render(r#"builtin_log_compact"#), @r###"
rlvkpnrz (no email set) 2001-02-03 08:05:08 my-branch dc315397
(empty) (no description set)
qpvuntsm test.user@example.com 2001-02-03 08:05:07 230dd059
(empty) (no description set)
zzzzzzzz root() 00000000
[EOF]
"###);
insta::assert_snapshot!(render(r#"builtin_log_comfortable"#), @r###"
rlvkpnrz (no email set) 2001-02-03 08:05:08 my-branch dc315397
(empty) (no description set)
qpvuntsm test.user@example.com 2001-02-03 08:05:07 230dd059
(empty) (no description set)
zzzzzzzz root() 00000000
[EOF]
"###);
insta::assert_snapshot!(render(r#"builtin_log_detailed"#), @r###"
Commit ID: dc31539712c7294d1d712cec63cef4504b94ca74
Change ID: rlvkpnrzqnoowoytxnquwvuryrwnrmlp
Branches: my-branch
Author: (no name set) <(no email set)> (2001-02-03 08:05:08)
Committer: (no name set) <(no email set)> (2001-02-03 08:05:08)
(no description set)
Commit ID: 230dd059e1b059aefc0da06a2e5a7dbf22362f22
Change ID: qpvuntsmwlqtpsluzzsnyyzlmlwvmlnu
Author: Test User <test.user@example.com> (2001-02-03 08:05:07)
Committer: Test User <test.user@example.com> (2001-02-03 08:05:07)
(no description set)
Commit ID: 0000000000000000000000000000000000000000
Change ID: zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
Author: (no name set) <(no email set)> (1970-01-01 11:00:00)
Committer: (no name set) <(no email set)> (1970-01-01 11:00:00)
(no description set)
[EOF]
"###);
}
#[test]
fn test_log_builtin_templates_colored() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
let render =
|template| test_env.jj_cmd_success(&repo_path, &["--color=always", "log", "-T", template]);
test_env.jj_cmd_ok(
&repo_path,
&[
"--config-toml=user.email=''",
"--config-toml=user.name=''",
"new",
],
);
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "my-branch"]);
insta::assert_snapshot!(render(r#"builtin_log_oneline"#), @r###"
@ rlvkpnrz (no email set) 2001-02-03 08:05:08 my-branch dc315397 (empty) (no description set)
qpvuntsm test.user 2001-02-03 08:05:07 230dd059 (empty) (no description set)
zzzzzzzz root() 00000000
"###);
insta::assert_snapshot!(render(r#"builtin_log_compact"#), @r###"
@ rlvkpnrz (no email set) 2001-02-03 08:05:08 my-branch dc315397
(empty) (no description set)
qpvuntsm test.user@example.com 2001-02-03 08:05:07 230dd059
(empty) (no description set)
zzzzzzzz root() 00000000
"###);
insta::assert_snapshot!(render(r#"builtin_log_comfortable"#), @r###"
@ rlvkpnrz (no email set) 2001-02-03 08:05:08 my-branch dc315397
(empty) (no description set)
qpvuntsm test.user@example.com 2001-02-03 08:05:07 230dd059
(empty) (no description set)
zzzzzzzz root() 00000000
"###);
insta::assert_snapshot!(render(r#"builtin_log_detailed"#), @r###"
@ Commit ID: dc31539712c7294d1d712cec63cef4504b94ca74
│ Change ID: rlvkpnrzqnoowoytxnquwvuryrwnrmlp
│ Branches: my-branch
│ Author: (no name set) <(no email set)> (2001-02-03 08:05:08)
│ Committer: (no name set) <(no email set)> (2001-02-03 08:05:08)
 (no description set)
◉ Commit ID: 230dd059e1b059aefc0da06a2e5a7dbf22362f22
│ Change ID: qpvuntsmwlqtpsluzzsnyyzlmlwvmlnu
│ Author: Test User <test.user@example.com> (2001-02-03 08:05:07)
│ Committer: Test User <test.user@example.com> (2001-02-03 08:05:07)
 (no description set)
◉ Commit ID: 0000000000000000000000000000000000000000
Change ID: zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
Author: (no name set) <(no email set)> (1970-01-01 11:00:00)
Committer: (no name set) <(no email set)> (1970-01-01 11:00:00)
 (no description set)
"###);
}
#[test]
fn test_log_builtin_templates_colored_debug() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
let render =
|template| test_env.jj_cmd_success(&repo_path, &["--color=debug", "log", "-T", template]);
test_env.jj_cmd_ok(
&repo_path,
&[
"--config-toml=user.email=''",
"--config-toml=user.name=''",
"new",
],
);
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "my-branch"]);
insta::assert_snapshot!(render(r#"builtin_log_oneline"#), @r###"
<<node::@>> <<log working_copy change_id shortest prefix::r>><<log working_copy change_id shortest rest::lvkpnrz>><<log working_copy:: >><<log working_copy email placeholder::(no email set)>><<log working_copy:: >><<log working_copy committer timestamp local format::2001-02-03 08:05:08>><<log working_copy:: >><<log working_copy branches name::my-branch>><<log working_copy:: >><<log working_copy commit_id shortest prefix::d>><<log working_copy commit_id shortest rest::c315397>><<log working_copy:: >><<log working_copy empty::(empty)>><<log working_copy:: >><<log working_copy empty description placeholder::(no description set)>><<log working_copy::>>
<<node::◉>> <<log change_id shortest prefix::q>><<log change_id shortest rest::pvuntsm>><<log:: >><<log author username::test.user>><<log:: >><<log committer timestamp local format::2001-02-03 08:05:07>><<log:: >><<log commit_id shortest prefix::2>><<log commit_id shortest rest::30dd059>><<log:: >><<log empty::(empty)>><<log:: >><<log empty description placeholder::(no description set)>><<log::>>
<<node::◉>> <<log change_id shortest prefix::z>><<log change_id shortest rest::zzzzzzz>><<log:: >><<log root::root()>><<log:: >><<log commit_id shortest prefix::0>><<log commit_id shortest rest::0000000>><<log::>>
"###);
insta::assert_snapshot!(render(r#"builtin_log_compact"#), @r###"
<<node::@>> <<log working_copy change_id shortest prefix::r>><<log working_copy change_id shortest rest::lvkpnrz>><<log working_copy:: >><<log working_copy email placeholder::(no email set)>><<log working_copy:: >><<log working_copy committer timestamp local format::2001-02-03 08:05:08>><<log working_copy:: >><<log working_copy branches name::my-branch>><<log working_copy:: >><<log working_copy commit_id shortest prefix::d>><<log working_copy commit_id shortest rest::c315397>><<log working_copy::>>
<<log working_copy empty::(empty)>><<log working_copy:: >><<log working_copy empty description placeholder::(no description set)>><<log working_copy::>>
<<node::◉>> <<log change_id shortest prefix::q>><<log change_id shortest rest::pvuntsm>><<log:: >><<log author email::test.user@example.com>><<log:: >><<log committer timestamp local format::2001-02-03 08:05:07>><<log:: >><<log commit_id shortest prefix::2>><<log commit_id shortest rest::30dd059>><<log::>>
<<log empty::(empty)>><<log:: >><<log empty description placeholder::(no description set)>><<log::>>
<<node::◉>> <<log change_id shortest prefix::z>><<log change_id shortest rest::zzzzzzz>><<log:: >><<log root::root()>><<log:: >><<log commit_id shortest prefix::0>><<log commit_id shortest rest::0000000>><<log::>>
"###);
insta::assert_snapshot!(render(r#"builtin_log_comfortable"#), @r###"
<<node::@>> <<log working_copy change_id shortest prefix::r>><<log working_copy change_id shortest rest::lvkpnrz>><<log working_copy:: >><<log working_copy email placeholder::(no email set)>><<log working_copy:: >><<log working_copy committer timestamp local format::2001-02-03 08:05:08>><<log working_copy:: >><<log working_copy branches name::my-branch>><<log working_copy:: >><<log working_copy commit_id shortest prefix::d>><<log working_copy commit_id shortest rest::c315397>><<log working_copy::>>
<<log working_copy empty::(empty)>><<log working_copy:: >><<log working_copy empty description placeholder::(no description set)>><<log working_copy::>>
│ <<log::>>
<<node::◉>> <<log change_id shortest prefix::q>><<log change_id shortest rest::pvuntsm>><<log:: >><<log author email::test.user@example.com>><<log:: >><<log committer timestamp local format::2001-02-03 08:05:07>><<log:: >><<log commit_id shortest prefix::2>><<log commit_id shortest rest::30dd059>><<log::>>
<<log empty::(empty)>><<log:: >><<log empty description placeholder::(no description set)>><<log::>>
│ <<log::>>
<<node::◉>> <<log change_id shortest prefix::z>><<log change_id shortest rest::zzzzzzz>><<log:: >><<log root::root()>><<log:: >><<log commit_id shortest prefix::0>><<log commit_id shortest rest::0000000>><<log::>>
<<log::>>
"###);
insta::assert_snapshot!(render(r#"builtin_log_detailed"#), @r###"
<<node::@>> <<log::Commit ID: >><<log commit_id::dc31539712c7294d1d712cec63cef4504b94ca74>><<log::>>
│ <<log::Change ID: >><<log change_id::rlvkpnrzqnoowoytxnquwvuryrwnrmlp>><<log::>>
│ <<log::Branches: >><<log local_branches name::my-branch>><<log::>>
│ <<log::Author: >><<log name placeholder::(no name set)>><<log:: <>><<log email placeholder::(no email set)>><<log::>>><<log:: (>><<log author timestamp local format::2001-02-03 08:05:08>><<log::)>><<log::>>
│ <<log::Committer: >><<log name placeholder::(no name set)>><<log:: <>><<log email placeholder::(no email set)>><<log::>>><<log:: (>><<log committer timestamp local format::2001-02-03 08:05:08>><<log::)>><<log::>>
│ <<log::>>
<<log empty description placeholder:: >><<log empty description placeholder::(no description set)>><<log::>>
│ <<log::>>
<<node::◉>> <<log::Commit ID: >><<log commit_id::230dd059e1b059aefc0da06a2e5a7dbf22362f22>><<log::>>
│ <<log::Change ID: >><<log change_id::qpvuntsmwlqtpsluzzsnyyzlmlwvmlnu>><<log::>>
│ <<log::Author: >><<log author name::Test User>><<log:: <>><<log author email::test.user@example.com>><<log::>>><<log:: (>><<log author timestamp local format::2001-02-03 08:05:07>><<log::)>><<log::>>
│ <<log::Committer: >><<log committer name::Test User>><<log:: <>><<log committer email::test.user@example.com>><<log::>>><<log:: (>><<log committer timestamp local format::2001-02-03 08:05:07>><<log::)>><<log::>>
│ <<log::>>
<<log empty description placeholder:: >><<log empty description placeholder::(no description set)>><<log::>>
│ <<log::>>
<<node::◉>> <<log::Commit ID: >><<log commit_id::0000000000000000000000000000000000000000>><<log::>>
<<log::Change ID: >><<log change_id::zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz>><<log::>>
<<log::Author: >><<log name placeholder::(no name set)>><<log:: <>><<log email placeholder::(no email set)>><<log::>>><<log:: (>><<log author timestamp local format::1970-01-01 11:00:00>><<log::)>><<log::>>
<<log::Committer: >><<log name placeholder::(no name set)>><<log:: <>><<log email placeholder::(no email set)>><<log::>>><<log:: (>><<log committer timestamp local format::1970-01-01 11:00:00>><<log::)>><<log::>>
<<log::>>
<<log empty description placeholder:: >><<log empty description placeholder::(no description set)>><<log::>>
<<log::>>
"###);
}
#[test]
fn test_log_obslog_divergence() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
std::fs::write(repo_path.join("file"), "foo\n").unwrap();
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "description 1"]);
let stdout = test_env.jj_cmd_success(&repo_path, &["log"]);
// No divergence
insta::assert_snapshot!(stdout, @r###"
@ qpvuntsm test.user@example.com 2001-02-03 08:05:08 7a17d52e
│ description 1
◉ zzzzzzzz root() 00000000
"###);
// Create divergence
test_env.jj_cmd_ok(
&repo_path,
&["describe", "-m", "description 2", "--at-operation", "@-"],
);
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["log"]);
insta::assert_snapshot!(stdout, @r###"
◉ qpvuntsm?? test.user@example.com 2001-02-03 08:05:10 8979953d
│ description 2
│ @ qpvuntsm?? test.user@example.com 2001-02-03 08:05:08 7a17d52e
├─╯ description 1
◉ zzzzzzzz root() 00000000
"###);
insta::assert_snapshot!(stderr, @r###"
Concurrent modification detected, resolving automatically.
"###);
// Color
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "--color=always"]);
insta::assert_snapshot!(stdout, @r###"
qpvuntsm?? test.user@example.com 2001-02-03 08:05:10 8979953d
│ description 2
│ @ qpvuntsm?? test.user@example.com 2001-02-03 08:05:08 7a17d52e
├─╯ description 1
zzzzzzzz root() 00000000
"###);
// Obslog and hidden divergent
let stdout = test_env.jj_cmd_success(&repo_path, &["obslog"]);
insta::assert_snapshot!(stdout, @r###"
@ qpvuntsm?? test.user@example.com 2001-02-03 08:05:08 7a17d52e
│ description 1
◉ qpvuntsm hidden test.user@example.com 2001-02-03 08:05:08 3b68ce25
│ (no description set)
◉ qpvuntsm hidden test.user@example.com 2001-02-03 08:05:07 230dd059
(empty) (no description set)
"###);
// Colored obslog
let stdout = test_env.jj_cmd_success(&repo_path, &["obslog", "--color=always"]);
insta::assert_snapshot!(stdout, @r###"
@ qpvuntsm?? test.user@example.com 2001-02-03 08:05:08 7a17d52e
description 1
qpvuntsm hidden test.user@example.com 2001-02-03 08:05:08 3b68ce25
(no description set)
qpvuntsm hidden test.user@example.com 2001-02-03 08:05:07 230dd059
(empty) (no description set)
"###);
}
#[test]
fn test_log_branches() {
let test_env = TestEnvironment::default();
test_env.add_config("git.auto-local-branch = true");
test_env.add_config(r#"revset-aliases."immutable_heads()" = "none()""#);
test_env.jj_cmd_ok(test_env.env_root(), &["init", "--git", "origin"]);
let origin_path = test_env.env_root().join("origin");
let origin_git_repo_path = origin_path
.join(".jj")
.join("repo")
.join("store")
.join("git");
// Created some branches on the remote
test_env.jj_cmd_ok(&origin_path, &["describe", "-m=description 1"]);
test_env.jj_cmd_ok(&origin_path, &["branch", "create", "branch1"]);
test_env.jj_cmd_ok(&origin_path, &["new", "root()", "-m=description 2"]);
test_env.jj_cmd_ok(&origin_path, &["branch", "create", "branch2", "unchanged"]);
test_env.jj_cmd_ok(&origin_path, &["new", "root()", "-m=description 3"]);
test_env.jj_cmd_ok(&origin_path, &["branch", "create", "branch3"]);
test_env.jj_cmd_ok(&origin_path, &["git", "export"]);
test_env.jj_cmd_ok(
test_env.env_root(),
&[
"git",
"clone",
origin_git_repo_path.to_str().unwrap(),
"local",
],
);
let workspace_root = test_env.env_root().join("local");
// Rewrite branch1, move branch2 forward, create conflict in branch3, add
// new-branch
test_env.jj_cmd_ok(
&workspace_root,
&["describe", "branch1", "-m", "modified branch1 commit"],
);
test_env.jj_cmd_ok(&workspace_root, &["new", "branch2"]);
test_env.jj_cmd_ok(&workspace_root, &["branch", "set", "branch2"]);
test_env.jj_cmd_ok(&workspace_root, &["branch", "create", "new-branch"]);
test_env.jj_cmd_ok(&workspace_root, &["describe", "branch3", "-m=local"]);
test_env.jj_cmd_ok(&origin_path, &["describe", "branch3", "-m=origin"]);
test_env.jj_cmd_ok(&origin_path, &["git", "export"]);
test_env.jj_cmd_ok(&workspace_root, &["git", "fetch"]);
let template = r#"commit_id.short() ++ " " ++ if(branches, branches, "(no branches)")"#;
let output = test_env.jj_cmd_success(&workspace_root, &["log", "-T", template]);
insta::assert_snapshot!(output, @r###"
◉ fed794e2ba44 branch3?? branch3@origin
│ ◉ b1bb3766d584 branch3??
├─╯
│ ◉ 21c33875443e branch1*
├─╯
│ @ a5b4d15489cc branch2* new-branch
│ ◉ 8476341eb395 branch2@origin unchanged
├─╯
◉ 000000000000 (no branches)
"###);
let template = r#"branches.map(|b| separate("/", b.remote(), b.name())).join(", ")"#;
let output = test_env.jj_cmd_success(&workspace_root, &["log", "-T", template]);
insta::assert_snapshot!(output, @r###"
◉ branch3, origin/branch3
│ ◉ branch3
├─╯
│ ◉ branch1
├─╯
│ @ branch2, new-branch
│ ◉ origin/branch2, unchanged
├─╯
"###);
let template = r#"separate(" ", "L:", local_branches, "R:", remote_branches)"#;
let output = test_env.jj_cmd_success(&workspace_root, &["log", "-T", template]);
insta::assert_snapshot!(output, @r###"
◉ L: branch3?? R: branch3@origin
│ ◉ L: branch3?? R:
├─╯
│ ◉ L: branch1* R:
├─╯
│ @ L: branch2* new-branch R:
│ ◉ L: unchanged R: branch2@origin unchanged@origin
├─╯
◉ L: R:
"###);
let template = r#"
remote_branches.map(|ref| concat(
ref,
if(ref.tracked(),
"(+" ++ ref.tracking_ahead_count().lower()
++ "/-" ++ ref.tracking_behind_count().lower() ++ ")"),
))
"#;
let output = test_env.jj_cmd_success(
&workspace_root,
&["log", "-r::remote_branches()", "-T", template],
);
insta::assert_snapshot!(output, @r###"
◉ branch3@origin(+0/-1)
│ ◉ branch2@origin(+0/-1) unchanged@origin(+0/-0)
├─╯
│ ◉ branch1@origin(+1/-1)
├─╯
"###);
}
#[test]
fn test_log_git_head() {
let test_env = TestEnvironment::default();
let repo_path = test_env.env_root().join("repo");
git2::Repository::init(&repo_path).unwrap();
test_env.jj_cmd_ok(&repo_path, &["init", "--git-repo=."]);
test_env.jj_cmd_ok(&repo_path, &["new", "-m=initial"]);
std::fs::write(repo_path.join("file"), "foo\n").unwrap();
let template = r#"
separate(", ",
if(git_head, "name: " ++ git_head.name()),
"remote: " ++ git_head.remote(),
) ++ "\n"
"#;
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", template]);
insta::assert_snapshot!(stdout, @r###"
@ remote: <Error: No RefName available>
◉ name: HEAD, remote: git
◉ remote: <Error: No RefName available>
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "--color=always"]);
insta::assert_snapshot!(stdout, @r###"
@ rlvkpnrz test.user@example.com 2001-02-03 08:05:09 50aaf475
initial
qpvuntsm test.user@example.com 2001-02-03 08:05:07 HEAD@git 230dd059
(empty) (no description set)
zzzzzzzz root() 00000000
"###);
}
#[test]
fn test_log_customize_short_id() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "first"]);
// Customize both the commit and the change id
let decl = "template-aliases.'format_short_id(id)'";
let stdout = test_env.jj_cmd_success(
&repo_path,
&[
"log",
"--config-toml",
&format!(r#"{decl}='id.shortest(5).prefix().upper() ++ "_" ++ id.shortest(5).rest()'"#),
],
);
insta::assert_snapshot!(stdout, @r###"
@ Q_pvun test.user@example.com 2001-02-03 08:05:08 6_9542
│ (empty) first
◉ Z_zzzz root() 0_0000
"###);
// Customize only the change id
let stdout = test_env.jj_cmd_success(
&repo_path,
&[
"log",
"--config-toml",
r#"
[template-aliases]
'format_short_change_id(id)'='format_short_id(id).upper()'
"#,
],
);
insta::assert_snapshot!(stdout, @r###"
@ QPVUNTSM test.user@example.com 2001-02-03 08:05:08 69542c19
│ (empty) first
◉ ZZZZZZZZ root() 00000000
"###);
}
#[test]
fn test_log_immutable() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["new", "-mA", "root()"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-mB"]);
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "main"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-mC"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-mD", "root()"]);
let template = r#"
separate(" ",
description.first_line(),
branches,
if(immutable, "[immutable]"),
) ++ "\n"
"#;
test_env.add_config("revset-aliases.'immutable_heads()' = 'main'");
let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-r::", "-T", template]);
insta::assert_snapshot!(stdout, @r###"
@ D
│ ◉ C
│ ◉ B main [immutable]
│ ◉ A [immutable]
├─╯
◉ [immutable]
"###);
// Suppress error that could be detected earlier
test_env.add_config("revsets.short-prefixes = ''");
test_env.add_config("revset-aliases.'immutable_heads()' = 'unknown_fn()'");
let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-r::", "-T", template]);
insta::assert_snapshot!(stderr, @r###"
Error: Failed to parse template: Failed to parse revset
Caused by:
1: --> 5:10
|
5 | if(immutable, "[immutable]"),
| ^-------^
|
= Failed to parse revset
2: --> 1:1
|
1 | unknown_fn()
| ^--------^
|
= Function "unknown_fn" doesn't exist
"###);
test_env.add_config("revset-aliases.'immutable_heads()' = 'unknown_symbol'");
let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-r::", "-T", template]);
insta::assert_snapshot!(stderr, @r###"
Error: Failed to parse template: Failed to evaluate revset
Caused by:
1: --> 5:10
|
5 | if(immutable, "[immutable]"),
| ^-------^
|
= Failed to evaluate revset
2: Revision "unknown_symbol" doesn't exist
"###);
}
#[test]
fn test_log_contained_in() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
test_env.jj_cmd_ok(&repo_path, &["new", "-mA", "root()"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-mB"]);
test_env.jj_cmd_ok(&repo_path, &["branch", "create", "main"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-mC"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-mD", "root()"]);
let template_for_revset = |revset: &str| {
format!(
r#"
separate(" ",
description.first_line(),
branches,
if(self.contained_in("{revset}"), "[contained_in]"),
) ++ "\n"
"#
)
};
let stdout = test_env.jj_cmd_success(
&repo_path,
&[
"log",
"-r::",
"-T",
&template_for_revset(r#"description(A)::"#),
],
);
insta::assert_snapshot!(stdout, @r###"
@ D
│ ◉ C [contained_in]
│ ◉ B main [contained_in]
│ ◉ A [contained_in]
├─╯
"###);
let stdout = test_env.jj_cmd_success(
&repo_path,
&[
"log",
"-r::",
"-T",
&template_for_revset(r#"visible_heads()"#),
],
);
insta::assert_snapshot!(stdout, @r###"
@ D [contained_in]
│ ◉ C [contained_in]
│ ◉ B main
│ ◉ A
├─╯
"###);
// Suppress error that could be detected earlier
let stderr = test_env.jj_cmd_failure(
&repo_path,
&["log", "-r::", "-T", &template_for_revset("unknown_fn()")],
);
insta::assert_snapshot!(stderr, @r###"
Error: Failed to parse template: Failed to parse revset
Caused by:
1: --> 5:28
|
5 | if(self.contained_in("unknown_fn()"), "[contained_in]"),
| ^------------^
|
= Failed to parse revset
2: --> 1:1
|
1 | unknown_fn()
| ^--------^
|
= Function "unknown_fn" doesn't exist
"###);
let stderr = test_env.jj_cmd_failure(
&repo_path,
&["log", "-r::", "-T", &template_for_revset("author(x:'y')")],
);
insta::assert_snapshot!(stderr, @r###"
Error: Failed to parse template: Failed to parse revset
Caused by:
1: --> 5:28
|
5 | if(self.contained_in("author(x:'y')"), "[contained_in]"),
| ^-------------^
|
= Failed to parse revset
2: --> 1:8
|
1 | author(x:'y')
| ^---^
|
= Function "author": Invalid string pattern
3: Invalid string pattern kind "x:"
Hint: Try prefixing with one of `exact:`, `glob:` or `substring:`
"###);
let stderr = test_env.jj_cmd_failure(
&repo_path,
&["log", "-r::", "-T", &template_for_revset("maine")],
);
insta::assert_snapshot!(stderr, @r###"
Error: Failed to parse template: Failed to evaluate revset
Caused by:
1: --> 5:28
|
5 | if(self.contained_in("maine"), "[contained_in]"),
| ^-----^
|
= Failed to evaluate revset
2: Revision "maine" doesn't exist
Hint: Did you mean "main"?
"###);
}