Spaces:
Runtime error
Runtime error
| /** | |
| * Version-consistency guard. | |
| * | |
| * Stops the recurring "we cut a release but a doc still shows the old version" problem by failing | |
| * CI when a *current-version* reference drifts from package.json. It does NOT touch historical | |
| * version mentions (CHANGELOG history, roadmap milestones, example image tags) β only the three | |
| * places that must always reflect the shipped version: | |
| * | |
| * 1. The README version badges (root + docs/) must be the DYNAMIC shields endpoint that reads | |
| * package.json automatically β never a hardcoded `badge/version-x.y.z`. | |
| * 2. src/config/swagger.config.ts must source the version from package.json β never `setVersion('x.y.z')`. | |
| * 3. CHANGELOG.md must carry a `## [<current version>]` entry (the release notes exist). | |
| * 4. The runtime/framework majors the READMEs advertise (Node, NestJS, TypeScript) must match | |
| * package.json. The NestJS/TypeScript badges track it themselves via the shields | |
| * `dependency-version` endpoint, but the Tech Stack table and the Node badge are plain prose β | |
| * shields cannot read `engines.node` β so they are gated here instead. | |
| * | |
| * Run locally: `npm run check:versions`. Runs in CI (lint job). | |
| */ | |
| import { readFileSync } from 'node:fs'; | |
| const root = new URL('../', import.meta.url); | |
| const read = (rel) => readFileSync(new URL(rel, root), 'utf8'); | |
| const pkg = JSON.parse(read('package.json')); | |
| const version = pkg.version; | |
| const errors = []; | |
| // 1) README badges must be dynamic, not a pinned `badge/version-x`. | |
| for (const f of ['README.md', 'docs/README.md']) { | |
| if (/shields\.io\/badge\/version-\d/.test(read(f))) { | |
| errors.push(`${f}: hardcoded version badge β use the dynamic shields "github/package-json/v" badge so it tracks package.json.`); | |
| } | |
| } | |
| // 2) Swagger version must come from package.json, not a literal. | |
| if (/setVersion\(\s*['"]\d/.test(read('src/config/swagger.config.ts'))) { | |
| errors.push("src/config/swagger.config.ts: hardcoded setVersion('x.y.z') β use require('../../package.json').version."); | |
| } | |
| // 3) CHANGELOG must have an entry for the current version. | |
| if (!read('CHANGELOG.md').includes(`## [${version}]`)) { | |
| errors.push(`CHANGELOG.md: missing a "## [${version}]" entry for the current package.json version β add the release notes before tagging.`); | |
| } | |
| // 4) Runtime/framework majors advertised in the READMEs must match package.json. | |
| const majorOf = (range) => range?.match(/(\d+)/)?.[1]; | |
| const stack = [ | |
| ['Node', majorOf(pkg.engines?.node), /node-(\d+)_LTS|Node\.js (\d+) LTS/g], | |
| ['NestJS', majorOf(pkg.dependencies?.['@nestjs/core']), /NestJS[ -](\d+)\.x/g], | |
| ['TypeScript', majorOf(pkg.devDependencies?.typescript), /TypeScript[ -](\d+)\.x/g], | |
| ]; | |
| for (const f of ['README.md', 'docs/README.md']) { | |
| const text = read(f); | |
| for (const [name, want, pattern] of stack) { | |
| if (!want) continue; | |
| for (const m of text.matchAll(pattern)) { | |
| const found = m[1] ?? m[2]; | |
| if (found !== want) { | |
| errors.push(`${f}: advertises ${name} ${found} but package.json declares ${want} β update the doc (or the dependency).`); | |
| } | |
| } | |
| } | |
| } | |
| if (errors.length) { | |
| console.error(`\nβ Version consistency check failed (package.json = ${version}):`); | |
| for (const e of errors) console.error(` - ${e}`); | |
| console.error('\nFix the above so docs track the release automatically, then re-run `npm run check:versions`.\n'); | |
| process.exit(1); | |
| } | |
| console.log(`β Version consistency OK (package.json = ${version}).`); | |