diff --git a/models/pull.go b/models/pull.go index c6da63ec557..45a1daac467 100644 --- a/models/pull.go +++ b/models/pull.go @@ -16,7 +16,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/process" @@ -26,7 +25,6 @@ import ( "code.gitea.io/gitea/modules/timeutil" "github.com/unknwon/com" - "xorm.io/xorm" ) var pullRequestQueue = sync.NewUniqueQueue(setting.Repository.PullRequestQueueLength) @@ -753,66 +751,6 @@ func newPullRequestAttempt(repo *Repository, pull *Issue, labelIDs []int64, uuid return nil } -// PullRequestsOptions holds the options for PRs -type PullRequestsOptions struct { - Page int - State string - SortType string - Labels []string - MilestoneID int64 -} - -func listPullRequestStatement(baseRepoID int64, opts *PullRequestsOptions) (*xorm.Session, error) { - sess := x.Where("pull_request.base_repo_id=?", baseRepoID) - - sess.Join("INNER", "issue", "pull_request.issue_id = issue.id") - switch opts.State { - case "closed", "open": - sess.And("issue.is_closed=?", opts.State == "closed") - } - - if labelIDs, err := base.StringsToInt64s(opts.Labels); err != nil { - return nil, err - } else if len(labelIDs) > 0 { - sess.Join("INNER", "issue_label", "issue.id = issue_label.issue_id"). - In("issue_label.label_id", labelIDs) - } - - if opts.MilestoneID > 0 { - sess.And("issue.milestone_id=?", opts.MilestoneID) - } - - return sess, nil -} - -// PullRequests returns all pull requests for a base Repo by the given conditions -func PullRequests(baseRepoID int64, opts *PullRequestsOptions) ([]*PullRequest, int64, error) { - if opts.Page <= 0 { - opts.Page = 1 - } - - countSession, err := listPullRequestStatement(baseRepoID, opts) - if err != nil { - log.Error("listPullRequestStatement: %v", err) - return nil, 0, err - } - maxResults, err := countSession.Count(new(PullRequest)) - if err != nil { - log.Error("Count PRs: %v", err) - return nil, maxResults, err - } - - prs := make([]*PullRequest, 0, ItemsPerPage) - findSession, err := listPullRequestStatement(baseRepoID, opts) - sortIssuesSession(findSession, opts.SortType) - if err != nil { - log.Error("listPullRequestStatement: %v", err) - return nil, maxResults, err - } - findSession.Limit(ItemsPerPage, (opts.Page-1)*ItemsPerPage) - return prs, maxResults, findSession.Find(&prs) -} - // GetUnmergedPullRequest returns a pull request that is open and has not been merged // by given head/base and repo/branch. func GetUnmergedPullRequest(headRepoID, baseRepoID int64, headBranch, baseBranch string) (*PullRequest, error) { @@ -831,17 +769,6 @@ func GetUnmergedPullRequest(headRepoID, baseRepoID int64, headBranch, baseBranch return pr, nil } -// GetUnmergedPullRequestsByHeadInfo returns all pull requests that are open and has not been merged -// by given head information (repo and branch). -func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string) ([]*PullRequest, error) { - prs := make([]*PullRequest, 0, 2) - return prs, x. - Where("head_repo_id = ? AND head_branch = ? AND has_merged = ? AND issue.is_closed = ?", - repoID, branch, false, false). - Join("INNER", "issue", "issue.id = pull_request.issue_id"). - Find(&prs) -} - // GetLatestPullRequestByHeadInfo returns the latest pull request (regardless of its status) // by given head information (repo and branch). func GetLatestPullRequestByHeadInfo(repoID int64, branch string) (*PullRequest, error) { @@ -856,17 +783,6 @@ func GetLatestPullRequestByHeadInfo(repoID int64, branch string) (*PullRequest, return pr, err } -// GetUnmergedPullRequestsByBaseInfo returns all pull requests that are open and has not been merged -// by given base information (repo and branch). -func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequest, error) { - prs := make([]*PullRequest, 0, 2) - return prs, x. - Where("base_repo_id=? AND base_branch=? AND has_merged=? AND issue.is_closed=?", - repoID, branch, false, false). - Join("INNER", "issue", "issue.id=pull_request.issue_id"). - Find(&prs) -} - // GetPullRequestByIndex returns a pull request by the given index func GetPullRequestByIndex(repoID int64, index int64) (*PullRequest, error) { pr := &PullRequest{ @@ -1035,72 +951,6 @@ func (pr *PullRequest) AddToTaskQueue() { }) } -// PullRequestList defines a list of pull requests -type PullRequestList []*PullRequest - -func (prs PullRequestList) loadAttributes(e Engine) error { - if len(prs) == 0 { - return nil - } - - // Load issues. - issueIDs := prs.getIssueIDs() - issues := make([]*Issue, 0, len(issueIDs)) - if err := e. - Where("id > 0"). - In("id", issueIDs). - Find(&issues); err != nil { - return fmt.Errorf("find issues: %v", err) - } - - set := make(map[int64]*Issue) - for i := range issues { - set[issues[i].ID] = issues[i] - } - for i := range prs { - prs[i].Issue = set[prs[i].IssueID] - } - return nil -} - -func (prs PullRequestList) getIssueIDs() []int64 { - issueIDs := make([]int64, 0, len(prs)) - for i := range prs { - issueIDs = append(issueIDs, prs[i].IssueID) - } - return issueIDs -} - -// LoadAttributes load all the prs attributes -func (prs PullRequestList) LoadAttributes() error { - return prs.loadAttributes(x) -} - -func (prs PullRequestList) invalidateCodeComments(e Engine, doer *User, repo *git.Repository, branch string) error { - if len(prs) == 0 { - return nil - } - issueIDs := prs.getIssueIDs() - var codeComments []*Comment - if err := e. - Where("type = ? and invalidated = ?", CommentTypeCode, false). - In("issue_id", issueIDs). - Find(&codeComments); err != nil { - return fmt.Errorf("find code comments: %v", err) - } - for _, comment := range codeComments { - if err := comment.CheckInvalidation(repo, doer, branch); err != nil { - return err - } - } - return nil -} - -// InvalidateCodeComments will lookup the prs for code comments which got invalidated by change -func (prs PullRequestList) InvalidateCodeComments(doer *User, repo *git.Repository, branch string) error { - return prs.invalidateCodeComments(x, doer, repo, branch) -} - // checkAndUpdateStatus checks if pull request is possible to leaving checking status, // and set to be either conflict or mergeable. func (pr *PullRequest) checkAndUpdateStatus() { @@ -1152,64 +1002,3 @@ func (pr *PullRequest) GetWorkInProgressPrefix() string { } return "" } - -// TestPullRequests checks and tests untested patches of pull requests. -// TODO: test more pull requests at same time. -func TestPullRequests() { - prs := make([]*PullRequest, 0, 10) - - err := x.Where("status = ?", PullRequestStatusChecking).Find(&prs) - if err != nil { - log.Error("Find Checking PRs: %v", err) - return - } - - var checkedPRs = make(map[int64]struct{}) - - // Update pull request status. - for _, pr := range prs { - checkedPRs[pr.ID] = struct{}{} - if err := pr.GetBaseRepo(); err != nil { - log.Error("GetBaseRepo: %v", err) - continue - } - if pr.manuallyMerged() { - continue - } - if err := pr.testPatch(x); err != nil { - log.Error("testPatch: %v", err) - continue - } - - pr.checkAndUpdateStatus() - } - - // Start listening on new test requests. - for prID := range pullRequestQueue.Queue() { - log.Trace("TestPullRequests[%v]: processing test task", prID) - pullRequestQueue.Remove(prID) - - id := com.StrTo(prID).MustInt64() - if _, ok := checkedPRs[id]; ok { - continue - } - - pr, err := GetPullRequestByID(id) - if err != nil { - log.Error("GetPullRequestByID[%s]: %v", prID, err) - continue - } else if pr.manuallyMerged() { - continue - } else if err = pr.testPatch(x); err != nil { - log.Error("testPatch[%d]: %v", pr.ID, err) - continue - } - - pr.checkAndUpdateStatus() - } -} - -// InitTestPullRequests runs the task to test all the checking status pull requests -func InitTestPullRequests() { - go TestPullRequests() -} diff --git a/models/pull_list.go b/models/pull_list.go new file mode 100644 index 00000000000..4ec6fdde3b5 --- /dev/null +++ b/models/pull_list.go @@ -0,0 +1,224 @@ +// 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 models + +import ( + "fmt" + + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "github.com/unknwon/com" + "xorm.io/xorm" +) + +// PullRequestsOptions holds the options for PRs +type PullRequestsOptions struct { + Page int + State string + SortType string + Labels []string + MilestoneID int64 +} + +func listPullRequestStatement(baseRepoID int64, opts *PullRequestsOptions) (*xorm.Session, error) { + sess := x.Where("pull_request.base_repo_id=?", baseRepoID) + + sess.Join("INNER", "issue", "pull_request.issue_id = issue.id") + switch opts.State { + case "closed", "open": + sess.And("issue.is_closed=?", opts.State == "closed") + } + + if labelIDs, err := base.StringsToInt64s(opts.Labels); err != nil { + return nil, err + } else if len(labelIDs) > 0 { + sess.Join("INNER", "issue_label", "issue.id = issue_label.issue_id"). + In("issue_label.label_id", labelIDs) + } + + if opts.MilestoneID > 0 { + sess.And("issue.milestone_id=?", opts.MilestoneID) + } + + return sess, nil +} + +// GetUnmergedPullRequestsByHeadInfo returns all pull requests that are open and has not been merged +// by given head information (repo and branch). +func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string) ([]*PullRequest, error) { + prs := make([]*PullRequest, 0, 2) + return prs, x. + Where("head_repo_id = ? AND head_branch = ? AND has_merged = ? AND issue.is_closed = ?", + repoID, branch, false, false). + Join("INNER", "issue", "issue.id = pull_request.issue_id"). + Find(&prs) +} + +// GetUnmergedPullRequestsByBaseInfo returns all pull requests that are open and has not been merged +// by given base information (repo and branch). +func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequest, error) { + prs := make([]*PullRequest, 0, 2) + return prs, x. + Where("base_repo_id=? AND base_branch=? AND has_merged=? AND issue.is_closed=?", + repoID, branch, false, false). + Join("INNER", "issue", "issue.id=pull_request.issue_id"). + Find(&prs) +} + +// PullRequests returns all pull requests for a base Repo by the given conditions +func PullRequests(baseRepoID int64, opts *PullRequestsOptions) ([]*PullRequest, int64, error) { + if opts.Page <= 0 { + opts.Page = 1 + } + + countSession, err := listPullRequestStatement(baseRepoID, opts) + if err != nil { + log.Error("listPullRequestStatement: %v", err) + return nil, 0, err + } + maxResults, err := countSession.Count(new(PullRequest)) + if err != nil { + log.Error("Count PRs: %v", err) + return nil, maxResults, err + } + + prs := make([]*PullRequest, 0, ItemsPerPage) + findSession, err := listPullRequestStatement(baseRepoID, opts) + sortIssuesSession(findSession, opts.SortType) + if err != nil { + log.Error("listPullRequestStatement: %v", err) + return nil, maxResults, err + } + findSession.Limit(ItemsPerPage, (opts.Page-1)*ItemsPerPage) + return prs, maxResults, findSession.Find(&prs) +} + +// PullRequestList defines a list of pull requests +type PullRequestList []*PullRequest + +func (prs PullRequestList) loadAttributes(e Engine) error { + if len(prs) == 0 { + return nil + } + + // Load issues. + issueIDs := prs.getIssueIDs() + issues := make([]*Issue, 0, len(issueIDs)) + if err := e. + Where("id > 0"). + In("id", issueIDs). + Find(&issues); err != nil { + return fmt.Errorf("find issues: %v", err) + } + + set := make(map[int64]*Issue) + for i := range issues { + set[issues[i].ID] = issues[i] + } + for i := range prs { + prs[i].Issue = set[prs[i].IssueID] + } + return nil +} + +func (prs PullRequestList) getIssueIDs() []int64 { + issueIDs := make([]int64, 0, len(prs)) + for i := range prs { + issueIDs = append(issueIDs, prs[i].IssueID) + } + return issueIDs +} + +// LoadAttributes load all the prs attributes +func (prs PullRequestList) LoadAttributes() error { + return prs.loadAttributes(x) +} + +func (prs PullRequestList) invalidateCodeComments(e Engine, doer *User, repo *git.Repository, branch string) error { + if len(prs) == 0 { + return nil + } + issueIDs := prs.getIssueIDs() + var codeComments []*Comment + if err := e. + Where("type = ? and invalidated = ?", CommentTypeCode, false). + In("issue_id", issueIDs). + Find(&codeComments); err != nil { + return fmt.Errorf("find code comments: %v", err) + } + for _, comment := range codeComments { + if err := comment.CheckInvalidation(repo, doer, branch); err != nil { + return err + } + } + return nil +} + +// InvalidateCodeComments will lookup the prs for code comments which got invalidated by change +func (prs PullRequestList) InvalidateCodeComments(doer *User, repo *git.Repository, branch string) error { + return prs.invalidateCodeComments(x, doer, repo, branch) +} + +// TestPullRequests checks and tests untested patches of pull requests. +// TODO: test more pull requests at same time. +func TestPullRequests() { + prs := make([]*PullRequest, 0, 10) + + err := x.Where("status = ?", PullRequestStatusChecking).Find(&prs) + if err != nil { + log.Error("Find Checking PRs: %v", err) + return + } + + var checkedPRs = make(map[int64]struct{}) + + // Update pull request status. + for _, pr := range prs { + checkedPRs[pr.ID] = struct{}{} + if err := pr.GetBaseRepo(); err != nil { + log.Error("GetBaseRepo: %v", err) + continue + } + if pr.manuallyMerged() { + continue + } + if err := pr.testPatch(x); err != nil { + log.Error("testPatch: %v", err) + continue + } + + pr.checkAndUpdateStatus() + } + + // Start listening on new test requests. + for prID := range pullRequestQueue.Queue() { + log.Trace("TestPullRequests[%v]: processing test task", prID) + pullRequestQueue.Remove(prID) + + id := com.StrTo(prID).MustInt64() + if _, ok := checkedPRs[id]; ok { + continue + } + + pr, err := GetPullRequestByID(id) + if err != nil { + log.Error("GetPullRequestByID[%s]: %v", prID, err) + continue + } else if pr.manuallyMerged() { + continue + } else if err = pr.testPatch(x); err != nil { + log.Error("testPatch[%d]: %v", pr.ID, err) + continue + } + + pr.checkAndUpdateStatus() + } +} + +// InitTestPullRequests runs the task to test all the checking status pull requests +func InitTestPullRequests() { + go TestPullRequests() +}