]> source.dussan.org Git - gitea.git/commitdiff
Add API to get commits of PR (#16300)
authorsebastian-sauer <sauer.sebastian@gmail.com>
Fri, 2 Jul 2021 12:19:57 +0000 (14:19 +0200)
committerGitHub <noreply@github.com>
Fri, 2 Jul 2021 12:19:57 +0000 (14:19 +0200)
* Add API to get commits of PR

fixes #10918

Co-authored-by: Andrew Bezold <andrew.bezold@gmail.com>
Co-authored-by: 6543 <6543@obermui.de>
integrations/api_pull_commits_test.go [new file with mode: 0644]
routers/api/v1/api.go
routers/api/v1/repo/pull.go
templates/swagger/v1_json.tmpl

diff --git a/integrations/api_pull_commits_test.go b/integrations/api_pull_commits_test.go
new file mode 100644 (file)
index 0000000..30682d9
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2021 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 integrations
+
+import (
+       "net/http"
+       "testing"
+
+       "code.gitea.io/gitea/models"
+       api "code.gitea.io/gitea/modules/structs"
+       "github.com/stretchr/testify/assert"
+)
+
+func TestAPIPullCommits(t *testing.T) {
+       defer prepareTestEnv(t)()
+       pullIssue := models.AssertExistsAndLoadBean(t, &models.PullRequest{ID: 2}).(*models.PullRequest)
+       assert.NoError(t, pullIssue.LoadIssue())
+       repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: pullIssue.HeadRepoID}).(*models.Repository)
+
+       session := loginUser(t, "user2")
+       req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/commits", repo.OwnerName, repo.Name, pullIssue.Index)
+       resp := session.MakeRequest(t, req, http.StatusOK)
+
+       var commits []*api.Commit
+       DecodeJSON(t, resp, &commits)
+
+       if !assert.Len(t, commits, 2) {
+               return
+       }
+
+       assert.Equal(t, "5f22f7d0d95d614d25a5b68592adb345a4b5c7fd", commits[0].SHA)
+       assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", commits[1].SHA)
+}
+
+// TODO add tests for already merged PR and closed PR
index c6b4ff04dec9dbf49e2815d03ac95fb73dfaa635..b6913ea1bc783d739f41fd67e942a020f66faa2c 100644 (file)
@@ -905,6 +905,7 @@ func Routes() *web.Route {
                                                m.Get(".diff", repo.DownloadPullDiff)
                                                m.Get(".patch", repo.DownloadPullPatch)
                                                m.Post("/update", reqToken(), repo.UpdatePullRequest)
+                                               m.Get("/commits", repo.GetPullRequestCommits)
                                                m.Combo("/merge").Get(repo.IsPullRequestMerged).
                                                        Post(reqToken(), mustNotBeArchived, bind(forms.MergePullRequestForm{}), repo.MergePullRequest)
                                                m.Group("/reviews", func() {
index eff998ee996a18a8ec7e2d107f6085cbdf840c2d..0c09a9a86b0ee12306c359ee8305f1f3fb938983 100644 (file)
@@ -6,7 +6,9 @@ package repo
 
 import (
        "fmt"
+       "math"
        "net/http"
+       "strconv"
        "strings"
        "time"
 
@@ -1101,3 +1103,122 @@ func UpdatePullRequest(ctx *context.APIContext) {
 
        ctx.Status(http.StatusOK)
 }
+
+// GetPullRequestCommits gets all commits associated with a given PR
+func GetPullRequestCommits(ctx *context.APIContext) {
+       // swagger:operation GET /repos/{owner}/{repo}/pulls/{index}/commits repository repoGetPullRequestCommits
+       // ---
+       // summary: Get commits for a pull request
+       // produces:
+       // - application/json
+       // parameters:
+       // - name: owner
+       //   in: path
+       //   description: owner of the repo
+       //   type: string
+       //   required: true
+       // - name: repo
+       //   in: path
+       //   description: name of the repo
+       //   type: string
+       //   required: true
+       // - name: index
+       //   in: path
+       //   description: index of the pull request to get
+       //   type: integer
+       //   format: int64
+       //   required: true
+       // - name: page
+       //   in: query
+       //   description: page number of results to return (1-based)
+       //   type: integer
+       // - name: limit
+       //   in: query
+       //   description: page size of results
+       //   type: integer
+       // responses:
+       //   "200":
+       //     "$ref": "#/responses/CommitList"
+       //   "404":
+       //     "$ref": "#/responses/notFound"
+
+       pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
+       if err != nil {
+               if models.IsErrPullRequestNotExist(err) {
+                       ctx.NotFound()
+               } else {
+                       ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err)
+               }
+               return
+       }
+
+       if err := pr.LoadBaseRepo(); err != nil {
+               ctx.InternalServerError(err)
+               return
+       }
+
+       var prInfo *git.CompareInfo
+       baseGitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
+       if err != nil {
+               ctx.ServerError("OpenRepository", err)
+               return
+       }
+       defer baseGitRepo.Close()
+       if pr.HasMerged {
+               prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName())
+       } else {
+               prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName())
+       }
+       if err != nil {
+               ctx.ServerError("GetCompareInfo", err)
+               return
+       }
+       commits := prInfo.Commits
+
+       listOptions := utils.GetListOptions(ctx)
+
+       totalNumberOfCommits := commits.Len()
+       totalNumberOfPages := int(math.Ceil(float64(totalNumberOfCommits) / float64(listOptions.PageSize)))
+
+       userCache := make(map[string]*models.User)
+
+       start, end := listOptions.GetStartEnd()
+
+       if end > totalNumberOfCommits {
+               end = totalNumberOfCommits
+       }
+
+       apiCommits := make([]*api.Commit, end-start)
+
+       i := 0
+       addedCommitsCount := 0
+       for commitPointer := commits.Front(); commitPointer != nil; commitPointer = commitPointer.Next() {
+               if i < start {
+                       i++
+                       continue
+               }
+               if i >= end {
+                       break
+               }
+
+               commit := commitPointer.Value.(*git.Commit)
+
+               // Create json struct
+               apiCommits[addedCommitsCount], err = convert.ToCommit(ctx.Repo.Repository, commit, userCache)
+               addedCommitsCount++
+               if err != nil {
+                       ctx.ServerError("toCommit", err)
+                       return
+               }
+               i++
+       }
+
+       ctx.SetLinkHeader(int(totalNumberOfCommits), listOptions.PageSize)
+
+       ctx.Header().Set("X-Page", strconv.Itoa(listOptions.Page))
+       ctx.Header().Set("X-PerPage", strconv.Itoa(listOptions.PageSize))
+       ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", totalNumberOfCommits))
+       ctx.Header().Set("X-PageCount", strconv.Itoa(totalNumberOfPages))
+       ctx.Header().Set("X-HasMore", strconv.FormatBool(listOptions.Page < totalNumberOfPages))
+       ctx.JSON(http.StatusOK, &apiCommits)
+}
index dfd08bcc68f8ad64eadc745e685262d3f45f7315..a2e449228e1a61ceeb6f1d25645edb565b0dff0d 100644 (file)
         }
       }
     },
