mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-09-10 06:43:36 +08:00
Compare commits
3 Commits
2.0.0-beta
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
ed3538f72f | ||
|
c6a029a895 | ||
|
c6048d56b4 |
@@ -24,9 +24,7 @@ if (! exists) {
|
||||
// Also update package-lock.json
|
||||
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
|
||||
childProcess.spawnSync(npm, [ "install" ]);
|
||||
|
||||
commit(version);
|
||||
tag(version);
|
||||
|
||||
} else {
|
||||
console.log("version tag exists, please delete the tag or use another tag");
|
||||
@@ -54,19 +52,6 @@ function commit(version) {
|
||||
console.log(res.stdout.toString().trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tag with the specified version
|
||||
* @param {string} version Tag to create
|
||||
* @returns {void}
|
||||
*/
|
||||
function tag(version) {
|
||||
let res = childProcess.spawnSync("git", [ "tag", version ]);
|
||||
console.log(res.stdout.toString().trim());
|
||||
|
||||
res = childProcess.spawnSync("git", [ "push", "origin", version ]);
|
||||
console.log(res.stdout.toString().trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a tag exists for the specified version
|
||||
* @param {string} version Version to check
|
||||
|
201
extra/generate-changelog.mjs
Normal file
201
extra/generate-changelog.mjs
Normal file
@@ -0,0 +1,201 @@
|
||||
// Script to generate changelog
|
||||
// Usage: node generate-changelog.mjs <previous-version-tag>
|
||||
// GitHub CLI (gh command) is required
|
||||
|
||||
import * as childProcess from "child_process";
|
||||
|
||||
const ignoreList = [
|
||||
"louislam",
|
||||
"CommanderStorm",
|
||||
"UptimeKumaBot",
|
||||
"weblate",
|
||||
"Copilot"
|
||||
];
|
||||
|
||||
const mergeList = [
|
||||
"Translations Update from Weblate",
|
||||
"Update dependencies",
|
||||
];
|
||||
|
||||
const template = `
|
||||
|
||||
LLM Task: Please help to put above PRs into the following sections based on their content. If a PR fits multiple sections, choose the most relevant one. If a PR doesn't fit any section, place it in "Others". If there are grammatical errors in the PR titles, please correct them. Don't change the PR numbers and authors, and keep the format. Output as markdown.
|
||||
|
||||
Changelog:
|
||||
|
||||
### 🆕 New Features
|
||||
|
||||
### 💇♀️ Improvements
|
||||
|
||||
### 🐞 Bug Fixes
|
||||
|
||||
### ⬆️ Security Fixes
|
||||
|
||||
### 🦎 Translation Contributions
|
||||
|
||||
### Others
|
||||
- Other small changes, code refactoring and comment/doc updates in this repo:
|
||||
`;
|
||||
|
||||
await main();
|
||||
|
||||
/**
|
||||
* Main Function
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function main() {
|
||||
const previousVersion = process.argv[2];
|
||||
|
||||
if (!previousVersion) {
|
||||
console.error("Please provide the previous version as the first argument.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Generating changelog since version ${previousVersion}...`);
|
||||
|
||||
try {
|
||||
const prList = await getPullRequestList(previousVersion);
|
||||
const list = [];
|
||||
|
||||
let i = 1;
|
||||
for (const pr of prList) {
|
||||
console.log(`Progress: ${i++}/${prList.length}`);
|
||||
let authorSet = await getAuthorList(pr.number);
|
||||
authorSet = await mainAuthorToFront(pr.author.login, authorSet);
|
||||
|
||||
if (mergeList.includes(pr.title)) {
|
||||
// Check if it is already in the list
|
||||
const existingItem = list.find(item => item.title === pr.title);
|
||||
if (existingItem) {
|
||||
existingItem.numbers.push(pr.number);
|
||||
for (const author of authorSet) {
|
||||
existingItem.authors.add(author);
|
||||
// Sort the authors
|
||||
existingItem.authors = new Set([ ...existingItem.authors ].sort((a, b) => a.localeCompare(b)));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const item = {
|
||||
numbers: [ pr.number ],
|
||||
title: pr.title,
|
||||
authors: authorSet,
|
||||
};
|
||||
|
||||
list.push(item);
|
||||
}
|
||||
|
||||
for (const item of list) {
|
||||
// Concat pr numbers into a string like #123 #456
|
||||
const prPart = item.numbers.map(num => `#${num}`).join(" ");
|
||||
|
||||
// Concat authors into a string like @user1 @user2
|
||||
let authorPart = [ ...item.authors ].map(author => `@${author}`).join(" ");
|
||||
|
||||
if (authorPart) {
|
||||
authorPart = `(Thanks ${authorPart})`;
|
||||
}
|
||||
|
||||
console.log(`- ${prPart} ${item.title} ${authorPart}`);
|
||||
}
|
||||
|
||||
console.log(template);
|
||||
|
||||
} catch (e) {
|
||||
console.error("Failed to get pull request list:", e);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} previousVersion Previous Version Tag
|
||||
* @returns {Promise<object>} List of Pull Requests merged since previousVersion
|
||||
*/
|
||||
async function getPullRequestList(previousVersion) {
|
||||
// Get the date of previousVersion in YYYY-MM-DD format from git
|
||||
const previousVersionDate = childProcess.execSync(`git log -1 --format=%cd --date=short ${previousVersion}`).toString().trim();
|
||||
|
||||
if (!previousVersionDate) {
|
||||
throw new Error(`Unable to find the date of version ${previousVersion}. Please make sure the version tag exists.`);
|
||||
}
|
||||
|
||||
const ghProcess = childProcess.spawnSync("gh", [
|
||||
"pr",
|
||||
"list",
|
||||
"--state",
|
||||
"merged",
|
||||
"--base",
|
||||
"master",
|
||||
"--search",
|
||||
`merged:>=${previousVersionDate}`,
|
||||
"--json",
|
||||
"number,title,author",
|
||||
"--limit",
|
||||
"1000"
|
||||
], {
|
||||
encoding: "utf-8"
|
||||
});
|
||||
|
||||
if (ghProcess.error) {
|
||||
throw ghProcess.error;
|
||||
}
|
||||
|
||||
if (ghProcess.status !== 0) {
|
||||
throw new Error(`gh command failed with status ${ghProcess.status}: ${ghProcess.stderr}`);
|
||||
}
|
||||
|
||||
return JSON.parse(ghProcess.stdout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} prID Pull Request ID
|
||||
* @returns {Promise<Set<string>>} Set of Authors' GitHub Usernames
|
||||
*/
|
||||
async function getAuthorList(prID) {
|
||||
const ghProcess = childProcess.spawnSync("gh", [
|
||||
"pr",
|
||||
"view",
|
||||
prID,
|
||||
"--json",
|
||||
"commits"
|
||||
], {
|
||||
encoding: "utf-8"
|
||||
});
|
||||
|
||||
if (ghProcess.error) {
|
||||
throw ghProcess.error;
|
||||
}
|
||||
|
||||
if (ghProcess.status !== 0) {
|
||||
throw new Error(`gh command failed with status ${ghProcess.status}: ${ghProcess.stderr}`);
|
||||
}
|
||||
|
||||
const prInfo = JSON.parse(ghProcess.stdout);
|
||||
const commits = prInfo.commits;
|
||||
|
||||
const set = new Set();
|
||||
|
||||
for (const commit of commits) {
|
||||
for (const author of commit.authors) {
|
||||
if (author.login && !ignoreList.includes(author.login)) {
|
||||
set.add(author.login);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the set
|
||||
return new Set([ ...set ].sort((a, b) => a.localeCompare(b)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} mainAuthor Main Author
|
||||
* @param {Set<string>} authorSet Set of Authors
|
||||
* @returns {Set<string>} New Set with mainAuthor at the front
|
||||
*/
|
||||
async function mainAuthorToFront(mainAuthor, authorSet) {
|
||||
if (ignoreList.includes(mainAuthor)) {
|
||||
return authorSet;
|
||||
}
|
||||
return new Set([ mainAuthor, ...authorSet ]);
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
// Generate on GitHub
|
||||
const input = `
|
||||
* Add Korean translation by @Alanimdeo in https://github.com/louislam/dockge/pull/86
|
||||
`;
|
||||
|
||||
const template = `
|
||||
### 🆕 New Features
|
||||
|
||||
### 💇♀️ Improvements
|
||||
|
||||
### 🐞 Bug Fixes
|
||||
|
||||
### ⬆️ Security Fixes
|
||||
|
||||
### 🦎 Translation Contributions
|
||||
|
||||
### Others
|
||||
- Other small changes, code refactoring and comment/doc updates in this repo:
|
||||
`;
|
||||
|
||||
const lines = input.split("\n").filter((line) => line.trim() !== "");
|
||||
|
||||
for (const line of lines) {
|
||||
// Split the last " by "
|
||||
const usernamePullRequesURL = line.split(" by ").pop();
|
||||
|
||||
if (!usernamePullRequesURL) {
|
||||
console.log("Unable to parse", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
const [ username, pullRequestURL ] = usernamePullRequesURL.split(" in ");
|
||||
const pullRequestID = "#" + pullRequestURL.split("/").pop();
|
||||
let message = line.split(" by ").shift();
|
||||
|
||||
if (!message) {
|
||||
console.log("Unable to parse", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
message = message.split("* ").pop();
|
||||
console.log("-", pullRequestID, message, `(Thanks ${username})`);
|
||||
}
|
||||
console.log(template);
|
@@ -8,7 +8,7 @@ import {
|
||||
checkVersionFormat,
|
||||
getRepoNames,
|
||||
pressAnyKey,
|
||||
execSync, uploadArtifacts,
|
||||
execSync, uploadArtifacts, checkReleaseBranch,
|
||||
} from "./lib.mjs";
|
||||
import semver from "semver";
|
||||
|
||||
@@ -23,6 +23,9 @@ if (!githubToken) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if the current branch is "release"
|
||||
checkReleaseBranch();
|
||||
|
||||
// Check if the version is a valid semver
|
||||
checkVersionFormat(version);
|
||||
|
||||
|
@@ -7,7 +7,7 @@ import {
|
||||
checkTagExists,
|
||||
checkVersionFormat,
|
||||
getRepoNames,
|
||||
pressAnyKey, execSync, uploadArtifacts
|
||||
pressAnyKey, execSync, uploadArtifacts, checkReleaseBranch
|
||||
} from "./lib.mjs";
|
||||
|
||||
const repoNames = getRepoNames();
|
||||
@@ -21,6 +21,9 @@ if (!githubToken) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if the current branch is "release"
|
||||
checkReleaseBranch();
|
||||
|
||||
// Check if the version is a valid semver
|
||||
checkVersionFormat(version);
|
||||
|
||||
|
@@ -249,3 +249,16 @@ export function execSync(cmd) {
|
||||
console.info(`[DRY RUN] ${cmd}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current branch is "release"
|
||||
* @returns {void}
|
||||
*/
|
||||
export function checkReleaseBranch() {
|
||||
const res = childProcess.spawnSync("git", [ "rev-parse", "--abbrev-ref", "HEAD" ]);
|
||||
const branch = res.stdout.toString().trim();
|
||||
if (branch !== "release") {
|
||||
console.error(`Current branch is ${branch}, please switch to "release" branch`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
@@ -28,9 +28,7 @@ if (! exists) {
|
||||
// Also update package-lock.json
|
||||
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
|
||||
childProcess.spawnSync(npm, [ "install" ]);
|
||||
|
||||
commit(newVersion);
|
||||
tag(newVersion);
|
||||
|
||||
} else {
|
||||
console.log("version exists");
|
||||
@@ -54,16 +52,6 @@ function commit(version) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tag with the specified version
|
||||
* @param {string} version Tag to create
|
||||
* @returns {void}
|
||||
*/
|
||||
function tag(version) {
|
||||
let res = childProcess.spawnSync("git", [ "tag", version ]);
|
||||
console.log(res.stdout.toString().trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a tag exists for the specified version
|
||||
* @param {string} version Version to check
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "uptime-kuma",
|
||||
"version": "2.0.0-beta.3",
|
||||
"version": "2.0.0-beta.4",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -64,7 +64,8 @@
|
||||
"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",
|
||||
"reset-migrate-aggregate-table-state": "node extra/reset-migrate-aggregate-table-state.js"
|
||||
"reset-migrate-aggregate-table-state": "node extra/reset-migrate-aggregate-table-state.js",
|
||||
"generate-changelog": "node ./extra/generate-changelog.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "~1.8.22",
|
||||
|
@@ -47,6 +47,7 @@ const languageList = {
|
||||
"ge": "ქართული",
|
||||
"uz": "O'zbek tili",
|
||||
"ga": "Gaeilge",
|
||||
"sk": "Slovenčina",
|
||||
};
|
||||
|
||||
let messages = {
|
||||
|
Reference in New Issue
Block a user