diff --git a/models/fixtures/pull_request.yml b/models/fixtures/pull_request.yml index 560674c370..54590fb830 100644 --- a/models/fixtures/pull_request.yml +++ b/models/fixtures/pull_request.yml @@ -9,6 +9,7 @@ head_branch: branch1 base_branch: master merge_base: 4a357436d925b5c974181ff12a994538ddc5a269 + merged_commit_id: 1a8823cd1a9549fde083f992f6b9b87a7ab74fb3 has_merged: true merger_id: 2 diff --git a/models/issues/pull.go b/models/issues/pull.go index 2cb1e1b971..18e6b2776d 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -1093,3 +1093,23 @@ func InsertPullRequests(ctx context.Context, prs ...*PullRequest) error { } return committer.Commit() } + +// GetPullRequestByMergedCommit returns a merged pull request by the given commit +func GetPullRequestByMergedCommit(ctx context.Context, repoID int64, sha string) (*PullRequest, error) { + pr := new(PullRequest) + has, err := db.GetEngine(ctx).Where("base_repo_id = ? AND merged_commit_id = ?", repoID, sha).Get(pr) + if err != nil { + return nil, err + } else if !has { + return nil, ErrPullRequestNotExist{0, 0, 0, repoID, "", ""} + } + + if err = pr.LoadAttributes(ctx); err != nil { + return nil, err + } + if err = pr.LoadIssue(ctx); err != nil { + return nil, err + } + + return pr, nil +} diff --git a/models/issues/pull_test.go b/models/issues/pull_test.go index 173417136c..3a30b2f3de 100644 --- a/models/issues/pull_test.go +++ b/models/issues/pull_test.go @@ -339,6 +339,18 @@ func TestGetApprovers(t *testing.T) { assert.EqualValues(t, expected, approvers) } +func TestGetPullRequestByMergedCommit(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + pr, err := issues_model.GetPullRequestByMergedCommit(db.DefaultContext, 1, "1a8823cd1a9549fde083f992f6b9b87a7ab74fb3") + assert.NoError(t, err) + assert.EqualValues(t, 1, pr.ID) + + _, err = issues_model.GetPullRequestByMergedCommit(db.DefaultContext, 0, "1a8823cd1a9549fde083f992f6b9b87a7ab74fb3") + assert.ErrorAs(t, err, &issues_model.ErrPullRequestNotExist{}) + _, err = issues_model.GetPullRequestByMergedCommit(db.DefaultContext, 1, "") + assert.ErrorAs(t, err, &issues_model.ErrPullRequestNotExist{}) +} + func TestMigrate_InsertPullRequests(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) reponame := "repo1" diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 3fafb96b8e..e7bdef1489 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1235,6 +1235,7 @@ func Routes() *web.Route { m.Group("/{ref}", func() { m.Get("/status", repo.GetCombinedCommitStatusByRef) m.Get("/statuses", repo.GetCommitStatusesByRef) + m.Get("/pull", repo.GetCommitPullRequest) }, context.ReferencesGitRepo()) }, reqRepoReader(unit.TypeCode)) m.Group("/git", func() { diff --git a/routers/api/v1/repo/commits.go b/routers/api/v1/repo/commits.go index 43b6400009..d01cf6b8bc 100644 --- a/routers/api/v1/repo/commits.go +++ b/routers/api/v1/repo/commits.go @@ -10,6 +10,7 @@ import ( "net/http" "strconv" + issues_model "code.gitea.io/gitea/models/issues" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" @@ -323,3 +324,53 @@ func DownloadCommitDiffOrPatch(ctx *context.APIContext) { return } } + +// GetCommitPullRequest returns the pull request of the commit +func GetCommitPullRequest(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/commits/{sha}/pull repository repoGetCommitPullRequest + // --- + // summary: Get the pull request of the commit + // 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: sha + // in: path + // description: SHA of the commit to get + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/PullRequest" + // "404": + // "$ref": "#/responses/notFound" + + pr, err := issues_model.GetPullRequestByMergedCommit(ctx, ctx.Repo.Repository.ID, ctx.Params(":sha")) + if err != nil { + if issues_model.IsErrPullRequestNotExist(err) { + ctx.Error(http.StatusNotFound, "GetPullRequestByMergedCommit", err) + } else { + ctx.Error(http.StatusInternalServerError, "GetPullRequestByIndex", err) + } + return + } + + if err = pr.LoadBaseRepo(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, "LoadBaseRepo", err) + return + } + if err = pr.LoadHeadRepo(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err) + return + } + ctx.JSON(http.StatusOK, convert.ToAPIPullRequest(ctx, pr, ctx.Doer)) +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index d26bed53aa..eaa1448b2b 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -4565,6 +4565,49 @@ } } }, + "/repos/{owner}/{repo}/commits/{sha}/pull": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Get the pull request of the commit", + "operationId": "repoGetCommitPullRequest", + "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": "string", + "description": "SHA of the commit to get", + "name": "sha", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/PullRequest" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/repos/{owner}/{repo}/contents": { "get": { "produces": [