Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 34 additions & 6 deletions src/commands/build/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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(),
Expand Down
33 changes: 32 additions & 1 deletion src/utils/vcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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<Option<String>> {
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also consider checking the upstream remote of the current branch? If so, would that take precedence over origin or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point. I checked back with our team. We should prefer upstream over origin for forked workflows. I'll update this in a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow up PR on this: #2737

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<u32> {
Expand Down