Skip to content

Commit fb37eef

Browse files
authored
Add API for License templates (#23009)
This adds a API for getting License templates. This tries to be as close to the [GitHub API](https://docs.github.com/en/rest/licenses?apiVersion=2022-11-28) as possible, but Gitea does not support all features that GitHub has. I think they should been added, but this out f the scope of this PR. You should merge #23006 before this PR for security reasons.
1 parent 4d5c803 commit fb37eef

File tree

6 files changed

+270
-0
lines changed

6 files changed

+270
-0
lines changed

modules/structs/miscellaneous.go

+16
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ type ServerVersion struct {
7272
Version string `json:"version"`
7373
}
7474

75+
// LicensesListEntry is used for the API
76+
type LicensesTemplateListEntry struct {
77+
Key string `json:"key"`
78+
Name string `json:"name"`
79+
URL string `json:"url"`
80+
}
81+
82+
// LicensesInfo contains information about a License
83+
type LicenseTemplateInfo struct {
84+
Key string `json:"key"`
85+
Name string `json:"name"`
86+
URL string `json:"url"`
87+
Implementation string `json:"implementation"`
88+
Body string `json:"body"`
89+
}
90+
7591
// APIError is an api error with a message
7692
type APIError struct {
7793
Message string `json:"message"`

routers/api/v1/api.go

+2
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,8 @@ func Routes(ctx gocontext.Context) *web.Route {
719719
m.Post("/markup", bind(api.MarkupOption{}), misc.Markup)
720720
m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown)
721721
m.Post("/markdown/raw", misc.MarkdownRaw)
722+
m.Get("/licenses", misc.ListLicenseTemplates)
723+
m.Get("/licenses/{name}", misc.GetLicenseTemplateInfo)
722724
m.Group("/settings", func() {
723725
m.Get("/ui", settings.GetGeneralUISettings)
724726
m.Get("/api", settings.GetGeneralAPISettings)

routers/api/v1/misc/licenses.go

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package misc
5+
6+
import (
7+
"fmt"
8+
"net/http"
9+
"net/url"
10+
11+
"code.gitea.io/gitea/modules/context"
12+
"code.gitea.io/gitea/modules/options"
13+
repo_module "code.gitea.io/gitea/modules/repository"
14+
"code.gitea.io/gitea/modules/setting"
15+
api "code.gitea.io/gitea/modules/structs"
16+
"code.gitea.io/gitea/modules/util"
17+
)
18+
19+
// Returns a list of all License templates
20+
func ListLicenseTemplates(ctx *context.APIContext) {
21+
// swagger:operation GET /licenses miscellaneous listLicenseTemplates
22+
// ---
23+
// summary: Returns a list of all license templates
24+
// produces:
25+
// - application/json
26+
// responses:
27+
// "200":
28+
// "$ref": "#/responses/LicenseTemplateList"
29+
response := make([]api.LicensesTemplateListEntry, len(repo_module.Licenses))
30+
for i, license := range repo_module.Licenses {
31+
response[i] = api.LicensesTemplateListEntry{
32+
Key: license,
33+
Name: license,
34+
URL: fmt.Sprintf("%sapi/v1/licenses/%s", setting.AppURL, url.PathEscape(license)),
35+
}
36+
}
37+
ctx.JSON(http.StatusOK, response)
38+
}
39+
40+
// Returns information about a gitignore template
41+
func GetLicenseTemplateInfo(ctx *context.APIContext) {
42+
// swagger:operation GET /licenses/{name} miscellaneous getLicenseTemplateInfo
43+
// ---
44+
// summary: Returns information about a license template
45+
// produces:
46+
// - application/json
47+
// parameters:
48+
// - name: name
49+
// in: path
50+
// description: name of the license
51+
// type: string
52+
// required: true
53+
// responses:
54+
// "200":
55+
// "$ref": "#/responses/LicenseTemplateInfo"
56+
// "404":
57+
// "$ref": "#/responses/notFound"
58+
name := util.PathJoinRelX(ctx.Params("name"))
59+
60+
text, err := options.License(name)
61+
if err != nil {
62+
ctx.NotFound()
63+
return
64+
}
65+
66+
response := api.LicenseTemplateInfo{
67+
Key: name,
68+
Name: name,
69+
URL: fmt.Sprintf("%sapi/v1/licenses/%s", setting.AppURL, url.PathEscape(name)),
70+
Body: string(text),
71+
// This is for combatibilty with the GitHub API. This Text is for some reason added to each License response.
72+
Implementation: "Create a text file (typically named LICENSE or LICENSE.txt) in the root of your source code and copy the text of the license into the file",
73+
}
74+
75+
ctx.JSON(http.StatusOK, response)
76+
}

routers/api/v1/swagger/misc.go

+14
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@ type swaggerResponseServerVersion struct {
1414
Body api.ServerVersion `json:"body"`
1515
}
1616

17+
// LicenseTemplateList
18+
// swagger:response LicenseTemplateList
19+
type swaggerResponseLicensesTemplateList struct {
20+
// in:body
21+
Body []api.LicensesTemplateListEntry `json:"body"`
22+
}
23+
24+
// LicenseTemplateInfo
25+
// swagger:response LicenseTemplateInfo
26+
type swaggerResponseLicenseTemplateInfo struct {
27+
// in:body
28+
Body api.LicenseTemplateInfo `json:"body"`
29+
}
30+
1731
// StringSlice
1832
// swagger:response StringSlice
1933
type swaggerResponseStringSlice struct {

templates/swagger/v1_json.tmpl

+107
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package integration
5+
6+
import (
7+
"fmt"
8+
"net/http"
9+
"net/url"
10+
"testing"
11+
12+
"code.gitea.io/gitea/modules/options"
13+
repo_module "code.gitea.io/gitea/modules/repository"
14+
api "code.gitea.io/gitea/modules/structs"
15+
"code.gitea.io/gitea/tests"
16+
17+
"github.com/stretchr/testify/assert"
18+
)
19+
20+
func TestAPIListLicenseTemplates(t *testing.T) {
21+
defer tests.PrepareTestEnv(t)()
22+
23+
req := NewRequest(t, "GET", "/api/v1/licenses")
24+
resp := MakeRequest(t, req, http.StatusOK)
25+
26+
// This tests if the API returns a list of strings
27+
var licenseList []api.LicensesTemplateListEntry
28+
DecodeJSON(t, resp, &licenseList)
29+
}
30+
31+
func TestAPIGetLicenseTemplateInfo(t *testing.T) {
32+
defer tests.PrepareTestEnv(t)()
33+
34+
// If Gitea has for some reason no License templates, we need to skip this test
35+
if len(repo_module.Licenses) == 0 {
36+
return
37+
}
38+
39+
// Use the first template for the test
40+
licenseName := repo_module.Licenses[0]
41+
42+
urlStr := fmt.Sprintf("/api/v1/licenses/%s", url.PathEscape(licenseName))
43+
req := NewRequest(t, "GET", urlStr)
44+
resp := MakeRequest(t, req, http.StatusOK)
45+
46+
var licenseInfo api.LicenseTemplateInfo
47+
DecodeJSON(t, resp, &licenseInfo)
48+
49+
// We get the text of the template here
50+
text, _ := options.License(licenseName)
51+
52+
assert.Equal(t, licenseInfo.Key, licenseName)
53+
assert.Equal(t, licenseInfo.Name, licenseName)
54+
assert.Equal(t, licenseInfo.Body, string(text))
55+
}

0 commit comments

Comments
 (0)