Skip to content

Commit e0ee4aa

Browse files
feat(revset): Support custom revset aliases
Alias can be defined via git config, either globally or per repo. For example: ``` $ git config --global \ git-branchless.revsets.alias.oldest \ 'sole(roots(intersection(ancestors($1), descendants($1))))' $ git query 'oldest(message(fixup))' ... $ git config \ git-branchless.revsets.alias.grandChildren \ 'children(children($1))' $ git query 'grandChildren(abc123)' ... ```
1 parent 4cef69c commit e0ee4aa

File tree

1 file changed

+104
-9
lines changed

1 file changed

+104
-9
lines changed

git-branchless/src/revset/eval.rs

Lines changed: 104 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,18 @@ use std::sync::Arc;
44

55
use eden_dag::errors::BackendError;
66
use eden_dag::DagAlgorithm;
7+
use eyre::Context as EyreContext;
78
use itertools::Itertools;
89
use lib::core::effects::{Effects, OperationType};
910
use once_cell::unsync::OnceCell;
1011
use thiserror::Error;
1112

1213
use lib::core::dag::{CommitSet, Dag};
13-
use lib::git::{Repo, ResolvedReferenceInfo};
14+
use lib::git::{ConfigRead, Repo, ResolvedReferenceInfo};
1415
use tracing::instrument;
1516

1617
use super::builtins::FUNCTIONS;
18+
use super::parser::parse;
1719
use super::pattern::{Pattern, PatternError};
1820
use super::Expr;
1921

@@ -204,14 +206,33 @@ pub(super) fn eval_name(ctx: &mut Context, name: &str) -> EvalResult {
204206
}
205207

206208
pub(super) fn eval_fn(ctx: &mut Context, name: &str, args: &[Expr]) -> EvalResult {
207-
let function = FUNCTIONS
208-
.get(name)
209-
.ok_or_else(|| EvalError::UnboundFunction {
210-
name: name.to_owned(),
211-
available_names: FUNCTIONS.keys().sorted().copied().collect(),
212-
})?;
213-
214-
function(ctx, name, args)
209+
if let Some(function) = FUNCTIONS.get(name) {
210+
return function(ctx, name, args);
211+
}
212+
213+
let alias_key = format!("git-branchless.revsets.alias.{}", name);
214+
let alias_template = ctx
215+
.repo
216+
.get_readonly_config()
217+
.map_err(EvalError::OtherError)?
218+
.get::<String, String>(alias_key)
219+
.map_err(EvalError::OtherError)?;
220+
if let Some(mut alias_template) = alias_template {
221+
for (i, arg) in args.iter().enumerate() {
222+
alias_template =
223+
alias_template.replace(format!("${}", i + 1).as_str(), format!("{}", arg).as_str());
224+
}
225+
let expr = parse(&alias_template)
226+
.wrap_err("Parsing alias expression")
227+
.map_err(EvalError::OtherError)?;
228+
let commits = eval_inner(ctx, &expr);
229+
return commits;
230+
}
231+
232+
Err(EvalError::UnboundFunction {
233+
name: name.to_owned(),
234+
available_names: FUNCTIONS.keys().sorted().copied().collect(),
235+
})
215236
}
216237

217238
#[instrument]
@@ -935,4 +956,78 @@ mod tests {
935956

936957
Ok(())
937958
}
959+
960+
#[test]
961+
fn test_eval_aliases() -> eyre::Result<()> {
962+
let git = make_git()?;
963+
git.init_repo()?;
964+
965+
git.detach_head()?;
966+
let test1_oid = git.commit_file("test1", 1)?;
967+
let _test2_oid = git.commit_file("test2", 2)?;
968+
let _test3_oid = git.commit_file("test3", 3)?;
969+
970+
git.run(&["config", "git-branchless.revsets.alias.oldest", "roots($1)"])?;
971+
972+
git.run(&[
973+
"config",
974+
"git-branchless.revsets.alias.grandChildren",
975+
"children(children($1))",
976+
])?;
977+
978+
let effects = Effects::new_suppress_for_test(Glyphs::text());
979+
let repo = git.get_repo()?;
980+
let conn = repo.get_db_conn()?;
981+
let event_log_db = EventLogDb::new(&conn)?;
982+
let event_replayer = EventReplayer::from_event_log_db(&effects, &repo, &event_log_db)?;
983+
let event_cursor = event_replayer.make_default_cursor();
984+
let references_snapshot = repo.get_references_snapshot()?;
985+
let mut dag = Dag::open_and_sync(
986+
&effects,
987+
&repo,
988+
&event_replayer,
989+
event_cursor,
990+
&references_snapshot,
991+
)?;
992+
993+
{
994+
let expr = Expr::FunctionCall(
995+
Cow::Borrowed("oldest"),
996+
vec![Expr::FunctionCall(Cow::Borrowed("stack"), vec![])],
997+
);
998+
insta::assert_debug_snapshot!(eval_and_sort(&effects, &repo, &mut dag, &expr), @r###"
999+
Ok(
1000+
[
1001+
Commit {
1002+
inner: Commit {
1003+
id: 62fc20d2a290daea0d52bdc2ed2ad4be6491010e,
1004+
summary: "create test1.txt",
1005+
},
1006+
},
1007+
],
1008+
)
1009+
"###);
1010+
}
1011+
1012+
{
1013+
let expr = Expr::FunctionCall(
1014+
Cow::Borrowed("grandChildren"),
1015+
vec![Expr::Name(Cow::Owned(test1_oid.to_string()))],
1016+
);
1017+
insta::assert_debug_snapshot!(eval_and_sort(&effects, &repo, &mut dag, &expr), @r###"
1018+
Ok(
1019+
[
1020+
Commit {
1021+
inner: Commit {
1022+
id: 70deb1e28791d8e7dd5a1f0c871a51b91282562f,
1023+
summary: "create test3.txt",
1024+
},
1025+
},
1026+
],
1027+
)
1028+
"###);
1029+
}
1030+
1031+
Ok(())
1032+
}
9381033
}

0 commit comments

Comments
 (0)