// Publish the built hub binary to a rolling "dev" release on Gitea. // Runs in the CI job with only Node available (the runner image has no // curl/jq/sudo), so this uses Node built-ins + global fetch/FormData/Blob. // // Env: TOKEN (Gitea token), SERVER (github.server_url), REPO (owner/repo), // SHA (github.sha). Expects ./remoterig in the working dir. import { readFileSync } from 'node:fs'; import { createHash } from 'node:crypto'; const { TOKEN, SERVER, REPO, SHA } = process.env; const BIN = 'remoterig'; const VERSION = SHA.slice(0, 8); const API = `${SERVER}/api/v1/repos/${REPO}`; const H = { Authorization: `token ${TOKEN}` }; const ok = async (r) => { if (!r.ok) throw new Error(`${r.status} ${r.url}\n${await r.text()}`); const t = await r.text(); return t ? JSON.parse(t) : null; }; const bin = readFileSync(BIN); const sha256 = createHash('sha256').update(bin).digest('hex'); const files = { [BIN]: bin, [`${BIN}.sha256`]: Buffer.from(sha256 + '\n'), 'version.txt': Buffer.from(VERSION + '\n'), }; // Roll the "dev" release forward to this commit: delete the old release + tag. const existing = await fetch(`${API}/releases/tags/dev`, { headers: H }); if (existing.ok) { const rel = await existing.json(); await fetch(`${API}/releases/${rel.id}`, { method: 'DELETE', headers: H }); } await fetch(`${API}/tags/dev`, { method: 'DELETE', headers: H }); // ignore if absent const rel = await ok(await fetch(`${API}/releases`, { method: 'POST', headers: { ...H, 'Content-Type': 'application/json' }, body: JSON.stringify({ tag_name: 'dev', target_commitish: SHA, name: `dev (${VERSION})`, body: `Rolling dev build ${SHA}`, prerelease: true, }), })); for (const [name, buf] of Object.entries(files)) { const fd = new FormData(); fd.append('attachment', new Blob([buf]), name); await ok(await fetch(`${API}/releases/${rel.id}/assets?name=${encodeURIComponent(name)}`, { method: 'POST', headers: H, body: fd, })); console.log(`uploaded ${name}`); } console.log(`Published dev release ${VERSION}`);