diff --git a/src/commands/build/upload.rs b/src/commands/build/upload.rs index 1406b672b2..c47e948df2 100644 --- a/src/commands/build/upload.rs +++ b/src/commands/build/upload.rs @@ -25,7 +25,7 @@ use crate::utils::fs::TempFile; use crate::utils::progress::ProgressBar; use crate::utils::vcs::{ self, get_github_pr_number, get_provider_from_remote, get_repo_from_remote, git_repo_base_ref, - git_repo_head_ref, git_repo_remote_url, + git_repo_base_repo_name, git_repo_head_ref, git_repo_remote_url, }; pub fn make_command(command: Command) -> Command { @@ -116,7 +116,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { let cached_remote = config.get_cached_vcs_remote(); // Try to open the git repository and find the remote, but handle errors gracefully. - let (vcs_provider, head_repo_name, head_ref, base_ref) = { + let (vcs_provider, head_repo_name, head_ref, base_ref, base_repo_name) = { // Try to open the repo and get the remote URL, but don't fail if not in a repo. let repo = git2::Repository::open_from_env().ok(); let repo_ref = repo.as_ref(); @@ -191,10 +191,38 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { .map(Cow::Owned) }); - (vcs_provider, head_repo_name, head_ref, base_ref) - }; + let base_repo_name = matches + .get_one("base_repo_name") + .map(String::as_str) + .map(Cow::Borrowed) + .or_else(|| { + // Try to get the base repo name from the VCS if not provided + repo_ref + .and_then(|r| match git_repo_base_repo_name(r) { + Ok(Some(base_repo_name)) => { + debug!("Found base repository name: {}", base_repo_name); + Some(base_repo_name) + } + Ok(None) => { + debug!("No base repository found - not a fork"); + None + } + Err(e) => { + warn!("Could not detect base repository name: {}", e); + None + } + }) + .map(Cow::Owned) + }); - let base_repo_name = matches.get_one("base_repo_name").map(String::as_str); + ( + vcs_provider, + head_repo_name, + head_ref, + base_ref, + base_repo_name, + ) + }; let base_sha = matches.get_one("base_sha").map(String::as_str); let pr_number = matches .get_one("pr_number") @@ -261,7 +289,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { base_sha, vcs_provider: vcs_provider.as_deref(), head_repo_name: head_repo_name.as_deref(), - base_repo_name, + base_repo_name: base_repo_name.as_deref(), head_ref: head_ref.as_deref(), base_ref: base_ref.as_deref(), pr_number: pr_number.as_ref(), diff --git a/src/utils/vcs.rs b/src/utils/vcs.rs index 9fb1d1da89..6b52a0e87b 100644 --- a/src/utils/vcs.rs +++ b/src/utils/vcs.rs @@ -8,7 +8,7 @@ use chrono::{DateTime, FixedOffset, TimeZone as _}; use git2::{Commit, Repository, Time}; use if_chain::if_chain; use lazy_static::lazy_static; -use log::{debug, info}; +use log::{debug, info, warn}; use regex::Regex; use crate::api::{GitCommit, PatchSet, Ref, Repo}; @@ -283,6 +283,37 @@ fn find_merge_base_ref( Ok(merge_base_sha) } +/// Attempts to get the base repository name from git remotes. +/// Prefers "origin" remote if it exists, otherwise uses the first available remote. +/// Returns the base repository name if a remote is found. +pub fn git_repo_base_repo_name(repo: &git2::Repository) -> Result> { + let remotes = repo.remotes()?; + let remote_names: Vec<&str> = remotes.iter().flatten().collect(); + + if remote_names.is_empty() { + warn!("No remotes found in repository"); + return Ok(None); + } + + // Prefer "origin" remote if it exists, otherwise use the first one + let chosen_remote = if remote_names.contains(&"origin") { + "origin" + } else { + remote_names[0] + }; + + match git_repo_remote_url(repo, chosen_remote) { + Ok(remote_url) => { + debug!("Found remote '{}': {}", chosen_remote, remote_url); + Ok(Some(get_repo_from_remote(&remote_url))) + } + Err(e) => { + warn!("Could not get URL for remote '{}': {}", chosen_remote, e); + Ok(None) + } + } +} + /// Attempts to get the PR number from GitHub Actions environment variables. /// Returns the PR number if running in a GitHub Actions pull request environment. pub fn get_github_pr_number() -> Option {