Skip to content

Commit

Permalink
config: propogate --when.command through cli
Browse files Browse the repository at this point in the history
  • Loading branch information
bryceberger committed Jan 22, 2025
1 parent 5464ba9 commit dedbc47
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 13 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
* New `subject(pattern)` revset function that matches first line of commit
descriptions.

* Conditional configuration now supports `--when.command` to change configuration
based on subcommand.

### Fixed bugs

* Fixed diff selection by external tools with `jj split`/`commit -i FILESETS`.
Expand Down
20 changes: 19 additions & 1 deletion cli/src/cli_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3701,6 +3701,23 @@ impl CliRunner {
process_global_args_fn(ui, &matches)?;
}

let subcommand_combined =
if let Some((subcommand, mut subcommand_matches)) = matches.subcommand() {
let mut subcommand_combined = String::from(subcommand);
while let Some((subcommand, new_matches)) = subcommand_matches.subcommand() {
subcommand_combined.push(' ');
subcommand_combined.push_str(subcommand);
subcommand_matches = new_matches;
}
config = config_env
.resolve_config_with_command(&raw_config, Some(&subcommand_combined))?;
migrate_config(&mut config)?;
ui.reset(&config)?;
Some(subcommand_combined)
} else {
None
};

let maybe_workspace_loader = if let Some(path) = &args.global_args.repository {
// TODO: maybe path should be canonicalized by WorkspaceLoader?
let abs_path = cwd.join(path);
Expand All @@ -3712,7 +3729,8 @@ impl CliRunner {
.map_err(|err| map_workspace_load_error(err, Some(path)))?;
config_env.reset_repo_path(loader.repo_path());
config_env.reload_repo_config(&mut raw_config)?;
config = config_env.resolve_config(&raw_config)?;
config = config_env
.resolve_config_with_command(&raw_config, subcommand_combined.as_deref())?;
migrate_config(&mut config)?;
Ok(loader)
} else {
Expand Down
9 changes: 9 additions & 0 deletions cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,9 +395,18 @@ impl ConfigEnv {
/// Resolves conditional scopes within the current environment. Returns new
/// resolved config.
pub fn resolve_config(&self, config: &RawConfig) -> Result<StackedConfig, ConfigGetError> {
self.resolve_config_with_command(config, None)
}

pub fn resolve_config_with_command(
&self,
config: &RawConfig,
command: Option<&str>,
) -> Result<StackedConfig, ConfigGetError> {
let context = ConfigResolutionContext {
home_dir: self.home_dir.as_deref(),
repo_path: self.repo_path.as_deref(),
command,
};
jj_lib::config::resolve(config.as_ref(), &context)
}
Expand Down
69 changes: 65 additions & 4 deletions cli/tests/test_config_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1078,12 +1078,25 @@ fn test_config_conditional() {
&user_config_path,
indoc! {"
foo = 'global'
baz = 'global'
qux = 'global'
[[--scope]]
--when.repositories = ['~/repo1']
foo = 'repo1'
[[--scope]]
--when.repositories = ['~/repo2']
foo = 'repo2'
[[--scope]]
--when.commands = ['config']
baz = 'config'
[[--scope]]
--when.commands = ['config get']
qux = 'get'
[[--scope]]
--when.commands = ['config list']
qux = 'list'
"},
)
.unwrap();
Expand All @@ -1093,16 +1106,38 @@ fn test_config_conditional() {
insta::assert_snapshot!(stdout, @"global");
let stdout = test_env.jj_cmd_success(&repo1_path, &["config", "get", "foo"]);
insta::assert_snapshot!(stdout, @"repo1");
// baz should be the same for `jj config get` and `jj config list`
// qux should be different
let stdout = test_env.jj_cmd_success(&repo1_path, &["config", "get", "baz"]);
insta::assert_snapshot!(stdout, @"config");
let stdout = test_env.jj_cmd_success(&repo1_path, &["config", "get", "qux"]);
insta::assert_snapshot!(stdout, @"get");
let stdout = test_env.jj_cmd_success(test_env.env_root(), &["config", "list", "--user"]);
insta::assert_snapshot!(stdout, @"foo = 'global'");
insta::assert_snapshot!(stdout, @r#"
foo = 'global'
baz = 'config'
qux = 'list'
"#);
let stdout = test_env.jj_cmd_success(&repo1_path, &["config", "list", "--user"]);
insta::assert_snapshot!(stdout, @"foo = 'repo1'");
insta::assert_snapshot!(stdout, @r#"
foo = 'repo1'
baz = 'config'
qux = 'list'
"#);
let stdout = test_env.jj_cmd_success(&repo2_path, &["config", "list", "--user"]);
insta::assert_snapshot!(stdout, @"foo = 'repo2'");
insta::assert_snapshot!(stdout, @r#"
foo = 'repo2'
baz = 'config'
qux = 'list'
"#);

// relative workspace path
let stdout = test_env.jj_cmd_success(&repo2_path, &["config", "list", "--user", "-R../repo1"]);
insta::assert_snapshot!(stdout, @"foo = 'repo1'");
insta::assert_snapshot!(stdout, @r#"
foo = 'repo1'
baz = 'config'
qux = 'list'
"#);

// set and unset should refer to the source config
// (there's no option to update scoped table right now.)
Expand All @@ -1113,24 +1148,50 @@ fn test_config_conditional() {
insta::assert_snapshot!(stderr, @"");
insta::assert_snapshot!(std::fs::read_to_string(&user_config_path).unwrap(), @r#"
foo = 'global'
baz = 'global'
qux = 'global'
bar = "new value"
[[--scope]]
--when.repositories = ['~/repo1']
foo = 'repo1'
[[--scope]]
--when.repositories = ['~/repo2']
foo = 'repo2'
[[--scope]]
--when.commands = ['config']
baz = 'config'
[[--scope]]
--when.commands = ['config get']
qux = 'get'
[[--scope]]
--when.commands = ['config list']
qux = 'list'
"#);
let (_stdout, stderr) = test_env.jj_cmd_ok(&repo1_path, &["config", "unset", "--user", "foo"]);
insta::assert_snapshot!(stderr, @"");
insta::assert_snapshot!(std::fs::read_to_string(&user_config_path).unwrap(), @r#"
baz = 'global'
qux = 'global'
bar = "new value"
[[--scope]]
--when.repositories = ['~/repo1']
foo = 'repo1'
[[--scope]]
--when.repositories = ['~/repo2']
foo = 'repo2'
[[--scope]]
--when.commands = ['config']
baz = 'config'
[[--scope]]
--when.commands = ['config get']
qux = 'get'
[[--scope]]
--when.commands = ['config list']
qux = 'list'
"#);
}

Expand Down
28 changes: 20 additions & 8 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -1371,6 +1371,9 @@ You can conditionally enable config variables by using `--when` and
`[[--scope]]` tables. Variables defined in `[[--scope]]` tables are expanded to
the root table. `--when` specifies the condition to enable the scope table.

If no conditions are specified, table is always enabled. If multiple conditions
are specified, the intersection is used.

```toml
[user]
name = "YOUR NAME"
Expand All @@ -1387,13 +1390,22 @@ Condition keys:

* `--when.repositories`: List of paths to match the repository path prefix.

Paths should be absolute. Each path component (directory or file name, drive
letter, etc.) is compared case-sensitively on all platforms. A path starting
with `~` is expanded to the home directory. On Windows, directory separator may
be either `\` or `/`. (Beware that `\` needs escape in double-quoted strings.)
Paths should be absolute. Each path component (directory or file name, drive
letter, etc.) is compared case-sensitively on all platforms. A path starting
with `~` is expanded to the home directory. On Windows, directory separator may
be either `\` or `/`. (Beware that `\` needs escape in double-quoted strings.)

Use `jj root` to see the workspace root directory. Note that the repository path
is in the main workspace if you're using multiple workspaces with `jj
workspace`.


* `--when.command`: List of subcommands to match.

Use `jj root` to see the workspace root directory. Note that the repository path
is in the main workspace if you're using multiple workspaces with `jj
workspace`.
Subcommands are space-separated and matched by prefix.

If no conditions are specified, table is always enabled.
```toml
--when.command = ["file"] # matches `jj file show`, `jj file list`, etc
--when.command = ["file show"] # matches `jj file show` but *NOT* `jj file list`
--when.command = ["file", "log"] # matches `jj file` *OR* `jj log` (or subcommand of either)
```

0 comments on commit dedbc47

Please sign in to comment.