144 lines
3.9 KiB
JavaScript
144 lines
3.9 KiB
JavaScript
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);
|
|
});
|