From dc9c5f251c06c2c0193aff779a5074cff3d233ee Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 9 Sep 2024 20:18:06 +0300 Subject: [PATCH] implement `build_helper::git::get_closest_merge_commit` Compare to `get_git_merge_base`, this doesn't require configuring the upstream remote. Signed-off-by: onur-ozkan --- src/tools/build_helper/src/git.rs | 40 ++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs index 98e5b7a328eb9..7da3c9de60c45 100644 --- a/src/tools/build_helper/src/git.rs +++ b/src/tools/build_helper/src/git.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; pub struct GitConfig<'a> { @@ -96,10 +96,7 @@ pub fn updated_master_branch( Err("Cannot find any suitable upstream master branch".to_owned()) } -pub fn get_git_merge_base( - config: &GitConfig<'_>, - git_dir: Option<&Path>, -) -> Result { +fn get_git_merge_base(config: &GitConfig<'_>, git_dir: Option<&Path>) -> Result { let updated_master = updated_master_branch(config, git_dir)?; let mut git = Command::new("git"); if let Some(git_dir) = git_dir { @@ -108,6 +105,37 @@ pub fn get_git_merge_base( Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned()) } +/// Resolves the closest merge commit by the given `author` and `target_paths`. +/// +/// If it fails to find the commit from upstream using `git merge-base`, fallbacks to HEAD. +pub fn get_closest_merge_commit( + git_dir: Option<&Path>, + config: &GitConfig<'_>, + target_paths: &[PathBuf], +) -> Result { + let mut git = Command::new("git"); + + if let Some(git_dir) = git_dir { + git.current_dir(git_dir); + } + + let merge_base = get_git_merge_base(config, git_dir).unwrap_or_else(|_| "HEAD".into()); + + git.args([ + "rev-list", + &format!("--author={}", config.git_merge_commit_email), + "-n1", + "--first-parent", + &merge_base, + ]); + + if !target_paths.is_empty() { + git.arg("--").args(target_paths); + } + + Ok(output_result(&mut git)?.trim().to_owned()) +} + /// Returns the files that have been modified in the current branch compared to the master branch. /// The `extensions` parameter can be used to filter the files by their extension. /// Does not include removed files. @@ -117,7 +145,7 @@ pub fn get_git_modified_files( git_dir: Option<&Path>, extensions: &[&str], ) -> Result>, String> { - let merge_base = get_git_merge_base(config, git_dir)?; + let merge_base = get_closest_merge_commit(git_dir, config, &[])?; let mut git = Command::new("git"); if let Some(git_dir) = git_dir {