Fix wrong git status for remote branches (#903)
* Fix wrong git status for remote branches * Fix edge case where prefix may be stripped multiple times
This commit is contained in:
@@ -925,70 +925,72 @@ pub async fn get_task_attempt_branch_status(
|
||||
.git()
|
||||
.find_branch_type(&ctx.project.git_repo_path, &task_attempt.target_branch)?;
|
||||
|
||||
let (commits_ahead, commits_behind) = if matches!(target_branch_type, BranchType::Local) {
|
||||
let (a, b) = deployment.git().get_branch_status(
|
||||
&ctx.project.git_repo_path,
|
||||
&task_attempt.branch,
|
||||
&task_attempt.target_branch,
|
||||
)?;
|
||||
(Some(a), Some(b))
|
||||
} else {
|
||||
(None, None)
|
||||
let (commits_ahead, commits_behind) = match target_branch_type {
|
||||
BranchType::Local => {
|
||||
let (a, b) = deployment.git().get_branch_status(
|
||||
&ctx.project.git_repo_path,
|
||||
&task_attempt.branch,
|
||||
&task_attempt.target_branch,
|
||||
)?;
|
||||
(Some(a), Some(b))
|
||||
}
|
||||
BranchType::Remote => {
|
||||
let github_config = deployment.config().read().await.github.clone();
|
||||
let token = github_config
|
||||
.token()
|
||||
.ok_or(ApiError::GitHubService(GitHubServiceError::TokenInvalid))?;
|
||||
let (remote_commits_ahead, remote_commits_behind) =
|
||||
deployment.git().get_remote_branch_status(
|
||||
&ctx.project.git_repo_path,
|
||||
&task_attempt.branch,
|
||||
Some(&task_attempt.target_branch),
|
||||
token,
|
||||
)?;
|
||||
(Some(remote_commits_ahead), Some(remote_commits_behind))
|
||||
}
|
||||
};
|
||||
// Fetch merges for this task attempt and add to branch status
|
||||
let merges = Merge::find_by_task_attempt_id(pool, task_attempt.id).await?;
|
||||
let mut branch_status = BranchStatus {
|
||||
let (remote_ahead, remote_behind) = if let Some(Merge::Pr(PrMerge {
|
||||
pr_info: PullRequestInfo {
|
||||
status: MergeStatus::Open,
|
||||
..
|
||||
},
|
||||
..
|
||||
})) = merges.first()
|
||||
{
|
||||
// check remote status if the attempt has an open PR
|
||||
let github_config = deployment.config().read().await.github.clone();
|
||||
let token = github_config
|
||||
.token()
|
||||
.ok_or(ApiError::GitHubService(GitHubServiceError::TokenInvalid))?;
|
||||
let (remote_commits_ahead, remote_commits_behind) =
|
||||
deployment.git().get_remote_branch_status(
|
||||
&ctx.project.git_repo_path,
|
||||
&task_attempt.branch,
|
||||
None,
|
||||
token,
|
||||
)?;
|
||||
(Some(remote_commits_ahead), Some(remote_commits_behind))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let branch_status = BranchStatus {
|
||||
commits_ahead,
|
||||
commits_behind,
|
||||
has_uncommitted_changes,
|
||||
head_oid,
|
||||
uncommitted_count,
|
||||
untracked_count,
|
||||
remote_commits_ahead: None,
|
||||
remote_commits_behind: None,
|
||||
remote_commits_ahead: remote_ahead,
|
||||
remote_commits_behind: remote_behind,
|
||||
merges,
|
||||
target_branch_name: task_attempt.target_branch.clone(),
|
||||
target_branch_name: task_attempt.target_branch,
|
||||
is_rebase_in_progress,
|
||||
conflict_op,
|
||||
conflicted_files,
|
||||
};
|
||||
let has_open_pr = branch_status.merges.first().is_some_and(|m| {
|
||||
matches!(
|
||||
m,
|
||||
Merge::Pr(PrMerge {
|
||||
pr_info: PullRequestInfo {
|
||||
status: MergeStatus::Open,
|
||||
..
|
||||
},
|
||||
..
|
||||
})
|
||||
)
|
||||
});
|
||||
|
||||
// check remote status if the attempt has an open PR or the target_branch is a remote branch
|
||||
if has_open_pr || target_branch_type == BranchType::Remote {
|
||||
let github_config = deployment.config().read().await.github.clone();
|
||||
let token = github_config
|
||||
.token()
|
||||
.ok_or(ApiError::GitHubService(GitHubServiceError::TokenInvalid))?;
|
||||
|
||||
// For an attempt with a remote target branch, we compare against that
|
||||
// After opening a PR, the attempt has a remote branch itself, so we use that
|
||||
let remote_target_branch = if target_branch_type == BranchType::Remote && !has_open_pr {
|
||||
Some(task_attempt.target_branch)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let (remote_commits_ahead, remote_commits_behind) =
|
||||
deployment.git().get_remote_branch_status(
|
||||
&ctx.project.git_repo_path,
|
||||
&task_attempt.branch,
|
||||
remote_target_branch.as_deref(),
|
||||
token,
|
||||
)?;
|
||||
branch_status.remote_commits_ahead = Some(remote_commits_ahead);
|
||||
branch_status.remote_commits_behind = Some(remote_commits_behind);
|
||||
}
|
||||
Ok(ResponseJson(ApiResponse::success(branch_status)))
|
||||
}
|
||||
|
||||
|
||||
@@ -1407,9 +1407,7 @@ impl GitService {
|
||||
// If the target base is remote, update it first so CLI sees latest
|
||||
if nbr.is_remote() {
|
||||
let github_token = github_token.ok_or(GitServiceError::TokenUnavailable)?;
|
||||
let remote = self.get_remote_from_branch_ref(&main_repo, &nbr)?;
|
||||
// First, fetch the latest changes from remote
|
||||
self.fetch_branch_from_remote(&main_repo, &github_token, &remote, new_base_branch)?;
|
||||
self.fetch_branch_from_remote(&main_repo, &github_token, &nbr)?;
|
||||
}
|
||||
|
||||
// Ensure identity for any commits produced by rebase
|
||||
@@ -1806,7 +1804,6 @@ impl GitService {
|
||||
.ok_or_else(|| GitServiceError::InvalidRepository("Remote has no URL".to_string()))?;
|
||||
|
||||
let https_url = self.convert_to_https_url(remote_url);
|
||||
// Create temporary HTTPS remote
|
||||
let git_cli = GitCli::new();
|
||||
if let Err(e) =
|
||||
git_cli.fetch_with_token_and_refspec(repo.path(), &https_url, refspec, github_token)
|
||||
@@ -1822,13 +1819,18 @@ impl GitService {
|
||||
&self,
|
||||
repo: &Repository,
|
||||
github_token: &str,
|
||||
remote: &Remote,
|
||||
branch_name: &str,
|
||||
branch: &Reference,
|
||||
) -> Result<(), GitServiceError> {
|
||||
let remote = self.get_remote_from_branch_ref(repo, branch)?;
|
||||
let default_remote_name = self.default_remote_name(repo);
|
||||
let remote_name = remote.name().unwrap_or(&default_remote_name);
|
||||
let refspec = format!("+refs/heads/{branch_name}:refs/remotes/{remote_name}/{branch_name}");
|
||||
self.fetch_from_remote(repo, github_token, remote, &refspec)
|
||||
let dest_ref = branch
|
||||
.name()
|
||||
.ok_or_else(|| GitServiceError::InvalidRepository("Invalid branch ref".into()))?;
|
||||
let remote_prefix = format!("refs/remotes/{remote_name}/");
|
||||
let src_ref = dest_ref.replacen(&remote_prefix, "refs/heads/", 1);
|
||||
let refspec = format!("+{src_ref}:{dest_ref}");
|
||||
self.fetch_from_remote(repo, github_token, &remote, &refspec)
|
||||
}
|
||||
|
||||
/// Fetch from remote repository using GitHub token authentication
|
||||
|
||||
Reference in New Issue
Block a user