summaryrefslogtreecommitdiffstats
path: root/services/convert/pull.go
diff options
context:
space:
mode:
Diffstat (limited to 'services/convert/pull.go')
-rw-r--r--services/convert/pull.go261
1 files changed, 261 insertions, 0 deletions
diff --git a/services/convert/pull.go b/services/convert/pull.go
new file mode 100644
index 0000000..4ec24a8
--- /dev/null
+++ b/services/convert/pull.go
@@ -0,0 +1,261 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package convert
+
+import (
+ "context"
+ "fmt"
+
+ issues_model "code.gitea.io/gitea/models/issues"
+ "code.gitea.io/gitea/models/perm"
+ access_model "code.gitea.io/gitea/models/perm/access"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/cache"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/modules/log"
+ api "code.gitea.io/gitea/modules/structs"
+)
+
+// ToAPIPullRequest assumes following fields have been assigned with valid values:
+// Required - Issue
+// Optional - Merger
+func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User) *api.PullRequest {
+ var (
+ baseBranch *git.Branch
+ headBranch *git.Branch
+ baseCommit *git.Commit
+ err error
+ )
+
+ if err = pr.Issue.LoadRepo(ctx); err != nil {
+ log.Error("pr.Issue.LoadRepo[%d]: %v", pr.ID, err)
+ return nil
+ }
+
+ apiIssue := ToAPIIssue(ctx, doer, pr.Issue)
+ if err := pr.LoadBaseRepo(ctx); err != nil {
+ log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
+ return nil
+ }
+
+ if err := pr.LoadHeadRepo(ctx); err != nil {
+ log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
+ return nil
+ }
+
+ var doerID int64
+ if doer != nil {
+ doerID = doer.ID
+ }
+
+ const repoDoerPermCacheKey = "repo_doer_perm_cache"
+ p, err := cache.GetWithContextCache(ctx, repoDoerPermCacheKey, fmt.Sprintf("%d_%d", pr.BaseRepoID, doerID),
+ func() (access_model.Permission, error) {
+ return access_model.GetUserRepoPermission(ctx, pr.BaseRepo, doer)
+ })
+ if err != nil {
+ log.Error("GetUserRepoPermission[%d]: %v", pr.BaseRepoID, err)
+ p.AccessMode = perm.AccessModeNone
+ }
+
+ apiPullRequest := &api.PullRequest{
+ ID: pr.ID,
+ URL: pr.Issue.HTMLURL(),
+ Index: pr.Index,
+ Poster: apiIssue.Poster,
+ Title: apiIssue.Title,
+ Body: apiIssue.Body,
+ Labels: apiIssue.Labels,
+ Milestone: apiIssue.Milestone,
+ Assignee: apiIssue.Assignee,
+ Assignees: apiIssue.Assignees,
+ State: apiIssue.State,
+ Draft: pr.IsWorkInProgress(ctx),
+ IsLocked: apiIssue.IsLocked,
+ Comments: apiIssue.Comments,
+ ReviewComments: pr.GetReviewCommentsCount(ctx),
+ HTMLURL: pr.Issue.HTMLURL(),
+ DiffURL: pr.Issue.DiffURL(),
+ PatchURL: pr.Issue.PatchURL(),
+ HasMerged: pr.HasMerged,
+ MergeBase: pr.MergeBase,
+ Mergeable: pr.Mergeable(ctx),
+ Deadline: apiIssue.Deadline,
+ Created: pr.Issue.CreatedUnix.AsTimePtr(),
+ Updated: pr.Issue.UpdatedUnix.AsTimePtr(),
+ PinOrder: apiIssue.PinOrder,
+
+ AllowMaintainerEdit: pr.AllowMaintainerEdit,
+
+ Base: &api.PRBranchInfo{
+ Name: pr.BaseBranch,
+ Ref: pr.BaseBranch,
+ RepoID: pr.BaseRepoID,
+ Repository: ToRepo(ctx, pr.BaseRepo, p),
+ },
+ Head: &api.PRBranchInfo{
+ Name: pr.HeadBranch,
+ Ref: fmt.Sprintf("%s%d/head", git.PullPrefix, pr.Index),
+ RepoID: -1,
+ },
+ }
+
+ if err = pr.LoadRequestedReviewers(ctx); err != nil {
+ log.Error("LoadRequestedReviewers[%d]: %v", pr.ID, err)
+ return nil
+ }
+ if err = pr.LoadRequestedReviewersTeams(ctx); err != nil {
+ log.Error("LoadRequestedReviewersTeams[%d]: %v", pr.ID, err)
+ return nil
+ }
+
+ for _, reviewer := range pr.RequestedReviewers {
+ apiPullRequest.RequestedReviewers = append(apiPullRequest.RequestedReviewers, ToUser(ctx, reviewer, nil))
+ }
+
+ for _, reviewerTeam := range pr.RequestedReviewersTeams {
+ convertedTeam, err := ToTeam(ctx, reviewerTeam, true)
+ if err != nil {
+ log.Error("LoadRequestedReviewersTeams[%d]: %v", pr.ID, err)
+ return nil
+ }
+
+ apiPullRequest.RequestedReviewersTeams = append(apiPullRequest.RequestedReviewersTeams, convertedTeam)
+ }
+
+ if pr.Issue.ClosedUnix != 0 {
+ apiPullRequest.Closed = pr.Issue.ClosedUnix.AsTimePtr()
+ }
+
+ gitRepo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo)
+ if err != nil {
+ log.Error("OpenRepository[%s]: %v", pr.BaseRepo.RepoPath(), err)
+ return nil
+ }
+ defer gitRepo.Close()
+
+ baseBranch, err = gitRepo.GetBranch(pr.BaseBranch)
+ if err != nil && !git.IsErrBranchNotExist(err) {
+ log.Error("GetBranch[%s]: %v", pr.BaseBranch, err)
+ return nil
+ }
+
+ if err == nil {
+ baseCommit, err = baseBranch.GetCommit()
+ if err != nil && !git.IsErrNotExist(err) {
+ log.Error("GetCommit[%s]: %v", baseBranch.Name, err)
+ return nil
+ }
+
+ if err == nil {
+ apiPullRequest.Base.Sha = baseCommit.ID.String()
+ }
+ }
+
+ if pr.Flow == issues_model.PullRequestFlowAGit {
+ gitRepo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo)
+ if err != nil {
+ log.Error("OpenRepository[%s]: %v", pr.GetGitRefName(), err)
+ return nil
+ }
+ defer gitRepo.Close()
+
+ apiPullRequest.Head.Sha, err = gitRepo.GetRefCommitID(pr.GetGitRefName())
+ if err != nil {
+ log.Error("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
+ return nil
+ }
+ apiPullRequest.Head.RepoID = pr.BaseRepoID
+ apiPullRequest.Head.Repository = apiPullRequest.Base.Repository
+ apiPullRequest.Head.Name = ""
+ }
+
+ if pr.HeadRepo != nil && pr.Flow == issues_model.PullRequestFlowGithub {
+ p, err := access_model.GetUserRepoPermission(ctx, pr.HeadRepo, doer)
+ if err != nil {
+ log.Error("GetUserRepoPermission[%d]: %v", pr.HeadRepoID, err)
+ p.AccessMode = perm.AccessModeNone
+ }
+
+ apiPullRequest.Head.RepoID = pr.HeadRepo.ID
+ apiPullRequest.Head.Repository = ToRepo(ctx, pr.HeadRepo, p)
+
+ headGitRepo, err := gitrepo.OpenRepository(ctx, pr.HeadRepo)
+ if err != nil {
+ log.Error("OpenRepository[%s]: %v", pr.HeadRepo.RepoPath(), err)
+ return nil
+ }
+ defer headGitRepo.Close()
+
+ headBranch, err = headGitRepo.GetBranch(pr.HeadBranch)
+ if err != nil && !git.IsErrBranchNotExist(err) {
+ log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
+ return nil
+ }
+
+ // Outer scope variables to be used in diff calculation
+ var (
+ startCommitID string
+ endCommitID string
+ )
+
+ if git.IsErrBranchNotExist(err) {
+ headCommitID, err := headGitRepo.GetRefCommitID(apiPullRequest.Head.Ref)
+ if err != nil && !git.IsErrNotExist(err) {
+ log.Error("GetCommit[%s]: %v", pr.HeadBranch, err)
+ return nil
+ }
+ if err == nil {
+ apiPullRequest.Head.Sha = headCommitID
+ endCommitID = headCommitID
+ }
+ } else {
+ commit, err := headBranch.GetCommit()
+ if err != nil && !git.IsErrNotExist(err) {
+ log.Error("GetCommit[%s]: %v", headBranch.Name, err)
+ return nil
+ }
+ if err == nil {
+ apiPullRequest.Head.Ref = pr.HeadBranch
+ apiPullRequest.Head.Sha = commit.ID.String()
+ endCommitID = commit.ID.String()
+ }
+ }
+
+ // Calculate diff
+ startCommitID = pr.MergeBase
+
+ apiPullRequest.ChangedFiles, apiPullRequest.Additions, apiPullRequest.Deletions, err = gitRepo.GetDiffShortStat(startCommitID, endCommitID)
+ if err != nil {
+ log.Error("GetDiffShortStat: %v", err)
+ }
+ }
+
+ if len(apiPullRequest.Head.Sha) == 0 && len(apiPullRequest.Head.Ref) != 0 {
+ baseGitRepo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo)
+ if err != nil {
+ log.Error("OpenRepository[%s]: %v", pr.BaseRepo.RepoPath(), err)
+ return nil
+ }
+ defer baseGitRepo.Close()
+ refs, err := baseGitRepo.GetRefsFiltered(apiPullRequest.Head.Ref)
+ if err != nil {
+ log.Error("GetRefsFiltered[%s]: %v", apiPullRequest.Head.Ref, err)
+ return nil
+ } else if len(refs) == 0 {
+ log.Error("unable to resolve PR head ref")
+ } else {
+ apiPullRequest.Head.Sha = refs[0].Object.String()
+ }
+ }
+
+ if pr.HasMerged {
+ apiPullRequest.Merged = pr.MergedUnix.AsTimePtr()
+ apiPullRequest.MergedCommitID = &pr.MergedCommitID
+ apiPullRequest.MergedBy = ToUser(ctx, pr.Merger, nil)
+ }
+
+ return apiPullRequest
+}