From b2bf79ef63e905d6fdff8d3666b753369f48ca47 Mon Sep 17 00:00:00 2001 From: Matthew LeRay <30029105+mleray24@users.noreply.github.com> Date: Wed, 10 Jun 2026 15:12:44 -0400 Subject: [PATCH 1/3] Check redirects in CI --- .github/workflows/main.yaml | 3 + .github/workflows/pr.yaml | 3 + scripts/check-redirects.mjs | 131 ++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 scripts/check-redirects.mjs diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index e95223d0..26d2137d 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -38,6 +38,9 @@ jobs: with: install-command: yarn --frozen-lockfile --silent + - name: check redirects + run: node scripts/check-redirects.mjs HEAD~1 + - name: build run: yarn build diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 770e8e2f..46472c48 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -32,6 +32,9 @@ jobs: with: install-command: yarn --frozen-lockfile --silent + - name: check redirects + run: node scripts/check-redirects.mjs origin/main + - name: configure aws credentials uses: aws-actions/configure-aws-credentials@v4 with: diff --git a/scripts/check-redirects.mjs b/scripts/check-redirects.mjs new file mode 100644 index 00000000..f54073f4 --- /dev/null +++ b/scripts/check-redirects.mjs @@ -0,0 +1,131 @@ +/** + * check-redirects.mjs + * + * Validates that any deleted or renamed documentation files under docs/ + * have corresponding redirect entries in docusaurus.config.js. + * + * Usage: + * node scripts/check-redirects.mjs # staged changes vs HEAD + * node scripts/check-redirects.mjs origin/main # CI: HEAD vs base branch + * + * Exits with code 1 if any missing redirects are found. + */ + +import { readFileSync, existsSync } from "node:fs"; +import { execSync } from "node:child_process"; +import path from "node:path"; +import { cwd } from "node:process"; + +const WORK_DIR = cwd(); +const CONFIG_FILE = path.resolve(WORK_DIR, "docusaurus.config.js"); + +// ── helpers ──────────────────────────────────────────── + +/** Convert a file path under `docs/` to its Docusaurus URL path */ +function docPathToUrl(docPath) { + let relative = docPath.replace("docs/", ""); + relative = relative.replace(/\.(md|mdx)$/, ""); + relative = relative.replace(/\/index$/, ""); + return `/${relative}/`.replace(/\/+/g, "/"); +} + +/** Parse redirect entries from docusaurus.config.js */ +function parseRedirects(configContent) { + const redirects = []; + const redirectRegex = + /\{\s*from\s*:\s*["']([^"']+)["']\s*,\s*to\s*:\s*["']([^"']+)["']\s*,?\s*\}/g; + let match; + while ((match = redirectRegex.exec(configContent)) !== null) { + redirects.push({ from: match[1], to: match[2] }); + } + return redirects; +} + +/** Get changed files by diff-filter status */ +function getChangedFiles(filter, baseRef) { + const args = baseRef + ? `git diff --diff-filter=${filter} --name-only HEAD...${baseRef}` + : `git diff --diff-filter=${filter} --name-only --cached`; + try { + const files = execSync(args, { cwd: WORK_DIR, encoding: "utf-8" }) + .trim() + .split("\n") + .filter(Boolean); + return files; + } catch { + return []; + } +} + +// ── main ─────────────────────────────────────────────── + +const baseRef = process.argv[2]; // e.g., "origin/main" for CI + +const deletedFiles = getChangedFiles("D", baseRef); +const addedFiles = getChangedFiles("A", baseRef); +const renamedFiles = getChangedFiles("R", baseRef); + +function findManualRenames(deleted, added) { + const renames = []; + for (const del of deleted) { + const delBase = path.basename(del); + for (const add of added) { + const addBase = path.basename(add); + if (delBase === addBase && del !== add) { + renames.push({ from: del, to: add }); + } + } + } + return renames; +} + +const manualRenames = findManualRenames(deletedFiles, addedFiles); + +const deletedDocs = deletedFiles.filter( + (f) => f.startsWith("docs/") && /\.(md|mdx)$/.test(f), +); + +if (!existsSync(CONFIG_FILE)) { + console.error("❌ docusaurus.config.js not found"); + process.exit(1); +} +const configContent = readFileSync(CONFIG_FILE, "utf-8"); +const redirects = parseRedirects(configContent); +const redirectFromPaths = new Set(redirects.map((r) => r.from)); + +let errors = 0; + +for (const docFile of deletedDocs) { + const url = docPathToUrl(docFile); + if (!redirectFromPaths.has(url)) { + console.error( + `❌ Missing redirect for deleted doc: ${docFile} → URL ${url}`, + ); + console.error( + ` Add a redirect entry to docusaurus.config.js:\n { from: "${url}", to: "/target-path/" }`, + ); + errors++; + } +} + +for (const { from, to } of manualRenames) { + if (!from.startsWith("docs/") || !to.startsWith("docs/")) continue; + if (!/\.(md|mdx)$/.test(from)) continue; + const fromUrl = docPathToUrl(from); + if (!redirectFromPaths.has(fromUrl)) { + console.error(`❌ Missing redirect for renamed doc: ${from} → ${to}`); + console.error( + ` Expected redirect: { from: "${fromUrl}", to: "${docPathToUrl(to)}" }`, + ); + errors++; + } +} + +if (errors > 0) { + console.error( + `\n${errors} missing redirect(s) found. Add them to the redirects array in docusaurus.config.js.`, + ); + process.exit(1); +} else { + console.log("✅ All deleted/renamed docs have corresponding redirects."); +} From 1503e51541de2916539ab6e72cc991d49e41cbee Mon Sep 17 00:00:00 2001 From: Matthew LeRay <30029105+mleray24@users.noreply.github.com> Date: Wed, 10 Jun 2026 15:31:35 -0400 Subject: [PATCH 2/3] fix CI --- .github/workflows/main.yaml | 2 +- .github/workflows/pr.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 26d2137d..9526576d 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -39,7 +39,7 @@ jobs: install-command: yarn --frozen-lockfile --silent - name: check redirects - run: node scripts/check-redirects.mjs HEAD~1 + run: node scripts/check-redirects.mjs ${{ github.before }} - name: build run: yarn build diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 46472c48..aa838629 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -33,7 +33,7 @@ jobs: install-command: yarn --frozen-lockfile --silent - name: check redirects - run: node scripts/check-redirects.mjs origin/main + run: node scripts/check-redirects.mjs ${{ github.event.pull_request.base.sha }} - name: configure aws credentials uses: aws-actions/configure-aws-credentials@v4 From 4852704087abdd9f586574f90c48da45e947b0e8 Mon Sep 17 00:00:00 2001 From: Matthew LeRay <30029105+mleray24@users.noreply.github.com> Date: Wed, 10 Jun 2026 15:42:27 -0400 Subject: [PATCH 3/3] next: --- .github/workflows/main.yaml | 2 ++ .github/workflows/pr.yaml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 9526576d..3147a566 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -21,6 +21,8 @@ jobs: steps: - name: checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: configure aws credentials uses: aws-actions/configure-aws-credentials@v4 diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index aa838629..893410aa 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -21,6 +21,8 @@ jobs: steps: - name: checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v4