From 38d263f000781478e1fe91963b939e01e831d1cd Mon Sep 17 00:00:00 2001 From: JakobDev Date: Tue, 9 May 2023 10:59:30 +0200 Subject: [PATCH 1/3] Add API for Label templates --- modules/structs/issue_label.go | 10 +++ routers/api/v1/api.go | 2 + routers/api/v1/misc/label_templates.go | 60 +++++++++++++ routers/api/v1/swagger/misc.go | 14 +++ services/convert/issue.go | 22 +++++ templates/swagger/v1_json.tmpl | 89 +++++++++++++++++++ tests/integration/api_label_templates_test.go | 61 +++++++++++++ 7 files changed, 258 insertions(+) create mode 100644 routers/api/v1/misc/label_templates.go create mode 100644 tests/integration/api_label_templates_test.go diff --git a/modules/structs/issue_label.go b/modules/structs/issue_label.go index 5bb6cc3b845b5..2610d3e93f187 100644 --- a/modules/structs/issue_label.go +++ b/modules/structs/issue_label.go @@ -44,3 +44,13 @@ type IssueLabelsOption struct { // list of label IDs Labels []int64 `json:"labels"` } + +// LabelTemplate info of a Label template +type LabelTemplate struct { + Name string `json:"name"` + // example: false + Exclusive bool `json:"exclusive"` + // example: 00aabb + Color string `json:"color"` + Description string `json:"description"` +} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index a67a5420ac66e..2e51198cd8c02 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -723,6 +723,8 @@ func Routes(ctx gocontext.Context) *web.Route { m.Get("/gitignore/templates/{name}", misc.GetGitignoreTemplateInfo) m.Get("/licenses", misc.ListLicenseTemplates) m.Get("/licenses/{name}", misc.GetLicenseTemplateInfo) + m.Get("/label_templates", misc.ListLabelTemplates) + m.Get("/label_templates/{name}", misc.GetLabelTemplate) m.Group("/settings", func() { m.Get("/ui", settings.GetGeneralUISettings) m.Get("/api", settings.GetGeneralAPISettings) diff --git a/routers/api/v1/misc/label_templates.go b/routers/api/v1/misc/label_templates.go new file mode 100644 index 0000000000000..2bdcd9572361e --- /dev/null +++ b/routers/api/v1/misc/label_templates.go @@ -0,0 +1,60 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package misc + +import ( + "net/http" + + "code.gitea.io/gitea/modules/context" + repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/convert" +) + +// Shows a list of all Label templates +func ListLabelTemplates(ctx *context.APIContext) { + // swagger:operation GET /label_templates miscellaneous listLabelTemplates + // --- + // summary: Returns a list of all label templates + // produces: + // - application/json + // responses: + // "200": + // "$ref": "#/responses/LabelTemplateList" + result := make([]string, len(repo_module.LabelTemplateFiles)) + for i := range repo_module.LabelTemplateFiles { + result[i] = repo_module.LabelTemplateFiles[i].DisplayName + } + + ctx.JSON(http.StatusOK, result) +} + +// Shows all labels in a template +func GetLabelTemplate(ctx *context.APIContext) { + // swagger:operation GET /label_templates/{name} miscellaneous getLabelTemplateInfo + // --- + // summary: Returns all labels in a template + // produces: + // - application/json + // parameters: + // - name: name + // in: path + // description: name of the template + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/LabelTemplateInfo" + // "404": + // "$ref": "#/responses/notFound" + name := util.PathJoinRelX(ctx.Params("name")) + + labels, err := repo_module.LoadTemplateLabelsByDisplayName(name) + if err != nil { + ctx.NotFound() + return + } + + ctx.JSON(http.StatusOK, convert.ToLabelTemplateList(labels)) +} diff --git a/routers/api/v1/swagger/misc.go b/routers/api/v1/swagger/misc.go index 5778b659b52be..df8a813dfb664 100644 --- a/routers/api/v1/swagger/misc.go +++ b/routers/api/v1/swagger/misc.go @@ -48,3 +48,17 @@ type swaggerResponseStringSlice struct { // in:body Body []string `json:"body"` } + +// LabelTemplateList +// swagger:response LabelTemplateList +type swaggerResponseLabelTemplateList struct { + // in:body + Body []string `json:"body"` +} + +// LabelTemplateInfo +// swagger:response LabelTemplateInfo +type swaggerResponseLabelTemplateInfo struct { + // in:body + Body []api.LabelTemplate `json:"body"` +} diff --git a/services/convert/issue.go b/services/convert/issue.go index 6d31a123bd9fc..3d1b21c6bf860 100644 --- a/services/convert/issue.go +++ b/services/convert/issue.go @@ -13,6 +13,7 @@ import ( issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/label" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" @@ -238,3 +239,24 @@ func ToAPIMilestone(m *issues_model.Milestone) *api.Milestone { } return apiMilestone } + +// ToLabelTemplate converts Label to API format +func ToLabelTemplate(label *label.Label) *api.LabelTemplate { + result := &api.LabelTemplate{ + Name: label.Name, + Exclusive: label.Exclusive, + Color: strings.TrimLeft(label.Color, "#"), + Description: label.Description, + } + + return result +} + +// ToLabelTemplateList converts list of Label to API format +func ToLabelTemplateList(labels []*label.Label) []*api.LabelTemplate { + result := make([]*api.LabelTemplate, len(labels)) + for i := range labels { + result[i] = ToLabelTemplate(labels[i]) + } + return result +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 99c49fec9cd31..57364b70e2592 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -929,6 +929,52 @@ } } }, + "/label_templates": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "miscellaneous" + ], + "summary": "Returns a list of all label templates", + "operationId": "listLabelTemplates", + "responses": { + "200": { + "$ref": "#/responses/LabelTemplateList" + } + } + } + }, + "/label_templates/{name}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "miscellaneous" + ], + "summary": "Returns all labels in a template", + "operationId": "getLabelTemplateInfo", + "parameters": [ + { + "type": "string", + "description": "name of the template", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/LabelTemplateInfo" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/licenses": { "get": { "produces": [ @@ -18831,6 +18877,31 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "LabelTemplate": { + "description": "LabelTemplate info of a Label template", + "type": "object", + "properties": { + "color": { + "type": "string", + "x-go-name": "Color", + "example": "00aabb" + }, + "description": { + "type": "string", + "x-go-name": "Description" + }, + "exclusive": { + "type": "boolean", + "x-go-name": "Exclusive", + "example": false + }, + "name": { + "type": "string", + "x-go-name": "Name" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "LicenseTemplateInfo": { "description": "LicensesInfo contains information about a License", "type": "object", @@ -21770,6 +21841,24 @@ } } }, + "LabelTemplateInfo": { + "description": "LabelTemplateInfo", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/LabelTemplate" + } + } + }, + "LabelTemplateList": { + "description": "LabelTemplateList", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, "LanguageStatistics": { "description": "LanguageStatistics", "schema": { diff --git a/tests/integration/api_label_templates_test.go b/tests/integration/api_label_templates_test.go new file mode 100644 index 0000000000000..90386b398449f --- /dev/null +++ b/tests/integration/api_label_templates_test.go @@ -0,0 +1,61 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "fmt" + "net/http" + "net/url" + "strings" + "testing" + + 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 TestAPIListLabelTemplates(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + req := NewRequest(t, "GET", "/api/v1/label_templates") + resp := MakeRequest(t, req, http.StatusOK) + + var templateList []string + DecodeJSON(t, resp, &templateList) + + for i := range repo_module.LabelTemplateFiles { + assert.Equal(t, repo_module.LabelTemplateFiles[i].DisplayName, templateList[i]) + } +} + +func TestAPIGetLabelTemplateInfo(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + // If Gitea has for some reason no Label templates, we need to skip this test + if len(repo_module.LabelTemplateFiles) == 0 { + return + } + + // Use the first template for the test + templateName := repo_module.LabelTemplateFiles[0].DisplayName + + urlStr := fmt.Sprintf("/api/v1/label_templates/%s", url.PathEscape(templateName)) + req := NewRequest(t, "GET", urlStr) + resp := MakeRequest(t, req, http.StatusOK) + + var templateInfo []api.LabelTemplate + DecodeJSON(t, resp, &templateInfo) + + labels, err := repo_module.LoadTemplateLabelsByDisplayName(templateName) + assert.NoError(t, err) + + for i := range labels { + assert.Equal(t, strings.TrimLeft(labels[i].Color, "#"), templateInfo[i].Color) + assert.Equal(t, labels[i].Description, templateInfo[i].Description) + assert.Equal(t, labels[i].Exclusive, templateInfo[i].Exclusive) + assert.Equal(t, labels[i].Name, templateInfo[i].Name) + } +} From 36cecc2c0d9eac8714712fb02416c915aa10ecd1 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Tue, 23 May 2023 09:58:57 +0200 Subject: [PATCH 2/3] Change to /label/templates --- routers/api/v1/api.go | 4 ++-- routers/api/v1/misc/label_templates.go | 4 ++-- templates/swagger/v1_json.tmpl | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 299227fe6fb3f..53c58c4b9b6fe 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -723,8 +723,8 @@ func Routes(ctx gocontext.Context) *web.Route { m.Get("/gitignore/templates/{name}", misc.GetGitignoreTemplateInfo) m.Get("/licenses", misc.ListLicenseTemplates) m.Get("/licenses/{name}", misc.GetLicenseTemplateInfo) - m.Get("/label_templates", misc.ListLabelTemplates) - m.Get("/label_templates/{name}", misc.GetLabelTemplate) + m.Get("/label/templates", misc.ListLabelTemplates) + m.Get("/label/templates/{name}", misc.GetLabelTemplate) m.Group("/settings", func() { m.Get("/ui", settings.GetGeneralUISettings) m.Get("/api", settings.GetGeneralAPISettings) diff --git a/routers/api/v1/misc/label_templates.go b/routers/api/v1/misc/label_templates.go index 2bdcd9572361e..0e0ca39fc5d46 100644 --- a/routers/api/v1/misc/label_templates.go +++ b/routers/api/v1/misc/label_templates.go @@ -14,7 +14,7 @@ import ( // Shows a list of all Label templates func ListLabelTemplates(ctx *context.APIContext) { - // swagger:operation GET /label_templates miscellaneous listLabelTemplates + // swagger:operation GET /label/templates miscellaneous listLabelTemplates // --- // summary: Returns a list of all label templates // produces: @@ -32,7 +32,7 @@ func ListLabelTemplates(ctx *context.APIContext) { // Shows all labels in a template func GetLabelTemplate(ctx *context.APIContext) { - // swagger:operation GET /label_templates/{name} miscellaneous getLabelTemplateInfo + // swagger:operation GET /label/templates/{name} miscellaneous getLabelTemplateInfo // --- // summary: Returns all labels in a template // produces: diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 4a9af5d9d3d85..15402ecdfd8ff 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -929,7 +929,7 @@ } } }, - "/label_templates": { + "/label/templates": { "get": { "produces": [ "application/json" @@ -946,7 +946,7 @@ } } }, - "/label_templates/{name}": { + "/label/templates/{name}": { "get": { "produces": [ "application/json" From 8b9f5c9af69b1bf3a5d0d4d028480f1375f5a99d Mon Sep 17 00:00:00 2001 From: JakobDev Date: Tue, 23 May 2023 10:27:19 +0200 Subject: [PATCH 3/3] Update tests --- tests/integration/api_label_templates_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/api_label_templates_test.go b/tests/integration/api_label_templates_test.go index 90386b398449f..007e9790113e0 100644 --- a/tests/integration/api_label_templates_test.go +++ b/tests/integration/api_label_templates_test.go @@ -20,7 +20,7 @@ import ( func TestAPIListLabelTemplates(t *testing.T) { defer tests.PrepareTestEnv(t)() - req := NewRequest(t, "GET", "/api/v1/label_templates") + req := NewRequest(t, "GET", "/api/v1/label/templates") resp := MakeRequest(t, req, http.StatusOK) var templateList []string @@ -42,7 +42,7 @@ func TestAPIGetLabelTemplateInfo(t *testing.T) { // Use the first template for the test templateName := repo_module.LabelTemplateFiles[0].DisplayName - urlStr := fmt.Sprintf("/api/v1/label_templates/%s", url.PathEscape(templateName)) + urlStr := fmt.Sprintf("/api/v1/label/templates/%s", url.PathEscape(templateName)) req := NewRequest(t, "GET", urlStr) resp := MakeRequest(t, req, http.StatusOK)