about summary refs log tree commit diff
diff options
context:
space:
mode:
authoronur-ozkan <work@onurozkan.dev>2024-09-09 20:18:06 +0300
committeronur-ozkan <work@onurozkan.dev>2024-09-09 20:18:06 +0300
commitdc9c5f251c06c2c0193aff779a5074cff3d233ee (patch)
treece508ecfb828a1db1a3950bbb72e0adf5fbc6182
parent05043a370a77f8647b5fa609488dbdfebb71d1a4 (diff)
downloadrust-dc9c5f251c06c2c0193aff779a5074cff3d233ee.tar.gz
rust-dc9c5f251c06c2c0193aff779a5074cff3d233ee.zip
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 <work@onurozkan.dev>
-rw-r--r--src/tools/build_helper/src/git.rs40
1 files changed, 34 insertions, 6 deletions
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs
index 98e5b7a328e..7da3c9de60c 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<String, String> {
+fn get_git_merge_base(config: &GitConfig<'_>, git_dir: Option<&Path>) -> Result<String, String> {
     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<String, String> {
+    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<Option<Vec<String>>, 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 {