From f7dbd6ddf1bd93532a8a043a0a89a1911b919dce Mon Sep 17 00:00:00 2001 From: JakobDev Date: Mon, 6 Feb 2023 13:07:04 +0100 Subject: [PATCH 1/8] Add API for gitignore templates --- modules/structs/miscellaneous.go | 6 +++ routers/api/v1/api.go | 2 + routers/api/v1/misc/gitignore.go | 55 +++++++++++++++++++++++ routers/api/v1/swagger/misc.go | 14 ++++++ templates/swagger/v1_json.tmpl | 76 ++++++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+) create mode 100644 routers/api/v1/misc/gitignore.go diff --git a/modules/structs/miscellaneous.go b/modules/structs/miscellaneous.go index 596a551e0d48..d0bc68bf79c4 100644 --- a/modules/structs/miscellaneous.go +++ b/modules/structs/miscellaneous.go @@ -44,6 +44,12 @@ type ServerVersion struct { Version string `json:"version"` } +// GitignoreTemplateInfo name and text of a gitignore template +type GitignoreTemplateInfo struct { + Name string `json:"name"` + Source string `json:"source"` +} + // APIError is an api error with a message type APIError struct { Message string `json:"message"` diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 5f57977c290b..8eade087232c 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -713,6 +713,8 @@ func Routes(ctx gocontext.Context) *web.Route { m.Get("/signing-key.gpg", misc.SigningKey) m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown) m.Post("/markdown/raw", misc.MarkdownRaw) + m.Get("/gitignore/templates", misc.ListGitignoresTemplates) + m.Get("/gitignore/templates/{name}", misc.GetGitignoreTemplateInfo) m.Group("/settings", func() { m.Get("/ui", settings.GetGeneralUISettings) m.Get("/api", settings.GetGeneralAPISettings) diff --git a/routers/api/v1/misc/gitignore.go b/routers/api/v1/misc/gitignore.go new file mode 100644 index 000000000000..8be695953f56 --- /dev/null +++ b/routers/api/v1/misc/gitignore.go @@ -0,0 +1,55 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package misc + +import ( + "net/http" + + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/options" + repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/structs" +) + +// Shows a list of all Gitignore templates +func ListGitignoresTemplates(ctx *context.APIContext) { + // swagger:operation GET /gitignore/templates miscellaneous listGitignoresTemplates + // --- + // summary: Returns a list of all gitignore templates + // produces: + // - application/json + // responses: + // "200": + // "$ref": "#/responses/GitignoreTemplateList" + ctx.JSON(http.StatusOK, repo_module.Gitignores) +} + +// SHows information about a gitignore template +func GetGitignoreTemplateInfo(ctx *context.APIContext) { + // swagger:operation GET /gitignore/templates/{name} miscellaneous getGitignoreTemplateInfo + // --- + // summary: Returns information about a gitignore template + // produces: + // - application/json + // parameters: + // - name: name + // in: path + // description: name of the template + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/GitignoreTemplateInfo" + // "404": + // "$ref": "#/responses/notFound" + name := ctx.Params("name") + + text, err := options.Gitignore(name) + if err != nil { + ctx.NotFound() + return + } + + ctx.JSON(http.StatusOK, &structs.GitignoreTemplateInfo{Name: name, Source: string(text[:])}) +} diff --git a/routers/api/v1/swagger/misc.go b/routers/api/v1/swagger/misc.go index a4052a6a763e..4606d8766fa5 100644 --- a/routers/api/v1/swagger/misc.go +++ b/routers/api/v1/swagger/misc.go @@ -14,6 +14,20 @@ type swaggerResponseServerVersion struct { Body api.ServerVersion `json:"body"` } +// GitignoreTemplateList +// swagger:response GitignoreTemplateList +type swaggerResponseGitignoreTemplateList struct { + // in:body + Body []string `json:"body"` +} + +// GitignoreTemplateInfo +// swagger:response GitignoreTemplateInfo +type swaggerResponseGitignoreTemplateInfo struct { + // in:body + Body api.GitignoreTemplateInfo `json:"body"` +} + // StringSlice // swagger:response StringSlice type swaggerResponseStringSlice struct { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 812e626d2d9f..12333d7759a8 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -749,6 +749,52 @@ } } }, + "/gitignore/templates": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "miscellaneous" + ], + "summary": "Returns a list of all gitignore templates", + "operationId": "listGitignoresTemplates", + "responses": { + "200": { + "$ref": "#/responses/GitignoreTemplateList" + } + } + } + }, + "/gitignore/templates/{name}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "miscellaneous" + ], + "summary": "Returns information about a gitignore template", + "operationId": "getGitignoreTemplateInfo", + "parameters": [ + { + "type": "string", + "description": "name of the template", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/GitignoreTemplateInfo" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/markdown": { "post": { "consumes": [ @@ -17286,6 +17332,21 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "GitignoreTemplateInfo": { + "description": "GitignoreTemplateInfo name and text of a gitignore template", + "type": "object", + "properties": { + "name": { + "type": "string", + "x-go-name": "Name" + }, + "source": { + "type": "string", + "x-go-name": "Source" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "Hook": { "description": "Hook a hook is a web hook when one repository changed", "type": "object", @@ -20361,6 +20422,21 @@ "$ref": "#/definitions/GitTreeResponse" } }, + "GitignoreTemplateInfo": { + "description": "GitignoreTemplateInfo", + "schema": { + "$ref": "#/definitions/GitignoreTemplateInfo" + } + }, + "GitignoreTemplateList": { + "description": "GitignoreTemplateList", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, "Hook": { "description": "Hook", "schema": { From 3b9d13c1c5d2f7fd04d2ba36f17b689c0c404a6f Mon Sep 17 00:00:00 2001 From: JakobDev Date: Tue, 7 Feb 2023 12:56:41 +0100 Subject: [PATCH 2/8] Add test --- .../api_gitignore_templates_test.go | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/integration/api_gitignore_templates_test.go diff --git a/tests/integration/api_gitignore_templates_test.go b/tests/integration/api_gitignore_templates_test.go new file mode 100644 index 000000000000..619c140ec4f9 --- /dev/null +++ b/tests/integration/api_gitignore_templates_test.go @@ -0,0 +1,53 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "fmt" + "net/http" + "testing" + + "code.gitea.io/gitea/modules/options" + repo_module "code.gitea.io/gitea/modules/repository" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/tests" + + "github.com/stretchr/testify/assert" +) + +func TestAPIListGitignoresTemplates(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + req := NewRequest(t, "GET", "/api/v1/gitignore/templates") + resp := MakeRequest(t, req, http.StatusOK) + + // This tests if the API returns a list of strings + var gitignoreList []string + DecodeJSON(t, resp, &gitignoreList) +} + +func TestAPIGetGitignoreTemplateInfo(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + // If Gitea has for some reason no Gitignore templates, we need to skip this test + if len(repo_module.Gitignores) == 0 { + return + } + + // Use the first template for the test + templateName := repo_module.Gitignores[0] + + urlStr := fmt.Sprintf("/api/v1/gitignore/templates/%s", templateName) + req := NewRequest(t, "GET", urlStr) + resp := MakeRequest(t, req, http.StatusOK) + + var templateInfo api.GitignoreTemplateInfo + DecodeJSON(t, resp, &templateInfo) + + // We get the text of the template here + text, _ := options.Gitignore(templateName) + + assert.Equal(t, templateInfo.Name, templateName) + assert.Equal(t, templateInfo.Source, string(text[:])) +} From 345e0e67f8c8275024ddeaf87d2b0ebe63308761 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Fri, 10 Feb 2023 08:41:20 +0100 Subject: [PATCH 3/8] Try to fix lint --- routers/api/v1/misc/gitignore.go | 110 +++++++++--------- .../api_gitignore_templates_test.go | 106 ++++++++--------- 2 files changed, 108 insertions(+), 108 deletions(-) diff --git a/routers/api/v1/misc/gitignore.go b/routers/api/v1/misc/gitignore.go index 8be695953f56..374b06fa4a1b 100644 --- a/routers/api/v1/misc/gitignore.go +++ b/routers/api/v1/misc/gitignore.go @@ -1,55 +1,55 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package misc - -import ( - "net/http" - - "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/options" - repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/structs" -) - -// Shows a list of all Gitignore templates -func ListGitignoresTemplates(ctx *context.APIContext) { - // swagger:operation GET /gitignore/templates miscellaneous listGitignoresTemplates - // --- - // summary: Returns a list of all gitignore templates - // produces: - // - application/json - // responses: - // "200": - // "$ref": "#/responses/GitignoreTemplateList" - ctx.JSON(http.StatusOK, repo_module.Gitignores) -} - -// SHows information about a gitignore template -func GetGitignoreTemplateInfo(ctx *context.APIContext) { - // swagger:operation GET /gitignore/templates/{name} miscellaneous getGitignoreTemplateInfo - // --- - // summary: Returns information about a gitignore template - // produces: - // - application/json - // parameters: - // - name: name - // in: path - // description: name of the template - // type: string - // required: true - // responses: - // "200": - // "$ref": "#/responses/GitignoreTemplateInfo" - // "404": - // "$ref": "#/responses/notFound" - name := ctx.Params("name") - - text, err := options.Gitignore(name) - if err != nil { - ctx.NotFound() - return - } - - ctx.JSON(http.StatusOK, &structs.GitignoreTemplateInfo{Name: name, Source: string(text[:])}) -} +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package misc + +import ( + "net/http" + + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/options" + repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/structs" +) + +// Shows a list of all Gitignore templates +func ListGitignoresTemplates(ctx *context.APIContext) { + // swagger:operation GET /gitignore/templates miscellaneous listGitignoresTemplates + // --- + // summary: Returns a list of all gitignore templates + // produces: + // - application/json + // responses: + // "200": + // "$ref": "#/responses/GitignoreTemplateList" + ctx.JSON(http.StatusOK, repo_module.Gitignores) +} + +// SHows information about a gitignore template +func GetGitignoreTemplateInfo(ctx *context.APIContext) { + // swagger:operation GET /gitignore/templates/{name} miscellaneous getGitignoreTemplateInfo + // --- + // summary: Returns information about a gitignore template + // produces: + // - application/json + // parameters: + // - name: name + // in: path + // description: name of the template + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/GitignoreTemplateInfo" + // "404": + // "$ref": "#/responses/notFound" + name := ctx.Params("name") + + text, err := options.Gitignore(name) + if err != nil { + ctx.NotFound() + return + } + + ctx.JSON(http.StatusOK, &structs.GitignoreTemplateInfo{Name: name, Source: string(text[:])}) +} diff --git a/tests/integration/api_gitignore_templates_test.go b/tests/integration/api_gitignore_templates_test.go index 619c140ec4f9..e350ad67c621 100644 --- a/tests/integration/api_gitignore_templates_test.go +++ b/tests/integration/api_gitignore_templates_test.go @@ -1,53 +1,53 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package integration - -import ( - "fmt" - "net/http" - "testing" - - "code.gitea.io/gitea/modules/options" - repo_module "code.gitea.io/gitea/modules/repository" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/tests" - - "github.com/stretchr/testify/assert" -) - -func TestAPIListGitignoresTemplates(t *testing.T) { - defer tests.PrepareTestEnv(t)() - - req := NewRequest(t, "GET", "/api/v1/gitignore/templates") - resp := MakeRequest(t, req, http.StatusOK) - - // This tests if the API returns a list of strings - var gitignoreList []string - DecodeJSON(t, resp, &gitignoreList) -} - -func TestAPIGetGitignoreTemplateInfo(t *testing.T) { - defer tests.PrepareTestEnv(t)() - - // If Gitea has for some reason no Gitignore templates, we need to skip this test - if len(repo_module.Gitignores) == 0 { - return - } - - // Use the first template for the test - templateName := repo_module.Gitignores[0] - - urlStr := fmt.Sprintf("/api/v1/gitignore/templates/%s", templateName) - req := NewRequest(t, "GET", urlStr) - resp := MakeRequest(t, req, http.StatusOK) - - var templateInfo api.GitignoreTemplateInfo - DecodeJSON(t, resp, &templateInfo) - - // We get the text of the template here - text, _ := options.Gitignore(templateName) - - assert.Equal(t, templateInfo.Name, templateName) - assert.Equal(t, templateInfo.Source, string(text[:])) -} +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "fmt" + "net/http" + "testing" + + "code.gitea.io/gitea/modules/options" + repo_module "code.gitea.io/gitea/modules/repository" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/tests" + + "github.com/stretchr/testify/assert" +) + +func TestAPIListGitignoresTemplates(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + req := NewRequest(t, "GET", "/api/v1/gitignore/templates") + resp := MakeRequest(t, req, http.StatusOK) + + // This tests if the API returns a list of strings + var gitignoreList []string + DecodeJSON(t, resp, &gitignoreList) +} + +func TestAPIGetGitignoreTemplateInfo(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + // If Gitea has for some reason no Gitignore templates, we need to skip this test + if len(repo_module.Gitignores) == 0 { + return + } + + // Use the first template for the test + templateName := repo_module.Gitignores[0] + + urlStr := fmt.Sprintf("/api/v1/gitignore/templates/%s", templateName) + req := NewRequest(t, "GET", urlStr) + resp := MakeRequest(t, req, http.StatusOK) + + var templateInfo api.GitignoreTemplateInfo + DecodeJSON(t, resp, &templateInfo) + + // We get the text of the template here + text, _ := options.Gitignore(templateName) + + assert.Equal(t, templateInfo.Name, templateName) + assert.Equal(t, templateInfo.Source, string(text[:])) +} From 9a5273b0464d008bfda21558d17c76923a30e140 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Fri, 10 Feb 2023 09:18:05 +0100 Subject: [PATCH 4/8] Remove [:] --- routers/api/v1/misc/gitignore.go | 2 +- tests/integration/api_gitignore_templates_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/misc/gitignore.go b/routers/api/v1/misc/gitignore.go index 374b06fa4a1b..ecf4f26fcd11 100644 --- a/routers/api/v1/misc/gitignore.go +++ b/routers/api/v1/misc/gitignore.go @@ -51,5 +51,5 @@ func GetGitignoreTemplateInfo(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, &structs.GitignoreTemplateInfo{Name: name, Source: string(text[:])}) + ctx.JSON(http.StatusOK, &structs.GitignoreTemplateInfo{Name: name, Source: string(text)}) } diff --git a/tests/integration/api_gitignore_templates_test.go b/tests/integration/api_gitignore_templates_test.go index e350ad67c621..c58f5eebfeaa 100644 --- a/tests/integration/api_gitignore_templates_test.go +++ b/tests/integration/api_gitignore_templates_test.go @@ -49,5 +49,5 @@ func TestAPIGetGitignoreTemplateInfo(t *testing.T) { text, _ := options.Gitignore(templateName) assert.Equal(t, templateInfo.Name, templateName) - assert.Equal(t, templateInfo.Source, string(text[:])) + assert.Equal(t, templateInfo.Source, string(text)) } From ea5f6ad970f15dc0251f77917d8e43c9670daf37 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Mon, 24 Apr 2023 15:46:36 +0200 Subject: [PATCH 5/8] Use util.PathJoinRelX() --- routers/api/v1/misc/gitignore.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/misc/gitignore.go b/routers/api/v1/misc/gitignore.go index ecf4f26fcd11..1d684f33d234 100644 --- a/routers/api/v1/misc/gitignore.go +++ b/routers/api/v1/misc/gitignore.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/modules/options" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" ) // Shows a list of all Gitignore templates @@ -22,7 +23,13 @@ func ListGitignoresTemplates(ctx *context.APIContext) { // responses: // "200": // "$ref": "#/responses/GitignoreTemplateList" - ctx.JSON(http.StatusOK, repo_module.Gitignores) + gitignoreList := make([]string, len(repo_module.Gitignores)) + + for position, currentGitignore := range repo_module.Gitignores { + gitignoreList[position] = util.PathJoinRelX(currentGitignore) + } + + ctx.JSON(http.StatusOK, gitignoreList) } // SHows information about a gitignore template @@ -43,7 +50,7 @@ func GetGitignoreTemplateInfo(ctx *context.APIContext) { // "$ref": "#/responses/GitignoreTemplateInfo" // "404": // "$ref": "#/responses/notFound" - name := ctx.Params("name") + name := util.PathJoinRelX(ctx.Params("name")) text, err := options.Gitignore(name) if err != nil { From 4eea78d6795b68d16c4d655993c042501168845d Mon Sep 17 00:00:00 2001 From: JakobDev Date: Mon, 24 Apr 2023 16:28:05 +0200 Subject: [PATCH 6/8] Don't use util.PathJoinRelX() with built-in data --- routers/api/v1/misc/gitignore.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/routers/api/v1/misc/gitignore.go b/routers/api/v1/misc/gitignore.go index 1d684f33d234..7c7fe4b125fa 100644 --- a/routers/api/v1/misc/gitignore.go +++ b/routers/api/v1/misc/gitignore.go @@ -23,13 +23,7 @@ func ListGitignoresTemplates(ctx *context.APIContext) { // responses: // "200": // "$ref": "#/responses/GitignoreTemplateList" - gitignoreList := make([]string, len(repo_module.Gitignores)) - - for position, currentGitignore := range repo_module.Gitignores { - gitignoreList[position] = util.PathJoinRelX(currentGitignore) - } - - ctx.JSON(http.StatusOK, gitignoreList) + ctx.JSON(http.StatusOK, repo_module.Gitignores) } // SHows information about a gitignore template From dca83ce4aea3c2399fd8fceb60e76c38e3ec7ac4 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Tue, 25 Apr 2023 08:07:49 +0200 Subject: [PATCH 7/8] Run make generate-swagger --- templates/swagger/v1_json.tmpl | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 09e8bb8902a7..af112ba8d6ba 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -883,33 +883,6 @@ } } }, - "/amdin/hooks/{id}": { - "delete": { - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "Delete a hook", - "operationId": "adminDeleteHook", - "parameters": [ - { - "type": "integer", - "format": "int64", - "description": "id of the hook to delete", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "$ref": "#/responses/empty" - } - } - } - }, "/gitignore/templates": { "get": { "produces": [ From 2c43d730575edf91b90aa2611438058bbf4c023b Mon Sep 17 00:00:00 2001 From: JakobDev Date: Wed, 26 Apr 2023 15:49:07 +0200 Subject: [PATCH 8/8] Run make generate-swagger --- templates/swagger/v1_json.tmpl | 64 +++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 5a01fb693eea..6f3a441a3de6 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -884,7 +884,6 @@ } }, "/gitignore/templates": { - "/licenses": { "get": { "produces": [ "application/json" @@ -897,6 +896,47 @@ "responses": { "200": { "$ref": "#/responses/GitignoreTemplateList" + } + } + } + }, + "/gitignore/templates/{name}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "miscellaneous" + ], + "summary": "Returns information about a gitignore template", + "operationId": "getGitignoreTemplateInfo", + "parameters": [ + { + "type": "string", + "description": "name of the template", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/GitignoreTemplateInfo" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, + "/licenses": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "miscellaneous" + ], "summary": "Returns a list of all license templates", "operationId": "listLicenseTemplates", "responses": { @@ -906,6 +946,28 @@ } } }, + "/licenses/{name}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "miscellaneous" + ], + "summary": "Returns information about a license template", + "operationId": "getLicenseTemplateInfo", + "parameters": [ + { + "type": "string", + "description": "name of the license", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/LicenseTemplateInfo" }, "404": { "$ref": "#/responses/notFound"