// 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::git; use crate::common::to_toml_value;use crate::common::CommandOutput;use crate::common::TestEnvironment;use crate::common::TestWorkDir; #[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, @r" @ 12f7cbba4278 test-username@host.example.com 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' ○ 8f47435a3990 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), @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); // "@" resolves to the head operation insta::assert_snapshot!(get_log_output(&work_dir, "@"), @r" @ 3ae22e7f50a15d393e412cca72d09a61165d0c84 ◆ 0000000000000000000000000000000000000000 [EOF] "); // "@-" resolves to the parent of the head operation insta::assert_snapshot!(get_log_output(&work_dir, "@-"), @r" @ 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, @r" @ 12f7cbba4278 test-username@host.example.com 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 hidden e8849ae1 (empty) (no description set) │ │ Changed working copy default@: │ + qpvuntsm 3ae22e7f (empty) description 0 │ - qpvuntsm hidden e8849ae1 (empty) (no description set) ○ 8f47435a3990 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, @r" [1m[38;5;2m@[0m [1m[38;5;12m12f7cbba4278[39m [38;5;3mtest-username@host.example.com[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[39m hidden [1m[38;5;4me[0m[38;5;8m8849ae1[39m [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[39m hidden [1m[38;5;4me[0m[38;5;8m8849ae1[39m [38;5;2m(empty)[39m [38;5;2m(no description set)[39m ○ [38;5;4m8f47435a3990[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: a57c1debcef0, 6a23c2d6dc15 [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, @r" $ 12f7cbba4278 test-username@host.example.com 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' ┝ 8f47435a3990 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, @r" ------- 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_log_comfortable - builtin_log_compact - builtin_log_compact_full_description - builtin_log_detailed - builtin_log_node - builtin_log_node_ascii - builtin_log_oneline - builtin_op_log_comfortable - builtin_op_log_compact - builtin_op_log_node - builtin_op_log_node_ascii - builtin_op_log_oneline - commit_summary_separator - default_commit_description - description_placeholder - email_placeholder - 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, @r" @ 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, @r" [1m[38;5;12m8f47435a3990[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, @r" 8f47435a3990 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, @r" ○ 000000000000 root() ○ 8f47435a3990 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' @ 12f7cbba4278 test-username@host.example.com 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, @r" ○ 000000000000 root() ○ 8f47435a3990 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' │ ○ 39f59ea3ec6e test-username@host.example.com 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 @- ○ │ 12f7cbba4278 test-username@host.example.com 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' @ fa6e12f12705 test-username@host.example.com 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, @r" 000000000000 root() 8f47435a3990 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' 39f59ea3ec6e test-username@host.example.com 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 @- 12f7cbba4278 test-username@host.example.com 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' fa6e12f12705 test-username@host.example.com 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, @r" ○ 39f59ea3ec6e test-username@host.example.com 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 @- │ ○ 12f7cbba4278 test-username@host.example.com 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' @ fa6e12f12705 test-username@host.example.com 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, @r" 12f7cbba4278 test-username@host.example.com 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' fa6e12f12705 test-username@host.example.com 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#""a9e5\00265\08f47\00000\0""#);} #[test]fn test_op_log_template() { 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""#), @r" @ 8f47435a3990362feaf967ca6de2eb0a31c8b883dfcb66fba5c22200d12bbe61e3dc8bc855f1f6879285fcafaf85ac792f9a43bcc36e57d28737d18347d5e752 ○ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!( render(r#"separate(" ", id.short(5), current_operation, user, time.start(), time.end(), time.duration()) ++ "\n""#), @r" @ 8f474 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) ++ "|""#), @r" @ <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":"8f47435a3990362feaf967ca6de2eb0a31c8b883dfcb66fba5c22200d12bbe61e3dc8bc855f1f6879285fcafaf85ac792f9a43bcc36e57d28737d18347d5e752","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,"tags":{}} ○ {"id":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","parents":[],"time":{"start":"1970-01-01T00:00:00Z","end":"1970-01-01T00:00:00Z"},"description":"","hostname":"","username":"","is_snapshot":false,"tags":{}} [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").unwrap(); let output = work_dir.run_jj(["op", "log"]); insta::assert_snapshot!( output.normalize_stdout_with(|s| regex.replace_all(&s, "NN years").into_owned()), @r" @ 8f47435a3990 test-username@host.example.com NN years ago, lasted less than a microsecond │ add workspace 'default' ○ 000000000000 root() [EOF] ");} #[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"#), @r" 12f7cbba4278 test-username@host.example.com 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' 8f47435a3990 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"#), @r" 12f7cbba4278 test-username@host.example.com 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' 8f47435a3990 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"#), @r" 12f7cbba4278 test-username@host.example.com 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' 8f47435a3990 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), @r" @ 2144f9621985 test-username@host.example.com 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 ○ 8f47435a3990 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(&["op", "log"], 40, true), @r" @ 2144f9621985 │ test-username@host.example.com │ 2001-02-03 04:05:08.000 +07:00 - │ 2001-02-03 04:05:08.000 +07:00 │ snapshot working copyLines 1–500 of 2783. 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::git; use crate::common::to_toml_value; use crate::common::CommandOutput; use crate::common::TestEnvironment; use crate::common::TestWorkDir; #[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, @r" @ 12f7cbba4278 test-username@host.example.com 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' ○ 8f47435a3990 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), @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); // "@" resolves to the head operation insta::assert_snapshot!(get_log_output(&work_dir, "@"), @r" @ 3ae22e7f50a15d393e412cca72d09a61165d0c84 ◆ 0000000000000000000000000000000000000000 [EOF] "); // "@-" resolves to the parent of the head operation insta::assert_snapshot!(get_log_output(&work_dir, "@-"), @r" @ 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, @r" @ 12f7cbba4278 test-username@host.example.com 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 hidden e8849ae1 (empty) (no description set) │ │ Changed working copy default@: │ + qpvuntsm 3ae22e7f (empty) description 0 │ - qpvuntsm hidden e8849ae1 (empty) (no description set) ○ 8f47435a3990 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, @r" [1m[38;5;2m@[0m [1m[38;5;12m12f7cbba4278[39m [38;5;3mtest-username@host.example.com[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[39m hidden [1m[38;5;4me[0m[38;5;8m8849ae1[39m [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[39m hidden [1m[38;5;4me[0m[38;5;8m8849ae1[39m [38;5;2m(empty)[39m [38;5;2m(no description set)[39m ○ [38;5;4m8f47435a3990[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: a57c1debcef0, 6a23c2d6dc15 [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, @r" $ 12f7cbba4278 test-username@host.example.com 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' ┝ 8f47435a3990 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, @r" ------- 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_log_comfortable - builtin_log_compact - builtin_log_compact_full_description - builtin_log_detailed - builtin_log_node - builtin_log_node_ascii - builtin_log_oneline - builtin_op_log_comfortable - builtin_op_log_compact - builtin_op_log_node - builtin_op_log_node_ascii - builtin_op_log_oneline - commit_summary_separator - default_commit_description - description_placeholder - email_placeholder - 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, @r" @ 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, @r" [1m[38;5;12m8f47435a3990[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, @r" 8f47435a3990 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, @r" ○ 000000000000 root() ○ 8f47435a3990 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' @ 12f7cbba4278 test-username@host.example.com 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, @r" ○ 000000000000 root() ○ 8f47435a3990 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' │ ○ 39f59ea3ec6e test-username@host.example.com 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 @- ○ │ 12f7cbba4278 test-username@host.example.com 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' @ fa6e12f12705 test-username@host.example.com 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, @r" 000000000000 root() 8f47435a3990 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' 39f59ea3ec6e test-username@host.example.com 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 @- 12f7cbba4278 test-username@host.example.com 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' fa6e12f12705 test-username@host.example.com 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, @r" ○ 39f59ea3ec6e test-username@host.example.com 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 @- │ ○ 12f7cbba4278 test-username@host.example.com 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' @ fa6e12f12705 test-username@host.example.com 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, @r" 12f7cbba4278 test-username@host.example.com 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' fa6e12f12705 test-username@host.example.com 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#""a9e5\00265\08f47\00000\0""#); } #[test] fn test_op_log_template() { 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""#), @r" @ 8f47435a3990362feaf967ca6de2eb0a31c8b883dfcb66fba5c22200d12bbe61e3dc8bc855f1f6879285fcafaf85ac792f9a43bcc36e57d28737d18347d5e752 ○ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [EOF] "); insta::assert_snapshot!( render(r#"separate(" ", id.short(5), current_operation, user, time.start(), time.end(), time.duration()) ++ "\n""#), @r" @ 8f474 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) ++ "|""#), @r" @ <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":"8f47435a3990362feaf967ca6de2eb0a31c8b883dfcb66fba5c22200d12bbe61e3dc8bc855f1f6879285fcafaf85ac792f9a43bcc36e57d28737d18347d5e752","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,"tags":{}} ○ {"id":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","parents":[],"time":{"start":"1970-01-01T00:00:00Z","end":"1970-01-01T00:00:00Z"},"description":"","hostname":"","username":"","is_snapshot":false,"tags":{}} [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").unwrap(); let output = work_dir.run_jj(["op", "log"]); insta::assert_snapshot!( output.normalize_stdout_with(|s| regex.replace_all(&s, "NN years").into_owned()), @r" @ 8f47435a3990 test-username@host.example.com NN years ago, lasted less than a microsecond │ add workspace 'default' ○ 000000000000 root() [EOF] "); } #[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"#), @r" 12f7cbba4278 test-username@host.example.com 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' 8f47435a3990 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"#), @r" 12f7cbba4278 test-username@host.example.com 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' 8f47435a3990 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"#), @r" 12f7cbba4278 test-username@host.example.com 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' 8f47435a3990 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), @r" @ 2144f9621985 test-username@host.example.com 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 ○ 8f47435a3990 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(&["op", "log"], 40, true), @r" @ 2144f9621985 │ test-username@host.example.com │ 2001-02-03 04:05:08.000 +07:00 - │ 2001-02-03 04:05:08.000 +07:00 │ snapshot working copy