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 23, 2025
1 parent 40840a2 commit 6e9ec50
Show file tree
Hide file tree
Showing 5 changed files with 115 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
19 changes: 19 additions & 0 deletions cli/src/cli_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3701,6 +3701,25 @@ impl CliRunner {
process_global_args_fn(ui, &matches)?;
}

config_env.set_command(
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(&raw_config)?;
migrate_config(&mut config)?;
ui.reset(&config)?;
Some(subcommand_combined)
} else {
Some(String::from(""))
},
);
config = config_env.resolve_config(&raw_config)?;
migrate_config(&mut config)?;

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 Down
9 changes: 8 additions & 1 deletion cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ pub struct ConfigEnv {
repo_path: Option<PathBuf>,
user_config_path: ConfigPath,
repo_config_path: ConfigPath,
command: Option<String>,
}

impl ConfigEnv {
Expand All @@ -281,9 +282,14 @@ impl ConfigEnv {
repo_path: None,
user_config_path: env.resolve()?,
repo_config_path: ConfigPath::Unavailable,
command: None,
})
}

pub fn set_command(&mut self, command: Option<String>) {
self.command = command;
}

/// Returns a path to the user-specific config file or directory.
pub fn user_config_path(&self) -> Option<&Path> {
self.user_config_path.as_path()
Expand Down Expand Up @@ -398,7 +404,7 @@ impl ConfigEnv {
let context = ConfigResolutionContext {
home_dir: self.home_dir.as_deref(),
repo_path: self.repo_path.as_deref(),
command: None,
command: self.command.as_deref(),
};
jj_lib::config::resolve(config.as_ref(), &context)
}
Expand Down Expand Up @@ -1370,6 +1376,7 @@ mod tests {
repo_path: None,
user_config_path: env.resolve()?,
repo_config_path: ConfigPath::Unavailable,
command: None,
})
}

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 6e9ec50

Please sign in to comment.