fix(api): show the name of a type in the reference, document the gmail app password (#541)

Two unrelated but small fixes, closes #258 and closes #32.

**The reference does not name its types (#258)**

Since the api reference is rendered from the openapi 3.0 document, a field of type `ReviewStateType` is rendered as the bare string enum the `$ref` points at: starlight-openapi dereferences everything and the schema has no `title`, so the name of the type is nowhere on the page. Searching the current reference for `ReviewStateType` returns nothing, which is what the issue reports (the plugin also has no route for `components/schemas`, so there is no page per type either).

`normalizeSchema()` now titles every named schema of an openapi 3.0 document with its own name, which the plugin renders next to the type of a field:

- before: `state` · `string` · Allowed values: APPROVED …
- after: `state` · `ReviewStateType` · `string` · Allowed values: APPROVED …

The go doc comments start with the name of the type, so the description would repeat it ("ChangeFilesOptions — ChangeFilesOptions options for creating …"); a leading `<name> ` is stripped from the description.

For the record, how the three generations of documents describe that type:

| Versions | Type name | Allowed values |
| --- | --- | --- |
| 1.22 – 1.25 (swagger, `ReviewStateType` definition without `enum`) | shown | missing |
| 1.26 – 1.27 (swagger, enum inlined upstream) | missing | shown |
| 1.27, next (openapi 3.0, with this change) | shown | shown |

The released swagger documents are frozen, so 1.22 – 1.26 keep what they have; from 1.27 on the reference answers the question the issue asks.

**Gmail needs an app password (#32)**

The configuration in the guide is still correct after Google turned off password-only access, because it already asks for an app password. What was missing is why there is no alternative: Gitea's mailer authenticates with `CRAM-MD5`, `PLAIN` or `LOGIN` and has no XOAUTH2, so "Sign in with Google" is not an option. Added that, together with the two things people run into — an app password needs 2-step verification and a Workspace administrator can disable app passwords for the domain — and the `587` + `smtp+starttls` variant.

Verified by building the api and the next docs: the type names show up on the operation pages, the descriptions are not duplicated, and 1.26 and older are unchanged. `pnpm check` passes.

<!-- cloudflare-preview --> Preview: https://pr-541.docs-gitea-com.pages.dev

---------

Co-authored-by: bircni <[email protected]>
Reviewed-on: https://gitea.com/gitea/docs/pulls/541
Reviewed-by: bircni <[email protected]>
Co-authored-by: Lunny Xiao <[email protected]>
This commit is contained in:
Lunny Xiao
2026-09-12 11:27:21 +00:00
committed by bircni
co-authored by bircni
parent 9a6d0d90bf
commit 3258717d62
2 changed files with 48 additions and 0 deletions
+15
View File
@@ -86,6 +86,21 @@ PROTOCOL = smtps
Note that you'll need to create and use an [App password](https://support.google.com/accounts/answer/185833?hl=en) by enabling 2FA on your Google Note that you'll need to create and use an [App password](https://support.google.com/accounts/answer/185833?hl=en) by enabling 2FA on your Google
account. You won't be able to use your Google account password directly. account. You won't be able to use your Google account password directly.
An app password is the only option: Google
[turned off access for apps that sign in with a password alone](https://workspaceupdates.googleblog.com/2023/09/winding-down-google-sync-and-less-secure-apps-support.html)
in 2024 and asks applications to use OAuth instead, which Gitea's mailer does
not implement — it authenticates with `CRAM-MD5`, `PLAIN` or `LOGIN`.
Two things to keep in mind:
- app passwords require 2-step verification on the account, and a Google
Workspace administrator can switch them off for the whole domain. If they are
not available, send through the
[Workspace SMTP relay service](https://support.google.com/a/answer/2956491)
or through another mail provider.
- port `587` works as well, with `SMTP_PORT = 587` and
`PROTOCOL = smtp+starttls`.
### ProtonMail ### ProtonMail
This feature is currently only available for select Proton for Business customers and those with Visionary and Family plans with custom domain addresses. See [ProtonMail's SMTP documentation](https://proton.me/support/smtp-submission) for more information. This limitation can be circumvented by using the ProtonMail Bridge application. This feature is currently only available for select Proton for Business customers and those with Visionary and Family plans with custom domain addresses. See [ProtonMail's SMTP documentation](https://proton.me/support/smtp-submission) for more information. This limitation can be circumvented by using the ProtonMail Bridge application.
+33
View File
@@ -27,6 +27,11 @@ interface Operation {
operationId?: string; operationId?: string;
} }
interface Schema {
title?: string;
description?: string;
}
interface SwaggerDocument { interface SwaggerDocument {
openapi?: string; openapi?: string;
basePath?: string; basePath?: string;
@@ -34,6 +39,7 @@ interface SwaggerDocument {
schemes?: string[]; schemes?: string[];
tags?: { name: string; description?: string }[]; tags?: { name: string; description?: string }[];
paths?: Record<string, Record<string, Operation | unknown>>; paths?: Record<string, Record<string, Operation | unknown>>;
components?: { schemas?: Record<string, Schema> };
} }
const httpMethods = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch']; const httpMethods = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch'];
@@ -95,6 +101,7 @@ function normalizeSchema(source: string, name: string): string {
hyphenateOperationIds(document); hyphenateOperationIds(document);
describeTags(document); describeTags(document);
nameSchemas(document);
mkdirSync(cacheDir, { recursive: true }); mkdirSync(cacheDir, { recursive: true });
const target = path.join(cacheDir, name); const target = path.join(cacheDir, name);
@@ -123,6 +130,32 @@ function describeTags(document: SwaggerDocument): void {
document.tags = [...described.values()]; document.tags = [...described.values()];
} }
/**
* Titles the named schemas of an openapi 3.0 document with their own name.
*
* starlight-openapi dereferences every `$ref`, so a field of type
* `ReviewStateType` is rendered as the bare string enum it points at and the
* name of the type is nowhere on the page: searching the reference for a type
* name found in an sdk or in an error message turns up nothing (gitea/docs#258).
* The plugin renders `title` next to the type of a field, so setting it brings
* the name back, next to the allowed values.
*
* Swagger 2.0 documents are left alone, they are rendered with the name of the
* definition already.
*/
function nameSchemas(document: SwaggerDocument): void {
for (const [name, schema] of Object.entries(document.components?.schemas ?? {})) {
if (!schema || typeof schema !== 'object') continue;
if (!schema.title) schema.title = name;
// the go doc comments start with the name of the type, which would read
// "ChangeFilesOptions — ChangeFilesOptions options for ..." once the title
// is rendered in front of the description
if (schema.description?.startsWith(`${name} `)) {
schema.description = schema.description.slice(name.length + 1);
}
}
}
/** /**
* One starlight-openapi schema per documented api version, each mounted at the * One starlight-openapi schema per documented api version, each mounted at the
* route of its version: `/api/` for the latest release, `/api/1.26/` and * route of its version: `/api/` for the latest release, `/api/1.26/` and