Skip to content

Commit 1a0e73b

Browse files
committed
feat(build): Auto-detect base_ref from git merge-base
Add automatic detection of base reference for build uploads by finding the merge-base between current HEAD and remote tracking branch. This works by: - Finding the remote tracking branch (origin/HEAD, main, master, develop) - Calculating git merge-base between HEAD and remote branch - Returning the branch name pointing to merge-base or commit SHA This mirrors the existing head_ref auto-detection behavior.
1 parent 87be223 commit 1a0e73b

File tree

4 files changed

+78
-8
lines changed

4 files changed

+78
-8
lines changed

src/commands/build/upload.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ use crate::utils::fs::TempDir;
2424
use crate::utils::fs::TempFile;
2525
use crate::utils::progress::ProgressBar;
2626
use crate::utils::vcs::{
27-
self, get_provider_from_remote, get_repo_from_remote, git_repo_head_ref, git_repo_remote_url,
27+
self, get_provider_from_remote, get_repo_from_remote, git_repo_base_ref, git_repo_head_ref,
28+
git_repo_remote_url,
2829
};
2930

3031
pub fn make_command(command: Command) -> Command {
@@ -79,7 +80,7 @@ pub fn make_command(command: Command) -> Command {
7980
.arg(
8081
Arg::new("base_ref")
8182
.long("base-ref")
82-
.help("The reference (branch) to use for the upload. If not provided, the current reference will be used.")
83+
.help("The base reference (branch) to use for the upload. If not provided, the merge-base with the remote tracking branch will be used.")
8384
)
8485
.arg(
8586
Arg::new("pr_number")
@@ -172,7 +173,28 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
172173

173174
let base_repo_name = matches.get_one("base_repo_name").map(String::as_str);
174175
let base_sha = matches.get_one("base_sha").map(String::as_str);
175-
let base_ref = matches.get_one("base_ref").map(String::as_str);
176+
let base_ref = matches
177+
.get_one("base_ref")
178+
.map(String::as_str)
179+
.map(Cow::Borrowed)
180+
.or_else(|| {
181+
// Try to get the base ref from the VCS if not provided
182+
// This attempts to find the merge-base with the remote tracking branch
183+
if let Ok(repo) = git2::Repository::open_from_env() {
184+
match git_repo_base_ref(&repo, &cached_remote) {
185+
Ok(base_ref_name) => {
186+
debug!("Found base branch reference: {}", base_ref_name);
187+
Some(Cow::Owned(base_ref_name))
188+
}
189+
Err(e) => {
190+
debug!("No base branch reference found: {}", e);
191+
None
192+
}
193+
}
194+
} else {
195+
None
196+
}
197+
});
176198
let pr_number = matches.get_one::<u32>("pr_number");
177199

178200
let build_configuration = matches.get_one("build_configuration").map(String::as_str);
@@ -237,7 +259,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
237259
head_repo_name: head_repo_name.as_deref(),
238260
base_repo_name,
239261
head_ref: head_ref.as_deref(),
240-
base_ref,
262+
base_ref: base_ref.as_deref(),
241263
pr_number,
242264
};
243265
match upload_file(

src/utils/vcs.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,54 @@ pub fn git_repo_head_ref(repo: &git2::Repository) -> Result<String> {
249249
}
250250
}
251251

252+
pub fn git_repo_base_ref(repo: &git2::Repository, remote_name: &str) -> Result<String> {
253+
// Get the current HEAD commit
254+
let head_commit = repo.head()?.peel_to_commit()?;
255+
256+
// Try to find the remote tracking branch
257+
let remote_branch_name = format!("refs/remotes/{remote_name}/HEAD");
258+
let remote_ref = match repo.find_reference(&remote_branch_name) {
259+
Ok(r) => r,
260+
Err(_) => {
261+
// If remote/HEAD doesn't exist, try to find the default branch
262+
// First try common default branch names
263+
for branch in &["main", "master", "develop"] {
264+
let remote_branch = format!("refs/remotes/{remote_name}/{branch}");
265+
if let Ok(r) = repo.find_reference(&remote_branch) {
266+
return find_merge_base_ref(repo, &head_commit, &r);
267+
}
268+
}
269+
bail!("Could not find remote tracking branch for {}", remote_name);
270+
}
271+
};
272+
273+
find_merge_base_ref(repo, &head_commit, &remote_ref)
274+
}
275+
276+
fn find_merge_base_ref(
277+
repo: &git2::Repository,
278+
head_commit: &git2::Commit,
279+
remote_ref: &git2::Reference,
280+
) -> Result<String> {
281+
let remote_commit = remote_ref.peel_to_commit()?;
282+
let merge_base_oid = repo.merge_base(head_commit.id(), remote_commit.id())?;
283+
284+
// Try to find a branch name that points to this commit
285+
let branches = repo.branches(Some(git2::BranchType::Local))?;
286+
for (branch, _) in branches.flatten() {
287+
if let Ok(branch_commit) = branch.get().peel_to_commit() {
288+
if branch_commit.id() == merge_base_oid {
289+
if let Some(branch_name) = branch.name()? {
290+
return Ok(branch_name.to_owned());
291+
}
292+
}
293+
}
294+
}
295+
296+
// If no branch name found, return the commit SHA
297+
Ok(merge_base_oid.to_string())
298+
}
299+
252300
fn find_reference_url(repo: &str, repos: &[Repo]) -> Result<Option<String>> {
253301
let mut non_git = false;
254302
for configured_repo in repos {

tests/integration/_cases/build/build-upload-help-macos.trycmd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ Options:
4242
The reference (branch) to use for the upload. If not provided, the current reference will
4343
be used.
4444
--base-ref <base_ref>
45-
The reference (branch) to use for the upload. If not provided, the current reference will
46-
be used.
45+
The base reference (branch) to use for the upload. If not provided, the merge-base with
46+
the remote tracking branch will be used.
4747
--pr-number <pr_number>
4848
The pull request number to use for the upload. If not provided, the current pull request
4949
number will be used.

tests/integration/_cases/build/build-upload-help-not-macos.trycmd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ Options:
4141
The reference (branch) to use for the upload. If not provided, the current reference will
4242
be used.
4343
--base-ref <base_ref>
44-
The reference (branch) to use for the upload. If not provided, the current reference will
45-
be used.
44+
The base reference (branch) to use for the upload. If not provided, the merge-base with
45+
the remote tracking branch will be used.
4646
--pr-number <pr_number>
4747
The pull request number to use for the upload. If not provided, the current pull request
4848
number will be used.

0 commit comments

Comments
 (0)