252 lines
6.5 KiB
JavaScript
252 lines
6.5 KiB
JavaScript
import "dotenv/config";
|
|
import * as childProcess from "child_process";
|
|
import semver from "semver";
|
|
|
|
export const dryRun = process.env.RELEASE_DRY_RUN === "1";
|
|
|
|
if (dryRun) {
|
|
console.info("Dry run enabled.");
|
|
}
|
|
|
|
/**
|
|
* Check if docker is running
|
|
* @returns {void}
|
|
*/
|
|
export function checkDocker() {
|
|
try {
|
|
childProcess.execSync("docker ps");
|
|
} catch (error) {
|
|
console.error("Docker is not running. Please start docker and try again.");
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get Docker Hub repository name
|
|
*/
|
|
export function getRepoNames() {
|
|
if (process.env.RELEASE_REPO_NAMES) {
|
|
// Split by comma
|
|
return process.env.RELEASE_REPO_NAMES.split(",").map((name) => name.trim());
|
|
}
|
|
return [
|
|
"louislam/uptime-kuma",
|
|
"ghcr.io/louislam/uptime-kuma",
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Build frontend dist
|
|
* @returns {void}
|
|
*/
|
|
export function buildDist() {
|
|
if (!dryRun) {
|
|
childProcess.execSync("npm run build", { stdio: "inherit" });
|
|
} else {
|
|
console.info("[DRY RUN] npm run build");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build docker image and push to Docker Hub
|
|
* @param {string[]} repoNames Docker Hub repository names
|
|
* @param {string[]} tags Docker image tags
|
|
* @param {string} target Dockerfile's target name
|
|
* @param {string} buildArgs Docker build args
|
|
* @param {string} dockerfile Path to Dockerfile
|
|
* @param {string} platform Build platform
|
|
* @returns {void}
|
|
*/
|
|
export function buildImage(repoNames, tags, target, buildArgs = "", dockerfile = "docker/dockerfile", platform = "linux/amd64,linux/arm64,linux/arm/v7") {
|
|
let args = [
|
|
"buildx",
|
|
"build",
|
|
"-f",
|
|
dockerfile,
|
|
"--platform",
|
|
platform,
|
|
];
|
|
|
|
for (let repoName of repoNames) {
|
|
// Add tags
|
|
for (let tag of tags) {
|
|
args.push("-t", `${repoName}:${tag}`);
|
|
}
|
|
}
|
|
|
|
args = [
|
|
...args,
|
|
"--target",
|
|
target,
|
|
];
|
|
|
|
// Add build args
|
|
if (buildArgs) {
|
|
args.push("--build-arg", buildArgs);
|
|
}
|
|
|
|
args = [
|
|
...args,
|
|
".",
|
|
"--push",
|
|
];
|
|
|
|
if (!dryRun) {
|
|
childProcess.spawnSync("docker", args, { stdio: "inherit" });
|
|
} else {
|
|
console.log(`[DRY RUN] docker ${args.join(" ")}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if the version already exists on Docker Hub
|
|
* TODO: use semver to compare versions if it is greater than the previous?
|
|
* @param {string[]} repoNames repository name (Only check the name with single slash)
|
|
* @param {string} version Version to check
|
|
* @returns {void}
|
|
*/
|
|
export async function checkTagExists(repoNames, version) {
|
|
// Skip if the tag is not on Docker Hub
|
|
// louislam/uptime-kuma
|
|
let dockerHubRepoNames = repoNames.filter((name) => {
|
|
return name.split("/").length === 2;
|
|
});
|
|
|
|
for (let repoName of dockerHubRepoNames) {
|
|
await checkTagExistsSingle(repoName, version);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if the version already exists on Docker Hub
|
|
* @param {string} repoName repository name
|
|
* @param {string} version Version to check
|
|
* @returns {Promise<void>}
|
|
*/
|
|
export async function checkTagExistsSingle(repoName, version) {
|
|
console.log(`Checking if version ${version} exists on Docker Hub:`, repoName);
|
|
|
|
// Get a list of tags from the Docker Hub repository
|
|
let tags = [];
|
|
|
|
// It is mainly to check my careless mistake that I forgot to update the release version in .env, so `page_size` is set to 100 is enough, I think.
|
|
const response = await fetch(`https://hub.docker.com/v2/repositories/${repoName}/tags/?page_size=100`);
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
tags = data.results.map((tag) => tag.name);
|
|
} else {
|
|
console.error("Failed to get tags from Docker Hub");
|
|
process.exit(1);
|
|
}
|
|
|
|
// Check if the version already exists
|
|
if (tags.includes(version)) {
|
|
console.error(`Version ${version} already exists`);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check the version format
|
|
* @param {string} version Version to check
|
|
* @returns {void}
|
|
*/
|
|
export function checkVersionFormat(version) {
|
|
if (!version) {
|
|
console.error("VERSION is required");
|
|
process.exit(1);
|
|
}
|
|
|
|
// Check the version format, it should be a semver and must be like this: "2.0.0-beta.0"
|
|
if (!semver.valid(version)) {
|
|
console.error("VERSION is not a valid semver version");
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Press any key to continue
|
|
* @returns {Promise<void>}
|
|
*/
|
|
export function pressAnyKey() {
|
|
console.log("Git Push and Publish the release note on github, then press any key to continue");
|
|
process.stdin.setRawMode(true);
|
|
process.stdin.resume();
|
|
return new Promise(resolve => process.stdin.once("data", data => {
|
|
process.stdin.setRawMode(false);
|
|
process.stdin.pause();
|
|
resolve();
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Append version identifier
|
|
* @param {string} version Version
|
|
* @param {string} identifier Identifier
|
|
* @returns {string} Version with identifier
|
|
*/
|
|
export function ver(version, identifier) {
|
|
const obj = semver.parse(version);
|
|
|
|
if (obj.prerelease.length === 0) {
|
|
obj.prerelease = [ identifier ];
|
|
} else {
|
|
obj.prerelease[0] = [ obj.prerelease[0], identifier ].join("-");
|
|
}
|
|
return obj.format();
|
|
}
|
|
|
|
/**
|
|
* Upload artifacts to GitHub
|
|
* docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain
|
|
* @param {string} version Version
|
|
* @param {string} githubToken GitHub token
|
|
* @returns {void}
|
|
*/
|
|
export function uploadArtifacts(version, githubToken) {
|
|
let args = [
|
|
"buildx",
|
|
"build",
|
|
"-f",
|
|
"docker/dockerfile",
|
|
"--platform",
|
|
"linux/amd64",
|
|
"-t",
|
|
"louislam/uptime-kuma:upload-artifact",
|
|
"--build-arg",
|
|
`VERSION=${version}`,
|
|
"--build-arg",
|
|
"GITHUB_TOKEN",
|
|
"--target",
|
|
"upload-artifact",
|
|
".",
|
|
"--progress",
|
|
"plain",
|
|
];
|
|
|
|
if (!dryRun) {
|
|
childProcess.spawnSync("docker", args, {
|
|
stdio: "inherit",
|
|
env: {
|
|
...process.env,
|
|
GITHUB_TOKEN: githubToken,
|
|
},
|
|
});
|
|
} else {
|
|
console.log(`[DRY RUN] docker ${args.join(" ")}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute a command
|
|
* @param {string} cmd Command to execute
|
|
* @returns {void}
|
|
*/
|
|
export function execSync(cmd) {
|
|
if (!dryRun) {
|
|
childProcess.execSync(cmd, { stdio: "inherit" });
|
|
} else {
|
|
console.info(`[DRY RUN] ${cmd}`);
|
|
}
|
|
}
|