Skip to content

Commit c1616c0

Browse files
committed
ci(openapi): split monolithic spec into multi-file structure, generate bundle in CI
- Run `redocly split` to break docs/openapi.yaml (4975 lines) into 133 files under docs/openapi/ (entry point 353 lines, paths and components each in their own file) - Remove docs/openapi.yaml from git tracking; add to .gitignore — it is now a CI-generated bundle artifact - Add generate-openapi-bundle.yml: triggers on push to main when docs/openapi/** changes, lints the split spec then rebundles into docs/openapi.yaml and commits as github-actions[bot] - Add check-no-openapi-bundle-in-pr.yml: blocks any PR that touches docs/openapi.yaml, mirroring check-no-migrations-in-pr.yml - Add bundle:openapi and preview:openapi scripts to package.json; update lint:openapi to point at docs/openapi/openapi.yaml - Update OPENAPIPLAN.md to reflect the new split layout and CI workflow
1 parent 7112007 commit c1616c0

139 files changed

Lines changed: 5162 additions & 4991 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Check No OpenAPI Bundle in PR
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'docs/openapi.yaml'
7+
8+
jobs:
9+
check-bundle:
10+
name: Block OpenAPI bundle in PR
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Reject bundled spec
14+
run: |
15+
echo "::error::This PR modifies docs/openapi.yaml (the generated bundle)."
16+
echo ""
17+
echo "docs/openapi.yaml is auto-generated by CI after merge."
18+
echo "Edit the split source files under docs/openapi/ instead."
19+
echo ""
20+
echo "To validate locally: run 'bun run lint:openapi'."
21+
echo "To preview locally: run 'bun run preview:openapi'."
22+
exit 1
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Generate OpenAPI Bundle
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- 'docs/openapi/**'
8+
workflow_dispatch:
9+
10+
concurrency:
11+
group: generate-openapi-bundle
12+
cancel-in-progress: false
13+
14+
jobs:
15+
bundle:
16+
name: Bundle OpenAPI spec
17+
runs-on: ubuntu-latest
18+
permissions:
19+
contents: write
20+
steps:
21+
- name: Checkout repository
22+
uses: actions/checkout@v6
23+
with:
24+
token: ${{ secrets.GITHUB_TOKEN }}
25+
26+
- name: Set up Bun
27+
uses: oven-sh/setup-bun@v2
28+
with:
29+
bun-version: latest
30+
31+
- name: Install dependencies
32+
run: bun install --frozen-lockfile
33+
34+
- name: Lint split spec
35+
run: bun run lint:openapi
36+
37+
- name: Bundle into docs/openapi.yaml
38+
run: bun run bundle:openapi
39+
40+
- name: Check for changes
41+
id: check
42+
run: |
43+
if git diff --quiet docs/openapi.yaml; then
44+
echo "has_changes=false" >> "$GITHUB_OUTPUT"
45+
else
46+
echo "has_changes=true" >> "$GITHUB_OUTPUT"
47+
fi
48+
49+
- name: Commit and push bundle
50+
if: steps.check.outputs.has_changes == 'true'
51+
run: |
52+
git config user.name "github-actions[bot]"
53+
git config user.email "github-actions[bot]@users.noreply.github.com"
54+
git add docs/openapi.yaml
55+
git commit --no-verify -m "chore: regenerate OpenAPI bundle"
56+
git push

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,4 @@ packages/backend/.test-db.sqlite-wal
6565
.test-db.sqlite-shm
6666
.test-db.sqlite-wal
6767
.pi-lens
68+
docs/openapi.yaml

OPENAPIPLAN.md

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# OpenAPI Documentation Plan
22

3-
Goal: bring `docs/openapi.yaml` to full parity with `docs/API.md` (and beyond),
3+
Goal: bring `docs/openapi/openapi.yaml` (the multi-file split entry point) to full parity with `docs/API.md` (and beyond),
44
then delete `docs/API.md`. The target is **Option C** from the audit: every
55
operation, schema property, parameter, and enum is documented, plus global
66
narrative sections that replace the reference tables currently in API.md.
@@ -11,7 +11,7 @@ phase has an explicit scope, a checklist, and a "done" test.
1111

1212
## Current coverage snapshot (baseline)
1313

14-
Measured on the committed `docs/openapi.yaml`:
14+
Measured on `docs/openapi/openapi.yaml` (split entry point — individual paths live in `docs/openapi/paths/`, schemas in `docs/openapi/components/schemas/`):
1515

1616
| Artifact | Total | Documented | Gap |
1717
|----------------------|------:|-----------:|-----:|
@@ -25,7 +25,8 @@ Re-run the audit any time with:
2525
```bash
2626
bun -e '
2727
import yaml from "yaml"; import fs from "fs";
28-
const doc = yaml.parse(fs.readFileSync("docs/openapi.yaml","utf8"));
28+
// Bundle first so $refs are resolved, then parse
29+
const doc = yaml.parse(require("child_process").execSync("npx @redocly/cli bundle docs/openapi/openapi.yaml --format yaml 2>/dev/null").toString());
2930
let ops=0,opsNoDesc=0; for(const[p,pi]of Object.entries(doc.paths))for(const m of["get","post","put","delete","patch"])if(pi[m]){ops++;if(!pi[m].description)opsNoDesc++}
3031
let props=0,propsNoDesc=0; for(const s of Object.values(doc.components.schemas))for(const p of Object.values(s.properties||{})){props++;if(!p.description)propsNoDesc++}
3132
console.log({opsNoDesc,ops,propsNoDesc,props})
@@ -35,11 +36,9 @@ console.log({opsNoDesc,ops,propsNoDesc,props})
3536
## Working process per phase
3637

3738
1. Read the relevant source files listed under **Source material**.
38-
2. Edit `docs/openapi.yaml` — descriptions only, never touch the endpoint
39-
list, schema structure, or lint config.
40-
3. Run `bun run lint:openapi` — must pass with 0 warnings.
41-
4. Optional: `npx @redocly/cli preview-docs docs/openapi.yaml` to visually
42-
confirm before committing.
39+
2. Edit the relevant file under `docs/openapi/` (`paths/` for operations, `components/schemas/` for schemas) — descriptions only, never touch the endpoint list, schema structure, or lint config.
40+
3. Run `bun run lint:openapi` (lints `docs/openapi/openapi.yaml`) — must pass with 0 warnings.
41+
4. Optional: `bun run preview:openapi` (`npx @redocly/cli preview-docs docs/openapi/openapi.yaml`) to visually confirm before committing.
4342
5. Tick the phase off in the checklist at the bottom of this file.
4443

4544
## Global invariants (enforced by every phase)
@@ -616,15 +615,17 @@ Final plumbing to retire `docs/API.md` without information loss.
616615
- [ ] Grep API.md for any facts not yet in the spec and port the
617616
remaining ones (final diff).
618617
- [ ] Add a `docs/` README section or top-of-file comment in
619-
`docs/openapi.yaml` linking the rendered spec preview command
620-
(`npx @redocly/cli preview-docs docs/openapi.yaml`) and build
621-
command (`npx @redocly/cli build-docs docs/openapi.yaml -o
622-
docs/api.html`).
618+
`docs/openapi/openapi.yaml` linking the rendered spec preview command
619+
(`bun run preview:openapi`) and build
620+
command (`npx @redocly/cli build-docs docs/openapi.yaml -o docs/api.html`
621+
— note: `docs/openapi.yaml` is CI-generated; run `bun run bundle:openapi` locally first).
623622
- [ ] Update top-level `README.md` and `AGENTS.md` — any links to
624-
`docs/API.md` become links to `docs/openapi.yaml` (or the rendered
623+
`docs/API.md` become links to `docs/openapi/openapi.yaml` (or the rendered
625624
HTML).
626-
- [ ] Add a CI step (GitHub Actions) that runs `bun run lint:openapi`
627-
on every PR touching `docs/openapi.yaml` or the route source files.
625+
- [x] Add a CI step (GitHub Actions) that runs `bun run lint:openapi` and
626+
regenerates `docs/openapi.yaml` on every merge to `main` touching `docs/openapi/`
627+
(`generate-openapi-bundle.yml`). PRs that touch the generated bundle are
628+
blocked by `check-no-openapi-bundle-in-pr.yml`.
628629
- [ ] Delete `docs/API.md`.
629630
- [ ] Update any CHANGELOG entries or migration notes.
630631

0 commit comments

Comments
 (0)