Skip to content

Commit 3c48dab

Browse files
runningcodeclaude
andauthored
feat(build): Add auto-detection of base_repo_name from git remote (#2735)
## Summary Implements EME-232 to automatically detect `base_repo_name` for build uploads when not explicitly provided by the user. ## Changes - **Added `git_repo_base_repo_name()` function** in `src/utils/vcs.rs` that: - Fetches the first available git remote from the repository - Extracts the repository name using existing `get_repo_from_remote()` function 🤖 Generated with [Claude Code](https://claude.ai/code) Closes https://linear.app/getsentry/issue/EME-232/sentry-cli-provide-default-value-for-base-repo-name-if-user-doesnt --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent e7574b3 commit 3c48dab

File tree

2 files changed

+66
-7
lines changed

2 files changed

+66
-7
lines changed

src/commands/build/upload.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::utils::fs::TempFile;
2525
use crate::utils::progress::ProgressBar;
2626
use crate::utils::vcs::{
2727
self, get_github_pr_number, get_provider_from_remote, get_repo_from_remote, git_repo_base_ref,
28-
git_repo_head_ref, git_repo_remote_url,
28+
git_repo_base_repo_name, git_repo_head_ref, git_repo_remote_url,
2929
};
3030

3131
pub fn make_command(command: Command) -> Command {
@@ -116,7 +116,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
116116

117117
let cached_remote = config.get_cached_vcs_remote();
118118
// Try to open the git repository and find the remote, but handle errors gracefully.
119-
let (vcs_provider, head_repo_name, head_ref, base_ref) = {
119+
let (vcs_provider, head_repo_name, head_ref, base_ref, base_repo_name) = {
120120
// Try to open the repo and get the remote URL, but don't fail if not in a repo.
121121
let repo = git2::Repository::open_from_env().ok();
122122
let repo_ref = repo.as_ref();
@@ -191,10 +191,38 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
191191
.map(Cow::Owned)
192192
});
193193

194-
(vcs_provider, head_repo_name, head_ref, base_ref)
195-
};
194+
let base_repo_name = matches
195+
.get_one("base_repo_name")
196+
.map(String::as_str)
197+
.map(Cow::Borrowed)
198+
.or_else(|| {
199+
// Try to get the base repo name from the VCS if not provided
200+
repo_ref
201+
.and_then(|r| match git_repo_base_repo_name(r) {
202+
Ok(Some(base_repo_name)) => {
203+
debug!("Found base repository name: {}", base_repo_name);
204+
Some(base_repo_name)
205+
}
206+
Ok(None) => {
207+
debug!("No base repository found - not a fork");
208+
None
209+
}
210+
Err(e) => {
211+
warn!("Could not detect base repository name: {}", e);
212+
None
213+
}
214+
})
215+
.map(Cow::Owned)
216+
});
196217

197-
let base_repo_name = matches.get_one("base_repo_name").map(String::as_str);
218+
(
219+
vcs_provider,
220+
head_repo_name,
221+
head_ref,
222+
base_ref,
223+
base_repo_name,
224+
)
225+
};
198226
let base_sha = matches.get_one("base_sha").map(String::as_str);
199227
let pr_number = matches
200228
.get_one("pr_number")
@@ -261,7 +289,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
261289
base_sha,
262290
vcs_provider: vcs_provider.as_deref(),
263291
head_repo_name: head_repo_name.as_deref(),
264-
base_repo_name,
292+
base_repo_name: base_repo_name.as_deref(),
265293
head_ref: head_ref.as_deref(),
266294
base_ref: base_ref.as_deref(),
267295
pr_number: pr_number.as_ref(),

src/utils/vcs.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use chrono::{DateTime, FixedOffset, TimeZone as _};
88
use git2::{Commit, Repository, Time};
99
use if_chain::if_chain;
1010
use lazy_static::lazy_static;
11-
use log::{debug, info};
11+
use log::{debug, info, warn};
1212
use regex::Regex;
1313

1414
use crate::api::{GitCommit, PatchSet, Ref, Repo};
@@ -283,6 +283,37 @@ fn find_merge_base_ref(
283283
Ok(merge_base_sha)
284284
}
285285

286+
/// Attempts to get the base repository name from git remotes.
287+
/// Prefers "origin" remote if it exists, otherwise uses the first available remote.
288+
/// Returns the base repository name if a remote is found.
289+
pub fn git_repo_base_repo_name(repo: &git2::Repository) -> Result<Option<String>> {
290+
let remotes = repo.remotes()?;
291+
let remote_names: Vec<&str> = remotes.iter().flatten().collect();
292+
293+
if remote_names.is_empty() {
294+
warn!("No remotes found in repository");
295+
return Ok(None);
296+
}
297+
298+
// Prefer "origin" remote if it exists, otherwise use the first one
299+
let chosen_remote = if remote_names.contains(&"origin") {
300+
"origin"
301+
} else {
302+
remote_names[0]
303+
};
304+
305+
match git_repo_remote_url(repo, chosen_remote) {
306+
Ok(remote_url) => {
307+
debug!("Found remote '{}': {}", chosen_remote, remote_url);
308+
Ok(Some(get_repo_from_remote(&remote_url)))
309+
}
310+
Err(e) => {
311+
warn!("Could not get URL for remote '{}': {}", chosen_remote, e);
312+
Ok(None)
313+
}
314+
}
315+
}
316+
286317
/// Attempts to get the PR number from GitHub Actions environment variables.
287318
/// Returns the PR number if running in a GitHub Actions pull request environment.
288319
pub fn get_github_pr_number() -> Option<u32> {

0 commit comments

Comments
 (0)