summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/pull/pull.go88
1 files changed, 88 insertions, 0 deletions
diff --git a/services/pull/pull.go b/services/pull/pull.go
index e7f4e4eede..fb47df1c3a 100644
--- a/services/pull/pull.go
+++ b/services/pull/pull.go
@@ -46,6 +46,94 @@ func NewPullRequest(repo *models.Repository, pull *models.Issue, labelIDs []int6
return nil
}
+// ChangeTargetBranch changes the target branch of this pull request, as the given user.
+func ChangeTargetBranch(pr *models.PullRequest, doer *models.User, targetBranch string) (err error) {
+ // Current target branch is already the same
+ if pr.BaseBranch == targetBranch {
+ return nil
+ }
+
+ if pr.Issue.IsClosed {
+ return models.ErrIssueIsClosed{
+ ID: pr.Issue.ID,
+ RepoID: pr.Issue.RepoID,
+ Index: pr.Issue.Index,
+ }
+ }
+
+ if pr.HasMerged {
+ return models.ErrPullRequestHasMerged{
+ ID: pr.ID,
+ IssueID: pr.Index,
+ HeadRepoID: pr.HeadRepoID,
+ BaseRepoID: pr.BaseRepoID,
+ HeadBranch: pr.HeadBranch,
+ BaseBranch: pr.BaseBranch,
+ }
+ }
+
+ // Check if branches are equal
+ branchesEqual, err := pr.IsHeadEqualWithBranch(targetBranch)
+ if err != nil {
+ return err
+ }
+ if branchesEqual {
+ return models.ErrBranchesEqual{
+ HeadBranchName: pr.HeadBranch,
+ BaseBranchName: targetBranch,
+ }
+ }
+
+ // Check if pull request for the new target branch already exists
+ existingPr, err := models.GetUnmergedPullRequest(pr.HeadRepoID, pr.BaseRepoID, pr.HeadBranch, targetBranch)
+ if existingPr != nil {
+ return models.ErrPullRequestAlreadyExists{
+ ID: existingPr.ID,
+ IssueID: existingPr.Index,
+ HeadRepoID: existingPr.HeadRepoID,
+ BaseRepoID: existingPr.BaseRepoID,
+ HeadBranch: existingPr.HeadBranch,
+ BaseBranch: existingPr.BaseBranch,
+ }
+ }
+ if err != nil && !models.IsErrPullRequestNotExist(err) {
+ return err
+ }
+
+ // Set new target branch
+ oldBranch := pr.BaseBranch
+ pr.BaseBranch = targetBranch
+
+ // Refresh patch
+ if err := TestPatch(pr); err != nil {
+ return err
+ }
+
+ // Update target branch, PR diff and status
+ // This is the same as checkAndUpdateStatus in check service, but also updates base_branch
+ if pr.Status == models.PullRequestStatusChecking {
+ pr.Status = models.PullRequestStatusMergeable
+ }
+ if err := pr.UpdateCols("status, conflicted_files, base_branch"); err != nil {
+ return err
+ }
+
+ // Create comment
+ options := &models.CreateCommentOptions{
+ Type: models.CommentTypeChangeTargetBranch,
+ Doer: doer,
+ Repo: pr.Issue.Repo,
+ Issue: pr.Issue,
+ OldRef: oldBranch,
+ NewRef: targetBranch,
+ }
+ if _, err = models.CreateComment(options); err != nil {
+ return fmt.Errorf("CreateChangeTargetBranchComment: %v", err)
+ }
+
+ return nil
+}
+
func checkForInvalidation(requests models.PullRequestList, repoID int64, doer *models.User, branch string) error {
repo, err := models.GetRepositoryByID(repoID)
if err != nil {