// Copyright 2024 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. #[cfg(unix)]use std::os::unix::fs::PermissionsExt as _;use std::path::PathBuf; use indoc::formatdoc;use indoc::indoc;use jj_lib::file_util::try_symlink; use crate::common::to_toml_value;use crate::common::TestEnvironment; fn set_up_fake_formatter(test_env: &TestEnvironment, args: &[&str]) { let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); test_env.add_config(formatdoc! {" [fix.tools.fake-formatter] command = {command} patterns = ['all()'] ", command = toml_edit::Value::from_iter( [formatter_path.to_str().unwrap()] .iter() .chain(args) .copied() ) });} #[test]fn test_config_no_tools() { 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("file", "content\n"); let output = work_dir.run_jj(["fix"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Config error: No `fix.tools` are configured For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. [EOF] [exit status: 1] "); let output = work_dir.run_jj(["file", "show", "file", "-r", "@"]); insta::assert_snapshot!(output, @r" content [EOF] ");} #[test]fn test_config_multiple_tools() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.tool-1] command = [{formatter}, "--uppercase"] patterns = ["foo"] [fix.tools.tool-2] command = [{formatter}, "--lowercase"] patterns = ["bar"] "###, )); work_dir.write_file("foo", "Foo\n"); work_dir.write_file("bar", "Bar\n"); work_dir.write_file("baz", "Baz\n"); work_dir.run_jj(["fix"]).success(); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" FOO [EOF] "); let output = work_dir.run_jj(["file", "show", "bar", "-r", "@"]); insta::assert_snapshot!(output, @r" bar [EOF] "); let output = work_dir.run_jj(["file", "show", "baz", "-r", "@"]); insta::assert_snapshot!(output, @r" Baz [EOF] ");} #[test]fn test_config_multiple_tools_with_same_name() { let mut test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); // Multiple definitions with the same `name` are not allowed, because it is // likely to be a mistake, and mistakes are risky when they rewrite files. test_env.add_config(format!( r###" [fix.tools.my-tool] command = [{formatter}, "--uppercase"] patterns = ["foo"] [fix.tools.my-tool] command = [{formatter}, "--lowercase"] patterns = ["bar"] "###, )); work_dir.write_file("foo", "Foo\n"); work_dir.write_file("bar", "Bar\n"); let output = work_dir.run_jj(["fix"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Config error: Configuration cannot be parsed as TOML document Caused by: TOML parse error at line 6, column 9 | 6 | [fix.tools.my-tool] | ^ invalid table header duplicate key `my-tool` in table `fix.tools` Hint: Check the config file: $TEST_ENV/config/config0002.toml For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. [EOF] [exit status: 1] "); test_env.set_config_path("/dev/null"); let work_dir = test_env.work_dir("repo"); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" Foo [EOF] "); let output = work_dir.run_jj(["file", "show", "bar", "-r", "@"]); insta::assert_snapshot!(output, @r" Bar [EOF] ");} #[test]fn test_config_disabled_tools() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.tool-1] # default is enabled command = [{formatter}, "--uppercase"] patterns = ["foo"] [fix.tools.tool-2] enabled = true command = [{formatter}, "--lowercase"] patterns = ["bar"] [fix.tools.tool-3] enabled = false command = [{formatter}, "--lowercase"] patterns = ["baz"] "### )); work_dir.write_file("foo", "Foo\n"); work_dir.write_file("bar", "Bar\n"); work_dir.write_file("baz", "Baz\n"); work_dir.run_jj(["fix"]).success(); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" FOO [EOF] "); let output = work_dir.run_jj(["file", "show", "bar", "-r", "@"]); insta::assert_snapshot!(output, @r" bar [EOF] "); let output = work_dir.run_jj(["file", "show", "baz", "-r", "@"]); insta::assert_snapshot!(output, @r" Baz [EOF] ");} #[test]fn test_config_disabled_tools_warning_when_all_tools_are_disabled() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.tool-2] enabled = false command = [{formatter}, "--lowercase"] patterns = ["bar"] "### )); work_dir.write_file("bar", "Bar\n"); let output = work_dir.run_jj(["fix"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Config error: At least one entry of `fix.tools` must be enabled. For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. [EOF] [exit status: 1] ");} #[test]fn test_config_tables_overlapping_patterns() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.tool-1] command = [{formatter}, "--append", "tool-1"] patterns = ["foo", "bar"] [fix.tools.tool-2] command = [{formatter}, "--append", "tool-2"] patterns = ["bar", "baz"] "###, )); work_dir.write_file("foo", "foo\n"); work_dir.write_file("bar", "bar\n"); work_dir.write_file("baz", "baz\n"); work_dir.run_jj(["fix"]).success(); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" foo tool-1[EOF] "); let output = work_dir.run_jj(["file", "show", "bar", "-r", "@"]); insta::assert_snapshot!(output, @r" bar tool-1 tool-2[EOF] "); let output = work_dir.run_jj(["file", "show", "baz", "-r", "@"]); insta::assert_snapshot!(output, @r" baz tool-2[EOF] ");} #[test]fn test_config_tables_all_commands_missing() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); test_env.add_config( r###" [fix.tools.my-tool-missing-command-1] patterns = ["foo"] [fix.tools.my-tool-missing-command-2] patterns = ['glob:"ba*"'] "###, ); work_dir.write_file("foo", "foo\n"); let output = work_dir.run_jj(["fix"]); insta::assert_snapshot!(output.normalize_backslash(), @r" ------- stderr ------- Config error: Invalid type or value for fix.tools.my-tool-missing-command-1 Caused by: missing field `command` Hint: Check the config file: $TEST_ENV/config/config0002.toml For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. [EOF] [exit status: 1] "); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" foo [EOF] ");} #[test]fn test_config_tables_some_commands_missing() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.tool-1] command = [{formatter}, "--uppercase"] patterns = ["foo"] [fix.tools.my-tool-missing-command] patterns = ['bar'] "###, )); work_dir.write_file("foo", "foo\n"); let output = work_dir.run_jj(["fix"]); insta::assert_snapshot!(output.normalize_backslash(), @r" ------- stderr ------- Config error: Invalid type or value for fix.tools.my-tool-missing-command Caused by: missing field `command` Hint: Check the config file: $TEST_ENV/config/config0002.toml For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. [EOF] [exit status: 1] "); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" foo [EOF] ");} #[test]fn test_config_tables_empty_patterns_list() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.my-tool-empty-patterns] command = [{formatter}, "--uppercase"] patterns = [] "###, )); work_dir.write_file("foo", "foo\n"); let output = work_dir.run_jj(["fix"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Fixed 0 commits of 1 checked. Nothing changed. [EOF] "); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" foo [EOF] ");} #[test]fn test_config_filesets() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.my-tool-match-one] command = [{formatter}, "--uppercase"] patterns = ['glob:"a*"'] [fix.tools.my-tool-match-two] command = [{formatter}, "--reverse"] patterns = ['glob:"b*"'] [fix.tools.my-tool-match-none] command = [{formatter}, "--append", "SHOULD NOT APPEAR"] patterns = ['glob:"this-doesnt-match-anything-*"'] "###, )); work_dir.write_file("a1", "a1\n"); work_dir.write_file("b1", "b1\n"); work_dir.write_file("b2", "b2\n"); work_dir.run_jj(["fix"]).success(); let output = work_dir.run_jj(["file", "show", "a1", "-r", "@"]); insta::assert_snapshot!(output, @r" A1 [EOF] "); let output = work_dir.run_jj(["file", "show", "b1", "-r", "@"]); insta::assert_snapshot!(output, @r" 1b [EOF] "); let output = work_dir.run_jj(["file", "show", "b2", "-r", "@"]); insta::assert_snapshot!(output, @r" 2b [EOF] ");} #[test]fn test_relative_paths() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.tool] command = [{formatter}, "--stdout", "Fixed!"] patterns = ['glob:"foo*"'] "###, )); let sub_dir = work_dir.create_dir("dir"); work_dir.write_file("foo1", "unfixed\n"); work_dir.write_file("foo2", "unfixed\n"); work_dir.write_file("dir/foo3", "unfixed\n"); // Positional arguments are cwd-relative, but the configured patterns are // repo-relative, so this command fixes the empty intersection of those // filesets. sub_dir.run_jj(["fix", "foo3"]).success(); let output = work_dir.run_jj(["file", "show", "foo1", "-r", "@"]); insta::assert_snapshot!(output, @r" unfixed [EOF] "); let output = work_dir.run_jj(["file", "show", "foo2", "-r", "@"]); insta::assert_snapshot!(output, @r" unfixed [EOF] "); let output = work_dir.run_jj(["file", "show", "dir/foo3", "-r", "@"]); insta::assert_snapshot!(output, @r" unfixed [EOF] "); // Positional arguments can specify a subset of the configured fileset. sub_dir.run_jj(["fix", "../foo1"]).success(); let output = work_dir.run_jj(["file", "show", "foo1", "-r", "@"]); insta::assert_snapshot!(output, @"Fixed![EOF]"); let output = work_dir.run_jj(["file", "show", "foo2", "-r", "@"]); insta::assert_snapshot!(output, @r" unfixed [EOF] "); let output = work_dir.run_jj(["file", "show", "dir/foo3", "-r", "@"]); insta::assert_snapshot!(output, @r" unfixed [EOF] ");Lines 1–500 of 1480. Load more
// Copyright 2024 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. #[cfg(unix)] use std::os::unix::fs::PermissionsExt as _; use std::path::PathBuf; use indoc::formatdoc; use indoc::indoc; use jj_lib::file_util::try_symlink; use crate::common::to_toml_value; use crate::common::TestEnvironment; fn set_up_fake_formatter(test_env: &TestEnvironment, args: &[&str]) { let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); test_env.add_config(formatdoc! {" [fix.tools.fake-formatter] command = {command} patterns = ['all()'] ", command = toml_edit::Value::from_iter( [formatter_path.to_str().unwrap()] .iter() .chain(args) .copied() ) }); } #[test] fn test_config_no_tools() { 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("file", "content\n"); let output = work_dir.run_jj(["fix"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Config error: No `fix.tools` are configured For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. [EOF] [exit status: 1] "); let output = work_dir.run_jj(["file", "show", "file", "-r", "@"]); insta::assert_snapshot!(output, @r" content [EOF] "); } #[test] fn test_config_multiple_tools() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.tool-1] command = [{formatter}, "--uppercase"] patterns = ["foo"] [fix.tools.tool-2] command = [{formatter}, "--lowercase"] patterns = ["bar"] "###, )); work_dir.write_file("foo", "Foo\n"); work_dir.write_file("bar", "Bar\n"); work_dir.write_file("baz", "Baz\n"); work_dir.run_jj(["fix"]).success(); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" FOO [EOF] "); let output = work_dir.run_jj(["file", "show", "bar", "-r", "@"]); insta::assert_snapshot!(output, @r" bar [EOF] "); let output = work_dir.run_jj(["file", "show", "baz", "-r", "@"]); insta::assert_snapshot!(output, @r" Baz [EOF] "); } #[test] fn test_config_multiple_tools_with_same_name() { let mut test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); // Multiple definitions with the same `name` are not allowed, because it is // likely to be a mistake, and mistakes are risky when they rewrite files. test_env.add_config(format!( r###" [fix.tools.my-tool] command = [{formatter}, "--uppercase"] patterns = ["foo"] [fix.tools.my-tool] command = [{formatter}, "--lowercase"] patterns = ["bar"] "###, )); work_dir.write_file("foo", "Foo\n"); work_dir.write_file("bar", "Bar\n"); let output = work_dir.run_jj(["fix"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Config error: Configuration cannot be parsed as TOML document Caused by: TOML parse error at line 6, column 9 | 6 | [fix.tools.my-tool] | ^ invalid table header duplicate key `my-tool` in table `fix.tools` Hint: Check the config file: $TEST_ENV/config/config0002.toml For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. [EOF] [exit status: 1] "); test_env.set_config_path("/dev/null"); let work_dir = test_env.work_dir("repo"); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" Foo [EOF] "); let output = work_dir.run_jj(["file", "show", "bar", "-r", "@"]); insta::assert_snapshot!(output, @r" Bar [EOF] "); } #[test] fn test_config_disabled_tools() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.tool-1] # default is enabled command = [{formatter}, "--uppercase"] patterns = ["foo"] [fix.tools.tool-2] enabled = true command = [{formatter}, "--lowercase"] patterns = ["bar"] [fix.tools.tool-3] enabled = false command = [{formatter}, "--lowercase"] patterns = ["baz"] "### )); work_dir.write_file("foo", "Foo\n"); work_dir.write_file("bar", "Bar\n"); work_dir.write_file("baz", "Baz\n"); work_dir.run_jj(["fix"]).success(); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" FOO [EOF] "); let output = work_dir.run_jj(["file", "show", "bar", "-r", "@"]); insta::assert_snapshot!(output, @r" bar [EOF] "); let output = work_dir.run_jj(["file", "show", "baz", "-r", "@"]); insta::assert_snapshot!(output, @r" Baz [EOF] "); } #[test] fn test_config_disabled_tools_warning_when_all_tools_are_disabled() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.tool-2] enabled = false command = [{formatter}, "--lowercase"] patterns = ["bar"] "### )); work_dir.write_file("bar", "Bar\n"); let output = work_dir.run_jj(["fix"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Config error: At least one entry of `fix.tools` must be enabled. For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. [EOF] [exit status: 1] "); } #[test] fn test_config_tables_overlapping_patterns() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.tool-1] command = [{formatter}, "--append", "tool-1"] patterns = ["foo", "bar"] [fix.tools.tool-2] command = [{formatter}, "--append", "tool-2"] patterns = ["bar", "baz"] "###, )); work_dir.write_file("foo", "foo\n"); work_dir.write_file("bar", "bar\n"); work_dir.write_file("baz", "baz\n"); work_dir.run_jj(["fix"]).success(); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" foo tool-1[EOF] "); let output = work_dir.run_jj(["file", "show", "bar", "-r", "@"]); insta::assert_snapshot!(output, @r" bar tool-1 tool-2[EOF] "); let output = work_dir.run_jj(["file", "show", "baz", "-r", "@"]); insta::assert_snapshot!(output, @r" baz tool-2[EOF] "); } #[test] fn test_config_tables_all_commands_missing() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); test_env.add_config( r###" [fix.tools.my-tool-missing-command-1] patterns = ["foo"] [fix.tools.my-tool-missing-command-2] patterns = ['glob:"ba*"'] "###, ); work_dir.write_file("foo", "foo\n"); let output = work_dir.run_jj(["fix"]); insta::assert_snapshot!(output.normalize_backslash(), @r" ------- stderr ------- Config error: Invalid type or value for fix.tools.my-tool-missing-command-1 Caused by: missing field `command` Hint: Check the config file: $TEST_ENV/config/config0002.toml For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. [EOF] [exit status: 1] "); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" foo [EOF] "); } #[test] fn test_config_tables_some_commands_missing() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.tool-1] command = [{formatter}, "--uppercase"] patterns = ["foo"] [fix.tools.my-tool-missing-command] patterns = ['bar'] "###, )); work_dir.write_file("foo", "foo\n"); let output = work_dir.run_jj(["fix"]); insta::assert_snapshot!(output.normalize_backslash(), @r" ------- stderr ------- Config error: Invalid type or value for fix.tools.my-tool-missing-command Caused by: missing field `command` Hint: Check the config file: $TEST_ENV/config/config0002.toml For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`. [EOF] [exit status: 1] "); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" foo [EOF] "); } #[test] fn test_config_tables_empty_patterns_list() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.my-tool-empty-patterns] command = [{formatter}, "--uppercase"] patterns = [] "###, )); work_dir.write_file("foo", "foo\n"); let output = work_dir.run_jj(["fix"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Fixed 0 commits of 1 checked. Nothing changed. [EOF] "); let output = work_dir.run_jj(["file", "show", "foo", "-r", "@"]); insta::assert_snapshot!(output, @r" foo [EOF] "); } #[test] fn test_config_filesets() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.my-tool-match-one] command = [{formatter}, "--uppercase"] patterns = ['glob:"a*"'] [fix.tools.my-tool-match-two] command = [{formatter}, "--reverse"] patterns = ['glob:"b*"'] [fix.tools.my-tool-match-none] command = [{formatter}, "--append", "SHOULD NOT APPEAR"] patterns = ['glob:"this-doesnt-match-anything-*"'] "###, )); work_dir.write_file("a1", "a1\n"); work_dir.write_file("b1", "b1\n"); work_dir.write_file("b2", "b2\n"); work_dir.run_jj(["fix"]).success(); let output = work_dir.run_jj(["file", "show", "a1", "-r", "@"]); insta::assert_snapshot!(output, @r" A1 [EOF] "); let output = work_dir.run_jj(["file", "show", "b1", "-r", "@"]); insta::assert_snapshot!(output, @r" 1b [EOF] "); let output = work_dir.run_jj(["file", "show", "b2", "-r", "@"]); insta::assert_snapshot!(output, @r" 2b [EOF] "); } #[test] fn test_relative_paths() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); assert!(formatter_path.is_file()); let formatter = to_toml_value(formatter_path.to_str().unwrap()); test_env.add_config(format!( r###" [fix.tools.tool] command = [{formatter}, "--stdout", "Fixed!"] patterns = ['glob:"foo*"'] "###, )); let sub_dir = work_dir.create_dir("dir"); work_dir.write_file("foo1", "unfixed\n"); work_dir.write_file("foo2", "unfixed\n"); work_dir.write_file("dir/foo3", "unfixed\n"); // Positional arguments are cwd-relative, but the configured patterns are // repo-relative, so this command fixes the empty intersection of those // filesets. sub_dir.run_jj(["fix", "foo3"]).success(); let output = work_dir.run_jj(["file", "show", "foo1", "-r", "@"]); insta::assert_snapshot!(output, @r" unfixed [EOF] "); let output = work_dir.run_jj(["file", "show", "foo2", "-r", "@"]); insta::assert_snapshot!(output, @r" unfixed [EOF] "); let output = work_dir.run_jj(["file", "show", "dir/foo3", "-r", "@"]); insta::assert_snapshot!(output, @r" unfixed [EOF] "); // Positional arguments can specify a subset of the configured fileset. sub_dir.run_jj(["fix", "../foo1"]).success(); let output = work_dir.run_jj(["file", "show", "foo1", "-r", "@"]); insta::assert_snapshot!(output, @"Fixed![EOF]"); let output = work_dir.run_jj(["file", "show", "foo2", "-r", "@"]); insta::assert_snapshot!(output, @r" unfixed [EOF] "); let output = work_dir.run_jj(["file", "show", "dir/foo3", "-r", "@"]); insta::assert_snapshot!(output, @r" unfixed [EOF] ");