From e77d2e4552b0d1999bb4a69b6ddf0c852ca80993 Mon Sep 17 00:00:00 2001 From: Clayton Carter Date: Tue, 7 Nov 2023 21:16:06 -0400 Subject: [PATCH] feat(revset): add merges() revset This returns merge commits in the given set, or all merge commits. --- git-branchless-revset/src/builtins.rs | 32 ++++++++++ git-branchless-revset/src/eval.rs | 86 +++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/git-branchless-revset/src/builtins.rs b/git-branchless-revset/src/builtins.rs index c81dcf96a..48b20ab4a 100644 --- a/git-branchless-revset/src/builtins.rs +++ b/git-branchless-revset/src/builtins.rs @@ -61,6 +61,7 @@ lazy_static! { ("committer.date", &fn_committer_date), ("exactly", &fn_exactly), ("current", &fn_current), + ("merges", &fn_merges), ("tests.passed", &fn_tests_passed), ("tests.failed", &fn_tests_failed), ("tests.fixable", &fn_tests_fixable), @@ -513,6 +514,37 @@ fn fn_current(ctx: &mut Context, name: &str, args: &[Expr]) -> EvalResult { Ok(result.into_iter().collect::()) } +#[instrument] +fn fn_merges(ctx: &mut Context, name: &str, args: &[Expr]) -> EvalResult { + let arg = eval0_or_1(ctx, name, args)?; + let arg = match arg { + Some(arg) => arg, + None => { + let visible_heads = ctx + .dag + .query_visible_heads() + .map_err(EvalError::OtherError)?; + let visible_commits = ctx.dag.query_ancestors(visible_heads.clone())?; + ctx.dag + .filter_visible_commits(visible_commits) + .map_err(EvalError::OtherError)? + } + }; + + let commit_oids = ctx + .dag + .commit_set_to_vec(&arg) + .map_err(EvalError::OtherError)?; + let mut result = Vec::new(); + for commit_oid in commit_oids { + if ctx.dag.query_parent_names(commit_oid)?.len() > 1 { + result.push(commit_oid) + } + } + + Ok(result.into_iter().collect::()) +} + fn read_all_test_results(repo: &Repo, commit: &Commit) -> Option> { let commit_test_dir = get_test_tree_dir(repo, commit).ok()?; let mut all_results = Vec::new(); diff --git a/git-branchless-revset/src/eval.rs b/git-branchless-revset/src/eval.rs index a81689286..68ccacb1d 100644 --- a/git-branchless-revset/src/eval.rs +++ b/git-branchless-revset/src/eval.rs @@ -1188,6 +1188,92 @@ mod tests { Ok(()) } + #[test] + fn test_eval_merges() -> eyre::Result<()> { + let git = make_git()?; + git.init_repo()?; + + git.detach_head()?; + let test1_oid = git.commit_file("test1", 1)?; + let test2_oid = git.commit_file("test2", 2)?; + git.run(&["checkout", "HEAD~2"])?; + git.run(&["merge", "--no-ff", &test1_oid.to_string()])?; + git.run(&["merge", "--no-ff", &test2_oid.to_string()])?; + + let effects = Effects::new_suppress_for_test(Glyphs::text()); + let repo = git.get_repo()?; + let conn = repo.get_db_conn()?; + let event_log_db = EventLogDb::new(&conn)?; + let event_replayer = EventReplayer::from_event_log_db(&effects, &repo, &event_log_db)?; + let event_cursor = event_replayer.make_default_cursor(); + let references_snapshot = repo.get_references_snapshot()?; + let mut dag = Dag::open_and_sync( + &effects, + &repo, + &event_replayer, + event_cursor, + &references_snapshot, + )?; + + { + let expr = Expr::FunctionCall( + Cow::Borrowed("merges"), + vec![] + ); + insta::assert_debug_snapshot!(eval_and_sort(&effects, &repo, &mut dag, &expr), @r###" + Ok( + [ + Commit { + inner: Commit { + id: f486a8b756cd3a928241576aa87827284f3e14d1, + summary: "Merge commit '62fc20d2a290daea0d52bdc2ed2ad4be6491010e' into HEAD", + }, + }, + Commit { + inner: Commit { + id: 0b75bdca271fdc188e68bca6e054013bbc2a373c, + summary: "Merge commit '96d1c37a3d4363611c49f7e52186e189a04c531f' into HEAD", + }, + }, + ], + ) + "###); + + let expr = Expr::FunctionCall( + Cow::Borrowed("not"), + vec![Expr::FunctionCall( + Cow::Borrowed("merges"), + vec![] + )], + ); + insta::assert_debug_snapshot!(eval_and_sort(&effects, &repo, &mut dag, &expr), @r###" + Ok( + [ + Commit { + inner: Commit { + id: f777ecc9b0db5ed372b2615695191a8a17f79f24, + summary: "create initial.txt", + }, + }, + Commit { + inner: Commit { + id: 62fc20d2a290daea0d52bdc2ed2ad4be6491010e, + summary: "create test1.txt", + }, + }, + Commit { + inner: Commit { + id: 96d1c37a3d4363611c49f7e52186e189a04c531f, + summary: "create test2.txt", + }, + }, + ], + ) + "###); + } + Ok(()) + } + #[test] fn test_eval_aliases() -> eyre::Result<()> { let git = make_git()?;