保留 entrypoint.sh 作為容器進入點,改為啟動 app/ 下的 Node.js 程式; 依功能拆分為 logger/config/version/releases/output/index,並更新 Dockerfile 改用 node:lts-alpine。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
141 lines
4.9 KiB
JavaScript
141 lines
4.9 KiB
JavaScript
'use strict';
|
||
|
||
// 每個版本號區段的進位上限:patch / minor 達到 10 即向上進位
|
||
const SEGMENT_LIMIT = 10;
|
||
|
||
/**
|
||
* 逐區段(element-wise)比較兩個版本號數值陣列,較短的陣列視為較小。
|
||
* @param {number[]} a - 第一個版本號區段陣列,例如 [1, 2, 3]。
|
||
* @param {number[]} b - 第二個版本號區段陣列,例如 [1, 2, 0]。
|
||
* @returns {number} 大於 0 表示 a 大於 b;小於 0 表示 a 小於 b;0 表示兩者相等。
|
||
*/
|
||
function compareVersionArrays(a, b) {
|
||
const length = Math.max(a.length, b.length);
|
||
|
||
for (let i = 0; i < length; i += 1) {
|
||
if (a[i] === undefined) {
|
||
return -1;
|
||
}
|
||
if (b[i] === undefined) {
|
||
return 1;
|
||
}
|
||
if (a[i] !== b[i]) {
|
||
return a[i] - b[i];
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* 從 release 清單解析出所有穩定版(排除 beta、排除格式不合法者)的版本號數值陣列。
|
||
* 會去除 tag 開頭的 'v',並將版本字串切成數字陣列。
|
||
* @param {Array<{tag_name?: string}>} releases - release 物件清單;每個項目以 tag_name 表示版本標籤。
|
||
* @returns {number[][]} 穩定版版本號的數值陣列清單,例如 [[1,2,3],[1,2,0]];輸入非陣列時回傳空陣列。
|
||
*/
|
||
function parseStableVersions(releases) {
|
||
if (!Array.isArray(releases)) {
|
||
return [];
|
||
}
|
||
|
||
return releases
|
||
.filter((release) => release
|
||
&& typeof release.tag_name === 'string'
|
||
&& !release.tag_name.includes('-beta.'))
|
||
.map((release) => release.tag_name.replace(/^v/, ''))
|
||
.filter((tag) => /^[0-9]+(\.[0-9]+)*$/.test(tag))
|
||
.map((tag) => tag.split('.').map(Number));
|
||
}
|
||
|
||
/**
|
||
* 取得 release 清單中最新(最大)的穩定版版本號字串,固定格式化為三段 "major.minor.patch"。
|
||
* @param {Array<{tag_name?: string}>} releases - release 物件清單。
|
||
* @returns {string} 最新穩定版版本號字串;查無穩定版時回傳 "0.0.0"。
|
||
*/
|
||
function latestStableVersion(releases) {
|
||
const versions = parseStableVersions(releases);
|
||
|
||
if (versions.length === 0) {
|
||
return '0.0.0';
|
||
}
|
||
|
||
const max = versions.reduce(
|
||
(best, current) => (compareVersionArrays(current, best) > 0 ? current : best),
|
||
);
|
||
|
||
return `${max[0] ?? 0}.${max[1] ?? 0}.${max[2] ?? 0}`;
|
||
}
|
||
|
||
/**
|
||
* 依最新穩定版字串計算下一個發行版本號:patch 加 1,patch 達 10 進位至 minor,minor 達 10 進位至 major。
|
||
* @param {string} latest - 最新穩定版版本號字串,例如 "1.2.9"。
|
||
* @returns {string} 下一個發行版本號字串,格式為 "major.minor.patch",例如 "1.3.0"。
|
||
*/
|
||
function nextReleaseVersion(latest) {
|
||
const parts = String(latest).split('.').map((part) => Number(part) || 0);
|
||
let [major = 0, minor = 0, patch = 0] = parts;
|
||
|
||
patch += 1;
|
||
if (patch >= SEGMENT_LIMIT) {
|
||
patch = 0;
|
||
minor += 1;
|
||
}
|
||
if (minor >= SEGMENT_LIMIT) {
|
||
minor = 0;
|
||
major += 1;
|
||
}
|
||
|
||
return `${major}.${minor}.${patch}`;
|
||
}
|
||
|
||
/**
|
||
* 計算指定版本號的下一個 beta 流水號:取現有相符 beta 標籤的最大序號加 1,查無時回傳 1。
|
||
* @param {Array<{tag_name?: string}>} releases - release 物件清單。
|
||
* @param {string} version - 不含前綴 'v' 的版本號字串,例如 "1.3.0";用於組出 "v<version>-beta." 前綴比對。
|
||
* @returns {number} 下一個 beta 流水號;查無對應 beta 時回傳 1。
|
||
*/
|
||
function nextBetaNumber(releases, version) {
|
||
if (!Array.isArray(releases)) {
|
||
return 1;
|
||
}
|
||
|
||
const prefix = `v${version}-beta.`;
|
||
const numbers = releases
|
||
.filter((release) => release
|
||
&& typeof release.tag_name === 'string'
|
||
&& release.tag_name.startsWith(prefix))
|
||
.map((release) => Number(release.tag_name.slice(prefix.length)))
|
||
.filter((number) => Number.isFinite(number));
|
||
|
||
const max = numbers.length > 0 ? Math.max(...numbers) : 0;
|
||
return max + 1;
|
||
}
|
||
|
||
/**
|
||
* 計算最新穩定版與下一個版本號;isBeta 為 true 時產生 beta 版本號。
|
||
* @param {Array<{tag_name?: string}>} releases - release 物件清單。
|
||
* @param {boolean} isBeta - 是否產生 beta 版本號;true 時 version 形如 "<next>-beta.<n>"。
|
||
* @returns {{latest: string, version: string}} 回傳物件:
|
||
* - latest: 現有最新穩定版版本號字串(查無時為 "0.0.0")。
|
||
* - version: 本次要使用的版本號字串;非 beta 為下一個發行版(如 "1.3.0"),beta 為 "<next>-beta.<n>"(如 "1.3.0-beta.1")。
|
||
*/
|
||
function calculateVersion(releases, isBeta) {
|
||
const latest = latestStableVersion(releases);
|
||
const next = nextReleaseVersion(latest);
|
||
|
||
const version = isBeta
|
||
? `${next}-beta.${nextBetaNumber(releases, next)}`
|
||
: next;
|
||
|
||
return { latest, version };
|
||
}
|
||
|
||
module.exports = {
|
||
compareVersionArrays,
|
||
parseStableVersions,
|
||
latestStableVersion,
|
||
nextReleaseVersion,
|
||
nextBetaNumber,
|
||
calculateVersion,
|
||
};
|