+    "/repos/{owner}/{repo}/pulls/{index}/commits": {
+      "get": {
+        "produces": [
+          "application/json"
+        ],
+        "tags": [
+          "repository"
+        ],
+        "summary": "Get commits for a pull request",
+        "operationId": "repoGetPullRequestCommits",
+        "parameters": [
+          {
+            "type": "string",
+            "description": "owner of the repo",
+            "name": "owner",
+            "in": "path",
+            "required": true
+          },
+          {
+            "type": "string",
+            "description": "name of the repo",
+            "name": "repo",
+            "in": "path",
+            "required": true
+          },
+          {
+            "type": "integer",
+            "format": "int64",
+            "description": "index of the pull request to get",
+            "name": "index",
+            "in": "path",
+            "required": true
+          },
+          {
+            "type": "integer",
+            "description": "page number of results to return (1-based)",
+            "name": "page",
+            "in": "query"
+          },
+          {
+            "type": "integer",
+            "description": "page size of results",
+            "name": "limit",
+            "in": "query"
+          }
+        ],
+        "responses": {
+          "200": {
+            "$ref": "#/responses/CommitList"
+          },
+          "404": {
+            "$ref": "#/responses/notFound"
+          }
+        }
+      }
+    },
     "/repos/{owner}/{repo}/pulls/{index}/merge": {
       "get": {
         "produces": [