// 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 std::path::Path;use std::path::PathBuf; use itertools::Itertools as _;use regex::Regex;use testutils::TestResult;use testutils::git; use crate::common::CommandOutput;use crate::common::TestEnvironment;use crate::common::TestWorkDir;use crate::common::to_toml_value; #[test]fn test_op_log() { 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(["describe", "-m", "description 0"]) .success(); let output = work_dir.run_jj(["op", "log"]); insta::assert_snapshot!(output, @" @ 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 │ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ args: jj describe -m 'description 0' ○ e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 │ add workspace 'default' ○ 000000000000 root() [EOF] "); let op_log_lines = output.stdout.raw().lines().collect_vec(); let add_workspace_id = op_log_lines[3].split(' ').nth(2).unwrap(); // Can load the repo at a specific operation ID insta::assert_snapshot!(get_log_output(&work_dir, add_workspace_id), @" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); // "@" resolves to the head operation insta::assert_snapshot!(get_log_output(&work_dir, "@"), @" @ 3ae22e7f50a15d393e412cca72d09a61165d0c84 ◆ 0000000000000000000000000000000000000000 [EOF] "); // "@-" resolves to the parent of the head operation insta::assert_snapshot!(get_log_output(&work_dir, "@-"), @" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(work_dir.run_jj(["log", "--at-op", "@---"]), @r#" ------- stderr ------- Error: The "@---" expression resolved to no operations [EOF] [exit status: 1] "#); // We get a reasonable message if an invalid operation ID is specified insta::assert_snapshot!(work_dir.run_jj(["log", "--at-op", "foo"]), @r#" ------- stderr ------- Error: Operation ID "foo" is not a valid hexadecimal prefix [EOF] [exit status: 1] "#); let output = work_dir.run_jj(["op", "log", "--op-diff"]); insta::assert_snapshot!(output, @" @ 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 │ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ args: jj describe -m 'description 0' │ │ Changed commits: │ ○ + qpvuntsm 3ae22e7f (empty) description 0 │ - qpvuntsm/1 e8849ae1 (hidden) (empty) (no description set) │ │ Changed working copy default@: │ + qpvuntsm 3ae22e7f (empty) description 0 │ - qpvuntsm/1 e8849ae1 (hidden) (empty) (no description set) ○ e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 │ add workspace 'default' │ │ Changed commits: │ ○ + qpvuntsm e8849ae1 (empty) (no description set) │ │ Changed working copy default@: │ + qpvuntsm e8849ae1 (empty) (no description set) │ - (absent) ○ 000000000000 root() [EOF] "); let output = work_dir.run_jj(["op", "log", "--op-diff", "--color=always"]); insta::assert_snapshot!(output, @" [1m[38;5;2m@[0m [1m[38;5;12m69e9fab8ce76[39m [38;5;3mtest-username@host.example.com[39m [38;5;2mdefault@[39m [38;5;14m2001-02-03 04:05:08.000 +07:00[39m - [38;5;14m2001-02-03 04:05:08.000 +07:00[39m[0m │ [1mdescribe commit e8849ae12c709f2321908879bc724fdb2ab8a781[0m │ [1m[38;5;13margs: jj describe -m 'description 0'[39m[0m │ │ Changed commits: │ ○ [38;5;2m+[39m [1m[38;5;13mq[38;5;8mpvuntsm[39m [38;5;12m3[38;5;8mae22e7f[39m [38;5;10m(empty)[39m description 0[0m │ [38;5;1m-[39m [1m[39mq[0m[38;5;8mpvuntsm[1m[39m/1[0m [1m[38;5;4me[0m[38;5;8m8849ae1[39m (hidden) [38;5;2m(empty)[39m [38;5;2m(no description set)[39m │ │ Changed working copy [38;5;2mdefault@[39m: │ [38;5;2m+[39m [1m[38;5;13mq[38;5;8mpvuntsm[39m [38;5;12m3[38;5;8mae22e7f[39m [38;5;10m(empty)[39m description 0[0m │ [38;5;1m-[39m [1m[39mq[0m[38;5;8mpvuntsm[1m[39m/1[0m [1m[38;5;4me[0m[38;5;8m8849ae1[39m (hidden) [38;5;2m(empty)[39m [38;5;2m(no description set)[39m ○ [38;5;4me39dc288903d[39m [38;5;3mtest-username@host.example.com[39m [38;5;6m2001-02-03 04:05:07.000 +07:00[39m - [38;5;6m2001-02-03 04:05:07.000 +07:00[39m │ add workspace 'default' │ │ Changed commits: │ ○ [38;5;2m+[39m [1m[38;5;13mq[38;5;8mpvuntsm[39m [38;5;12me[38;5;8m8849ae1[39m [38;5;10m(empty)[39m [38;5;10m(no description set)[0m │ │ Changed working copy [38;5;2mdefault@[39m: │ [38;5;2m+[39m [1m[38;5;13mq[38;5;8mpvuntsm[39m [38;5;12me[38;5;8m8849ae1[39m [38;5;10m(empty)[39m [38;5;10m(no description set)[0m │ [38;5;1m-[39m (absent) ○ [38;5;4m000000000000[39m [38;5;2mroot()[39m [EOF] "); work_dir .run_jj(["describe", "-m", "description 1"]) .success(); work_dir .run_jj([ "describe", "-m", "description 2", "--at-op", add_workspace_id, ]) .success(); insta::assert_snapshot!(work_dir.run_jj(["log", "--at-op", "@-"]), @r#" ------- stderr ------- Error: The "@" expression resolved to more than one operation Hint: Try specifying one of the operations by ID: 3e9cf8ff3f23, 4693396e777b [EOF] [exit status: 1] "#);} #[test]fn test_op_log_with_custom_symbols() { 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(["describe", "-m", "description 0"]) .success(); let output = work_dir.run_jj([ "op", "log", "--config=templates.op_log_node='if(current_operation, \"$\", if(root, \"┴\", \"┝\"))'", ]); insta::assert_snapshot!(output, @" $ 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 │ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ args: jj describe -m 'description 0' ┝ e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 │ add workspace 'default' ┴ 000000000000 root() [EOF] ");} #[test]fn test_op_log_with_no_template() { 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(["op", "log", "-T"]); insta::assert_snapshot!(output, @" ------- stderr ------- error: a value is required for '--template <TEMPLATE>' but none was supplied For more information, try '--help'. Hint: The following template aliases are defined: - builtin_config_list - builtin_config_list_detailed - builtin_draft_commit_description - builtin_draft_commit_description_with_diff - builtin_evolog_compact - builtin_log_comfortable - builtin_log_compact - builtin_log_compact_full_description - builtin_log_detailed - builtin_log_node - builtin_log_node_ascii - builtin_log_oneline - builtin_log_redacted - builtin_op_log_comfortable - builtin_op_log_compact - builtin_op_log_node - builtin_op_log_node_ascii - builtin_op_log_oneline - builtin_op_log_redacted - builtin_workspace_list - commit_summary_separator - default_commit_description - description_placeholder - email_placeholder - empty_commit_marker - git_format_patch_email_headers - name_placeholder [EOF] [exit status: 2] ");} #[test]fn test_op_log_limit() { 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(["op", "log", "-Tdescription", "--limit=1"]); insta::assert_snapshot!(output, @" @ add workspace 'default' [EOF] ");} #[test]fn test_op_log_no_graph() { 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(["op", "log", "--no-graph", "--color=always"]); insta::assert_snapshot!(output, @" [1m[38;5;12me39dc288903d[39m [38;5;3mtest-username@host.example.com[39m [38;5;14m2001-02-03 04:05:07.000 +07:00[39m - [38;5;14m2001-02-03 04:05:07.000 +07:00[39m[0m [1madd workspace 'default'[0m [38;5;4m000000000000[39m [38;5;2mroot()[39m [EOF] "); let output = work_dir.run_jj(["op", "log", "--op-diff", "--no-graph"]); insta::assert_snapshot!(output, @" e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 add workspace 'default' Changed commits: + qpvuntsm e8849ae1 (empty) (no description set) Changed working copy default@: + qpvuntsm e8849ae1 (empty) (no description set) - (absent) 000000000000 root() [EOF] ");} #[test]fn test_op_log_reversed() { 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(["describe", "-m", "description 0"]) .success(); let output = work_dir.run_jj(["op", "log", "--reversed"]); insta::assert_snapshot!(output, @" ○ 000000000000 root() ○ e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 │ add workspace 'default' @ 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 0' [EOF] "); work_dir .run_jj(["describe", "-m", "description 1", "--at-op", "@-"]) .success(); // Should be able to display log with fork and branch points let output = work_dir.run_jj(["op", "log", "--reversed"]); insta::assert_snapshot!(output, @" ○ 000000000000 root() ○ e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 ├─╮ add workspace 'default' │ ○ 4f59a3fcf7fb test-username@host.example.com default@ 2001-02-03 04:05:10.000 +07:00 - 2001-02-03 04:05:10.000 +07:00 │ │ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ │ args: jj describe -m 'description 1' --at-op @- ○ │ 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 ├─╯ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ args: jj describe -m 'description 0' @ 3257abe149b2 test-username@host.example.com default@ 2001-02-03 04:05:11.000 +07:00 - 2001-02-03 04:05:11.000 +07:00 reconcile divergent operations args: jj op log --reversed [EOF] ------- stderr ------- Concurrent modification detected, resolving automatically. [EOF] "); // Should work correctly with `--no-graph` let output = work_dir.run_jj(["op", "log", "--reversed", "--no-graph"]); insta::assert_snapshot!(output, @" 000000000000 root() e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 add workspace 'default' 4f59a3fcf7fb test-username@host.example.com default@ 2001-02-03 04:05:10.000 +07:00 - 2001-02-03 04:05:10.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 1' --at-op @- 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 0' 3257abe149b2 test-username@host.example.com default@ 2001-02-03 04:05:11.000 +07:00 - 2001-02-03 04:05:11.000 +07:00 reconcile divergent operations args: jj op log --reversed [EOF] "); // Should work correctly with `--limit` let output = work_dir.run_jj(["op", "log", "--reversed", "--limit=3"]); insta::assert_snapshot!(output, @" ○ 4f59a3fcf7fb test-username@host.example.com default@ 2001-02-03 04:05:10.000 +07:00 - 2001-02-03 04:05:10.000 +07:00 │ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ args: jj describe -m 'description 1' --at-op @- │ ○ 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 ├─╯ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ args: jj describe -m 'description 0' @ 3257abe149b2 test-username@host.example.com default@ 2001-02-03 04:05:11.000 +07:00 - 2001-02-03 04:05:11.000 +07:00 reconcile divergent operations args: jj op log --reversed [EOF] "); // Should work correctly with `--limit` and `--no-graph` let output = work_dir.run_jj(["op", "log", "--reversed", "--limit=2", "--no-graph"]); insta::assert_snapshot!(output, @" 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 0' 3257abe149b2 test-username@host.example.com default@ 2001-02-03 04:05:11.000 +07:00 - 2001-02-03 04:05:11.000 +07:00 reconcile divergent operations args: jj op log --reversed [EOF] ");} #[test]fn test_op_log_no_graph_null_terminated() { 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(["commit", "-m", "message1"]).success(); work_dir.run_jj(["commit", "-m", "message2"]).success(); let output = work_dir .run_jj([ "op", "log", "--no-graph", "--template", r#"id.short(4) ++ "\0""#, ]) .success(); insta::assert_debug_snapshot!(output.stdout.normalized(), @r#""932c\04693\0e39d\00000\0""#);} #[test]fn test_op_log_template() -> TestResult { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let render = |template| work_dir.run_jj(["op", "log", "-T", template]); insta::assert_snapshot!(render(r#"id ++ "\n""#), @" @ e39dc288903d96b1bfe662925e34157fd706fa2c213040ffc2fc535a9e87ff814a603e90cfe79fceed946e4367d302b5401a180d1e3a3946d739c6e0ca7362d1 ○ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!( render(r#"separate(" ", id.short(5), current_operation, user, time.start(), time.end(), time.duration()) ++ "\n""#), @" @ e39dc true test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 2001-02-03 04:05:07.000 +07:00 less than a microsecond ○ 00000 false @ 1970-01-01 00:00:00.000 +00:00 1970-01-01 00:00:00.000 +00:00 less than a microsecond [EOF] "); // Negative length shouldn't cause panic. insta::assert_snapshot!(render(r#"id.short(-1) ++ "|""#), @" @ <Error: out of range integral type conversion attempted>| ○ <Error: out of range integral type conversion attempted>| [EOF] "); insta::assert_snapshot!(render(r#"json(self) ++ "\n""#), @r#" @ {"id":"e39dc288903d96b1bfe662925e34157fd706fa2c213040ffc2fc535a9e87ff814a603e90cfe79fceed946e4367d302b5401a180d1e3a3946d739c6e0ca7362d1","parents":["00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"],"time":{"start":"2001-02-03T04:05:07+07:00","end":"2001-02-03T04:05:07+07:00"},"description":"add workspace 'default'","hostname":"host.example.com","username":"test-username","is_snapshot":false,"workspace_name":null,"attributes":{}} ○ {"id":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","parents":[],"time":{"start":"1970-01-01T00:00:00Z","end":"1970-01-01T00:00:00Z"},"description":"","hostname":"","username":"","is_snapshot":false,"workspace_name":null,"attributes":{}} [EOF] "#); // Test the default template, i.e. with relative start time and duration. We // don't generally use that template because it depends on the current time, // so we need to reset the time range format here. test_env.add_config( r#"[template-aliases]'format_time_range(time_range)' = 'time_range.end().ago() ++ ", lasted " ++ time_range.duration()' "#, ); let regex = Regex::new(r"\d\d years")?; let output = work_dir.run_jj(["op", "log"]); insta::assert_snapshot!( output.normalize_stdout_with(|s| regex.replace_all(&s, "NN years").into_owned()), @" @ e39dc288903d test-username@host.example.com NN years ago, lasted less than a microsecond │ add workspace 'default' ○ 000000000000 root() [EOF] "); Ok(())} #[test]fn test_op_log_builtin_templates() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); // Render without graph to test line ending let render = |template| work_dir.run_jj(["op", "log", "-T", template, "--no-graph"]); work_dir .run_jj(["describe", "-m", "description 0"]) .success(); insta::assert_snapshot!(render(r#"builtin_op_log_compact"#), @" 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 0' e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 add workspace 'default' 000000000000 root() [EOF] "); insta::assert_snapshot!(render(r#"builtin_op_log_comfortable"#), @" 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 0' e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 add workspace 'default' 000000000000 root() [EOF] "); insta::assert_snapshot!(render(r#"builtin_op_log_oneline"#), @" 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 0' e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 add workspace 'default' 000000000000 root() [EOF] ");} #[test]fn test_op_log_word_wrap() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); work_dir.write_file("file1", "foo\n".repeat(100)); work_dir.run_jj(["debug", "snapshot"]).success(); let render = |args: &[&str], columns: u32, word_wrap: bool| { let word_wrap = to_toml_value(word_wrap); work_dir.run_jj_with(|cmd| { cmd.args(args) .arg(format!("--config=ui.log-word-wrap={word_wrap}")) .env("COLUMNS", columns.to_string()) }) }; // ui.log-word-wrap option works insta::assert_snapshot!(render(&["op", "log"], 40, false), @" @ b16a25215f16 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 │ snapshot working copy │ args: jj debug snapshot ○ e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 │ add workspace 'default' ○ 000000000000 root()Lines 1–500 of 3924. Load more
// 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 std::path::Path; use std::path::PathBuf; use itertools::Itertools as _; use regex::Regex; use testutils::TestResult; use testutils::git; use crate::common::CommandOutput; use crate::common::TestEnvironment; use crate::common::TestWorkDir; use crate::common::to_toml_value; #[test] fn test_op_log() { 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(["describe", "-m", "description 0"]) .success(); let output = work_dir.run_jj(["op", "log"]); insta::assert_snapshot!(output, @" @ 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 │ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ args: jj describe -m 'description 0' ○ e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 │ add workspace 'default' ○ 000000000000 root() [EOF] "); let op_log_lines = output.stdout.raw().lines().collect_vec(); let add_workspace_id = op_log_lines[3].split(' ').nth(2).unwrap(); // Can load the repo at a specific operation ID insta::assert_snapshot!(get_log_output(&work_dir, add_workspace_id), @" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); // "@" resolves to the head operation insta::assert_snapshot!(get_log_output(&work_dir, "@"), @" @ 3ae22e7f50a15d393e412cca72d09a61165d0c84 ◆ 0000000000000000000000000000000000000000 [EOF] "); // "@-" resolves to the parent of the head operation insta::assert_snapshot!(get_log_output(&work_dir, "@-"), @" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!(work_dir.run_jj(["log", "--at-op", "@---"]), @r#" ------- stderr ------- Error: The "@---" expression resolved to no operations [EOF] [exit status: 1] "#); // We get a reasonable message if an invalid operation ID is specified insta::assert_snapshot!(work_dir.run_jj(["log", "--at-op", "foo"]), @r#" ------- stderr ------- Error: Operation ID "foo" is not a valid hexadecimal prefix [EOF] [exit status: 1] "#); let output = work_dir.run_jj(["op", "log", "--op-diff"]); insta::assert_snapshot!(output, @" @ 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 │ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ args: jj describe -m 'description 0' │ │ Changed commits: │ ○ + qpvuntsm 3ae22e7f (empty) description 0 │ - qpvuntsm/1 e8849ae1 (hidden) (empty) (no description set) │ │ Changed working copy default@: │ + qpvuntsm 3ae22e7f (empty) description 0 │ - qpvuntsm/1 e8849ae1 (hidden) (empty) (no description set) ○ e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 │ add workspace 'default' │ │ Changed commits: │ ○ + qpvuntsm e8849ae1 (empty) (no description set) │ │ Changed working copy default@: │ + qpvuntsm e8849ae1 (empty) (no description set) │ - (absent) ○ 000000000000 root() [EOF] "); let output = work_dir.run_jj(["op", "log", "--op-diff", "--color=always"]); insta::assert_snapshot!(output, @" [1m[38;5;2m@[0m [1m[38;5;12m69e9fab8ce76[39m [38;5;3mtest-username@host.example.com[39m [38;5;2mdefault@[39m [38;5;14m2001-02-03 04:05:08.000 +07:00[39m - [38;5;14m2001-02-03 04:05:08.000 +07:00[39m[0m │ [1mdescribe commit e8849ae12c709f2321908879bc724fdb2ab8a781[0m │ [1m[38;5;13margs: jj describe -m 'description 0'[39m[0m │ │ Changed commits: │ ○ [38;5;2m+[39m [1m[38;5;13mq[38;5;8mpvuntsm[39m [38;5;12m3[38;5;8mae22e7f[39m [38;5;10m(empty)[39m description 0[0m │ [38;5;1m-[39m [1m[39mq[0m[38;5;8mpvuntsm[1m[39m/1[0m [1m[38;5;4me[0m[38;5;8m8849ae1[39m (hidden) [38;5;2m(empty)[39m [38;5;2m(no description set)[39m │ │ Changed working copy [38;5;2mdefault@[39m: │ [38;5;2m+[39m [1m[38;5;13mq[38;5;8mpvuntsm[39m [38;5;12m3[38;5;8mae22e7f[39m [38;5;10m(empty)[39m description 0[0m │ [38;5;1m-[39m [1m[39mq[0m[38;5;8mpvuntsm[1m[39m/1[0m [1m[38;5;4me[0m[38;5;8m8849ae1[39m (hidden) [38;5;2m(empty)[39m [38;5;2m(no description set)[39m ○ [38;5;4me39dc288903d[39m [38;5;3mtest-username@host.example.com[39m [38;5;6m2001-02-03 04:05:07.000 +07:00[39m - [38;5;6m2001-02-03 04:05:07.000 +07:00[39m │ add workspace 'default' │ │ Changed commits: │ ○ [38;5;2m+[39m [1m[38;5;13mq[38;5;8mpvuntsm[39m [38;5;12me[38;5;8m8849ae1[39m [38;5;10m(empty)[39m [38;5;10m(no description set)[0m │ │ Changed working copy [38;5;2mdefault@[39m: │ [38;5;2m+[39m [1m[38;5;13mq[38;5;8mpvuntsm[39m [38;5;12me[38;5;8m8849ae1[39m [38;5;10m(empty)[39m [38;5;10m(no description set)[0m │ [38;5;1m-[39m (absent) ○ [38;5;4m000000000000[39m [38;5;2mroot()[39m [EOF] "); work_dir .run_jj(["describe", "-m", "description 1"]) .success(); work_dir .run_jj([ "describe", "-m", "description 2", "--at-op", add_workspace_id, ]) .success(); insta::assert_snapshot!(work_dir.run_jj(["log", "--at-op", "@-"]), @r#" ------- stderr ------- Error: The "@" expression resolved to more than one operation Hint: Try specifying one of the operations by ID: 3e9cf8ff3f23, 4693396e777b [EOF] [exit status: 1] "#); } #[test] fn test_op_log_with_custom_symbols() { 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(["describe", "-m", "description 0"]) .success(); let output = work_dir.run_jj([ "op", "log", "--config=templates.op_log_node='if(current_operation, \"$\", if(root, \"┴\", \"┝\"))'", ]); insta::assert_snapshot!(output, @" $ 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 │ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ args: jj describe -m 'description 0' ┝ e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 │ add workspace 'default' ┴ 000000000000 root() [EOF] "); } #[test] fn test_op_log_with_no_template() { 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(["op", "log", "-T"]); insta::assert_snapshot!(output, @" ------- stderr ------- error: a value is required for '--template <TEMPLATE>' but none was supplied For more information, try '--help'. Hint: The following template aliases are defined: - builtin_config_list - builtin_config_list_detailed - builtin_draft_commit_description - builtin_draft_commit_description_with_diff - builtin_evolog_compact - builtin_log_comfortable - builtin_log_compact - builtin_log_compact_full_description - builtin_log_detailed - builtin_log_node - builtin_log_node_ascii - builtin_log_oneline - builtin_log_redacted - builtin_op_log_comfortable - builtin_op_log_compact - builtin_op_log_node - builtin_op_log_node_ascii - builtin_op_log_oneline - builtin_op_log_redacted - builtin_workspace_list - commit_summary_separator - default_commit_description - description_placeholder - email_placeholder - empty_commit_marker - git_format_patch_email_headers - name_placeholder [EOF] [exit status: 2] "); } #[test] fn test_op_log_limit() { 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(["op", "log", "-Tdescription", "--limit=1"]); insta::assert_snapshot!(output, @" @ add workspace 'default' [EOF] "); } #[test] fn test_op_log_no_graph() { 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(["op", "log", "--no-graph", "--color=always"]); insta::assert_snapshot!(output, @" [1m[38;5;12me39dc288903d[39m [38;5;3mtest-username@host.example.com[39m [38;5;14m2001-02-03 04:05:07.000 +07:00[39m - [38;5;14m2001-02-03 04:05:07.000 +07:00[39m[0m [1madd workspace 'default'[0m [38;5;4m000000000000[39m [38;5;2mroot()[39m [EOF] "); let output = work_dir.run_jj(["op", "log", "--op-diff", "--no-graph"]); insta::assert_snapshot!(output, @" e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 add workspace 'default' Changed commits: + qpvuntsm e8849ae1 (empty) (no description set) Changed working copy default@: + qpvuntsm e8849ae1 (empty) (no description set) - (absent) 000000000000 root() [EOF] "); } #[test] fn test_op_log_reversed() { 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(["describe", "-m", "description 0"]) .success(); let output = work_dir.run_jj(["op", "log", "--reversed"]); insta::assert_snapshot!(output, @" ○ 000000000000 root() ○ e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 │ add workspace 'default' @ 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 0' [EOF] "); work_dir .run_jj(["describe", "-m", "description 1", "--at-op", "@-"]) .success(); // Should be able to display log with fork and branch points let output = work_dir.run_jj(["op", "log", "--reversed"]); insta::assert_snapshot!(output, @" ○ 000000000000 root() ○ e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 ├─╮ add workspace 'default' │ ○ 4f59a3fcf7fb test-username@host.example.com default@ 2001-02-03 04:05:10.000 +07:00 - 2001-02-03 04:05:10.000 +07:00 │ │ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ │ args: jj describe -m 'description 1' --at-op @- ○ │ 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 ├─╯ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ args: jj describe -m 'description 0' @ 3257abe149b2 test-username@host.example.com default@ 2001-02-03 04:05:11.000 +07:00 - 2001-02-03 04:05:11.000 +07:00 reconcile divergent operations args: jj op log --reversed [EOF] ------- stderr ------- Concurrent modification detected, resolving automatically. [EOF] "); // Should work correctly with `--no-graph` let output = work_dir.run_jj(["op", "log", "--reversed", "--no-graph"]); insta::assert_snapshot!(output, @" 000000000000 root() e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 add workspace 'default' 4f59a3fcf7fb test-username@host.example.com default@ 2001-02-03 04:05:10.000 +07:00 - 2001-02-03 04:05:10.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 1' --at-op @- 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 0' 3257abe149b2 test-username@host.example.com default@ 2001-02-03 04:05:11.000 +07:00 - 2001-02-03 04:05:11.000 +07:00 reconcile divergent operations args: jj op log --reversed [EOF] "); // Should work correctly with `--limit` let output = work_dir.run_jj(["op", "log", "--reversed", "--limit=3"]); insta::assert_snapshot!(output, @" ○ 4f59a3fcf7fb test-username@host.example.com default@ 2001-02-03 04:05:10.000 +07:00 - 2001-02-03 04:05:10.000 +07:00 │ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ args: jj describe -m 'description 1' --at-op @- │ ○ 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 ├─╯ describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 │ args: jj describe -m 'description 0' @ 3257abe149b2 test-username@host.example.com default@ 2001-02-03 04:05:11.000 +07:00 - 2001-02-03 04:05:11.000 +07:00 reconcile divergent operations args: jj op log --reversed [EOF] "); // Should work correctly with `--limit` and `--no-graph` let output = work_dir.run_jj(["op", "log", "--reversed", "--limit=2", "--no-graph"]); insta::assert_snapshot!(output, @" 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 0' 3257abe149b2 test-username@host.example.com default@ 2001-02-03 04:05:11.000 +07:00 - 2001-02-03 04:05:11.000 +07:00 reconcile divergent operations args: jj op log --reversed [EOF] "); } #[test] fn test_op_log_no_graph_null_terminated() { 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(["commit", "-m", "message1"]).success(); work_dir.run_jj(["commit", "-m", "message2"]).success(); let output = work_dir .run_jj([ "op", "log", "--no-graph", "--template", r#"id.short(4) ++ "\0""#, ]) .success(); insta::assert_debug_snapshot!(output.stdout.normalized(), @r#""932c\04693\0e39d\00000\0""#); } #[test] fn test_op_log_template() -> TestResult { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let render = |template| work_dir.run_jj(["op", "log", "-T", template]); insta::assert_snapshot!(render(r#"id ++ "\n""#), @" @ e39dc288903d96b1bfe662925e34157fd706fa2c213040ffc2fc535a9e87ff814a603e90cfe79fceed946e4367d302b5401a180d1e3a3946d739c6e0ca7362d1 ○ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!( render(r#"separate(" ", id.short(5), current_operation, user, time.start(), time.end(), time.duration()) ++ "\n""#), @" @ e39dc true test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 2001-02-03 04:05:07.000 +07:00 less than a microsecond ○ 00000 false @ 1970-01-01 00:00:00.000 +00:00 1970-01-01 00:00:00.000 +00:00 less than a microsecond [EOF] "); // Negative length shouldn't cause panic. insta::assert_snapshot!(render(r#"id.short(-1) ++ "|""#), @" @ <Error: out of range integral type conversion attempted>| ○ <Error: out of range integral type conversion attempted>| [EOF] "); insta::assert_snapshot!(render(r#"json(self) ++ "\n""#), @r#" @ {"id":"e39dc288903d96b1bfe662925e34157fd706fa2c213040ffc2fc535a9e87ff814a603e90cfe79fceed946e4367d302b5401a180d1e3a3946d739c6e0ca7362d1","parents":["00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"],"time":{"start":"2001-02-03T04:05:07+07:00","end":"2001-02-03T04:05:07+07:00"},"description":"add workspace 'default'","hostname":"host.example.com","username":"test-username","is_snapshot":false,"workspace_name":null,"attributes":{}} ○ {"id":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","parents":[],"time":{"start":"1970-01-01T00:00:00Z","end":"1970-01-01T00:00:00Z"},"description":"","hostname":"","username":"","is_snapshot":false,"workspace_name":null,"attributes":{}} [EOF] "#); // Test the default template, i.e. with relative start time and duration. We // don't generally use that template because it depends on the current time, // so we need to reset the time range format here. test_env.add_config( r#" [template-aliases] 'format_time_range(time_range)' = 'time_range.end().ago() ++ ", lasted " ++ time_range.duration()' "#, ); let regex = Regex::new(r"\d\d years")?; let output = work_dir.run_jj(["op", "log"]); insta::assert_snapshot!( output.normalize_stdout_with(|s| regex.replace_all(&s, "NN years").into_owned()), @" @ e39dc288903d test-username@host.example.com NN years ago, lasted less than a microsecond │ add workspace 'default' ○ 000000000000 root() [EOF] "); Ok(()) } #[test] fn test_op_log_builtin_templates() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); // Render without graph to test line ending let render = |template| work_dir.run_jj(["op", "log", "-T", template, "--no-graph"]); work_dir .run_jj(["describe", "-m", "description 0"]) .success(); insta::assert_snapshot!(render(r#"builtin_op_log_compact"#), @" 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 0' e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 add workspace 'default' 000000000000 root() [EOF] "); insta::assert_snapshot!(render(r#"builtin_op_log_comfortable"#), @" 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 0' e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 add workspace 'default' 000000000000 root() [EOF] "); insta::assert_snapshot!(render(r#"builtin_op_log_oneline"#), @" 69e9fab8ce76 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 describe commit e8849ae12c709f2321908879bc724fdb2ab8a781 args: jj describe -m 'description 0' e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 add workspace 'default' 000000000000 root() [EOF] "); } #[test] fn test_op_log_word_wrap() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); work_dir.write_file("file1", "foo\n".repeat(100)); work_dir.run_jj(["debug", "snapshot"]).success(); let render = |args: &[&str], columns: u32, word_wrap: bool| { let word_wrap = to_toml_value(word_wrap); work_dir.run_jj_with(|cmd| { cmd.args(args) .arg(format!("--config=ui.log-word-wrap={word_wrap}")) .env("COLUMNS", columns.to_string()) }) }; // ui.log-word-wrap option works insta::assert_snapshot!(render(&["op", "log"], 40, false), @" @ b16a25215f16 test-username@host.example.com default@ 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00 │ snapshot working copy │ args: jj debug snapshot ○ e39dc288903d test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00 │ add workspace 'default' ○ 000000000000 root()