From 08f4b3f31288bc4e12e94f00c7d88583ab04dd2e Mon Sep 17 00:00:00 2001 From: Viktor Yakovchuk Date: Thu, 24 Jun 2021 00:08:26 +0300 Subject: [PATCH] Fix 500 Error with branch and tag sharing the same name #15592 (#16040) * Fix 500 Error with branch and tag sharing the same name #15592 Fixed 500 error while create Pull request when there are more than one sources (branch, tag) with the same name Fix #15592 Signed-off-by: Viktor Yakovchuk * fix logging Co-authored-by: techknowlogick Co-authored-by: 6543 <6543@obermui.de> --- modules/git/error.go | 17 +++++++++++++++++ modules/git/repo.go | 7 +++++++ services/pull/pull.go | 14 +++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/modules/git/error.go b/modules/git/error.go index 85a938a7da..387dd724e5 100644 --- a/modules/git/error.go +++ b/modules/git/error.go @@ -159,3 +159,20 @@ func (err *ErrPushRejected) GenerateMessage() { } err.Message = strings.TrimSpace(messageBuilder.String()) } + +// ErrMoreThanOne represents an error if pull request fails when there are more than one sources (branch, tag) with the same name +type ErrMoreThanOne struct { + StdOut string + StdErr string + Err error +} + +// IsErrMoreThanOne checks if an error is a ErrMoreThanOne +func IsErrMoreThanOne(err error) bool { + _, ok := err.(*ErrMoreThanOne) + return ok +} + +func (err *ErrMoreThanOne) Error() string { + return fmt.Sprintf("ErrMoreThanOne Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut) +} diff --git a/modules/git/repo.go b/modules/git/repo.go index e06cd43935..43f329f448 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -225,6 +225,13 @@ func Push(repoPath string, opts PushOptions) error { } err.GenerateMessage() return err + } else if strings.Contains(errbuf.String(), "matches more than one") { + err := &ErrMoreThanOne{ + StdOut: outbuf.String(), + StdErr: errbuf.String(), + Err: err, + } + return err } } diff --git a/services/pull/pull.go b/services/pull/pull.go index 02c0a7fe7c..7b5dd6a964 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -389,6 +389,10 @@ func checkIfPRContentChanged(pr *models.PullRequest, oldCommitID, newCommitID st // corresponding branches of base repository. // FIXME: Only push branches that are actually updates? func PushToBaseRepo(pr *models.PullRequest) (err error) { + return pushToBaseRepoHelper(pr, "") +} + +func pushToBaseRepoHelper(pr *models.PullRequest, prefixHeadBranch string) (err error) { log.Trace("PushToBaseRepo[%d]: pushing commits to base repo '%s'", pr.BaseRepoID, pr.GetGitRefName()) if err := pr.LoadHeadRepo(); err != nil { @@ -414,7 +418,7 @@ func PushToBaseRepo(pr *models.PullRequest) (err error) { if err := git.Push(headRepoPath, git.PushOptions{ Remote: baseRepoPath, - Branch: pr.HeadBranch + ":" + gitRefName, + Branch: prefixHeadBranch + pr.HeadBranch + ":" + gitRefName, Force: true, // Use InternalPushingEnvironment here because we know that pre-receive and post-receive do not run on a refs/pulls/... Env: models.InternalPushingEnvironment(pr.Issue.Poster, pr.BaseRepo), @@ -427,6 +431,14 @@ func PushToBaseRepo(pr *models.PullRequest) (err error) { rejectErr := err.(*git.ErrPushRejected) log.Info("Unable to push PR head for %s#%d (%-v:%s) due to rejection:\nStdout: %s\nStderr: %s\nError: %v", pr.BaseRepo.FullName(), pr.Index, pr.BaseRepo, gitRefName, rejectErr.StdOut, rejectErr.StdErr, rejectErr.Err) return err + } else if git.IsErrMoreThanOne(err) { + if prefixHeadBranch != "" { + log.Info("Can't push with %s%s", prefixHeadBranch, pr.HeadBranch) + return err + } + log.Info("Retrying to push with refs/heads/%s", pr.HeadBranch) + err = pushToBaseRepoHelper(pr, "refs/heads/") + return err } log.Error("Unable to push PR head for %s#%d (%-v:%s) due to Error: %v", pr.BaseRepo.FullName(), pr.Index, pr.BaseRepo, gitRefName, err) return fmt.Errorf("Push: %s:%s %s:%s %v", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), gitRefName, err)