Add API to get merged PR of a commit (#29243)

Adds a new API `/repos/{owner}/{repo}/commits/{sha}/pull` that allows
you to get the merged PR associated to a commit.

---------

Co-authored-by: 6543 <6543@obermui.de>
(cherry picked from commit 0a426cc575734e5eff410d6a790f40473117f753)
This commit is contained in:
qwerty287 2024-02-24 09:18:39 +01:00 committed by Earl Warren
parent f0acc71ba1
commit 1608ef0ce9
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG key ID: 0579CB2928A78A00
6 changed files with 128 additions and 0 deletions

View file

@ -9,6 +9,7 @@
head_branch: branch1 head_branch: branch1
base_branch: master base_branch: master
merge_base: 4a357436d925b5c974181ff12a994538ddc5a269 merge_base: 4a357436d925b5c974181ff12a994538ddc5a269
merged_commit_id: 1a8823cd1a9549fde083f992f6b9b87a7ab74fb3
has_merged: true has_merged: true
merger_id: 2 merger_id: 2

View file

@ -1122,3 +1122,23 @@ func InsertPullRequests(ctx context.Context, prs ...*PullRequest) error {
} }
return committer.Commit() 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
}

View file

@ -425,6 +425,18 @@ func TestGetApprovers(t *testing.T) {
assert.EqualValues(t, expected, approvers) 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) { func TestMigrate_InsertPullRequests(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())
reponame := "repo1" reponame := "repo1"

View file

@ -1300,6 +1300,7 @@ func Routes() *web.Route {
m.Group("/{ref}", func() { m.Group("/{ref}", func() {
m.Get("/status", repo.GetCombinedCommitStatusByRef) m.Get("/status", repo.GetCombinedCommitStatusByRef)
m.Get("/statuses", repo.GetCommitStatusesByRef) m.Get("/statuses", repo.GetCommitStatusesByRef)
m.Get("/pull", repo.GetCommitPullRequest)
}, context.ReferencesGitRepo()) }, context.ReferencesGitRepo())
}, reqRepoReader(unit.TypeCode)) }, reqRepoReader(unit.TypeCode))
m.Group("/git", func() { m.Group("/git", func() {

View file

@ -10,6 +10,7 @@ import (
"net/http" "net/http"
"strconv" "strconv"
issues_model "code.gitea.io/gitea/models/issues"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
@ -323,3 +324,53 @@ func DownloadCommitDiffOrPatch(ctx *context.APIContext) {
return 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))
}

View file

@ -4686,6 +4686,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": { "/repos/{owner}/{repo}/contents": {
"get": { "get": {
"produces": [ "produces": [