CI on Gitea: cap test workers so a shared runner does not time out; tag pushes build and attach Windows, Linux and macOS installers to the Gitea release; version 1.5.0
CI / Typecheck, lint, tests, e2e (push) Successful in 3m29s
Build Release Installers / Release for the tag (push) Successful in 11s
Build Release Installers / Linux packages (AppImage + deb x64) (push) Failing after 37s
Build Release Installers / Windows installer (NSIS x64) (push) Successful in 55s
Build Release Installers / macOS installers (dmg + zip, x64 + arm64) (push) Successful in 6m53s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-10-09 16:33:46 -04:00
1 parent 15a93165e0
commit 8299346fbd
4 files changed
+111 -46

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
// Gitea release for the pushed tag: `create` checks the tag against package.json and opens the release; `upload` attaches installers.
import { openAsBlob } from "node:fs";
import { readdir, readFile } from "node:fs/promises";
import { basename, join } from "node:path";
const INSTALLER = /\.(exe|dmg|zip|AppImage|deb)$/;
function env(name) {
const value = process.env[name];
if (!value) throw new Error(`${name} is not set.`);
return value;
}
const api = `${env("GITHUB_SERVER_URL")}/api/v1/repos/${env("GITHUB_REPOSITORY")}`;
const tag = env("GITHUB_REF_NAME");
const headers = { Authorization: `token ${env("GITEA_TOKEN")}` };
async function call(method, path, body) {
const response = await fetch(`${api}${path}`, { method, headers: body instanceof FormData ? headers : { ...headers, "Content-Type": "application/json" }, body: body instanceof FormData ? body : body && JSON.stringify(body) });
if (!response.ok) throw new Error(`${method} ${path} failed: ${response.status} ${await response.text()}`);
return response.status === 204 ? null : response.json();
}
async function create() {
const { version } = JSON.parse(await readFile("package.json", "utf8"));
if (tag !== `v${version}`) throw new Error(`Tag ${tag} does not match package.json version ${version}; bump the version before tagging.`);
const existing = await fetch(`${api}/releases/tags/${tag}`, { headers });
if (existing.ok) return console.log(`Release ${tag} already exists.`);
if (existing.status !== 404) throw new Error(`Looking up release ${tag} failed: ${existing.status} ${await existing.text()}`);
await call("POST", "/releases", { tag_name: tag, name: `AgentCompany ${version}`, draft: false, prerelease: false });
console.log(`Created release ${tag}.`);
}
async function upload(dir) {
const files = (await readdir(dir)).filter((name) => INSTALLER.test(name)).map((name) => join(dir, name));
if (files.length === 0) throw new Error(`No installers found in ${dir}.`);
const release = await call("GET", `/releases/tags/${tag}`);
for (const file of files) {
const name = basename(file);
// A re-run replaces the asset instead of failing on the duplicate name.
const old = release.assets.find((asset) => asset.name === name);
if (old) await call("DELETE", `/releases/${release.id}/assets/${old.id}`);
const form = new FormData();
form.append("attachment", await openAsBlob(file), name);
await call("POST", `/releases/${release.id}/assets?name=${encodeURIComponent(name)}`, form);
console.log(`Uploaded ${name}.`);
}
}
const [command, dir] = process.argv.slice(2);
if (command === "create") await create();
else if (command === "upload") await upload(dir ?? "release");
else throw new Error(`Unknown command ${command}; use create or upload.`);