Spigot/index.mjs
Matheus Sampaio Queiroga bfe21134a7
All checks were successful
Spigot Build / build (push) Successful in 10s
Update fetch
Reviewed-on: #1
Co-authored-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
Co-committed-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
2024-08-18 09:18:00 +00:00

135 lines
5.6 KiB
JavaScript

#!/usr/bin/env node
import fs from "node:fs";
import path from "node:path";
import stream from "node:stream";
import os from "node:os";
import { finished } from "node:stream/promises";
import { execFileSync } from "node:child_process";
const rootURL = process.env.GITHUB_SERVER_URL || "https://sirherobrine23.org"
function concat(...args) {
return String.prototype.concat(...args)
}
/**
* get release
* @param {string} token
* @param {string} version
*
* @returns {{ tag_name: string; assets: { id: number; name: string; browser_download_url: string; }[]; }}
*/
async function getRelease(token, version) {
const rel = await fetch(concat(rootURL, "/api/v1/repos/Minecraft-Server/Spigot/releases/tags/", version), { headers: {"Authorization": ("token ").concat(token)} });
const data = await rel.json();
if (data.id === undefined) throw new Error("Tag not exists!");
return data;
}
function semverSort(a, b) {
if (!(typeof a === "number" || typeof a === "string" || typeof a === "bigint")) throw new TypeError("Require string, number or bigint");
if (!(typeof b === "number" || typeof b === "string" || typeof b === "bigint")) throw new TypeError("Require string, number or bigint");
if ((typeof a === "number" && typeof b === "number") || (typeof a === "bigint" && typeof b === "bigint")) {
if (a > b) return 1;
else if (a < b) return -1;
return 0;
}
if (!(typeof a === "string" && typeof b === "string")) throw new TypeError("The paraments have to be the same type!");
const partsA = a.split("."), partsB = b.split(".");
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
const numA = parseInt(partsA[i] || "0"), numB = parseInt(partsB[i] || "0");
if (numA > numB) return 1;
if (numA < numB) return -1;
}
return 0;
}
/**
* Upload file to release
* @param {string} token
* @param {boolean} prerelease
* @param {string} version
* @param {...{name: string, size: number, fileStream: Blob}} files
*/
async function uploadToRelease(token, prerelease, version, ...files) {
const exist = await fetch(concat(rootURL, "/api/v1/repos/Minecraft-Server/Spigot/releases/tags/", version), { headers: {"Authorization": ("token ").concat(token)} });
if (!exist.ok || (await exist.json()).id === undefined) {
const status = await fetch(concat(rootURL, "/api/v1/repos/Minecraft-Server/Spigot/releases"), {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": ("token ").concat(token),
},
body: JSON.stringify({
tag_name: version,
name: version,
prerelease: !!prerelease,
}),
});
if (status.status !== 201) throw new Error("Cannot create release, check token", { cause: { createRelease: status } });
}
const { upload_url } = (await (await fetch(concat(rootURL, "/api/v1/repos/Minecraft-Server/Spigot/releases/tags/", version))).json());
return Promise.all(Array.from(files).filter(Boolean).map(async ({ name, fileStream }) => {
const to = new URL(upload_url);
to.searchParams.set("name", name);
const form = new FormData;
form.set("attachment", fileStream);
const status = await fetch(to, {
method: "POST",
headers: { "Authorization": ("token ").concat(token) },
body: form,
});
if (status.status !== 201) throw new Error("Cannot upload file, check token", { cause: { name, blobUpload: await status.json(), status: { code: status.status, message: status.statusText } } });
return status.json();
}));
}
const { GH_TOKEN } = process.env;
/** @type {{ versions: {type: string, id: string}[] }} */
const dataHtml = await (await fetch("https://hub.spigotmc.org/versions/")).text();
const mcVersions = Array.from(dataHtml.match(/href=["'](.*)["']/g)).map(s => s.slice(6, -1)).filter(s => s.endsWith(".json") && s.slice(0, 2) === "1.").map(s => s.slice(0, -5)).sort(semverSort);
const versionsUpload = (await Promise.all(mcVersions.map(async ver => getRelease(GH_TOKEN, ver).then(() => ({exist: true, ver}), () => ({exist: false, ver}))))).filter(s => semverSort(s.ver, "1.8") >= 0 && !s.exist);
if (versionsUpload.length === 0) {
console.log("Servers are updated");
process.exit(0);
}
const builderPath = path.join(os.tmpdir(), "build.jar");
await finished(stream.Readable.fromWeb((await fetch("https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar")).body).pipe(fs.createWriteStream(builderPath)), { error: true });
for (const { ver: version } of versionsUpload) {
console.log("\n\n------- %s -------\n\n", version);
const buildFolder = path.join(process.cwd(), version);
await fs.promises.rm(buildFolder, { recursive: true }).catch(() => {});
await fs.promises.mkdir(buildFolder, { recursive: true });
try {
execFileSync("java", [
"-jar",
builderPath,
"--rev",
version
], {
cwd: buildFolder,
stdio: "inherit",
});
const files = (await fs.promises.readdir(buildFolder, { recursive: true })).filter(s => s.endsWith(".jar"));
if (files.length === 0) {
console.warn("No files to upload in ver %s", version);
continue;
}
const craftbukkit = files.find(s => s.toLowerCase().startsWith("craftbukkit"));
await uploadToRelease(GH_TOKEN, false, version,
{ name: "server.jar", fileStream: await fs.openAsBlob(path.join(buildFolder, files.find(s => s.toLowerCase().startsWith("spigot")))) },
craftbukkit ? { name: path.basename(craftbukkit), fileStream: await fs.openAsBlob(path.join(buildFolder, craftbukkit)) } : null,
);
} catch (err) {
console.error(err);
process.exit(-1);
} finally {
await fs.promises.rm(buildFolder, { recursive: true });
}
}