mirror of
https://github.com/louislam/uptime-kuma.git
synced 2026-03-13 09:52:49 +08:00
chore: Update final release workflow (#6875)
This commit is contained in:
93
.github/workflows/release-final.yml
vendored
Normal file
93
.github/workflows/release-final.yml
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
name: Final Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Release version number (e.g., 2.1.0)"
|
||||
required: true
|
||||
type: string
|
||||
previous_version:
|
||||
description: "Previous version tag for changelog (e.g., 2.1.0-beta.3)"
|
||||
required: true
|
||||
type: string
|
||||
dry_run:
|
||||
description: "Dry Run (The docker image will not be pushed to registries. PR will still be created.)"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: master
|
||||
persist-credentials: true
|
||||
fetch-depth: 0 # Fetch all history for changelog generation
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
|
||||
with:
|
||||
node-version: 24
|
||||
|
||||
- name: Create release branch
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git"
|
||||
# Delete remote branch if it exists
|
||||
git push origin --delete "release-${VERSION}" || true
|
||||
# Delete local branch if it exists
|
||||
git branch -D "release-${VERSION}" || true
|
||||
# For testing purpose
|
||||
# git checkout beta-workflow
|
||||
git checkout -b "release-${VERSION}"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm clean-install --no-fund
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ secrets.GHCR_USERNAME }}
|
||||
password: ${{ secrets.GHCR_TOKEN }}
|
||||
|
||||
- name: Run release-final
|
||||
env:
|
||||
RELEASE_VERSION: ${{ inputs.version }}
|
||||
RELEASE_PREVIOUS_VERSION: ${{ inputs.previous_version }}
|
||||
DRY_RUN: ${{ inputs.dry_run }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_RUN_ID: ${{ github.run_id }}
|
||||
run: npm run release-final
|
||||
|
||||
- name: Upload dist.tar.gz as artifact
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
with:
|
||||
name: dist-${{ inputs.version }}
|
||||
path: ./tmp/dist.tar.gz
|
||||
retention-days: 90
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
checkTagExists,
|
||||
checkVersionFormat,
|
||||
getRepoNames,
|
||||
execSync,
|
||||
checkReleaseBranch,
|
||||
createDistTarGz,
|
||||
createReleasePR,
|
||||
|
||||
@@ -7,26 +7,39 @@ import {
|
||||
checkTagExists,
|
||||
checkVersionFormat,
|
||||
getRepoNames,
|
||||
pressAnyKey, execSync, uploadArtifacts, checkReleaseBranch
|
||||
checkReleaseBranch,
|
||||
createDistTarGz,
|
||||
createReleasePR,
|
||||
} from "./lib.mjs";
|
||||
import semver from "semver";
|
||||
|
||||
const repoNames = getRepoNames();
|
||||
const version = process.env.RELEASE_VERSION;
|
||||
const githubToken = process.env.RELEASE_GITHUB_TOKEN;
|
||||
const dryRun = process.env.DRY_RUN === "true";
|
||||
const previousVersion = process.env.RELEASE_PREVIOUS_VERSION;
|
||||
const branchName = `release-${version}`;
|
||||
const githubRunId = process.env.GITHUB_RUN_ID;
|
||||
|
||||
if (dryRun) {
|
||||
console.log("Dry run mode enabled. No images will be pushed.");
|
||||
}
|
||||
|
||||
console.log("RELEASE_VERSION:", version);
|
||||
|
||||
if (!githubToken) {
|
||||
console.error("GITHUB_TOKEN is required");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if the current branch is "release"
|
||||
checkReleaseBranch();
|
||||
// Check if the current branch is "release-{version}"
|
||||
checkReleaseBranch(branchName);
|
||||
|
||||
// Check if the version is a valid semver
|
||||
checkVersionFormat(version);
|
||||
|
||||
// Check if the semver identifier is empty
|
||||
const semverIdentifier = semver.prerelease(version);
|
||||
console.log("Semver identifier:", semverIdentifier);
|
||||
if (semverIdentifier) {
|
||||
console.error("VERSION should not have a semver identifier for final release");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if docker is running
|
||||
checkDocker();
|
||||
|
||||
@@ -34,27 +47,42 @@ checkDocker();
|
||||
await checkTagExists(repoNames, version);
|
||||
|
||||
// node extra/beta/update-version.js
|
||||
execSync("node extra/update-version.js");
|
||||
await import("../update-version.mjs");
|
||||
|
||||
// Create Pull Request (gh pr create will handle pushing the branch)
|
||||
await createReleasePR(version, previousVersion, dryRun, branchName, githubRunId);
|
||||
|
||||
// Build frontend dist
|
||||
buildDist();
|
||||
|
||||
// Build slim image (rootless)
|
||||
buildImage(repoNames, [ "2-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
|
||||
if (!dryRun) {
|
||||
// Build slim image (rootless)
|
||||
buildImage(
|
||||
repoNames,
|
||||
["2-slim-rootless", ver(version, "slim-rootless")],
|
||||
"rootless",
|
||||
"BASE_IMAGE=louislam/uptime-kuma:base2-slim"
|
||||
);
|
||||
|
||||
// Build full image (rootless)
|
||||
buildImage(repoNames, [ "2-rootless", ver(version, "rootless") ], "rootless");
|
||||
// Build full image (rootless)
|
||||
buildImage(repoNames, ["2-rootless", ver(version, "rootless")], "rootless");
|
||||
|
||||
// Build slim image
|
||||
buildImage(repoNames, [ "next-slim", "2-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
|
||||
// Build slim image
|
||||
buildImage(
|
||||
repoNames,
|
||||
["next-slim", "2-slim", ver(version, "slim")],
|
||||
"release",
|
||||
"BASE_IMAGE=louislam/uptime-kuma:base2-slim"
|
||||
);
|
||||
|
||||
// Build full image
|
||||
buildImage(repoNames, [ "next", "2", version ], "release");
|
||||
// Build full image
|
||||
buildImage(repoNames, ["next", "2", version], "release");
|
||||
} else {
|
||||
console.log("Dry run mode - skipping image build and push.");
|
||||
}
|
||||
|
||||
await pressAnyKey();
|
||||
// Create dist.tar.gz
|
||||
await createDistTarGz();
|
||||
|
||||
// npm run upload-artifacts
|
||||
uploadArtifacts(version, githubToken);
|
||||
|
||||
// node extra/update-wiki-version.js
|
||||
execSync("node extra/update-wiki-version.js");
|
||||
// Removed update wiki to keep it simple
|
||||
// Do this in the wiki repo instead
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
const fs = require("fs");
|
||||
|
||||
// Read the file from private/sort-contributors.txt
|
||||
const file = fs.readFileSync("private/sort-contributors.txt", "utf8");
|
||||
|
||||
// Convert to an array of lines
|
||||
let lines = file.split("\n");
|
||||
|
||||
// Remove empty lines
|
||||
lines = lines.filter((line) => line !== "");
|
||||
|
||||
// Remove duplicates
|
||||
lines = [...new Set(lines)];
|
||||
|
||||
// Remove @weblate and @UptimeKumaBot
|
||||
lines = lines.filter((line) => line !== "@weblate" && line !== "@UptimeKumaBot" && line !== "@louislam");
|
||||
|
||||
// Sort the lines
|
||||
lines = lines.sort();
|
||||
|
||||
// Output the lines, concat with " "
|
||||
console.log(lines.join(" "));
|
||||
@@ -1,3 +1,6 @@
|
||||
import { createRequire } from "module";
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
const pkg = require("../package.json");
|
||||
const fs = require("fs");
|
||||
const childProcess = require("child_process");
|
||||
@@ -5,28 +8,28 @@ const util = require("../src/util");
|
||||
|
||||
util.polyfill();
|
||||
|
||||
const newVersion = process.env.RELEASE_VERSION;
|
||||
const version = process.env.RELEASE_VERSION;
|
||||
|
||||
console.log("New Version: " + newVersion);
|
||||
console.log("New Version: " + version);
|
||||
|
||||
if (!newVersion) {
|
||||
if (!version) {
|
||||
console.error("invalid version");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const exists = tagExists(newVersion);
|
||||
const exists = tagExists(version);
|
||||
|
||||
if (!exists) {
|
||||
// Process package.json
|
||||
pkg.version = newVersion;
|
||||
pkg.version = version;
|
||||
|
||||
// Replace the version: https://regex101.com/r/hmj2Bc/1
|
||||
pkg.scripts.setup = pkg.scripts.setup.replace(/(git checkout )([^\s]+)/, `$1${newVersion}`);
|
||||
pkg.scripts.setup = pkg.scripts.setup.replace(/(git checkout )([^\s]+)/, `$1${version}`);
|
||||
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n");
|
||||
|
||||
// Also update package-lock.json
|
||||
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
|
||||
const resultVersion = childProcess.spawnSync(npm, ["--no-git-tag-version", "version", newVersion], { shell: true });
|
||||
const resultVersion = childProcess.spawnSync(npm, ["--no-git-tag-version", "version", version], { shell: true });
|
||||
if (resultVersion.error) {
|
||||
console.error(resultVersion.error);
|
||||
console.error("error npm version!");
|
||||
@@ -38,9 +41,10 @@ if (!exists) {
|
||||
console.error("error update package-lock!");
|
||||
process.exit(1);
|
||||
}
|
||||
commit(newVersion);
|
||||
commit(version);
|
||||
} else {
|
||||
console.log("version exists");
|
||||
console.log("version tag exists, please delete the tag or use another tag");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,6 +63,14 @@ function commit(version) {
|
||||
if (stdout.includes("no changes added to commit")) {
|
||||
throw new Error("commit error");
|
||||
}
|
||||
|
||||
// Get the current branch name
|
||||
res = childProcess.spawnSync("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
|
||||
let branchName = res.stdout.toString().trim();
|
||||
console.log("Current branch:", branchName);
|
||||
|
||||
// Git push the branch
|
||||
childProcess.spawnSync("git", ["push", "origin", branchName, "--force"], { stdio: "inherit" });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1,58 +0,0 @@
|
||||
const childProcess = require("child_process");
|
||||
const fs = require("fs");
|
||||
|
||||
const newVersion = process.env.RELEASE_VERSION;
|
||||
|
||||
if (!newVersion) {
|
||||
console.log("Missing version");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
updateWiki(newVersion);
|
||||
|
||||
/**
|
||||
* Update the wiki with new version number
|
||||
* @param {string} newVersion Version to update to
|
||||
* @returns {void}
|
||||
*/
|
||||
function updateWiki(newVersion) {
|
||||
const wikiDir = "./tmp/wiki";
|
||||
const howToUpdateFilename = "./tmp/wiki/🆙-How-to-Update.md";
|
||||
|
||||
safeDelete(wikiDir);
|
||||
|
||||
childProcess.spawnSync("git", ["clone", "https://github.com/louislam/uptime-kuma.wiki.git", wikiDir]);
|
||||
let content = fs.readFileSync(howToUpdateFilename).toString();
|
||||
|
||||
// Replace the version: https://regex101.com/r/hmj2Bc/1
|
||||
content = content.replace(/(git checkout )([^\s]+)/, `$1${newVersion}`);
|
||||
fs.writeFileSync(howToUpdateFilename, content);
|
||||
|
||||
childProcess.spawnSync("git", ["add", "-A"], {
|
||||
cwd: wikiDir,
|
||||
});
|
||||
|
||||
childProcess.spawnSync("git", ["commit", "-m", `Update to ${newVersion}`], {
|
||||
cwd: wikiDir,
|
||||
});
|
||||
|
||||
console.log("Pushing to Github");
|
||||
childProcess.spawnSync("git", ["push"], {
|
||||
cwd: wikiDir,
|
||||
});
|
||||
|
||||
safeDelete(wikiDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a directory exists and then delete it
|
||||
* @param {string} dir Directory to delete
|
||||
* @returns {void}
|
||||
*/
|
||||
function safeDelete(dir) {
|
||||
if (fs.existsSync(dir)) {
|
||||
fs.rm(dir, {
|
||||
recursive: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Author: Stefan Buck
|
||||
# License: MIT
|
||||
# https://gist.github.com/stefanbuck/ce788fee19ab6eb0b4447a85fc99f447
|
||||
#
|
||||
#
|
||||
# This script accepts the following parameters:
|
||||
#
|
||||
# * owner
|
||||
# * repo
|
||||
# * tag
|
||||
# * filename
|
||||
# * github_api_token
|
||||
#
|
||||
# Script to upload a release asset using the GitHub API v3.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# upload-github-release-asset.sh github_api_token=TOKEN owner=stefanbuck repo=playground tag=v0.1.0 filename=./build.zip
|
||||
#
|
||||
|
||||
# Check dependencies.
|
||||
set -e
|
||||
xargs=$(which gxargs || which xargs)
|
||||
|
||||
# Validate settings.
|
||||
[ "$TRACE" ] && set -x
|
||||
|
||||
CONFIG=$@
|
||||
|
||||
for line in $CONFIG; do
|
||||
eval "$line"
|
||||
done
|
||||
|
||||
# Define variables.
|
||||
GH_API="https://api.github.com"
|
||||
GH_REPO="$GH_API/repos/$owner/$repo"
|
||||
GH_TAGS="$GH_REPO/releases/tags/$tag"
|
||||
AUTH="Authorization: token $github_api_token"
|
||||
WGET_ARGS="--content-disposition --auth-no-challenge --no-cookie"
|
||||
CURL_ARGS="-LJO#"
|
||||
|
||||
if [[ "$tag" == 'LATEST' ]]; then
|
||||
GH_TAGS="$GH_REPO/releases/latest"
|
||||
fi
|
||||
|
||||
# Validate token.
|
||||
curl -o /dev/null -sH "$AUTH" $GH_REPO || { echo "Error: Invalid repo, token or network issue!"; exit 1; }
|
||||
|
||||
# Read asset tags.
|
||||
response=$(curl -sH "$AUTH" $GH_TAGS)
|
||||
|
||||
# Get ID of the asset based on given filename.
|
||||
eval $(echo "$response" | grep -m 1 "id.:" | grep -w id | tr : = | tr -cd '[[:alnum:]]=')
|
||||
[ "$id" ] || { echo "Error: Failed to get release id for tag: $tag"; echo "$response" | awk 'length($0)<100' >&2; exit 1; }
|
||||
|
||||
# Upload asset
|
||||
echo "Uploading asset... "
|
||||
|
||||
# Construct url
|
||||
GH_ASSET="https://uploads.github.com/repos/$owner/$repo/releases/$id/assets?name=$(basename $filename)"
|
||||
|
||||
curl "$GITHUB_OAUTH_BASIC" --data-binary @"$filename" -H "Authorization: token $github_api_token" -H "Content-Type: application/octet-stream" $GH_ASSET
|
||||
@@ -63,7 +63,6 @@
|
||||
"start-pr-test": "node extra/checkout-pr.mjs && npm install && npm run dev",
|
||||
"build-healthcheck-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./extra/healthcheck-armv7 ./extra/healthcheck.go",
|
||||
"deploy-demo-server": "node extra/deploy-demo-server.js",
|
||||
"sort-contributors": "node extra/sort-contributors.js",
|
||||
"quick-run-nightly": "docker run --rm --env NODE_ENV=development -p 3001:3001 louislam/uptime-kuma:nightly2",
|
||||
"start-dev-container": "cd docker && docker-compose -f docker-compose-dev.yml up --force-recreate",
|
||||
"rebase-pr-to-1.23.X": "node extra/rebase-pr.js 1.23.X",
|
||||
|
||||
Reference in New Issue
Block a user