import { test } from "node:test"; import assert from "node:assert/strict"; import { mkdirSync, mkdtempSync, readFileSync, statSync, symlinkSync, writeFileSync } from "node:fs"; import os from "node:os"; import path from "node:path"; // Run with: pnpm --filter yt-dlp-transcript-common exec tsx --test bin/publish-out.test.ts // // `archilyzer publish build --out ` (release 19 A8): the row's // flags, the refusals that come before any build, and the lay-out itself over // a hand-made bundle — hard links into it, its symlinks kept, the destination // emptied, nothing recorded. The build stage is the stage tests'. const ROOT = mkdtempSync(path.join(os.tmpdir(), "publish-out-")); process.env.TRANSCRIPTS_DIR = path.join(ROOT, "transcripts"); process.env.EXPORT_BUILDS_DIR = path.join(ROOT, "builds"); mkdirSync(path.join(ROOT, "transcripts", "sites", "demo-site"), { recursive: true }); writeFileSync(path.join(ROOT, "transcripts", "sites", "demo-site", "site.json"), JSON.stringify({ siteId: "demo-site" })); const { COMMANDS } = await import("./archilyzer"); const { resolveCommand } = await import("./_cli"); const { layOutBundle, publishBuild } = await import("./publish"); const { getPaths } = await import("../lib/paths"); const { writeBuiltStamp } = await import("../publish/stamps"); function capture() { const lines: string[] = []; const errors: string[] = []; return { out: { log: (s: string) => lines.push(s), error: (s: string) => errors.push(s) }, lines, errors }; } test("the publish build row takes --allow-missing-media and --out ", () => { const row = resolveCommand(COMMANDS, ["publish", "build"])?.command; assert.equal(row?.flags?.["allow-missing-media"], "boolean"); assert.equal(row?.flags?.out, "string"); }); test("--out with all, an unknown site, or a guarded destination is refused before any build", async () => { const paths = getPaths(); const all = capture(); assert.equal(await publishBuild({ target: "all", out: path.join(ROOT, "x"), paths }, all.out), 2); assert.match(all.errors.join(""), /--out lays out ONE site's bundle/); const unknown = capture(); assert.equal(await publishBuild({ target: "nope", out: path.join(ROOT, "x"), paths }, unknown.out), 2); assert.match(unknown.errors.join(""), /no site "nope"/); const guarded = capture(); assert.equal(await publishBuild({ target: "demo-site", out: paths.transcriptsDir, paths }, guarded.out), 2); assert.match(guarded.errors.join(""), /--out .* holds the corpus .* --out empties its destination/); const notBundle = path.join(ROOT, "busy"); mkdirSync(notBundle); writeFileSync(path.join(notBundle, "keep.txt"), "x"); const busy = capture(); assert.equal(await publishBuild({ target: "demo-site", out: notBundle, paths }, busy.out), 2); assert.match(busy.errors.join(""), /holds no index\.html/); }); test("the lay-out hard-links the bundle into an emptied destination and records nothing", async () => { const paths = getPaths(); const empty = capture(); assert.equal(await layOutBundle(paths, "demo-site", path.join(ROOT, "none"), empty.out), 3); assert.match(empty.errors.join(""), /no build of demo-site/); const bundle = path.join(paths.exportBuildsDir, "demo-site", "out"); mkdirSync(path.join(bundle, "channels"), { recursive: true }); writeFileSync(path.join(bundle, "index.html"), ""); writeFileSync(path.join(bundle, "channels", "a.json"), "{}"); symlinkSync("index.html", path.join(bundle, "home.html")); await writeBuiltStamp(paths, { v: 1, stampId: "b-1", target: "demo-site", kind: "site", indexStampId: null, inputSig: "sig", builtAt: 1, commit: null, branch: null, runner: "local", audience: "private", corpusGeneratedAt: null, files: 2, bytes: 10, archivesStaged: 0, } as never); const dest = path.join(ROOT, "serve"); mkdirSync(dest); writeFileSync(path.join(dest, "index.html"), "old"); writeFileSync(path.join(dest, "stale.html"), "old"); const c = capture(); assert.equal(await layOutBundle(paths, "demo-site", dest, c.out), 0); assert.match(c.lines.join(""), /build b-1 laid out in .* — 2 hard-linked, 0 copied, 1 symlinks \(not a deploy: nothing recorded\)/); assert.equal(statSync(path.join(dest, "index.html")).ino, statSync(path.join(bundle, "index.html")).ino); assert.equal(readFileSync(path.join(dest, "channels", "a.json"), "utf8"), "{}"); assert.equal(readFileSync(path.join(dest, "home.html"), "utf8"), ""); assert.throws(() => statSync(path.join(dest, "stale.html"))); assert.throws(() => statSync(path.join(paths.exportBuildsDir, "demo-site", "deployed.json"))); });