const version = process.argv[2]; if (!version) { console.error("Version not passed to create-gitea-release.js"); process.exit(1); } import fs from "fs-extra"; import path from "path"; import { spawnSync } from "child_process"; import { fileURLToPath } from "url"; import fetch from "node-fetch"; import dotenv from "dotenv"; dotenv.config({ path: "./.env" }); import { createRequire } from "node:module"; const require = createRequire(import.meta.url); const conventionalChangelog = require("conventional-changelog"); // Resolve the directory of the current script const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Absolute path to BUILD_NUMBER const buildNumberPath = path.resolve(__dirname, "../BUILD_NUMBER"); // Load build number from BUILD_NUMBER file let buildNumber = "0"; try { const rawBuild = fs.readFileSync(buildNumberPath, "utf8"); console.log("Raw build", rawBuild); buildNumber = rawBuild.trim(); } catch (e) { console.log(e); console.warn("BUILD_NUMBER file not found, defaulting to 0"); } const fullVersion = `${version}.${buildNumber}`; const { GITEA_URL, GITEA_USERNAME, GITEA_REPO, GITEA_TOKEN } = process.env; if (!GITEA_URL || !GITEA_USERNAME || !GITEA_REPO || !GITEA_TOKEN) { console.error("Missing required environment variables"); process.exit(1); } // Step 1: Generate or update CHANGELOG.md console.log("Generating CHANGELOG.md..."); const result = spawnSync( "npx", [ "conventional-changelog", "-p", "conventionalcommits", "-i", "CHANGELOG.md", "-s", "-r", "1", ], { stdio: "inherit", shell: true } ); if (result.status !== 0) { console.error("Failed to generate changelog"); process.exit(1); } const getLatestChangelog = async () => { const changelogStream = conventionalChangelog({ preset: "conventionalcommits", releaseCount: 1, }); let changelog = ""; for await (const chunk of changelogStream) { changelog += chunk; } return changelog; }; const releaseNotes = await getLatestChangelog(); // Step 3: Create or update Gitea release const createOrUpdateRelease = async () => { const tagName = `v${version}`; const apiBase = `https://${GITEA_URL}/api/v1/repos/${GITEA_USERNAME}/${GITEA_REPO}`; const existing = await fetch(`${apiBase}/releases/tags/${tagName}`, { headers: { Authorization: `token ${GITEA_TOKEN}` }, }); let release; if (existing.ok) { const existingRelease = await existing.json(); console.log(`Release ${tagName} already exists. Updating it.`); const updateResponse = await fetch( `${apiBase}/releases/${existingRelease.id}`, { method: "PATCH", headers: { Authorization: `token ${GITEA_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ name: tagName, body: releaseNotes, draft: false, prerelease: true, }), } ); if (!updateResponse.ok) { const errorText = await updateResponse.text(); throw new Error( `Failed to update release: ${updateResponse.status} - ${errorText}` ); } release = await updateResponse.json(); console.log("Release updated:", release.html_url || release.url); } else if (existing.status === 404) { const createResponse = await fetch(`${apiBase}/releases`, { method: "POST", headers: { Authorization: `token ${GITEA_TOKEN}`, "Content-Type": "application/json", }, body: JSON.stringify({ tag_name: tagName, name: `Release ${fullVersion}`, body: releaseNotes, draft: false, prerelease: true, }), }); if (!createResponse.ok) { const errorText = await createResponse.text(); throw new Error( `Failed to create release: ${createResponse.status} - ${errorText}` ); } release = await createResponse.json(); console.log("Release created:", release.html_url || release.url); } else { const errorText = await existing.text(); throw new Error( `Failed to check release: ${existing.status} - ${errorText}` ); } return release; }; const uploadAsset = async (release) => { const apiUrl = `https://${GITEA_URL}/api/v1/repos/${GITEA_USERNAME}/${GITEA_REPO}/releases/assets?tag=${release.tag_name}`; const filePath = `releases/release-${fullVersion}.zip`; if (!(await fs.pathExists(filePath))) { console.warn(`Zip file not found: ${filePath}. Skipping asset upload.`); return; } const FormData = (await import("form-data")).default; const form = new FormData(); form.append("name", `release-${fullVersion}.zip`); form.append("attachment", fs.createReadStream(filePath)); const response = await fetch(apiUrl, { method: "POST", headers: { Authorization: `token ${GITEA_TOKEN}`, ...form.getHeaders(), }, body: form, }); if (!response.ok) { const errorText = await response.text(); throw new Error( `Failed to upload asset: ${response.status} - ${errorText}` ); } const asset = await response.json(); console.log("Asset uploaded:", asset.browser_download_url || asset.url); }; // Run everything (async () => { try { const release = await createOrUpdateRelease(); // await uploadAsset(release); // fix this later and just update the readme. } catch (err) { console.error(err); process.exit(1); } })();