Skip to content

Commit b7dad6b

Browse files
feat(revset): Add exactly function
1 parent 4cef69c commit b7dad6b

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

git-branchless/src/revset/builtins.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ lazy_static! {
4848
("committer.name", &fn_committer_name),
4949
("committer.email", &fn_committer_email),
5050
("committer.date", &fn_committer_date),
51+
("exactly", &fn_exactly),
5152
];
5253
functions.iter().cloned().collect()
5354
};
@@ -377,3 +378,21 @@ fn fn_committer_date(ctx: &mut Context, name: &str, args: &[Expr]) -> EvalResult
377378
}),
378379
)
379380
}
381+
382+
fn fn_exactly(ctx: &mut Context, name: &str, args: &[Expr]) -> EvalResult {
383+
let (lhs, expected_len) = eval_number_rhs(ctx, name, args)?;
384+
let actual_len: usize = lhs
385+
.count()
386+
.wrap_err("Counting commit set")
387+
.map_err(EvalError::OtherError)?;
388+
389+
if actual_len == expected_len {
390+
Ok(lhs)
391+
} else {
392+
Err(EvalError::ExpectedLengthSet {
393+
expr: format!("{}", args[0]),
394+
expected_len,
395+
actual_len,
396+
})
397+
}
398+
}

git-branchless/src/revset/eval.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use once_cell::unsync::OnceCell;
1010
use thiserror::Error;
1111

1212
use lib::core::dag::{CommitSet, Dag};
13+
use lib::core::formatting::Pluralize;
1314
use lib::git::{Repo, ResolvedReferenceInfo};
1415
use tracing::instrument;
1516

@@ -107,6 +108,20 @@ pub enum EvalError {
107108
#[error("expected {expr} to evaluate to 1 element, but got {actual_len}")]
108109
ExpectedSingletonSet { expr: String, actual_len: usize },
109110

111+
#[error(
112+
"expected '{expr}' to evaluate to {}, but got {actual_len}",
113+
Pluralize {
114+
determiner: None,
115+
amount: *expected_len,
116+
unit: ("element", "elements"),
117+
}
118+
)]
119+
ExpectedLengthSet {
120+
expr: String,
121+
expected_len: usize,
122+
actual_len: usize,
123+
},
124+
110125
#[error("not an integer: {from}")]
111126
ParseInt {
112127
#[from]
@@ -708,6 +723,59 @@ mod tests {
708723
"###);
709724
}
710725

726+
{
727+
let expr = Expr::FunctionCall(
728+
Cow::Borrowed("exactly"),
729+
vec![
730+
Expr::FunctionCall(Cow::Borrowed("stack"), vec![]),
731+
Expr::Name(Cow::Borrowed("3")),
732+
],
733+
);
734+
insta::assert_debug_snapshot!(eval_and_sort(&effects, &repo, &mut dag, &expr), @r###"
735+
Ok(
736+
[
737+
Commit {
738+
inner: Commit {
739+
id: 848121cb21bf9af8b064c91bc8930bd16d624a22,
740+
summary: "create test5.txt",
741+
},
742+
},
743+
Commit {
744+
inner: Commit {
745+
id: f0abf649939928fe5475179fd84e738d3d3725dc,
746+
summary: "create test6.txt",
747+
},
748+
},
749+
Commit {
750+
inner: Commit {
751+
id: ba07500a4adc661dc06a748d200ef92120e1b355,
752+
summary: "create test7.txt",
753+
},
754+
},
755+
],
756+
)
757+
"###);
758+
}
759+
760+
{
761+
let expr = Expr::FunctionCall(
762+
Cow::Borrowed("exactly"),
763+
vec![
764+
Expr::FunctionCall(Cow::Borrowed("stack"), vec![]),
765+
Expr::Name(Cow::Borrowed("2")),
766+
],
767+
);
768+
insta::assert_debug_snapshot!(eval_and_sort(&effects, &repo, &mut dag, &expr), @r###"
769+
Err(
770+
ExpectedLengthSet {
771+
expr: "stack()",
772+
expected_len: 2,
773+
actual_len: 3,
774+
},
775+
)
776+
"###);
777+
}
778+
711779
Ok(())
712780
}
713781

git-branchless/tests/command/test_query.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ fn test_query_eval_error() -> eyre::Result<()> {
8484
},
8585
)?;
8686
insta::assert_snapshot!(stderr, @r###"
87-
Evaluation error for expression 'foo()': no function with the name 'foo' could be found; these functions are available: all, ancestors, ancestors.nth, author.date, author.email, author.name, branches, children, committer.date, committer.email, committer.name, descendants, difference, draft, heads, intersection, message, none, not, only, parents, parents.nth, paths.changed, range, roots, stack, union
87+
Evaluation error for expression 'foo()': no function with the name 'foo' could be found; these functions are available: all, ancestors, ancestors.nth, author.date, author.email, author.name, branches, children, committer.date, committer.email, committer.name, descendants, difference, draft, exactly, heads, intersection, message, none, not, only, parents, parents.nth, paths.changed, range, roots, stack, union
8888
"###);
8989
insta::assert_snapshot!(stdout, @"");
9090
}

0 commit comments

Comments
 (0)