diff --git a/src/commands/build/upload.rs b/src/commands/build/upload.rs index dd425cc262..7be5a2d0a8 100644 --- a/src/commands/build/upload.rs +++ b/src/commands/build/upload.rs @@ -24,7 +24,8 @@ use crate::utils::fs::TempDir; use crate::utils::fs::TempFile; use crate::utils::progress::ProgressBar; use crate::utils::vcs::{ - self, get_provider_from_remote, get_repo_from_remote, git_repo_head_ref, git_repo_remote_url, + self, get_provider_from_remote, get_repo_from_remote, git_repo_base_ref, git_repo_head_ref, + git_repo_remote_url, }; pub fn make_command(command: Command) -> Command { @@ -79,7 +80,7 @@ pub fn make_command(command: Command) -> Command { .arg( Arg::new("base_ref") .long("base-ref") - .help("The reference (branch) to use for the upload. If not provided, the current reference will be used.") + .help("The base reference (branch) to use for the upload. If not provided, the merge-base with the remote tracking branch will be used.") ) .arg( Arg::new("pr_number") @@ -113,7 +114,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) = { + let (vcs_provider, head_repo_name, head_ref, base_ref) = { // 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(); @@ -167,12 +168,32 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { .map(Cow::Owned) }); - (vcs_provider, head_repo_name, head_ref) + let base_ref = matches + .get_one("base_ref") + .map(String::as_str) + .map(Cow::Borrowed) + .or_else(|| { + // Try to get the base ref from the VCS if not provided + // This attempts to find the merge-base with the remote tracking branch + repo_ref + .and_then(|r| match git_repo_base_ref(r, &cached_remote) { + Ok(base_ref_name) => { + debug!("Found base reference: {}", base_ref_name); + Some(base_ref_name) + } + Err(e) => { + warn!("Could not detect base branch reference: {}", e); + None + } + }) + .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); let base_sha = matches.get_one("base_sha").map(String::as_str); - let base_ref = matches.get_one("base_ref").map(String::as_str); let pr_number = matches.get_one::("pr_number"); let build_configuration = matches.get_one("build_configuration").map(String::as_str); @@ -237,7 +258,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { head_repo_name: head_repo_name.as_deref(), base_repo_name, head_ref: head_ref.as_deref(), - base_ref, + base_ref: base_ref.as_deref(), pr_number, }; match upload_file( diff --git a/src/utils/vcs.rs b/src/utils/vcs.rs index e92d0e5084..5e84a10a36 100644 --- a/src/utils/vcs.rs +++ b/src/utils/vcs.rs @@ -249,6 +249,40 @@ pub fn git_repo_head_ref(repo: &git2::Repository) -> Result { } } +pub fn git_repo_base_ref(repo: &git2::Repository, remote_name: &str) -> Result { + // Get the current HEAD commit + let head_commit = repo.head()?.peel_to_commit()?; + + // Try to find the remote tracking branch + let remote_branch_name = format!("refs/remotes/{remote_name}/HEAD"); + let remote_ref = repo.find_reference(&remote_branch_name).map_err(|e| { + anyhow::anyhow!( + "Could not find remote tracking branch for {}: {}", + remote_name, + e + ) + })?; + + find_merge_base_ref(repo, &head_commit, &remote_ref) +} + +fn find_merge_base_ref( + repo: &git2::Repository, + head_commit: &git2::Commit, + remote_ref: &git2::Reference, +) -> Result { + let remote_commit = remote_ref.peel_to_commit()?; + let merge_base_oid = repo.merge_base(head_commit.id(), remote_commit.id())?; + + // Return the merge-base commit SHA as the base reference + let merge_base_sha = merge_base_oid.to_string(); + debug!( + "Found merge-base commit as base reference: {}", + merge_base_sha + ); + Ok(merge_base_sha) +} + fn find_reference_url(repo: &str, repos: &[Repo]) -> Result> { let mut non_git = false; for configured_repo in repos { diff --git a/tests/integration/_cases/build/build-upload-apk-all-uploaded.trycmd b/tests/integration/_cases/build/build-upload-apk-all-uploaded.trycmd index 095710d2e5..3a5a317409 100644 --- a/tests/integration/_cases/build/build-upload-apk-all-uploaded.trycmd +++ b/tests/integration/_cases/build/build-upload-apk-all-uploaded.trycmd @@ -2,6 +2,7 @@ $ sentry-cli build upload tests/integration/_fixtures/build/apk.apk ? success [..]WARN[..]EXPERIMENTAL: The build subcommand is experimental. The command is subject to breaking changes and may be removed without notice in any release. + WARN [..] Could not detect base branch reference: [..] Successfully uploaded 1 file to Sentry - tests/integration/_fixtures/build/apk.apk (http[..]/wat-org/preprod/wat-project/42) diff --git a/tests/integration/_cases/build/build-upload-apk-no-token.trycmd b/tests/integration/_cases/build/build-upload-apk-no-token.trycmd index a29ebd4323..448173f456 100644 --- a/tests/integration/_cases/build/build-upload-apk-no-token.trycmd +++ b/tests/integration/_cases/build/build-upload-apk-no-token.trycmd @@ -2,6 +2,7 @@ $ sentry-cli build upload tests/integration/_fixtures/build/apk.apk ? failed [..]WARN[..]EXPERIMENTAL: The build subcommand is experimental. The command is subject to breaking changes and may be removed without notice in any release. + WARN [..] Could not detect base branch reference: [..] error: Auth token is required for this request. Please run `sentry-cli login` and try again! Add --log-level=[info|debug] or export SENTRY_LOG_LEVEL=[info|debug] to see more output. diff --git a/tests/integration/_cases/build/build-upload-apk.trycmd b/tests/integration/_cases/build/build-upload-apk.trycmd index 97868f4ae6..9b869af97a 100644 --- a/tests/integration/_cases/build/build-upload-apk.trycmd +++ b/tests/integration/_cases/build/build-upload-apk.trycmd @@ -2,6 +2,7 @@ $ sentry-cli build upload tests/integration/_fixtures/build/apk.apk --head-sha test_head_sha ? success [..]WARN[..]EXPERIMENTAL: The build subcommand is experimental. The command is subject to breaking changes and may be removed without notice in any release. + WARN [..] Could not detect base branch reference: [..] Successfully uploaded 1 file to Sentry - tests/integration/_fixtures/build/apk.apk (http[..]/wat-org/preprod/wat-project/42) diff --git a/tests/integration/_cases/build/build-upload-help-macos.trycmd b/tests/integration/_cases/build/build-upload-help-macos.trycmd index 2aeba20894..42bd371b76 100644 --- a/tests/integration/_cases/build/build-upload-help-macos.trycmd +++ b/tests/integration/_cases/build/build-upload-help-macos.trycmd @@ -42,8 +42,8 @@ Options: The reference (branch) to use for the upload. If not provided, the current reference will be used. --base-ref - The reference (branch) to use for the upload. If not provided, the current reference will - be used. + The base reference (branch) to use for the upload. If not provided, the merge-base with + the remote tracking branch will be used. --pr-number The pull request number to use for the upload. If not provided, the current pull request number will be used. diff --git a/tests/integration/_cases/build/build-upload-help-not-macos.trycmd b/tests/integration/_cases/build/build-upload-help-not-macos.trycmd index 5f6ee57c84..25518253d5 100644 --- a/tests/integration/_cases/build/build-upload-help-not-macos.trycmd +++ b/tests/integration/_cases/build/build-upload-help-not-macos.trycmd @@ -41,8 +41,8 @@ Options: The reference (branch) to use for the upload. If not provided, the current reference will be used. --base-ref - The reference (branch) to use for the upload. If not provided, the current reference will - be used. + The base reference (branch) to use for the upload. If not provided, the merge-base with + the remote tracking branch will be used. --pr-number The pull request number to use for the upload. If not provided, the current pull request number will be used. diff --git a/tests/integration/_cases/build/build-upload-ipa.trycmd b/tests/integration/_cases/build/build-upload-ipa.trycmd index 8d0bde6566..c259620e4f 100644 --- a/tests/integration/_cases/build/build-upload-ipa.trycmd +++ b/tests/integration/_cases/build/build-upload-ipa.trycmd @@ -2,6 +2,7 @@ $ sentry-cli build upload tests/integration/_fixtures/build/ipa.ipa --head-sha test_head_sha ? success [..]WARN[..]EXPERIMENTAL: The build subcommand is experimental. The command is subject to breaking changes and may be removed without notice in any release. + WARN [..] Could not detect base branch reference: [..] Successfully uploaded 1 file to Sentry - tests/integration/_fixtures/build/ipa.ipa (http[..]/wat-org/preprod/wat-project/some-text-id)