Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .changeset/readme-endpoint-table-in-openapi-gen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'lens': patch
---

`npm run openapi:gen` now also regenerates the README endpoint table from `openapi.yaml`, and CI runs `npm run readme:check`, which fails when the committed README differs from a fresh generation (#275).
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ jobs:
run: git diff --exit-code -- clients/typescript
- name: Typecheck the generated TypeScript client
run: npm run client:typecheck
- name: Fail if the committed README tables are out of date with openapi.yaml
run: npm run readme:check
- run: npx tsc --noEmit
- run: npm run build
- run: npm test --if-present
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ npx @modelcontextprotocol/inspector npm run mcp:server
| GET/POST | `/graphql` | GraphQL query/mutation endpoint (GraphiQL IDE at `/graphiql`, docs: [`docs/graphql.md`](docs/graphql.md)) |
<!-- ENDPOINTS:END -->

The table above is generated from [`openapi.yaml`](openapi.yaml) by `npm run openapi:gen`;
edit the spec rather than the table. CI runs `npm run readme:check` and fails when
the committed table differs from a fresh generation.

Every non-internal route above has a matching entry in [`openapi.yaml`](openapi.yaml);
`tests/openapi.test.ts` boots the server and fails if a registered route is
missing from the spec. Operator-only and non-HTTP routes (`/admin/keys*`,
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
"test": "vitest run",
"smoke": "node scripts/deployed-smoke.mjs",
"test:smoke": "node --test scripts/test-deployed-smoke.mjs",
"openapi:gen": "tsx scripts/generate-openapi.ts",
"openapi:gen": "tsx scripts/generate-openapi.ts && tsx scripts/generate-readme.ts",
"readme:gen": "tsx scripts/generate-readme.ts",
"readme:check": "tsx scripts/generate-readme.ts --check",
"spec:validate-live": "tsx scripts/validate-live-spec.ts",
"client:gen": "openapi-typescript openapi.yaml -o clients/typescript/src/schema.d.ts",
"client:typecheck": "tsc -p clients/typescript/tsconfig.json --noEmit",
Expand Down
28 changes: 25 additions & 3 deletions scripts/generate-readme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,30 @@ export function generateReadme(): void {
writeFileSync(readmePath, renderReadme())
}

// CLI entry point
/**
* Compares the committed README.md with a fresh render and reports whether it
* has drifted. Line endings are normalised first, as in `tests/readme.test.ts`,
* so a CRLF checkout of an identical table is not reported as drift.
*/
export function readmeIsCurrent(content?: string): boolean {
const committed = (content ?? readFileSync(readmePath, 'utf8')).replace(/\r\n/g, '\n')
return renderReadme(committed) === committed
}

// CLI entry point. `--check` (`npm run readme:check`, run in CI) writes
// nothing and exits non-zero when README.md differs from a fresh generation.
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
generateReadme()
console.log('Successfully generated README.md venues and endpoints sections')
if (process.argv.includes('--check')) {
if (!readmeIsCurrent()) {
console.error(
'README.md is out of date: its generated tables (endpoints from openapi.yaml, venues from src/ingest/venues) differ from a fresh generation.\n' +
'Run `npm run openapi:gen` and commit the result.',
)
process.exit(1)
}
console.log('README.md venue and endpoint tables are up to date')
} else {
generateReadme()
console.log('Successfully generated README.md venues and endpoints sections')
}
}
10 changes: 10 additions & 0 deletions tests/readme.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
renderVenuesTable,
renderEndpointsTable,
renderReadme,
readmeIsCurrent,
VENUES_START_TAG,
VENUES_END_TAG,
ENDPOINTS_START_TAG,
Expand Down Expand Up @@ -125,6 +126,15 @@ describe('README venue list and endpoint table generators', () => {
expect(currentEndpoints).not.toContain('/fake/nonexistent/endpoint')
})

it('readme:check passes on the committed README and fails once the endpoint table is edited by hand', () => {
const committed = readFileSync(readmePath, 'utf8')
expect(readmeIsCurrent(committed)).toBe(true)

const edited = committed.replace('| GET | `/tvl` |', '| GET | `/tvl-renamed` |')
expect(edited).not.toBe(committed)
expect(readmeIsCurrent(edited)).toBe(false)
})

it('renders README deterministically in-place', () => {
const initial = readFileSync(readmePath, 'utf8')
const rendered = renderReadme(initial)
Expand Down