refactor: serve the api specs as plain json (#38715)

The api specs were Go templates whose committed form was not a valid
swagger document, so `swagger-validate`, `generate-openapi.go` and
`.spectral.yaml` each worked around it. They are now plain json,
substituted at serve time.

Renaming them off `.tmpl` also stops `make fmt` rewriting them, which
used to bump their mtime and silently skip the next `make
generate-swagger`.

Also enables stricter spectral linting: extends `lint-swagger` to the
OpenAPI 3 spec, turns on `openapi-tags`, `operation-singular-tag` and
`operation-tag-defined`, adds a top-level `tags` array with descriptions
to the swagger input, and drops the redundant `repository` tag from
`POST /user/repos`.

---------

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
This commit is contained in:
silverwind
2026-07-31 16:16:27 +02:00
committed by GitHub
parent a3e7fe1f11
commit f0a95eebe3
16 changed files with 178 additions and 79 deletions
+9 -34
View File
@@ -10,7 +10,7 @@
// cleaner SDK output with proper enum types instead of anonymous strings.
//
// Run: go run build/generate-openapi.go
// Output: templates/swagger/v1_openapi3_json.tmpl
// Output: templates/swagger/v1-openapi3.generated.json
//go:build ignore
@@ -21,35 +21,21 @@ import (
"fmt"
"log"
"os"
"regexp"
"sort"
"strings"
"gitea.dev/build/openapi3gen"
"github.com/getkin/kin-openapi/openapi3"
)
const (
swaggerSpecPath = "templates/swagger/v1_json.tmpl"
openapi3OutPath = "templates/swagger/v1_openapi3_json.tmpl"
appSubUrlVar = "{{.SwaggerAppSubUrl}}"
appVerVar = "{{.SwaggerAppVer}}"
appSubUrlPlaceholder = "GITEA_APP_SUB_URL_PLACEHOLDER"
appVerPlaceholder = "0.0.0-gitea-placeholder"
swaggerSpecPath = "templates/swagger/v1-swagger.generated.json"
openapi3OutPath = "templates/swagger/v1-openapi3.generated.json"
)
var (
appSubUrlRe = regexp.MustCompile(regexp.QuoteMeta(appSubUrlVar))
appVerRe = regexp.MustCompile(regexp.QuoteMeta(appVerVar))
enumScanDirs = []string{
"modules/structs",
"modules/commitstatus",
}
)
var enumScanDirs = []string{
"modules/structs",
"modules/commitstatus",
}
func main() {
astEnumMap, err := openapi3gen.ScanSwaggerEnumTypes(enumScanDirs)
@@ -68,28 +54,17 @@ func main() {
log.Fatalf("reading swagger spec: %v", err)
}
cleaned := appSubUrlRe.ReplaceAll(data, []byte(appSubUrlPlaceholder))
cleaned = appVerRe.ReplaceAll(cleaned, []byte(appVerPlaceholder))
oas3, err := openapi3gen.Convert(cleaned, astEnumMap)
oas3, err := openapi3gen.Convert(data, astEnumMap)
if err != nil {
log.Fatalf("converting to openapi 3.0: %v", err)
}
oas3.Servers = openapi3.Servers{
{URL: appSubUrlPlaceholder + "/api/v1"},
}
out, err := json.MarshalIndent(oas3, "", " ")
if err != nil {
log.Fatalf("marshaling openapi 3.0: %v", err)
}
result := strings.ReplaceAll(string(out), appSubUrlPlaceholder, appSubUrlVar)
result = strings.ReplaceAll(result, appVerPlaceholder, appVerVar)
result = strings.TrimSpace(result)
if err := os.WriteFile(openapi3OutPath, []byte(result), 0o644); err != nil {
if err := os.WriteFile(openapi3OutPath, out, 0o644); err != nil {
log.Fatalf("writing openapi 3.0 spec: %v", err)
}
+3 -2
View File
@@ -23,8 +23,8 @@ import (
var rxDeprecated = regexp.MustCompile(`(?i)(?:^|[\n.;])\s*deprecated\b`)
// Convert parses a Swagger 2.0 spec and returns an OAS3 spec, applying
// Gitea-specific post-processing: file-schema fixups, URI formats,
// deprecated flags, and shared-enum extraction.
// Gitea-specific post-processing: server URL, file-schema fixups, URI
// formats, deprecated flags, and shared-enum extraction.
//
// astEnumMap is a value-set-key → Go-type-name(s) map (built by
// ScanSwaggerEnumTypes). When a value set is shared by multiple Go types,
@@ -42,6 +42,7 @@ func Convert(swaggerJSON []byte, astEnumMap map[string][]string) (*openapi3.T, e
return nil, fmt.Errorf("converting to openapi 3.0: %w", err)
}
oas3.Servers = openapi3.Servers{{URL: swagger2.BasePath}}
fixFileSchemas(oas3)
addURIFormats(oas3)
addDeprecatedFlags(oas3)