Initial Commit

This commit is contained in:
kossLAN 2026-06-06 23:08:48 -04:00
commit 0534f88f70
No known key found for this signature in database
14 changed files with 5590 additions and 0 deletions

144
scripts/pack-release.mjs Normal file
View file

@ -0,0 +1,144 @@
import { createHash } from "node:crypto";
import { createReadStream, createWriteStream } from "node:fs";
import { mkdir, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
import path from "node:path";
import process from "node:process";
import * as tar from "tar";
import { ZipFile } from "yazl";
const root = process.cwd();
const distDir = path.join(root, "dist");
const releaseDir = path.join(distDir, "release");
function releaseTag() {
const value = process.env.TAG ?? process.env.FORGEJO_REF_NAME ?? process.env.GITHUB_REF_NAME ?? "";
return value.replace(/^refs\/tags\//, "") || "dev";
}
function cleanTag(tag) {
return tag.replace(/[^A-Za-z0-9._-]+/g, "-");
}
async function ensureBuilt() {
const index = path.join(distDir, "index.html");
try {
const info = await stat(index);
if (!info.isFile()) throw new Error();
} catch {
throw new Error("dist/index.html is missing. Run `pnpm run build` before `pnpm run release:pack`.");
}
}
async function distEntries() {
const entries = await readdir(distDir);
return entries.filter((entry) => entry !== "release");
}
async function addZipPath(zip, source, name) {
const info = await stat(source);
if (info.isDirectory()) {
const children = await readdir(source);
if (children.length === 0) {
zip.addEmptyDirectory(name);
return;
}
for (const child of children) {
await addZipPath(zip, path.join(source, child), `${name}/${child}`);
}
return;
}
zip.addFile(source, name);
}
async function writeZip(file, entries, bundleName) {
await new Promise((resolve, reject) => {
const output = createWriteStream(file);
const zip = new ZipFile();
output.on("close", resolve);
output.on("error", reject);
zip.outputStream.on("error", reject);
zip.outputStream.pipe(output);
Promise.all(entries.map((entry) => addZipPath(zip, path.join(distDir, entry), `${bundleName}/${entry}`)))
.then(() => zip.end())
.catch(reject);
});
}
async function sha256(file) {
const hash = createHash("sha256");
await new Promise((resolve, reject) => {
createReadStream(file)
.on("data", (chunk) => hash.update(chunk))
.on("error", reject)
.on("end", resolve);
});
return hash.digest("hex");
}
async function readBuildInfo() {
try {
return JSON.parse(await readFile(path.join(distDir, "spec", "build-info.json"), "utf8"));
} catch {
return {};
}
}
async function main() {
await ensureBuilt();
const tag = cleanTag(releaseTag());
const bundleName = `wry-docs-${tag}`;
const entries = await distEntries();
await rm(releaseDir, { recursive: true, force: true });
await mkdir(releaseDir, { recursive: true });
const tarball = path.join(releaseDir, `${bundleName}.tar.gz`);
const zipfile = path.join(releaseDir, `${bundleName}.zip`);
await tar.c(
{
cwd: distDir,
file: tarball,
gzip: true,
portable: true,
prefix: `${bundleName}/`
},
entries
);
await writeZip(zipfile, entries, bundleName);
const assets = [tarball, zipfile];
const sums = [];
for (const file of assets) {
sums.push(`${await sha256(file)} ${path.basename(file)}`);
}
await writeFile(path.join(releaseDir, "SHA256SUMS"), `${sums.join("\n")}\n`);
const info = await readBuildInfo();
const notes = [
`# Wry Docs ${tag}`,
"",
"Static documentation bundle generated from Wry's TOML configuration specs.",
"",
"## Source",
"",
`- Wry branch: \`${info.sourceBranch ?? "unknown"}\``,
`- Wry commit: \`${info.sourceCommit ?? "unknown"}\``,
`- Generated at: \`${info.generatedAt ?? "unknown"}\``,
"",
"## Assets",
"",
`- \`${path.basename(tarball)}\``,
`- \`${path.basename(zipfile)}\``,
"- `SHA256SUMS`",
""
].join("\n");
await writeFile(path.join(releaseDir, "RELEASE_NOTES.md"), notes);
console.log(`Wrote release assets to ${releaseDir}`);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});