[API] Forgejo API /api/forgejo/v1
(cherry picked from commit20b5669269
) (cherry picked from commit1574643a6a
) Update semantic version according to specification (cherry picked from commit22510f4130
) Mise à jour de 'Makefile' (cherry picked from commitc3d85d8409
) (cherry picked from commit5ea2309851
) (cherry picked from commitec5217b9d1
) (cherry picked from commit14f08e364b
) (cherry picked from commitb4465c67b8
) [API] [SEMVER] replace number with version (cherry picked from commitfba48e6497
) (cherry picked from commit532ec5d878
) [API] [SEMVER] [v1.20] less is replaced by css (cherry picked from commit01ca3a4f42
) (cherry picked from commit1d928c3ab2
) (cherry picked from commita39dc804cd
) Conflicts: webpack.config.js (cherry picked from commitadc68578b3
) (cherry picked from commit9b8d98475f
) (cherry picked from commit2516103974
) (cherry picked from commit18e6287963
) (cherry picked from commite9694e67ab
) (cherry picked from commita9763edaf0
) (cherry picked from commite2b550f4fb
) (cherry picked from commit2edac36701
) [API] Forgejo API /api/forgejo/v1 (squash) Update semver as v1.20 is entering release candidate mode (cherry picked from commit4995098ec3
) (cherry picked from commit578ccfdd27
) (cherry picked from commit1bf6ac0952
) (cherry picked from commit2fe16b2bfe
) (cherry picked from commit7cd9d027ee
) (cherry picked from commiteaed4be2ae
) (cherry picked from commitcc94f3115f
) (cherry picked from commitd7a77e35cc
) (cherry picked from commitcd8eb68ab7
) (cherry picked from commit68487ac95f
) (cherry picked from commit616dceb565
) (cherry picked from commit545fe5975b
) (cherry picked from commitc042cf8eda
) (cherry picked from commitae5e5a7468
) (cherry picked from commit8034ef5fa2
) (cherry picked from commitaaf0293034
) (cherry picked from commitdaafa8ce58
) (cherry picked from commit7ca3681d3e
)
This commit is contained in:
parent
085b400b15
commit
e8ebceafc4
14 changed files with 398 additions and 2 deletions
32
Makefile
32
Makefile
|
@ -88,7 +88,10 @@ else
|
||||||
endif
|
endif
|
||||||
VERSION = ${GITEA_VERSION}
|
VERSION = ${GITEA_VERSION}
|
||||||
|
|
||||||
LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
|
# SemVer
|
||||||
|
FORGEJO_VERSION := 5.0.0+0-gitea-1.20.0
|
||||||
|
|
||||||
|
LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)" -X "code.gitea.io/gitea/routers/api/forgejo/v1.ForgejoVersion=$(FORGEJO_VERSION)"
|
||||||
|
|
||||||
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64
|
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64
|
||||||
|
|
||||||
|
@ -140,6 +143,8 @@ ifdef DEPS_PLAYWRIGHT
|
||||||
PLAYWRIGHT_FLAGS += --with-deps
|
PLAYWRIGHT_FLAGS += --with-deps
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
FORGEJO_API_SPEC := public/forgejo/api.v1.yml
|
||||||
|
|
||||||
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
|
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
|
||||||
SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|g
|
SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|g
|
||||||
SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|"basePath": "/api/v1"|g
|
SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|"basePath": "/api/v1"|g
|
||||||
|
@ -220,6 +225,8 @@ help:
|
||||||
@echo " - generate-license update license files"
|
@echo " - generate-license update license files"
|
||||||
@echo " - generate-gitignore update gitignore files"
|
@echo " - generate-gitignore update gitignore files"
|
||||||
@echo " - generate-manpage generate manpage"
|
@echo " - generate-manpage generate manpage"
|
||||||
|
@echo " - generate-forgejo-api generate the forgejo API from spec"
|
||||||
|
@echo " - forgejo-api-validate check if the forgejo API matches the specs"
|
||||||
@echo " - generate-swagger generate the swagger spec from code comments"
|
@echo " - generate-swagger generate the swagger spec from code comments"
|
||||||
@echo " - swagger-validate check if the swagger spec is valid"
|
@echo " - swagger-validate check if the swagger spec is valid"
|
||||||
@echo " - go-licenses regenerate go licenses"
|
@echo " - go-licenses regenerate go licenses"
|
||||||
|
@ -305,6 +312,27 @@ ifneq "$(TAGS)" "$(shell cat $(TAGS_EVIDENCE) 2>/dev/null)"
|
||||||
TAGS_PREREQ := $(TAGS_EVIDENCE)
|
TAGS_PREREQ := $(TAGS_EVIDENCE)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
OAPI_CODEGEN_PACKAGE ?= github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.12.4
|
||||||
|
KIN_OPENAPI_CODEGEN_PACKAGE ?= github.com/getkin/kin-openapi/cmd/validate@v0.114.0
|
||||||
|
FORGEJO_API_SERVER = routers/api/forgejo/v1/generated.go
|
||||||
|
|
||||||
|
.PHONY: generate-forgejo-api
|
||||||
|
generate-forgejo-api: $(FORGEJO_API_SPEC)
|
||||||
|
$(GO) run $(OAPI_CODEGEN_PACKAGE) -package v1 -generate chi-server,types $< > $(FORGEJO_API_SERVER)
|
||||||
|
|
||||||
|
.PHONY: forgejo-api-check
|
||||||
|
forgejo-api-check: generate-forgejo-api
|
||||||
|
@diff=$$(git diff $(FORGEJO_API_SERVER) ; \
|
||||||
|
if [ -n "$$diff" ]; then \
|
||||||
|
echo "Please run 'make generate-forgejo-api' and commit the result:"; \
|
||||||
|
echo "$${diff}"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
.PHONY: forgejo-api-validate
|
||||||
|
forgejo-api-validate:
|
||||||
|
$(GO) run $(KIN_OPENAPI_CODEGEN_PACKAGE) $(FORGEJO_API_SPEC)
|
||||||
|
|
||||||
.PHONY: generate-swagger
|
.PHONY: generate-swagger
|
||||||
generate-swagger: $(SWAGGER_SPEC)
|
generate-swagger: $(SWAGGER_SPEC)
|
||||||
|
|
||||||
|
@ -335,7 +363,7 @@ checks: checks-frontend checks-backend
|
||||||
checks-frontend: lockfile-check svg-check
|
checks-frontend: lockfile-check svg-check
|
||||||
|
|
||||||
.PHONY: checks-backend
|
.PHONY: checks-backend
|
||||||
checks-backend: tidy-check swagger-check fmt-check misspell-check swagger-validate security-check
|
checks-backend: tidy-check swagger-check fmt-check misspell-check forgejo-api-validate swagger-validate security-check
|
||||||
|
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
lint: lint-frontend lint-backend
|
lint: lint-frontend lint-backend
|
||||||
|
|
40
public/forgejo/api.v1.yml
Normal file
40
public/forgejo/api.v1.yml
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
openapi: 3.0.0
|
||||||
|
info:
|
||||||
|
title: Forgejo API
|
||||||
|
description: |-
|
||||||
|
Forgejo REST API
|
||||||
|
|
||||||
|
contact:
|
||||||
|
email: contact@forgejo.org
|
||||||
|
license:
|
||||||
|
name: MIT
|
||||||
|
url: https://codeberg.org/forgejo/forgejo/src/branch/forgejo/LICENSE
|
||||||
|
version: 1.0.0
|
||||||
|
externalDocs:
|
||||||
|
description: Find out more about Forgejo
|
||||||
|
url: http://forgejo.org
|
||||||
|
servers:
|
||||||
|
- url: /api/forgejo/v1
|
||||||
|
paths:
|
||||||
|
/version:
|
||||||
|
get:
|
||||||
|
summary: API version
|
||||||
|
description: Semantic version of the Forgejo API
|
||||||
|
operationId: getVersion
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: successful operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Version'
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
Version:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
version:
|
||||||
|
type: string
|
||||||
|
|
16
routers/api/forgejo/v1/api.go
Normal file
16
routers/api/forgejo/v1/api.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2023 The Forgejo Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.gitea.io/gitea/modules/web"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Routes() *web.Route {
|
||||||
|
m := web.NewRoute()
|
||||||
|
forgejo := NewForgejo()
|
||||||
|
m.Get("", Root)
|
||||||
|
m.Get("/version", forgejo.GetVersion)
|
||||||
|
return m
|
||||||
|
}
|
24
routers/api/forgejo/v1/forgejo.go
Normal file
24
routers/api/forgejo/v1/forgejo.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Forgejo struct{}
|
||||||
|
|
||||||
|
var _ ServerInterface = &Forgejo{}
|
||||||
|
|
||||||
|
func NewForgejo() *Forgejo {
|
||||||
|
return &Forgejo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ForgejoVersion = "development"
|
||||||
|
|
||||||
|
func (f *Forgejo) GetVersion(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_ = json.NewEncoder(w).Encode(Version{&ForgejoVersion})
|
||||||
|
}
|
167
routers/api/forgejo/v1/generated.go
Normal file
167
routers/api/forgejo/v1/generated.go
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
// Package v1 provides primitives to interact with the openapi HTTP API.
|
||||||
|
//
|
||||||
|
// Code generated by github.com/deepmap/oapi-codegen version v1.12.4 DO NOT EDIT.
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Version defines model for Version.
|
||||||
|
type Version struct {
|
||||||
|
Version *string `json:"version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerInterface represents all server handlers.
|
||||||
|
type ServerInterface interface {
|
||||||
|
// API version
|
||||||
|
// (GET /version)
|
||||||
|
GetVersion(w http.ResponseWriter, r *http.Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerInterfaceWrapper converts contexts to parameters.
|
||||||
|
type ServerInterfaceWrapper struct {
|
||||||
|
Handler ServerInterface
|
||||||
|
HandlerMiddlewares []MiddlewareFunc
|
||||||
|
ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type MiddlewareFunc func(http.Handler) http.Handler
|
||||||
|
|
||||||
|
// GetVersion operation middleware
|
||||||
|
func (siw *ServerInterfaceWrapper) GetVersion(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
siw.Handler.GetVersion(w, r)
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, middleware := range siw.HandlerMiddlewares {
|
||||||
|
handler = middleware(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnescapedCookieParamError struct {
|
||||||
|
ParamName string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnescapedCookieParamError) Error() string {
|
||||||
|
return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnescapedCookieParamError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnmarshallingParamError struct {
|
||||||
|
ParamName string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnmarshallingParamError) Error() string {
|
||||||
|
return fmt.Sprintf("Error unmarshalling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnmarshallingParamError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
type RequiredParamError struct {
|
||||||
|
ParamName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RequiredParamError) Error() string {
|
||||||
|
return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RequiredHeaderError struct {
|
||||||
|
ParamName string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RequiredHeaderError) Error() string {
|
||||||
|
return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RequiredHeaderError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
type InvalidParamFormatError struct {
|
||||||
|
ParamName string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidParamFormatError) Error() string {
|
||||||
|
return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidParamFormatError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
type TooManyValuesForParamError struct {
|
||||||
|
ParamName string
|
||||||
|
Count int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *TooManyValuesForParamError) Error() string {
|
||||||
|
return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler creates http.Handler with routing matching OpenAPI spec.
|
||||||
|
func Handler(si ServerInterface) http.Handler {
|
||||||
|
return HandlerWithOptions(si, ChiServerOptions{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChiServerOptions struct {
|
||||||
|
BaseURL string
|
||||||
|
BaseRouter chi.Router
|
||||||
|
Middlewares []MiddlewareFunc
|
||||||
|
ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
|
||||||
|
func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
|
||||||
|
return HandlerWithOptions(si, ChiServerOptions{
|
||||||
|
BaseRouter: r,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
|
||||||
|
return HandlerWithOptions(si, ChiServerOptions{
|
||||||
|
BaseURL: baseURL,
|
||||||
|
BaseRouter: r,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerWithOptions creates http.Handler with additional options
|
||||||
|
func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
|
||||||
|
r := options.BaseRouter
|
||||||
|
|
||||||
|
if r == nil {
|
||||||
|
r = chi.NewRouter()
|
||||||
|
}
|
||||||
|
if options.ErrorHandlerFunc == nil {
|
||||||
|
options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wrapper := ServerInterfaceWrapper{
|
||||||
|
Handler: si,
|
||||||
|
HandlerMiddlewares: options.Middlewares,
|
||||||
|
ErrorHandlerFunc: options.ErrorHandlerFunc,
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Group(func(r chi.Router) {
|
||||||
|
r.Get(options.BaseURL+"/version", wrapper.GetVersion)
|
||||||
|
})
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
14
routers/api/forgejo/v1/root.go
Normal file
14
routers/api/forgejo/v1/root.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright The Forgejo Authors.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Root(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// https://www.rfc-editor.org/rfc/rfc8631
|
||||||
|
w.Header().Set("Link", "</assets/forgejo/api.v1.yml>; rel=\"service-desc\"")
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/translation"
|
"code.gitea.io/gitea/modules/translation"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
actions_router "code.gitea.io/gitea/routers/api/actions"
|
actions_router "code.gitea.io/gitea/routers/api/actions"
|
||||||
|
forgejo "code.gitea.io/gitea/routers/api/forgejo/v1"
|
||||||
packages_router "code.gitea.io/gitea/routers/api/packages"
|
packages_router "code.gitea.io/gitea/routers/api/packages"
|
||||||
apiv1 "code.gitea.io/gitea/routers/api/v1"
|
apiv1 "code.gitea.io/gitea/routers/api/v1"
|
||||||
"code.gitea.io/gitea/routers/common"
|
"code.gitea.io/gitea/routers/common"
|
||||||
|
@ -175,6 +176,7 @@ func NormalRoutes() *web.Route {
|
||||||
|
|
||||||
r.Mount("/", web_routers.Routes())
|
r.Mount("/", web_routers.Routes())
|
||||||
r.Mount("/api/v1", apiv1.Routes())
|
r.Mount("/api/v1", apiv1.Routes())
|
||||||
|
r.Mount("/api/forgejo/v1", forgejo.Routes())
|
||||||
r.Mount("/api/internal", private.Routes())
|
r.Mount("/api/internal", private.Routes())
|
||||||
|
|
||||||
r.Post("/-/fetch-redirect", common.FetchRedirectDelegate)
|
r.Post("/-/fetch-redirect", common.FetchRedirectDelegate)
|
||||||
|
|
19
routers/web/misc/swagger-forgejo.go
Normal file
19
routers/web/misc/swagger-forgejo.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package misc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// tplSwagger swagger page template
|
||||||
|
const tplForgejoSwagger base.TplName = "swagger/forgejo-ui"
|
||||||
|
|
||||||
|
func SwaggerForgejo(ctx *context.Context) {
|
||||||
|
ctx.Data["APIVersion"] = "v1"
|
||||||
|
ctx.HTML(http.StatusOK, tplForgejoSwagger)
|
||||||
|
}
|
|
@ -261,6 +261,7 @@ func Routes() *web.Route {
|
||||||
if setting.API.EnableSwagger {
|
if setting.API.EnableSwagger {
|
||||||
// Note: The route is here but no in API routes because it renders a web page
|
// Note: The route is here but no in API routes because it renders a web page
|
||||||
routes.Get("/api/swagger", append(mid, misc.Swagger)...) // Render V1 by default
|
routes.Get("/api/swagger", append(mid, misc.Swagger)...) // Render V1 by default
|
||||||
|
routes.Get("/api/forgejo/swagger", append(mid, misc.SwaggerForgejo)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: These really seem like things that could be folded into Contexter or as helper functions
|
// TODO: These really seem like things that could be folded into Contexter or as helper functions
|
||||||
|
|
13
templates/swagger/forgejo-ui.tmpl
Normal file
13
templates/swagger/forgejo-ui.tmpl
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Forgejo API</title>
|
||||||
|
<link href="{{AssetUrlPrefix}}/css/swagger.css?v={{AssetVersion}}" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a class="swagger-back-link" href="{{AppUrl}}">{{svg "octicon-reply"}}{{.locale.Tr "return_to_gitea"}}</a>
|
||||||
|
<div id="swagger-ui" data-source="{{AssetUrlPrefix}}/forgejo/api.{{.APIVersion}}.yml"></div>
|
||||||
|
<script src="{{AssetUrlPrefix}}/js/forgejoswagger.js?v={{AssetVersion}}"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
21
tests/integration/api_forgejo_root_test.go
Normal file
21
tests/integration/api_forgejo_root_test.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright The Forgejo Authors.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAPIForgejoRoot(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", "/api/forgejo/v1")
|
||||||
|
resp := MakeRequest(t, req, http.StatusNoContent)
|
||||||
|
assert.Contains(t, resp.Header().Get("Link"), "/assets/forgejo/api.v1.yml")
|
||||||
|
}
|
25
tests/integration/api_forgejo_version_test.go
Normal file
25
tests/integration/api_forgejo_version_test.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright The Forgejo Authors.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/routers/api/forgejo/v1"
|
||||||
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAPIForgejoVersion(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", "/api/forgejo/v1/version")
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
var version v1.Version
|
||||||
|
DecodeJSON(t, resp, &version)
|
||||||
|
assert.Equal(t, "development", *version.Version)
|
||||||
|
}
|
22
web_src/js/standalone/forgejo-swagger.js
Normal file
22
web_src/js/standalone/forgejo-swagger.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import SwaggerUI from 'swagger-ui-dist/swagger-ui-es-bundle.js';
|
||||||
|
import 'swagger-ui-dist/swagger-ui.css';
|
||||||
|
|
||||||
|
window.addEventListener('load', async () => {
|
||||||
|
const url = document.getElementById('swagger-ui').getAttribute('data-source');
|
||||||
|
|
||||||
|
const ui = SwaggerUI({
|
||||||
|
url: url,
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
deepLinking: true,
|
||||||
|
docExpansion: 'none',
|
||||||
|
defaultModelRendering: 'model', // don't show examples by default, because they may be incomplete
|
||||||
|
presets: [
|
||||||
|
SwaggerUI.presets.apis
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
SwaggerUI.plugins.DownloadUrl
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
window.ui = ui;
|
||||||
|
});
|
|
@ -76,6 +76,10 @@ export default {
|
||||||
webcomponents: [
|
webcomponents: [
|
||||||
fileURLToPath(new URL('web_src/js/webcomponents/webcomponents.js', import.meta.url)),
|
fileURLToPath(new URL('web_src/js/webcomponents/webcomponents.js', import.meta.url)),
|
||||||
],
|
],
|
||||||
|
forgejoswagger: [ // Forgejo swagger is OpenAPI 3.0.0 and has specific parameters
|
||||||
|
fileURLToPath(new URL('web_src/js/standalone/forgejo-swagger.js', import.meta.url)),
|
||||||
|
fileURLToPath(new URL('web_src/css/standalone/swagger.css', import.meta.url)),
|
||||||
|
],
|
||||||
swagger: [
|
swagger: [
|
||||||
fileURLToPath(new URL('web_src/js/standalone/swagger.js', import.meta.url)),
|
fileURLToPath(new URL('web_src/js/standalone/swagger.js', import.meta.url)),
|
||||||
fileURLToPath(new URL('web_src/css/standalone/swagger.css', import.meta.url)),
|
fileURLToPath(new URL('web_src/css/standalone/swagger.css', import.meta.url)),
|
||||||
|
|
Loading…
Reference in a new issue