Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3521699
Serve OpenAPI 3.0 spec at /openapi.v1.json
myers Mar 24, 2026
9face95
fix: address review feedback on OpenAPI converter
myers Apr 11, 2026
d47935a
Fix unused variable error in OpenAPI generator
myers Apr 12, 2026
a08c425
feat: add openapi3gen package skeleton
myers Apr 19, 2026
320c8e8
feat: scan swagger:enum annotations via AST
myers Apr 19, 2026
e03a8d4
fix: harden ScanSwaggerEnumTypes against typos and string escapes
myers Apr 19, 2026
46bc47d
test: cover collision, parse, and orphan-annotation cases
myers Apr 19, 2026
fd2baba
refactor: move OAS3 conversion into build/openapi3gen package
myers Apr 19, 2026
c59294d
docs: clarify converter purpose and strict collision semantics
myers Apr 19, 2026
fb11744
test: cover deriveEnumName and extractSharedEnums
myers Apr 19, 2026
9082a57
feat: introduce UserVisibility named enum type
myers Apr 19, 2026
bcf35ef
test: update Visibility assertions for UserVisibility named type
myers Apr 19, 2026
484c29f
feat: introduce ObjectFormatName named enum type
myers Apr 19, 2026
29b8fd3
feat: introduce RepoWritePermission and AccessLevelName enums
myers Apr 19, 2026
83a048d
feat: add make openapi3-schema-check for schema-name assertions
myers Apr 19, 2026
c549c77
test: update integration assertions for permission enum types
myers Apr 19, 2026
ecc5d66
fix: use gitea modules/json wrapper in converter package
myers Apr 19, 2026
6961542
chore: wire openapi3-schema-check into checks-backend
myers Apr 19, 2026
b815430
Merge branch 'main' into feat/openapi3-conversion
myers Apr 19, 2026
c320a74
chore: update go-licenses.json after merging main
myers Apr 19, 2026
4dfb578
style: use new(literal) for *UserVisibility in api_org_test
myers Apr 19, 2026
b766a69
Revert "feat: add make openapi3-schema-check"
myers Apr 19, 2026
07e326a
fix: reserve openapi.v1.json username to match route
myers Apr 19, 2026
6e94d86
fix: tighten deprecated-description matcher and makefile deps
myers Apr 19, 2026
0529956
chore: rename served OAS3 URL to openapi3.v1.json
myers Apr 19, 2026
384c6dc
test: split rename-reserved test by expected error key
myers Apr 19, 2026
8af52d4
Merge branch 'main' into feat/openapi3-conversion
myers Apr 19, 2026
1427a91
Merge branch 'main' into feat/openapi3-conversion
silverwind Apr 20, 2026
3fa0484
fix(openapi3gen): recurse fixSchema into nested schemas
myers Apr 21, 2026
ada251a
fix(openapi3gen): recurse fixSchema into Not, extend test to oneOf/an…
myers Apr 21, 2026
d79b237
fix(openapi3gen): two-pass enum scan, ordering-independent
myers Apr 21, 2026
d6c37a5
test(openapi3gen): add cross-file ordering case for two-pass scan
myers Apr 21, 2026
c4213e2
fix(openapi3gen): read swagger:enum from per-spec TypeSpec.Doc
myers Apr 21, 2026
5f46aa4
Merge branch 'main' into feat/openapi3-conversion
myers Apr 27, 2026
5b4d949
chore: drop redundant openapi3-tools.go
silverwind Apr 28, 2026
20899c8
fix(openapi3gen): preserve Format when wrapping shared enums in allOf
silverwind Apr 28, 2026
8fdb180
Update build/generate-openapi.go
wxiaoguang Apr 29, 2026
ff61113
Update .editorconfig
wxiaoguang Apr 29, 2026
c9d6500
Add newline at end of v1_openapi3_json.tmpl
wxiaoguang Apr 29, 2026
1343799
Update v1_openapi3_json.tmpl
wxiaoguang Apr 29, 2026
a4cb68d
fix eol
wxiaoguang Apr 29, 2026
82808e7
Merge branch 'main' into feat/openapi3-conversion
wxiaoguang Apr 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ indent_style = tab
[templates/custom/*.tmpl]
insert_final_newline = false

[templates/swagger/v1_json.tmpl]
[templates/swagger/*_json.tmpl]
indent_style = space
insert_final_newline = false

Expand Down
20 changes: 18 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ ESLINT_CONCURRENCY ?= 2
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
SWAGGER_SPEC_INPUT := templates/swagger/v1_input.json
SWAGGER_EXCLUDE := code.gitea.io/sdk
OPENAPI3_SPEC := templates/swagger/v1_openapi3_json.tmpl
Comment thread
wxiaoguang marked this conversation as resolved.

TEST_MYSQL_HOST ?= mysql:3306
TEST_MYSQL_DBNAME ?= testgitea
Expand Down Expand Up @@ -233,7 +234,7 @@ TAGS_PREREQ := $(TAGS_EVIDENCE)
endif

.PHONY: generate-swagger
generate-swagger: $(SWAGGER_SPEC) ## generate the swagger spec from code comments
generate-swagger: $(SWAGGER_SPEC) $(OPENAPI3_SPEC) ## generate the swagger spec from code comments

$(SWAGGER_SPEC): $(GO_SOURCES) $(SWAGGER_SPEC_INPUT)
$(GO) run $(SWAGGER_PACKAGE) generate spec --exclude "$(SWAGGER_EXCLUDE)" --input "$(SWAGGER_SPEC_INPUT)" --output './$(SWAGGER_SPEC)'
Expand All @@ -255,14 +256,29 @@ swagger-validate: ## check if the swagger spec is valid
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
@$(SED_INPLACE) -E -e 's|"basePath":( *)"/(.*)"|"basePath":\1"\2"|g' './$(SWAGGER_SPEC)' # remove the prefix slash from basePath

.PHONY: generate-openapi3
generate-openapi3: $(OPENAPI3_SPEC) ## generate the OpenAPI 3.0 spec from the Swagger 2.0 spec

$(OPENAPI3_SPEC): $(SWAGGER_SPEC) build/generate-openapi.go $(wildcard build/openapi3gen/*.go)
$(GO) run build/generate-openapi.go

.PHONY: openapi3-check
openapi3-check: generate-openapi3
Copy link
Copy Markdown
Member

@silverwind silverwind Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still think these targets should not have a version, e.g. generate-openapi.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

swagger == openapi 2.0, so something labeled only openapi could be v2 or v3. The version number makes it clear

Copy link
Copy Markdown
Member

@silverwind silverwind Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never heard about openapi 2.0, and we don't want to rename this make target once we switch to openapi 3.1, 3.2 or 4.0. there will only ever be one openapi output.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The project already have a OpenAPI spec: the swagger spec. Swagger became OpenAPI 2.0, then OpenAPI came out with a new version, 3.0. If we rename the OpenAPI 3.0 spec "openapi", then it will be unclear what version this end point is.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think generate-openapi3 is a right name

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?
If we're being pedantic it should be generate-openapi2. Swagger has no version, It's the same as openapi2.
Besides I really don't follow here... what integrations? Who's dependent on gitea Makefile or integrating with it? Why would you even promise that makefile is stable, especially for something that's embedded in code and does not need to be generated by any end user or packager?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we upgrade to 3.1, should we rename to generate-openapi31 breaking existing integrations?

Why? 3.1 literally belongs to 3, right? 4 doesn't belong to 3 and it breaks from 3, right?

So generate-openapi3 is absolutely the right name

Copy link
Copy Markdown
Member

@silverwind silverwind Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OAS 3.1 is not strictly backwards-compatible with 3.0, there are subtle breaking changes. I don't get this discussion, we have a "swagger spec" and we have a "openapi spec", versions are irrelevant in both for the generation purpose. I would not recommend to have v3 and v4 specs to co-exist.

Copy link
Copy Markdown
Contributor

@wxiaoguang wxiaoguang Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not recommend to have v3 and v4 specs to co-exist.

But now v2 (swagger) and and v3 do co-exist.

I do not see anything wrong with the name "openapi3".

If "OAS 3.1 is not strictly backwards-compatible with 3.0", then "openapi3" is just even better.

Why you prefer to mix unclear things together? What's wrong with the number "3" to end users? Who will be hurt or confused?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OAS 3.1 is not strictly backwards-compatible with 3.0, there are subtle breaking changes

Then why have it as openapi3.v1.json in the router? If in the future we swap it to 3.1 then "the subtle breaking changes" will impact users. Should THAT be more of an issue than makefile?
The target could be named anything and it wouldn't make a difference since no user will ever run it in the first place.

@diff=$$(git diff --color=always '$(OPENAPI3_SPEC)'); \
if [ -n "$$diff" ]; then \
echo "Please run 'make generate-openapi3' and commit the result:"; \
printf "%s" "$${diff}"; \
exit 1; \
fi

Comment thread
myers marked this conversation as resolved.
.PHONY: checks
checks: checks-frontend checks-backend ## run various consistency checks

.PHONY: checks-frontend
checks-frontend: lockfile-check svg-check ## check frontend files

.PHONY: checks-backend
checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check ## check backend files
checks-backend: tidy-check swagger-check openapi3-check fmt-check swagger-validate security-check ## check backend files

.PHONY: lint
lint: lint-frontend lint-backend lint-spell ## lint everything
Expand Down
40 changes: 40 additions & 0 deletions assets/go-licenses.json

Large diffs are not rendered by default.

97 changes: 97 additions & 0 deletions build/generate-openapi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

// generate-openapi converts Gitea's Swagger 2.0 spec into an OpenAPI 3.0 spec.
//
// Gitea generates a Swagger 2.0 spec from code annotations (make generate-swagger).
// This tool converts it to OAS3 so that SDK generators and tools that require
// OAS3 (e.g. progenitor for Rust) can consume it directly. The conversion also
// deduplicates inline enum definitions into named schema components, producing
// 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

//go:build ignore

package main

import (
"encoding/json"
"fmt"
"log"
"os"
"regexp"
"sort"
"strings"

"code.gitea.io/gitea/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"
)

var (
appSubUrlRe = regexp.MustCompile(regexp.QuoteMeta(appSubUrlVar))
appVerRe = regexp.MustCompile(regexp.QuoteMeta(appVerVar))

enumScanDirs = []string{
"modules/structs",
"modules/commitstatus",
}
)

func main() {
astEnumMap, err := openapi3gen.ScanSwaggerEnumTypes(enumScanDirs)
if err != nil {
log.Fatalf("scanning swagger:enum annotations: %v", err)
}
names := make([]string, 0, len(astEnumMap))
for _, n := range astEnumMap {
names = append(names, n)
}
sort.Strings(names)
fmt.Fprintf(os.Stderr, "discovered %d swagger:enum types: %s\n", len(names), strings.Join(names, ", "))

data, err := os.ReadFile(swaggerSpecPath)
if err != nil {
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)
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 {
log.Fatalf("writing openapi 3.0 spec: %v", err)
}

fmt.Printf("Generated %s\n", openapi3OutPath)
}
Loading