2019-09-27 08:22:36 +08:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package pull
import (
"fmt"
2019-12-15 11:28:51 +08:00
"os"
"path"
2019-09-27 08:22:36 +08:00
"code.gitea.io/gitea/models"
2019-10-15 11:28:40 +08:00
"code.gitea.io/gitea/modules/git"
2019-09-27 08:22:36 +08:00
"code.gitea.io/gitea/modules/log"
2019-11-04 04:59:09 +08:00
"code.gitea.io/gitea/modules/notification"
2019-10-29 00:45:43 +08:00
issue_service "code.gitea.io/gitea/services/issue"
2019-09-27 08:22:36 +08:00
)
// NewPullRequest creates new pull request with labels for repository.
2019-12-13 22:21:06 +00:00
func NewPullRequest ( repo * models . Repository , pull * models . Issue , labelIDs [ ] int64 , uuids [ ] string , pr * models . PullRequest , assigneeIDs [ ] int64 ) error {
if err := TestPatch ( pr ) ; err != nil {
return err
}
if err := models . NewPullRequest ( repo , pull , labelIDs , uuids , pr ) ; err != nil {
2019-09-27 08:22:36 +08:00
return err
}
2019-10-29 00:45:43 +08:00
for _ , assigneeID := range assigneeIDs {
if err := issue_service . AddAssigneeIfNotAssigned ( pull , pull . Poster , assigneeID ) ; err != nil {
return err
}
}
2019-09-27 08:22:36 +08:00
pr . Issue = pull
pull . PullRequest = pr
2019-11-04 04:59:09 +08:00
2019-12-15 11:28:51 +08:00
if err := PushToBaseRepo ( pr ) ; err != nil {
return err
}
2019-11-04 04:59:09 +08:00
notification . NotifyNewPullRequest ( pr )
2019-09-27 08:22:36 +08:00
return nil
}
2019-10-15 11:28:40 +08:00
func checkForInvalidation ( requests models . PullRequestList , repoID int64 , doer * models . User , branch string ) error {
repo , err := models . GetRepositoryByID ( repoID )
if err != nil {
return fmt . Errorf ( "GetRepositoryByID: %v" , err )
}
gitRepo , err := git . OpenRepository ( repo . RepoPath ( ) )
if err != nil {
return fmt . Errorf ( "git.OpenRepository: %v" , err )
}
go func ( ) {
err := requests . InvalidateCodeComments ( doer , gitRepo , branch )
if err != nil {
log . Error ( "PullRequestList.InvalidateCodeComments: %v" , err )
}
2019-11-13 07:01:19 +00:00
gitRepo . Close ( )
2019-10-15 11:28:40 +08:00
} ( )
return nil
}
func addHeadRepoTasks ( prs [ ] * models . PullRequest ) {
for _ , pr := range prs {
log . Trace ( "addHeadRepoTasks[%d]: composing new test task" , pr . ID )
2019-12-15 11:28:51 +08:00
if err := PushToBaseRepo ( pr ) ; err != nil {
2019-10-15 11:28:40 +08:00
log . Error ( "PushToBaseRepo: %v" , err )
continue
}
2019-12-07 10:44:10 +08:00
AddToTaskQueue ( pr )
2019-10-15 11:28:40 +08:00
}
}
// AddTestPullRequestTask adds new test tasks by given head/base repository and head/base branch,
// and generate new patch for testing as needed.
func AddTestPullRequestTask ( doer * models . User , repoID int64 , branch string , isSync bool ) {
log . Trace ( "AddTestPullRequestTask [head_repo_id: %d, head_branch: %s]: finding pull requests" , repoID , branch )
prs , err := models . GetUnmergedPullRequestsByHeadInfo ( repoID , branch )
if err != nil {
log . Error ( "Find pull requests [head_repo_id: %d, head_branch: %s]: %v" , repoID , branch , err )
return
}
if isSync {
requests := models . PullRequestList ( prs )
if err = requests . LoadAttributes ( ) ; err != nil {
log . Error ( "PullRequestList.LoadAttributes: %v" , err )
}
if invalidationErr := checkForInvalidation ( requests , repoID , doer , branch ) ; invalidationErr != nil {
log . Error ( "checkForInvalidation: %v" , invalidationErr )
}
if err == nil {
for _ , pr := range prs {
pr . Issue . PullRequest = pr
2019-11-05 19:04:08 +08:00
notification . NotifyPullRequestSynchronized ( doer , pr )
2019-10-15 11:28:40 +08:00
}
}
}
addHeadRepoTasks ( prs )
log . Trace ( "AddTestPullRequestTask [base_repo_id: %d, base_branch: %s]: finding pull requests" , repoID , branch )
prs , err = models . GetUnmergedPullRequestsByBaseInfo ( repoID , branch )
if err != nil {
log . Error ( "Find pull requests [base_repo_id: %d, base_branch: %s]: %v" , repoID , branch , err )
return
}
for _ , pr := range prs {
2019-12-07 10:44:10 +08:00
AddToTaskQueue ( pr )
2019-10-15 11:28:40 +08:00
}
}
2019-12-15 11:28:51 +08:00
// PushToBaseRepo pushes commits from branches of head repository to
// corresponding branches of base repository.
// FIXME: Only push branches that are actually updates?
func PushToBaseRepo ( pr * models . PullRequest ) ( err error ) {
log . Trace ( "PushToBaseRepo[%d]: pushing commits to base repo '%s'" , pr . BaseRepoID , pr . GetGitRefName ( ) )
headRepoPath := pr . HeadRepo . RepoPath ( )
headGitRepo , err := git . OpenRepository ( headRepoPath )
if err != nil {
return fmt . Errorf ( "OpenRepository: %v" , err )
}
defer headGitRepo . Close ( )
tmpRemoteName := fmt . Sprintf ( "tmp-pull-%d" , pr . ID )
if err = headGitRepo . AddRemote ( tmpRemoteName , pr . BaseRepo . RepoPath ( ) , false ) ; err != nil {
return fmt . Errorf ( "headGitRepo.AddRemote: %v" , err )
}
// Make sure to remove the remote even if the push fails
defer func ( ) {
if err := headGitRepo . RemoveRemote ( tmpRemoteName ) ; err != nil {
log . Error ( "PushToBaseRepo: RemoveRemote: %s" , err )
}
} ( )
headFile := pr . GetGitRefName ( )
// Remove head in case there is a conflict.
file := path . Join ( pr . BaseRepo . RepoPath ( ) , headFile )
_ = os . Remove ( file )
if err = git . Push ( headRepoPath , git . PushOptions {
Remote : tmpRemoteName ,
Branch : fmt . Sprintf ( "%s:%s" , pr . HeadBranch , headFile ) ,
Force : true ,
} ) ; err != nil {
return fmt . Errorf ( "Push: %v" , err )
}
return nil
}