forked from mirrors/jj
cli: add kind:pattern syntax to branch delete/forget commands
The parse rule is lax compared to revset. We could require the pattern to be quoted, but that would mean glob patterns have to be quoted like 'glob:"foo*"'.
This commit is contained in:
parent
65c033e5d5
commit
c3f167e6cc
4 changed files with 57 additions and 34 deletions
|
@ -56,6 +56,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
* `branches()`/`remote_branches()`/`author()`/`committer()`/`description()`
|
||||
revsets now support glob matching.
|
||||
|
||||
* `jj branch delete`/`forget` now support [string pattern
|
||||
syntax](docs/revsets.md#string-patterns).
|
||||
|
||||
### Fixed bugs
|
||||
|
||||
* Updating the working copy to a commit where a file that's currently ignored
|
||||
|
|
|
@ -10,7 +10,7 @@ use jj_lib::git;
|
|||
use jj_lib::op_store::RefTarget;
|
||||
use jj_lib::repo::Repo;
|
||||
use jj_lib::revset::{self, RevsetExpression};
|
||||
use jj_lib::str_util::StringPattern;
|
||||
use jj_lib::str_util::{StringPattern, StringPatternParseError};
|
||||
use jj_lib::view::View;
|
||||
|
||||
use crate::cli_util::{user_error, user_error_with_hint, CommandError, CommandHelper, RevisionArg};
|
||||
|
@ -54,9 +54,13 @@ pub struct BranchCreateArgs {
|
|||
/// next push.
|
||||
#[derive(clap::Args, Clone, Debug)]
|
||||
pub struct BranchDeleteArgs {
|
||||
/// The branches to delete.
|
||||
#[arg(required_unless_present_any(& ["glob"]))]
|
||||
names: Vec<String>,
|
||||
/// The branches to delete
|
||||
///
|
||||
/// By default, the specified name matches exactly. Use `glob:` prefix to
|
||||
/// select branches by wildcard pattern. For details, see
|
||||
/// https://github.com/martinvonz/jj/blob/main/docs/revsets.md#string-patterns.
|
||||
#[arg(required_unless_present_any(&["glob"]), value_parser = parse_name_pattern)]
|
||||
pub names: Vec<StringPattern>,
|
||||
|
||||
/// A glob pattern indicating branches to delete.
|
||||
#[arg(long, value_parser = StringPattern::glob)]
|
||||
|
@ -95,9 +99,13 @@ pub struct BranchListArgs {
|
|||
/// recreated on future pulls if it still exists in the remote.
|
||||
#[derive(clap::Args, Clone, Debug)]
|
||||
pub struct BranchForgetArgs {
|
||||
/// The branches to forget.
|
||||
#[arg(required_unless_present_any(& ["glob"]))]
|
||||
pub names: Vec<String>,
|
||||
/// The branches to forget
|
||||
///
|
||||
/// By default, the specified name matches exactly. Use `glob:` prefix to
|
||||
/// select branches by wildcard pattern. For details, see
|
||||
/// https://github.com/martinvonz/jj/blob/main/docs/revsets.md#string-patterns.
|
||||
#[arg(required_unless_present_any(&["glob"]), value_parser = parse_name_pattern)]
|
||||
pub names: Vec<StringPattern>,
|
||||
|
||||
/// A glob pattern indicating branches to forget.
|
||||
#[arg(long, value_parser = StringPattern::glob)]
|
||||
|
@ -276,6 +284,14 @@ fn cmd_branch_set(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_name_pattern(src: &str) -> Result<StringPattern, StringPatternParseError> {
|
||||
if let Some((kind, pat)) = src.split_once(':') {
|
||||
StringPattern::from_str_kind(pat, kind)
|
||||
} else {
|
||||
Ok(StringPattern::exact(src))
|
||||
}
|
||||
}
|
||||
|
||||
fn find_local_branches(
|
||||
view: &View,
|
||||
name_patterns: &[StringPattern],
|
||||
|
@ -331,11 +347,7 @@ fn cmd_branch_delete(
|
|||
) -> Result<(), CommandError> {
|
||||
let mut workspace_command = command.workspace_helper(ui)?;
|
||||
let view = workspace_command.repo().view();
|
||||
let name_patterns = itertools::chain(
|
||||
args.names.iter().map(StringPattern::exact),
|
||||
args.glob.iter().cloned(),
|
||||
)
|
||||
.collect_vec();
|
||||
let name_patterns = [&args.names[..], &args.glob[..]].concat();
|
||||
let names = find_local_branches(view, &name_patterns)?;
|
||||
let mut tx =
|
||||
workspace_command.start_transaction(&format!("delete {}", make_branch_term(&names)));
|
||||
|
@ -357,11 +369,7 @@ fn cmd_branch_forget(
|
|||
) -> Result<(), CommandError> {
|
||||
let mut workspace_command = command.workspace_helper(ui)?;
|
||||
let view = workspace_command.repo().view();
|
||||
let name_patterns = itertools::chain(
|
||||
args.names.iter().map(StringPattern::exact),
|
||||
args.glob.iter().cloned(),
|
||||
)
|
||||
.collect_vec();
|
||||
let name_patterns = [&args.names[..], &args.glob[..]].concat();
|
||||
let names = find_forgettable_branches(view, &name_patterns)?;
|
||||
let mut tx =
|
||||
workspace_command.start_transaction(&format!("forget {}", make_branch_term(&names)));
|
||||
|
|
|
@ -313,6 +313,8 @@ fn cmd_git_fetch(
|
|||
"fetch from git remote(s) {}",
|
||||
remotes.iter().join(",")
|
||||
));
|
||||
// TODO: maybe this should error out if the pattern contained meta
|
||||
// characters and is not prefixed with "glob:".
|
||||
let branches = args.branch.iter().map(|b| b.as_str()).collect_vec();
|
||||
for remote in remotes {
|
||||
let stats = with_remote_callbacks(ui, |cb| {
|
||||
|
|
|
@ -101,6 +101,12 @@ fn test_branch_forget_glob() {
|
|||
insta::assert_snapshot!(stderr, @r###"
|
||||
Forgot 2 branches.
|
||||
"###);
|
||||
test_env.jj_cmd_ok(&repo_path, &["undo"]);
|
||||
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["branch", "forget", "glob:foo-[1-3]"]);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Forgot 2 branches.
|
||||
"###);
|
||||
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
||||
@ bar-2 foo-4 230dd059e1b0
|
||||
◉ 000000000000
|
||||
|
@ -110,9 +116,7 @@ fn test_branch_forget_glob() {
|
|||
// multiple glob patterns, shouldn't produce an error.
|
||||
let (stdout, stderr) = test_env.jj_cmd_ok(
|
||||
&repo_path,
|
||||
&[
|
||||
"branch", "forget", "foo-4", "--glob", "foo-*", "--glob", "foo-*",
|
||||
],
|
||||
&["branch", "forget", "foo-4", "--glob", "foo-*", "glob:foo-*"],
|
||||
);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
insta::assert_snapshot!(stderr, @"");
|
||||
|
@ -122,9 +126,9 @@ fn test_branch_forget_glob() {
|
|||
"###);
|
||||
|
||||
// Malformed glob
|
||||
let stderr = test_env.jj_cmd_cli_error(&repo_path, &["branch", "forget", "--glob", "foo-[1-3"]);
|
||||
let stderr = test_env.jj_cmd_cli_error(&repo_path, &["branch", "forget", "glob:foo-[1-3"]);
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
error: invalid value 'foo-[1-3' for '--glob <GLOB>': Pattern syntax error near position 4: invalid range pattern
|
||||
error: invalid value 'glob:foo-[1-3' for '[NAMES]...': Pattern syntax error near position 4: invalid range pattern
|
||||
|
||||
For more information, try '--help'.
|
||||
"###);
|
||||
|
@ -132,13 +136,7 @@ fn test_branch_forget_glob() {
|
|||
// We get an error if none of the globs match anything
|
||||
let stderr = test_env.jj_cmd_failure(
|
||||
&repo_path,
|
||||
&[
|
||||
"branch",
|
||||
"forget",
|
||||
"--glob=bar*",
|
||||
"--glob=baz*",
|
||||
"--glob=boom*",
|
||||
],
|
||||
&["branch", "forget", "glob:bar*", "glob:baz*", "--glob=boom*"],
|
||||
);
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Error: No matching branches for patterns: baz*, boom*
|
||||
|
@ -181,6 +179,12 @@ fn test_branch_delete_glob() {
|
|||
insta::assert_snapshot!(stderr, @r###"
|
||||
Deleted 2 branches.
|
||||
"###);
|
||||
test_env.jj_cmd_ok(&repo_path, &["undo"]);
|
||||
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["branch", "delete", "glob:foo-[1-3]"]);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Deleted 2 branches.
|
||||
"###);
|
||||
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
|
||||
@ bar-2 foo-1@origin foo-3@origin foo-4 6fbf398c2d59
|
||||
◉ 000000000000
|
||||
|
@ -197,9 +201,7 @@ fn test_branch_delete_glob() {
|
|||
// multiple glob patterns, shouldn't produce an error.
|
||||
let (stdout, stderr) = test_env.jj_cmd_ok(
|
||||
&repo_path,
|
||||
&[
|
||||
"branch", "delete", "foo-4", "--glob", "foo-*", "--glob", "foo-*",
|
||||
],
|
||||
&["branch", "delete", "foo-4", "--glob", "foo-*", "glob:foo-*"],
|
||||
);
|
||||
insta::assert_snapshot!(stdout, @"");
|
||||
insta::assert_snapshot!(stderr, @"");
|
||||
|
@ -227,9 +229,17 @@ fn test_branch_delete_glob() {
|
|||
"###);
|
||||
|
||||
// Malformed glob
|
||||
let stderr = test_env.jj_cmd_cli_error(&repo_path, &["branch", "delete", "--glob", "foo-[1-3"]);
|
||||
let stderr = test_env.jj_cmd_cli_error(&repo_path, &["branch", "delete", "glob:foo-[1-3"]);
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
error: invalid value 'foo-[1-3' for '--glob <GLOB>': Pattern syntax error near position 4: invalid range pattern
|
||||
error: invalid value 'glob:foo-[1-3' for '[NAMES]...': Pattern syntax error near position 4: invalid range pattern
|
||||
|
||||
For more information, try '--help'.
|
||||
"###);
|
||||
|
||||
// Unknown pattern kind
|
||||
let stderr = test_env.jj_cmd_cli_error(&repo_path, &["branch", "forget", "whatever:branch"]);
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
error: invalid value 'whatever:branch' for '[NAMES]...': Invalid string pattern kind "whatever"
|
||||
|
||||
For more information, try '--help'.
|
||||
"###);
|
||||
|
|
Loading…
Reference in a new issue