Files
AgentCompany/scripts/release-website.mjs
T

127 lines
4.1 KiB
JavaScript

import { existsSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { spawn } from "node:child_process";
import { prepareR2ReleaseHost } from "./release-local/r2.mjs";
import { loadEnvFile } from "./release/lib/dotenv.mjs";
import { applyD1Migrations } from "./release/lib/d1-migrations.mjs";
import { createRunner } from "./release/lib/process.mjs";
const __dirname = dirname(fileURLToPath(import.meta.url));
const rootDir = join(__dirname, "..");
const landingDir = join(rootDir, "landing");
const packageJsonPath = join(rootDir, "package.json");
const pagesProjectName = "agentcompany";
const pagesBranch = "main";
const run = createRunner(rootDir);
function parseArgs(argv) {
const options = { skipVerify: false };
for (const arg of argv) {
if (arg === "--skip-verify") {
options.skipVerify = true;
continue;
}
if (arg === "--help") {
console.log(`Usage: node scripts/release-website.mjs [options]
Options:
--skip-verify Do not assert the deployed page includes the current version.
--help Show this help.
`);
process.exit(0);
}
throw new Error(`Unknown argument: ${arg}`);
}
return options;
}
async function readPackageJson() {
return JSON.parse(await readFile(packageJsonPath, "utf8"));
}
async function runPlain(command, args, cwd = rootDir) {
await new Promise((resolve, reject) => {
const child = spawn(command, args, {
cwd,
stdio: "inherit",
shell: process.platform === "win32",
});
child.on("error", reject);
child.on("close", (code) => {
if (code === 0) {
resolve();
return;
}
reject(new Error(`${command} ${args.join(" ")} failed with exit code ${code ?? 1}`));
});
});
}
async function buildAndDeployLanding() {
if (!existsSync(join(landingDir, "node_modules"))) {
await runPlain("npm", ["ci"], landingDir);
}
await runPlain("npm", ["run", "build"], landingDir);
const deploy = await run(
"npx",
["wrangler", "pages", "deploy", "out", "--project-name", pagesProjectName, "--branch", pagesBranch, "--commit-dirty=true"],
{ cwd: landingDir, capture: true },
);
const output = `${deploy.stdout}\n${deploy.stderr}`;
const urlMatch = output.match(/https:\/\/[^\s]+\.agentcompany\.pages\.dev/);
return urlMatch?.[0] ?? null;
}
async function verifyPublishedAssets(version, deployUrl) {
const linksSource = await readFile(join(landingDir, "components", "release-links.generated.ts"), "utf8");
const required = [
`AgentCompany-${version}-arm64.dmg`,
`AgentCompany.Setup.${version}.exe`,
`agent-company-${version}.aarch64.rpm`,
`agent-company_${version}_arm64.deb`,
];
const missing = required.filter((frag) => !linksSource.includes(frag));
if (missing.length > 0) {
throw new Error(
`Missing expected release assets in generated links (did you run release:local-mac and release:local-winlinux first?):\n ${missing.join("\n ")}`,
);
}
if (deployUrl) {
const { stdout } = await run("curl", ["-L", "--silent", "-A", "Mozilla/5.0", deployUrl], { capture: true });
if (!stdout.includes(version)) {
throw new Error(`Deployed landing preview ${deployUrl} does not contain version ${version}.`);
}
}
}
async function main() {
const options = parseArgs(process.argv.slice(2));
await loadEnvFile(join(rootDir, ".env.release.local"));
await loadEnvFile(join(rootDir, ".env.release"));
await prepareR2ReleaseHost({ rootDir });
await runPlain("pnpm", ["audit:deps"]);
const version = (await readPackageJson()).version;
console.log(`[release-website] regenerating landing for version ${version}`);
await runPlain("node", ["scripts/generate-landing-release-links.mjs"]);
await applyD1Migrations({ landingDir, run });
const deployUrl = await buildAndDeployLanding();
if (!options.skipVerify) {
await verifyPublishedAssets(version, deployUrl);
}
console.log(JSON.stringify({
version,
deployUrl,
updateUrl: process.env.AGENTCOMPANY_UPDATE_URL ?? null,
}, null, 2));
}
await main();