From f761a37a0f024ea54c4eee9cbae22377616e84e0 Mon Sep 17 00:00:00 2001 From: zeripath Date: Fri, 5 Jun 2020 12:03:12 +0100 Subject: [PATCH] Provide diff and patch API endpoints (#11751) * Provide diff and patch API endpoints The diff and patch endpoints on the main routes are not accessible by token therefore we provide new API based endpoints for these Fix #10923 Signed-off-by: Andrew Thornton * placate swagger Signed-off-by: Andrew Thornton * Make the response an actual string Signed-off-by: Andrew Thornton Co-authored-by: techknowlogick Co-authored-by: Lauris BH --- modules/context/api.go | 4 ++ routers/api/v1/api.go | 2 + routers/api/v1/repo/pull.go | 82 +++++++++++++++++++++++++++++ templates/swagger/v1_json.tmpl | 94 ++++++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+) diff --git a/modules/context/api.go b/modules/context/api.go index 5d91ac49a..acecf8f26 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -65,6 +65,10 @@ type APINotFound struct{} // swagger:response redirect type APIRedirect struct{} +//APIString is a string response +// swagger:response string +type APIString string + // Error responds with an error message to client with given obj as the message. // If status is 500, also it prints error to log. func (ctx *APIContext) Error(status int, title string, obj interface{}) { diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 0f8a0326e..1ae4e7a58 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -796,6 +796,8 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/:index", func() { m.Combo("").Get(repo.GetPullRequest). Patch(reqToken(), reqRepoWriter(models.UnitTypePullRequests), bind(api.EditPullRequestOption{}), repo.EditPullRequest) + m.Get(".diff", repo.DownloadPullDiff) + m.Get(".patch", repo.DownloadPullPatch) m.Combo("/merge").Get(repo.IsPullRequestMerged). Post(reqToken(), mustNotBeArchived, bind(auth.MergePullRequestForm{}), repo.MergePullRequest) m.Group("/reviews", func() { diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index bddf4e48f..284c23162 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -169,6 +169,88 @@ func GetPullRequest(ctx *context.APIContext) { ctx.JSON(http.StatusOK, convert.ToAPIPullRequest(pr)) } +// DownloadPullDiff render a pull's raw diff +func DownloadPullDiff(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/pulls/{index}.diff repository repoDownloadPullDiff + // --- + // summary: Get a pull request diff + // produces: + // - text/plain + // 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 + // responses: + // "200": + // "$ref": "#/responses/string" + // "404": + // "$ref": "#/responses/notFound" + DownloadPullDiffOrPatch(ctx, false) +} + +// DownloadPullPatch render a pull's raw patch +func DownloadPullPatch(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/pulls/{index}.patch repository repoDownloadPullPatch + // --- + // summary: Get a pull request patch file + // produces: + // - text/plain + // 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 + // responses: + // "200": + // "$ref": "#/responses/string" + // "404": + // "$ref": "#/responses/notFound" + DownloadPullDiffOrPatch(ctx, true) +} + +// DownloadPullDiffOrPatch render a pull's raw diff or patch +func DownloadPullDiffOrPatch(ctx *context.APIContext, patch bool) { + pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + if err != nil { + if models.IsErrPullRequestNotExist(err) { + ctx.NotFound() + } else { + ctx.InternalServerError(err) + } + return + } + + if err := pull_service.DownloadDiffOrPatch(pr, ctx, patch); err != nil { + ctx.InternalServerError(err) + return + } +} + // CreatePullRequest does what it says func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption) { // swagger:operation POST /repos/{owner}/{repo}/pulls repository repoCreatePullRequest diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 687a6bc5e..d90fafd75 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -6649,6 +6649,94 @@ } } }, + "/repos/{owner}/{repo}/pulls/{index}.diff": { + "get": { + "produces": [ + "text/plain" + ], + "tags": [ + "repository" + ], + "summary": "Get a pull request diff", + "operationId": "repoDownloadPullDiff", + "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 + } + ], + "responses": { + "200": { + "$ref": "#/responses/string" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, + "/repos/{owner}/{repo}/pulls/{index}.patch": { + "get": { + "produces": [ + "text/plain" + ], + "tags": [ + "repository" + ], + "summary": "Get a pull request patch file", + "operationId": "repoDownloadPullPatch", + "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 + } + ], + "responses": { + "200": { + "$ref": "#/responses/string" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/repos/{owner}/{repo}/pulls/{index}/merge": { "get": { "produces": [ @@ -15209,6 +15297,12 @@ "redirect": { "description": "APIRedirect is a redirect response" }, + "string": { + "description": "APIString is a string response", + "schema": { + "type": "string" + } + }, "validationError": { "description": "APIValidationError is error format response related to input validation", "headers": {