import assert from "node:assert/strict"; import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import test from "node:test"; import { listReleaseFiles, validateSelfContainedRelease, } from "../scripts/lib/release-files.mjs"; async function makeTempDir(prefix) { return fs.mkdtemp(path.join(os.tmpdir(), prefix)); } async function writeFile(filePath, contents = "") { await fs.mkdir(path.dirname(filePath), { recursive: true }); await fs.writeFile(filePath, contents); } async function writeJson(filePath, value) { await writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`); } test("listReleaseFiles skips generated paths and returns sorted relative paths", async (t) => { const root = await makeTempDir("baoyu-release-files-"); t.after(() => fs.rm(root, { recursive: true, force: true })); await writeFile(path.join(root, "b.txt"), "b"); await writeFile(path.join(root, "a.txt"), "a"); await writeFile(path.join(root, "nested", "keep.txt"), "keep"); await writeFile(path.join(root, "node_modules", "skip.js"), "skip"); await writeFile(path.join(root, ".git", "config"), "skip"); await writeFile(path.join(root, "dist", "artifact.txt"), "skip"); await writeFile(path.join(root, "out", "artifact.txt"), "skip"); await writeFile(path.join(root, "build", "artifact.txt"), "skip"); await writeFile(path.join(root, ".DS_Store"), "skip"); await writeFile(path.join(root, "bun.lockb"), "skip"); const files = await listReleaseFiles(root); assert.deepEqual( files.map((file) => file.relPath), ["a.txt", "b.txt", "nested/keep.txt"], ); }); test("validateSelfContainedRelease accepts file dependencies that stay within the release root", async (t) => { const root = await makeTempDir("baoyu-release-ok-"); t.after(() => fs.rm(root, { recursive: true, force: true })); await writeJson(path.join(root, "shared", "package.json"), { name: "shared-package", version: "1.0.0", }); await writeFile(path.join(root, "shared", "index.js"), "export const shared = true;\n"); await writeJson(path.join(root, "skill", "package.json"), { name: "test-skill", version: "1.0.0", dependencies: { "shared-package": "file:../shared", }, }); await assert.doesNotReject(() => validateSelfContainedRelease(root)); }); test("validateSelfContainedRelease rejects missing local file dependencies", async (t) => { const root = await makeTempDir("baoyu-release-missing-"); t.after(() => fs.rm(root, { recursive: true, force: true })); await writeJson(path.join(root, "skill", "package.json"), { name: "test-skill", version: "1.0.0", dependencies: { "shared-package": "file:../shared", }, }); await assert.rejects( () => validateSelfContainedRelease(root), /Missing local dependency for release/, ); }); test("validateSelfContainedRelease rejects file dependencies outside the release root", async (t) => { const root = await makeTempDir("baoyu-release-root-"); const outside = await makeTempDir("baoyu-release-outside-"); t.after(() => fs.rm(root, { recursive: true, force: true })); t.after(() => fs.rm(outside, { recursive: true, force: true })); const skillDir = path.join(root, "skill"); const externalSpec = path .relative(skillDir, outside) .split(path.sep) .join("/"); await writeJson(path.join(skillDir, "package.json"), { name: "test-skill", version: "1.0.0", dependencies: { "outside-package": `file:${externalSpec}`, }, }); await assert.rejects( () => validateSelfContainedRelease(root), /Release target is not self-contained/, ); });