summaryrefslogtreecommitdiffstats
path: root/extra/release
diff options
context:
space:
mode:
Diffstat (limited to 'extra/release')
-rw-r--r--extra/release/beta.mjs65
-rw-r--r--extra/release/final.mjs57
-rw-r--r--extra/release/lib.mjs191
-rw-r--r--extra/release/nightly.mjs16
4 files changed, 329 insertions, 0 deletions
diff --git a/extra/release/beta.mjs b/extra/release/beta.mjs
new file mode 100644
index 0000000..a2c9809
--- /dev/null
+++ b/extra/release/beta.mjs
@@ -0,0 +1,65 @@
+import "dotenv/config";
+import {
+ ver,
+ buildDist,
+ buildImage,
+ checkDocker,
+ checkTagExists,
+ checkVersionFormat,
+ dryRun,
+ getRepoName,
+ pressAnyKey,
+ execSync, uploadArtifacts,
+} from "./lib.mjs";
+import semver from "semver";
+
+const repoName = getRepoName();
+const version = process.env.RELEASE_BETA_VERSION;
+const githubToken = process.env.RELEASE_GITHUB_TOKEN;
+
+console.log("RELEASE_BETA_VERSION:", version);
+
+if (!githubToken) {
+ console.error("GITHUB_TOKEN is required");
+ process.exit(1);
+}
+
+// Check if the version is a valid semver
+checkVersionFormat(version);
+
+// Check if the semver identifier is "beta"
+const semverIdentifier = semver.prerelease(version);
+console.log("Semver identifier:", semverIdentifier);
+if (semverIdentifier[0] !== "beta") {
+ console.error("VERSION should have a semver identifier of 'beta'");
+ process.exit(1);
+}
+
+// Check if docker is running
+checkDocker();
+
+// Check if the tag exists
+await checkTagExists(repoName, version);
+
+// node extra/beta/update-version.js
+execSync("node ./extra/beta/update-version.js");
+
+// Build frontend dist
+buildDist();
+
+// Build slim image (rootless)
+buildImage(repoName, [ "beta-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
+
+// Build full image (rootless)
+buildImage(repoName, [ "beta-rootless", ver(version, "rootless") ], "rootless");
+
+// Build slim image
+buildImage(repoName, [ "beta-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
+
+// Build full image
+buildImage(repoName, [ "beta", version ], "release");
+
+await pressAnyKey();
+
+// npm run upload-artifacts
+uploadArtifacts();
diff --git a/extra/release/final.mjs b/extra/release/final.mjs
new file mode 100644
index 0000000..d190ac0
--- /dev/null
+++ b/extra/release/final.mjs
@@ -0,0 +1,57 @@
+import "dotenv/config";
+import {
+ ver,
+ buildDist,
+ buildImage,
+ checkDocker,
+ checkTagExists,
+ checkVersionFormat,
+ getRepoName,
+ pressAnyKey, execSync, uploadArtifacts
+} from "./lib.mjs";
+
+const repoName = getRepoName();
+const version = process.env.RELEASE_VERSION;
+const githubToken = process.env.RELEASE_GITHUB_TOKEN;
+
+console.log("RELEASE_VERSION:", version);
+
+if (!githubToken) {
+ console.error("GITHUB_TOKEN is required");
+ process.exit(1);
+}
+
+// Check if the version is a valid semver
+checkVersionFormat(version);
+
+// Check if docker is running
+checkDocker();
+
+// Check if the tag exists
+await checkTagExists(repoName, version);
+
+// node extra/beta/update-version.js
+execSync("node extra/update-version.js");
+
+// Build frontend dist
+buildDist();
+
+// Build slim image (rootless)
+buildImage(repoName, [ "2-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
+
+// Build full image (rootless)
+buildImage(repoName, [ "2-rootless", ver(version, "rootless") ], "rootless");
+
+// Build slim image
+buildImage(repoName, [ "next-slim", "2-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
+
+// Build full image
+buildImage(repoName, [ "next", "2", version ], "release");
+
+await pressAnyKey();
+
+// npm run upload-artifacts
+uploadArtifacts();
+
+// node extra/update-wiki-version.js
+execSync("node extra/update-wiki-version.js");
diff --git a/extra/release/lib.mjs b/extra/release/lib.mjs
new file mode 100644
index 0000000..d6c294c
--- /dev/null
+++ b/extra/release/lib.mjs
@@ -0,0 +1,191 @@
+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 getRepoName() {
+ return process.env.RELEASE_REPO_NAME || "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} repoName Docker Hub repository name
+ * @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(repoName, tags, target, buildArgs = "", dockerfile = "docker/dockerfile", platform = "linux/amd64,linux/arm64,linux/arm/v7") {
+ let args = [
+ "buildx",
+ "build",
+ "-f",
+ dockerfile,
+ "--platform",
+ platform,
+ ];
+
+ // 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} repoName Docker Hub repository name
+ * @param {string} version Version to check
+ * @returns {void}
+ */
+export async function checkTagExists(repoName, version) {
+ console.log(`Checking if version ${version} exists on Docker Hub`);
+
+ // 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
+ * @returns {void}
+ */
+export function uploadArtifacts() {
+ execSync("npm run upload-artifacts");
+}
+
+/**
+ * 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}`);
+ }
+}
diff --git a/extra/release/nightly.mjs b/extra/release/nightly.mjs
new file mode 100644
index 0000000..c6641ba
--- /dev/null
+++ b/extra/release/nightly.mjs
@@ -0,0 +1,16 @@
+import { buildDist, buildImage, checkDocker, getRepoName } from "./lib.mjs";
+
+// Docker Hub repository name
+const repoName = getRepoName();
+
+// Check if docker is running
+checkDocker();
+
+// Build frontend dist (it will build on the host machine, TODO: build on a container?)
+buildDist();
+
+// Build full image (rootless)
+buildImage(repoName, [ "nightly2-rootless" ], "nightly-rootless");
+
+// Build full image
+buildImage(repoName, [ "nightly2" ], "nightly");