From 4f76320afa356ba568d3654830083397a6689e6c Mon Sep 17 00:00:00 2001 From: Stephen Jennings Date: Thu, 5 Sep 2024 16:26:28 -0700 Subject: [PATCH] fix: Add `enabled` config for fix tools Adds an optional `fix.tools.TOOL.enabled` config that disables use of a fix tool (if omitted, the tool is enabled). This is useful for defining tools in the user's configuration without enabling them for all repositories: ```toml # ~/.jjconfig.toml [fix.tools.rustfmt] enabled = false command = ["rustfmt", "--emit", "stdout"] patterns = ["glob:'**/*.rs'"] ``` Then to enable it in a repository: ```shell $ jj config set --repo fix.tools.rustfmt.enabled true ``` This also allows Jujutsu to ship some built-in tool configurations that are disabled by default. --- CHANGELOG.md | 4 +++ cli/src/commands/fix.rs | 22 +++++++++++++++-- cli/src/config-schema.json | 5 ++++ cli/tests/cli-reference@.md.snap | 3 +++ cli/tests/test_fix_command.rs | 42 ++++++++++++++++++++++++++++++++ docs/config.md | 21 ++++++++++++++++ 6 files changed, 95 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6498ec0c82..fda2667df2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). below it, similar to a "scissor line" in git. When editing multiple commits, only ignore until the next `JJ: describe` line. +* `enabled`: Enables or disables the tool. If omitted, the tool is enabled. + This is useful for defining disabled tools in user configuration that can be + enabled in individual repositories with one config setting. + ### Fixed bugs * The `$NO_COLOR` environment variable must now be non-empty to be respected. diff --git a/cli/src/commands/fix.rs b/cli/src/commands/fix.rs index e87f3e6a94..126cdbd17f 100644 --- a/cli/src/commands/fix.rs +++ b/cli/src/commands/fix.rs @@ -86,6 +86,9 @@ use crate::ui::Ui; /// empty, no files will be affected by the tool. If there are multiple /// patterns, the tool is applied only once to each file in the union of the /// patterns. +/// - `enabled`: Enables or disables the tool. If omitted, the tool is enabled. +/// This is useful for defining disabled tools in user configuration that can +/// be enabled in individual repositories with one config setting. /// /// For example, the following configuration defines how two code formatters /// (`clang-format` and `black`) will apply to three different file extensions @@ -440,6 +443,12 @@ struct ToolsConfig { struct RawToolConfig { command: CommandNameAndArgs, patterns: Vec, + #[serde(default = "default_tool_enabled")] + enabled: bool, +} + +fn default_tool_enabled() -> bool { + true } /// Parses the `fix.tools` config table. @@ -484,9 +493,18 @@ fn get_tools_config(ui: &mut Ui, settings: &UserSettings) -> Result Result { + .filter_map( + |name| -> Option> { + match settings.get::(["fix", "tools", name]) { + Ok(tool) if tool.enabled => Some(Ok((tool, name))), + Ok(_) => None, + Err(err) => Some(Err(err.into())), + } + }, + ) + .map(|r| -> Result { + let (tool, name) = r?; let mut diagnostics = FilesetDiagnostics::new(); - let tool: RawToolConfig = settings.get(["fix", "tools", name])?; let expression = FilesetExpression::union_all( tool.patterns .iter() diff --git a/cli/src/config-schema.json b/cli/src/config-schema.json index 8a02e71165..2d9c26e30c 100644 --- a/cli/src/config-schema.json +++ b/cli/src/config-schema.json @@ -611,6 +611,11 @@ "type": "string" }, "description": "Filesets that will be affected by this tool" + }, + "enabled": { + "type": "boolean", + "description": "Disables this tool if set to false", + "default": true } } }, diff --git a/cli/tests/cli-reference@.md.snap b/cli/tests/cli-reference@.md.snap index 49fe4c2156..29b564d58f 100644 --- a/cli/tests/cli-reference@.md.snap +++ b/cli/tests/cli-reference@.md.snap @@ -985,6 +985,9 @@ the values have the following properties: empty, no files will be affected by the tool. If there are multiple patterns, the tool is applied only once to each file in the union of the patterns. + - `enabled`: Enables or disables the tool. If omitted, the tool is enabled. + This is useful for defining disabled tools in user configuration that can + be enabled in individual repositories with one config setting. For example, the following configuration defines how two code formatters (`clang-format` and `black`) will apply to three different file extensions diff --git a/cli/tests/test_fix_command.rs b/cli/tests/test_fix_command.rs index 38b272e0f4..aac6b6b507 100644 --- a/cli/tests/test_fix_command.rs +++ b/cli/tests/test_fix_command.rs @@ -187,6 +187,48 @@ fn test_config_multiple_tools_with_same_name() { insta::assert_snapshot!(content, @"Bar\n"); } +#[test] +fn test_config_disabled_tools() { + let test_env = TestEnvironment::default(); + test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); + let repo_path = test_env.env_root().join("repo"); + let formatter_path = assert_cmd::cargo::cargo_bin("fake-formatter"); + assert!(formatter_path.is_file()); + let escaped_formatter_path = formatter_path.to_str().unwrap().replace('\\', r"\\"); + 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"] + "###, + formatter = escaped_formatter_path.as_str() + )); + + std::fs::write(repo_path.join("foo"), "Foo\n").unwrap(); + std::fs::write(repo_path.join("bar"), "Bar\n").unwrap(); + std::fs::write(repo_path.join("baz"), "Baz\n").unwrap(); + + let (_stdout, _stderr) = test_env.jj_cmd_ok(&repo_path, &["fix"]); + + let content = test_env.jj_cmd_success(&repo_path, &["file", "show", "foo", "-r", "@"]); + insta::assert_snapshot!(content, @"FOO\n"); + let content = test_env.jj_cmd_success(&repo_path, &["file", "show", "bar", "-r", "@"]); + insta::assert_snapshot!(content, @"bar\n"); + let content = test_env.jj_cmd_success(&repo_path, &["file", "show", "baz", "-r", "@"]); + insta::assert_snapshot!(content, @"Baz\n"); +} + #[test] fn test_config_tables_overlapping_patterns() { let test_env = TestEnvironment::default(); diff --git a/docs/config.md b/docs/config.md index 9d6463f842..dfd5b6cef4 100644 --- a/docs/config.md +++ b/docs/config.md @@ -960,6 +960,27 @@ command = ["head", "-n", "10"] patterns = ["numbers.txt"] ``` +### Disabling and enabling tools + +Tools can be disabled and enabled with the optional `enabled` config. This +allows you to define tools globally but enable them only for specific +repositories. + +In the user configuration, define a disabled tool for running rustfmt: + +```toml +[fix.tools.rustfmt] +enabled = false +command = ["rustfmt", "--emit", "stdout"] +patterns = ["glob:'**/*.rs'"] +``` + +Then to use the tool in a specific repository, set the `enabled` config: + +```shell +$ jj config set --repo fix.tools.rustfmt.enabled true +``` + ## Commit Signing `jj` can be configured to sign and verify the commits it creates using either