Skip to content

Commit

Permalink
Add API for License templates (#23009)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
JakobDev committed Apr 26, 2023
1 parent 4d5c803 commit fb37eef
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 0 deletions.
16 changes: 16 additions & 0 deletions modules/structs/miscellaneous.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ type ServerVersion struct {
Version string `json:"version"`
}

// LicensesListEntry is used for the API
type LicensesTemplateListEntry struct {
Key string `json:"key"`
Name string `json:"name"`
URL string `json:"url"`
}

// LicensesInfo contains information about a License
type LicenseTemplateInfo struct {
Key string `json:"key"`
Name string `json:"name"`
URL string `json:"url"`
Implementation string `json:"implementation"`
Body string `json:"body"`
}

// APIError is an api error with a message
type APIError struct {
Message string `json:"message"`
Expand Down
2 changes: 2 additions & 0 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,8 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Post("/markup", bind(api.MarkupOption{}), misc.Markup)
m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown)
m.Post("/markdown/raw", misc.MarkdownRaw)
m.Get("/licenses", misc.ListLicenseTemplates)
m.Get("/licenses/{name}", misc.GetLicenseTemplateInfo)
m.Group("/settings", func() {
m.Get("/ui", settings.GetGeneralUISettings)
m.Get("/api", settings.GetGeneralAPISettings)
Expand Down
76 changes: 76 additions & 0 deletions routers/api/v1/misc/licenses.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package misc

import (
"fmt"
"net/http"
"net/url"

"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/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
)

// Returns a list of all License templates
func ListLicenseTemplates(ctx *context.APIContext) {
// swagger:operation GET /licenses miscellaneous listLicenseTemplates
// ---
// summary: Returns a list of all license templates
// produces:
// - application/json
// responses:
// "200":
// "$ref": "#/responses/LicenseTemplateList"
response := make([]api.LicensesTemplateListEntry, len(repo_module.Licenses))
for i, license := range repo_module.Licenses {
response[i] = api.LicensesTemplateListEntry{
Key: license,
Name: license,
URL: fmt.Sprintf("%sapi/v1/licenses/%s", setting.AppURL, url.PathEscape(license)),
}
}
ctx.JSON(http.StatusOK, response)
}

// Returns information about a gitignore template
func GetLicenseTemplateInfo(ctx *context.APIContext) {
// swagger:operation GET /licenses/{name} miscellaneous getLicenseTemplateInfo
// ---
// summary: Returns information about a license template
// produces:
// - application/json
// parameters:
// - name: name
// in: path
// description: name of the license
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/LicenseTemplateInfo"
// "404":
// "$ref": "#/responses/notFound"
name := util.PathJoinRelX(ctx.Params("name"))

text, err := options.License(name)
if err != nil {
ctx.NotFound()
return
}

response := api.LicenseTemplateInfo{
Key: name,
Name: name,
URL: fmt.Sprintf("%sapi/v1/licenses/%s", setting.AppURL, url.PathEscape(name)),
Body: string(text),
// This is for combatibilty with the GitHub API. This Text is for some reason added to each License response.
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",
}

ctx.JSON(http.StatusOK, response)
}
14 changes: 14 additions & 0 deletions routers/api/v1/swagger/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@ type swaggerResponseServerVersion struct {
Body api.ServerVersion `json:"body"`
}

// LicenseTemplateList
// swagger:response LicenseTemplateList
type swaggerResponseLicensesTemplateList struct {
// in:body
Body []api.LicensesTemplateListEntry `json:"body"`
}

// LicenseTemplateInfo
// swagger:response LicenseTemplateInfo
type swaggerResponseLicenseTemplateInfo struct {
// in:body
Body api.LicenseTemplateInfo `json:"body"`
}

// StringSlice
// swagger:response StringSlice
type swaggerResponseStringSlice struct {
Expand Down
107 changes: 107 additions & 0 deletions templates/swagger/v1_json.tmpl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 55 additions & 0 deletions tests/integration/api_license_templates_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package integration

import (
"fmt"
"net/http"
"net/url"
"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 TestAPIListLicenseTemplates(t *testing.T) {
defer tests.PrepareTestEnv(t)()

req := NewRequest(t, "GET", "/api/v1/licenses")
resp := MakeRequest(t, req, http.StatusOK)

// This tests if the API returns a list of strings
var licenseList []api.LicensesTemplateListEntry
DecodeJSON(t, resp, &licenseList)
}

func TestAPIGetLicenseTemplateInfo(t *testing.T) {
defer tests.PrepareTestEnv(t)()

// If Gitea has for some reason no License templates, we need to skip this test
if len(repo_module.Licenses) == 0 {
return
}

// Use the first template for the test
licenseName := repo_module.Licenses[0]

urlStr := fmt.Sprintf("/api/v1/licenses/%s", url.PathEscape(licenseName))
req := NewRequest(t, "GET", urlStr)
resp := MakeRequest(t, req, http.StatusOK)

var licenseInfo api.LicenseTemplateInfo
DecodeJSON(t, resp, &licenseInfo)

// We get the text of the template here
text, _ := options.License(licenseName)

assert.Equal(t, licenseInfo.Key, licenseName)
assert.Equal(t, licenseInfo.Name, licenseName)
assert.Equal(t, licenseInfo.Body, string(text))
}

0 comments on commit fb37eef

Please sign in to comment.