diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c2199b6..311edb2 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -27,6 +27,17 @@ jobs: - name: Check out repository uses: actions/checkout@v6 + - name: Set up pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Set up Node + uses: actions/setup-node@v6 + with: + node-version: '22' + cache: pnpm + - name: Validate docs directory run: | set -euo pipefail @@ -45,12 +56,9 @@ jobs: test -s "$file" done < markdown-files.txt - - name: Print docs customization TODO + - name: Run docs release-readiness check run: | set -euo pipefail - if [ -f package.json ]; then - echo "Add docs build verification here when the repository has a docs toolchain." - else - echo "No package.json found; docs workflow is limited to markdown hygiene." - fi + pnpm install --frozen-lockfile + pnpm run docs:check diff --git a/package.json b/package.json index c8d06c1..5d8c764 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,11 @@ "build": "tsc", "dev": "tsx src/index.ts", "check": "tsc --noEmit", + "docs:check": "node scripts/check-docs.mjs", "start": "node dist/index.js", "check:templates": "pnpm build && node scripts/check-template-registry.mjs", "smoke:init": "bash scripts/smoke-init.sh", - "release:check": "pnpm run build && pnpm test && pnpm run smoke && pnpm run package:smoke", + "release:check": "pnpm run docs:check && pnpm run build && pnpm test && pnpm run smoke && pnpm run package:smoke", "test": "pnpm run build && node scripts/check-template-registry.mjs", "smoke": "pnpm run smoke:init", "package:smoke": "npm pack --dry-run" diff --git a/scripts/check-docs.mjs b/scripts/check-docs.mjs new file mode 100644 index 0000000..0da9adc --- /dev/null +++ b/scripts/check-docs.mjs @@ -0,0 +1,71 @@ +import { readFileSync, readdirSync, statSync } from 'node:fs'; +import { join, relative } from 'node:path'; + +const root = process.cwd(); +const requiredDocs = [ + 'README.md', + 'docs/PRD.md', + 'docs/TASKS.md', + 'docs/release-readiness.md', + 'docs/release-checklist.md', + 'docs/release-process.md', + 'docs/github-actions.md', + 'docs/template-variables.md', +]; + +const markdownFiles = []; + +function collectMarkdown(dir) { + for (const entry of readdirSync(dir)) { + if (entry === '.git' || entry === 'node_modules' || entry === 'dist') { + continue; + } + + const path = join(dir, entry); + const stats = statSync(path); + + if (stats.isDirectory()) { + collectMarkdown(path); + } else if (entry.endsWith('.md')) { + markdownFiles.push(relative(root, path)); + } + } +} + +for (const doc of requiredDocs) { + const content = readFileSync(join(root, doc), 'utf8').trim(); + + if (content.length === 0) { + throw new Error(`${doc} must not be empty`); + } +} + +collectMarkdown(root); + +if (markdownFiles.length === 0) { + throw new Error('Expected at least one markdown file'); +} + +for (const file of markdownFiles) { + const content = readFileSync(join(root, file), 'utf8'); + + if (content.trim().length === 0) { + throw new Error(`${file} must not be empty`); + } +} + +const docsWorkflow = readFileSync(join(root, '.github/workflows/docs.yml'), 'utf8'); + +if (/customization TODO|Add docs build verification here/.test(docsWorkflow)) { + throw new Error('docs workflow still contains placeholder verification text'); +} + +const readme = readFileSync(join(root, 'README.md'), 'utf8'); + +for (const doc of ['docs/release-readiness.md', 'docs/release-checklist.md', 'docs/release-process.md']) { + if (!readme.includes(doc)) { + throw new Error(`README.md must link ${doc}`); + } +} + +console.log(`Validated ${markdownFiles.length} markdown files and ${requiredDocs.length} required docs.`);