make PR workflow helpers more robust (#300)

improve handling of remote deleted branches

split git.TeaDeleteBranch

only delete remote branch if we have permission

add missing err check

Co-authored-by: Norwin Roosen <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/300
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-Authored-By: Norwin <noerw@noreply.gitea.io>
Co-Committed-By: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
Norwin 2020-12-17 22:00:16 +08:00 committed by 6543
parent a2e8b47c57
commit 8b588f5313
3 changed files with 47 additions and 30 deletions

View File

@ -47,35 +47,30 @@ func (r TeaRepo) TeaCheckout(branchName string) error {
return tree.Checkout(&git.CheckoutOptions{Branch: localBranchRefName}) return tree.Checkout(&git.CheckoutOptions{Branch: localBranchRefName})
} }
// TeaDeleteBranch removes the given branch locally, and if `remoteBranch` is // TeaDeleteLocalBranch removes the given branch locally
// not empty deletes it at it's remote repo. func (r TeaRepo) TeaDeleteLocalBranch(branch *git_config.Branch) error {
func (r TeaRepo) TeaDeleteBranch(branch *git_config.Branch, remoteBranch string, auth git_transport.AuthMethod) error {
err := r.DeleteBranch(branch.Name) err := r.DeleteBranch(branch.Name)
// if the branch is not found that's ok, as .git/config may have no entry if // if the branch is not found that's ok, as .git/config may have no entry if
// no remote tracking branch is configured for it (eg push without -u flag) // no remote tracking branch is configured for it (eg push without -u flag)
if err != nil && err.Error() != "branch not found" { if err != nil && err.Error() != "branch not found" {
return err return err
} }
err = r.Storer.RemoveReference(git_plumbing.NewBranchReferenceName(branch.Name)) return r.Storer.RemoveReference(git_plumbing.NewBranchReferenceName(branch.Name))
if err != nil {
return err
} }
if remoteBranch != "" { // TeaDeleteRemoteBranch removes the given branch on the given remote via git protocol
func (r TeaRepo) TeaDeleteRemoteBranch(remoteName, remoteBranch string, auth git_transport.AuthMethod) error {
// delete remote branch via git protocol: // delete remote branch via git protocol:
// an empty source in the refspec means remote deletion to git 🙃 // an empty source in the refspec means remote deletion to git 🙃
refspec := fmt.Sprintf(":%s", git_plumbing.NewBranchReferenceName(remoteBranch)) refspec := fmt.Sprintf(":%s", git_plumbing.NewBranchReferenceName(remoteBranch))
err = r.Push(&git.PushOptions{ return r.Push(&git.PushOptions{
RemoteName: branch.Remote, RemoteName: remoteName,
RefSpecs: []git_config.RefSpec{git_config.RefSpec(refspec)}, RefSpecs: []git_config.RefSpec{git_config.RefSpec(refspec)},
Prune: true, Prune: true,
Auth: auth, Auth: auth,
}) })
} }
return err
}
// TeaFindBranchBySha returns a branch that is at the the given SHA and syncs to the // TeaFindBranchBySha returns a branch that is at the the given SHA and syncs to the
// given remote repo. // given remote repo.
func (r TeaRepo) TeaFindBranchBySha(sha, repoURL string) (b *git_config.Branch, err error) { func (r TeaRepo) TeaFindBranchBySha(sha, repoURL string) (b *git_config.Branch, err error) {

View File

@ -27,6 +27,10 @@ func PullCheckout(login *config.Login, repoOwner, repoName string, index int64,
if err != nil { if err != nil {
return err return err
} }
remoteDeleted := pr.Head.Ref == fmt.Sprintf("refs/pull/%d/head", pr.Index)
if remoteDeleted {
return fmt.Errorf("Can't checkout: remote head branch was already deleted")
}
remoteURL := pr.Head.Repository.CloneURL remoteURL := pr.Head.Repository.CloneURL
if len(login.SSHKey) != 0 { if len(login.SSHKey) != 0 {

View File

@ -19,6 +19,9 @@ func PullClean(login *config.Login, repoOwner, repoName string, index int64, ign
client := login.Client() client := login.Client()
repo, _, err := client.GetRepo(repoOwner, repoName) repo, _, err := client.GetRepo(repoOwner, repoName)
if err != nil {
return err
}
defaultBranch := repo.DefaultBranch defaultBranch := repo.DefaultBranch
if len(defaultBranch) == 0 { if len(defaultBranch) == 0 {
defaultBranch = "master" defaultBranch = "master"
@ -33,7 +36,13 @@ func PullClean(login *config.Login, repoOwner, repoName string, index int64, ign
return fmt.Errorf("PR is still open, won't delete branches") return fmt.Errorf("PR is still open, won't delete branches")
} }
// IDEA: abort if PR.Head.Repository.CloneURL does not match login.URL? // if remote head branch is already deleted, pr.Head.Ref points to "pulls/<idx>/head"
remoteBranch := pr.Head.Ref
remoteDeleted := remoteBranch == fmt.Sprintf("refs/pull/%d/head", pr.Index)
if remoteDeleted {
remoteBranch = pr.Head.Name // this still holds the original branch name
fmt.Printf("Remote branch '%s' already deleted.\n", remoteBranch)
}
r, err := local_git.RepoForWorkdir() r, err := local_git.RepoForWorkdir()
if err != nil { if err != nil {
@ -43,7 +52,7 @@ func PullClean(login *config.Login, repoOwner, repoName string, index int64, ign
// find a branch with matching sha or name, that has a remote matching the repo url // find a branch with matching sha or name, that has a remote matching the repo url
var branch *git_config.Branch var branch *git_config.Branch
if ignoreSHA { if ignoreSHA {
branch, err = r.TeaFindBranchByName(pr.Head.Ref, pr.Head.Repository.CloneURL) branch, err = r.TeaFindBranchByName(remoteBranch, pr.Head.Repository.CloneURL)
} else { } else {
branch, err = r.TeaFindBranchBySha(pr.Head.Sha, pr.Head.Repository.CloneURL) branch, err = r.TeaFindBranchBySha(pr.Head.Sha, pr.Head.Repository.CloneURL)
} }
@ -52,12 +61,12 @@ func PullClean(login *config.Login, repoOwner, repoName string, index int64, ign
} }
if branch == nil { if branch == nil {
if ignoreSHA { if ignoreSHA {
return fmt.Errorf("Remote branch %s not found in local repo", pr.Head.Ref) return fmt.Errorf("Remote branch %s not found in local repo", remoteBranch)
} }
return fmt.Errorf(`Remote branch %s not found in local repo. return fmt.Errorf(`Remote branch %s not found in local repo.
Either you don't track this PR, or the local branch has diverged from the remote. Either you don't track this PR, or the local branch has diverged from the remote.
If you still want to continue & are sure you don't loose any important commits, If you still want to continue & are sure you don't loose any important commits,
call me again with the --ignore-sha flag`, pr.Head.Ref) call me again with the --ignore-sha flag`, remoteBranch)
} }
// prepare deletion of local branch: // prepare deletion of local branch:
@ -73,7 +82,14 @@ call me again with the --ignore-sha flag`, pr.Head.Ref)
} }
// remove local & remote branch // remove local & remote branch
fmt.Printf("Deleting local branch %s and remote branch %s\n", branch.Name, pr.Head.Ref) fmt.Printf("Deleting local branch %s\n", branch.Name)
err = r.TeaDeleteLocalBranch(branch)
if err != nil {
return err
}
if !remoteDeleted && pr.Head.Repository.Permissions.Push {
fmt.Printf("Deleting remote branch %s\n", remoteBranch)
url, err := r.TeaRemoteURL(branch.Remote) url, err := r.TeaRemoteURL(branch.Remote)
if err != nil { if err != nil {
return err return err
@ -82,5 +98,7 @@ call me again with the --ignore-sha flag`, pr.Head.Ref)
if err != nil { if err != nil {
return err return err
} }
return r.TeaDeleteBranch(branch, pr.Head.Ref, auth) err = r.TeaDeleteRemoteBranch(branch.Remote, remoteBranch, auth)
}
return err
} }