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()
|
.git()
|
||||||
.find_branch_type(&ctx.project.git_repo_path, &task_attempt.target_branch)?;
|
.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 (commits_ahead, commits_behind) = match target_branch_type {
|
||||||
let (a, b) = deployment.git().get_branch_status(
|
BranchType::Local => {
|
||||||
&ctx.project.git_repo_path,
|
let (a, b) = deployment.git().get_branch_status(
|
||||||
&task_attempt.branch,
|
&ctx.project.git_repo_path,
|
||||||
&task_attempt.target_branch,
|
&task_attempt.branch,
|
||||||
)?;
|
&task_attempt.target_branch,
|
||||||
(Some(a), Some(b))
|
)?;
|
||||||
} else {
|
(Some(a), Some(b))
|
||||||
(None, None)
|
}
|
||||||
|
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
|
// 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 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_ahead,
|
||||||
commits_behind,
|
commits_behind,
|
||||||
has_uncommitted_changes,
|
has_uncommitted_changes,
|
||||||
head_oid,
|
head_oid,
|
||||||
uncommitted_count,
|
uncommitted_count,
|
||||||
untracked_count,
|
untracked_count,
|
||||||
remote_commits_ahead: None,
|
remote_commits_ahead: remote_ahead,
|
||||||
remote_commits_behind: None,
|
remote_commits_behind: remote_behind,
|
||||||
merges,
|
merges,
|
||||||
target_branch_name: task_attempt.target_branch.clone(),
|
target_branch_name: task_attempt.target_branch,
|
||||||
is_rebase_in_progress,
|
is_rebase_in_progress,
|
||||||
conflict_op,
|
conflict_op,
|
||||||
conflicted_files,
|
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)))
|
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 the target base is remote, update it first so CLI sees latest
|
||||||
if nbr.is_remote() {
|
if nbr.is_remote() {
|
||||||
let github_token = github_token.ok_or(GitServiceError::TokenUnavailable)?;
|
let github_token = github_token.ok_or(GitServiceError::TokenUnavailable)?;
|
||||||
let remote = self.get_remote_from_branch_ref(&main_repo, &nbr)?;
|
self.fetch_branch_from_remote(&main_repo, &github_token, &nbr)?;
|
||||||
// First, fetch the latest changes from remote
|
|
||||||
self.fetch_branch_from_remote(&main_repo, &github_token, &remote, new_base_branch)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure identity for any commits produced by rebase
|
// 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()))?;
|
.ok_or_else(|| GitServiceError::InvalidRepository("Remote has no URL".to_string()))?;
|
||||||
|
|
||||||
let https_url = self.convert_to_https_url(remote_url);
|
let https_url = self.convert_to_https_url(remote_url);
|
||||||
// Create temporary HTTPS remote
|
|
||||||
let git_cli = GitCli::new();
|
let git_cli = GitCli::new();
|
||||||
if let Err(e) =
|
if let Err(e) =
|
||||||
git_cli.fetch_with_token_and_refspec(repo.path(), &https_url, refspec, github_token)
|
git_cli.fetch_with_token_and_refspec(repo.path(), &https_url, refspec, github_token)
|
||||||
@@ -1822,13 +1819,18 @@ impl GitService {
|
|||||||
&self,
|
&self,
|
||||||
repo: &Repository,
|
repo: &Repository,
|
||||||
github_token: &str,
|
github_token: &str,
|
||||||
remote: &Remote,
|
branch: &Reference,
|
||||||
branch_name: &str,
|
|
||||||
) -> Result<(), GitServiceError> {
|
) -> Result<(), GitServiceError> {
|
||||||
|
let remote = self.get_remote_from_branch_ref(repo, branch)?;
|
||||||
let default_remote_name = self.default_remote_name(repo);
|
let default_remote_name = self.default_remote_name(repo);
|
||||||
let remote_name = remote.name().unwrap_or(&default_remote_name);
|
let remote_name = remote.name().unwrap_or(&default_remote_name);
|
||||||
let refspec = format!("+refs/heads/{branch_name}:refs/remotes/{remote_name}/{branch_name}");
|
let dest_ref = branch
|
||||||
self.fetch_from_remote(repo, github_token, remote, &refspec)
|
.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
|
/// Fetch from remote repository using GitHub token authentication
|
||||||
|
|||||||
Reference in New Issue
Block a user