133 lines
3.8 KiB
JavaScript
Executable File
133 lines
3.8 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
// Create a Gitea release and upload an asset.
|
|
// Usage:
|
|
// node scripts/gitea-release.mjs --tag v1.1.1 --name "Q-Edit v1.1.1" \
|
|
// --notes docs/RELEASE_NOTES_v1.1.1.md --asset q-edit_dist.zip
|
|
// Env:
|
|
// GITEA_TOKEN (required)
|
|
// GITEA_BASE (optional, default parsed from git remote origin; fallback https://gitea.qortal.link)
|
|
|
|
import { execSync } from "node:child_process";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
function parseArgs(argv) {
|
|
const out = {};
|
|
for (let i = 2; i < argv.length; i++) {
|
|
const a = argv[i];
|
|
if (a === "--tag") {
|
|
out.tag = argv[++i];
|
|
} else if (a === "--name") {
|
|
out.name = argv[++i];
|
|
} else if (a === "--notes") {
|
|
out.notes = argv[++i];
|
|
} else if (a === "--asset") {
|
|
out.asset = argv[++i];
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
function getOrigin() {
|
|
try {
|
|
const s = execSync("git config --get remote.origin.url", { encoding: "utf8" }).trim();
|
|
return s;
|
|
} catch {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
function deriveRepo(originUrl) {
|
|
try {
|
|
const u = new URL(originUrl);
|
|
const parts = u.pathname
|
|
.replace(/\.git$/, "")
|
|
.split("/")
|
|
.filter(Boolean);
|
|
const owner = parts[0];
|
|
const repo = parts[1];
|
|
const base = `${u.protocol}//${u.host}`;
|
|
return { base, owner, repo };
|
|
} catch {
|
|
return { base: "https://gitea.qortal.link", owner: "", repo: "" };
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
const { tag, name, notes, asset } = parseArgs(process.argv);
|
|
if (!tag || !name) {
|
|
console.error("Usage: --tag vX.Y.Z --name 'Q-Edit vX.Y.Z' --notes <file> [--asset <file>]");
|
|
process.exit(1);
|
|
}
|
|
const token = process.env.GITEA_TOKEN;
|
|
if (!token) {
|
|
console.error("GITEA_TOKEN env var is required to create a release.");
|
|
process.exit(2);
|
|
}
|
|
|
|
const origin = getOrigin();
|
|
const parsed = deriveRepo(origin);
|
|
const base = process.env.GITEA_BASE || parsed.base || "https://gitea.qortal.link";
|
|
const owner = process.env.GITEA_OWNER || parsed.owner;
|
|
const repo = process.env.GITEA_REPO || parsed.repo;
|
|
if (!owner || !repo) {
|
|
console.error(
|
|
"Could not determine owner/repo from git remote. Set GITEA_OWNER and GITEA_REPO."
|
|
);
|
|
process.exit(3);
|
|
}
|
|
|
|
const body = notes ? fs.readFileSync(notes, "utf8") : "";
|
|
const createUrl = `${base}/api/v1/repos/${owner}/${repo}/releases`;
|
|
|
|
const createRes = await fetch(createUrl, {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
Authorization: `token ${token}`,
|
|
},
|
|
body: JSON.stringify({
|
|
tag_name: tag,
|
|
name,
|
|
body,
|
|
draft: false,
|
|
prerelease: false,
|
|
}),
|
|
});
|
|
if (!createRes.ok) {
|
|
const t = await createRes.text();
|
|
console.error("Failed to create release:", createRes.status, t);
|
|
process.exit(4);
|
|
}
|
|
const rel = await createRes.json();
|
|
console.log("Created release:", rel.html_url || rel.url || rel.id);
|
|
|
|
if (asset && fs.existsSync(asset)) {
|
|
const st = fs.statSync(asset);
|
|
const assetUrl = `${base}/api/v1/repos/${owner}/${repo}/releases/${rel.id}/assets?name=${encodeURIComponent(path.basename(asset))}`;
|
|
const buf = fs.readFileSync(asset);
|
|
const blob = new Blob([buf], { type: "application/zip" });
|
|
const fd = new FormData();
|
|
fd.append("attachment", blob, path.basename(asset));
|
|
|
|
const upRes = await fetch(assetUrl, {
|
|
method: "POST",
|
|
headers: { Authorization: `token ${token}` },
|
|
body: fd,
|
|
});
|
|
if (!upRes.ok) {
|
|
const t = await upRes.text();
|
|
console.error("Failed to upload asset:", upRes.status, t);
|
|
process.exit(5);
|
|
}
|
|
console.log(`Uploaded asset ${path.basename(asset)} (${st.size} bytes).`);
|
|
} else if (asset) {
|
|
console.warn(`Asset not found: ${asset} (skipping upload)`);
|
|
}
|
|
}
|
|
|
|
main().catch((e) => {
|
|
console.error("gitea-release failed:", e);
|
|
process.exit(99);
|
|
});
|