From ba513850c162cb06046cf20b08ebf0562b72bc37 Mon Sep 17 00:00:00 2001 From: Christian Visintin Date: Sun, 7 Jun 2026 21:30:23 +0200 Subject: [PATCH] feat(site): build-time man.md fetcher pinned to release ref --- site/scripts/fetch-man.mjs | 53 ++++++++++++++++++++++++++++++++++ site/scripts/fetch-man.test.ts | 21 ++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 site/scripts/fetch-man.mjs create mode 100644 site/scripts/fetch-man.test.ts diff --git a/site/scripts/fetch-man.mjs b/site/scripts/fetch-man.mjs new file mode 100644 index 0000000..9dd533c --- /dev/null +++ b/site/scripts/fetch-man.mjs @@ -0,0 +1,53 @@ +import { mkdir, writeFile } from "node:fs/promises"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +/** Pinned ref for reproducible builds. Bump when cutting a release. */ +export const MAN_REF = "v1.0.0"; + +export const LOCALES = ["en", "zh-CN", "it", "fr", "es"]; + +const REPO = "veeso/termscp"; + +export function manUrl(locale) { + const path = locale === "en" ? "docs/man.md" : `docs/${locale}/man.md`; + return `https://raw.githubusercontent.com/${REPO}/${MAN_REF}/${path}`; +} + +async function fetchText(url) { + const headers = process.env.GITHUB_TOKEN + ? { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` } + : {}; + const res = await fetch(url, { headers }); + if (!res.ok) { + throw new Error(`fetch ${url} failed: ${res.status} ${res.statusText}`); + } + return res.text(); +} + +async function main() { + const here = dirname(fileURLToPath(import.meta.url)); + const outDir = join(here, "..", "src", "content", "man"); + await mkdir(outDir, { recursive: true }); + + for (const locale of LOCALES) { + let md; + try { + md = await fetchText(manUrl(locale)); + } catch (err) { + if (locale === "en") throw err; // en is required — fail the build + console.warn(`[fetch-man] ${locale} missing, falling back to en: ${err.message}`); + md = await fetchText(manUrl("en")); + } + await writeFile(join(outDir, `${locale}.md`), md, "utf8"); + console.log(`[fetch-man] wrote ${locale}.md`); + } +} + +// Run only when invoked directly (not when imported by tests). +if (import.meta.url === `file://${process.argv[1]}`) { + main().catch((err) => { + console.error(err); + process.exit(1); + }); +} diff --git a/site/scripts/fetch-man.test.ts b/site/scripts/fetch-man.test.ts new file mode 100644 index 0000000..647510f --- /dev/null +++ b/site/scripts/fetch-man.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, it } from "vitest"; +import { manUrl, MAN_REF } from "./fetch-man.mjs"; + +describe("manUrl", () => { + it("uses the root man.md for en", () => { + expect(manUrl("en")).toBe( + `https://raw.githubusercontent.com/veeso/termscp/${MAN_REF}/docs/man.md` + ); + }); + + it("uses the per-locale path for non-en", () => { + expect(manUrl("it")).toBe( + `https://raw.githubusercontent.com/veeso/termscp/${MAN_REF}/docs/it/man.md` + ); + }); + + it("pins to a concrete ref, not a moving branch", () => { + expect(MAN_REF).not.toBe("main"); + expect(MAN_REF.length).toBeGreaterThan(0); + }); +});