diff options
Diffstat (limited to 'src/tools/build_helper/src/git.rs')
| -rw-r--r-- | src/tools/build_helper/src/git.rs | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs index cc48a8964a3..15d863caf0c 100644 --- a/src/tools/build_helper/src/git.rs +++ b/src/tools/build_helper/src/git.rs @@ -1,9 +1,10 @@ -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; pub struct GitConfig<'a> { pub git_repository: &'a str, pub nightly_branch: &'a str, + pub git_merge_commit_email: &'a str, } /// Runs a command and returns the output @@ -95,7 +96,11 @@ pub fn updated_master_branch( Err("Cannot find any suitable upstream master branch".to_owned()) } -pub fn get_git_merge_base( +/// Finds the nearest merge commit by comparing the local `HEAD` with the upstream branch's state. +/// To work correctly, the upstream remote must be properly configured using `git remote add <name> <url>`. +/// In most cases `get_closest_merge_commit` is the function you are looking for as it doesn't require remote +/// to be configured. +fn git_upstream_merge_base( config: &GitConfig<'_>, git_dir: Option<&Path>, ) -> Result<String, String> { @@ -107,6 +112,38 @@ pub fn get_git_merge_base( Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned()) } +/// Searches for the nearest merge commit in the repository that also exists upstream. +/// +/// If it fails to find the upstream remote, it then looks for the most recent commit made +/// by the merge bot by matching the author's email address with the merge bot's email. +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 = git_upstream_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. @@ -116,7 +153,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 { |
