From 7954fda31188d75fb0210826a91c11f0d0d9c6f4 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 30 Jun 2026 12:42:11 +0800 Subject: [PATCH] =?UTF-8?q?docs(calculate-version):=20=E8=A3=9C=E9=BD=8A?= =?UTF-8?q?=20function=20JSDoc=20=E8=88=87=E6=8C=87=E4=BB=A4=E6=AA=94?= =?UTF-8?q?=E9=80=90=E8=A1=8C=E8=A8=BB=E8=A7=A3=E4=B8=A6=E9=87=8D=E5=BB=BA?= =?UTF-8?q?=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/cd.yaml | 2 +- .gitea/workflows/ci.yaml | 2 +- README.md | 50 ++++++++++++++++++++-------------------- app/index.js | 4 ++++ app/output.js | 2 ++ app/version.js | 4 ++++ 6 files changed, 37 insertions(+), 27 deletions(-) diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml index 7ea67a4..2eb53fa 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/cd.yaml @@ -1,7 +1,7 @@ # ============================================================================= # 用途: calculate-version 專案的 CD workflow。 # 在程式碼推送至 master 分支時,自動釋出並標註 (tag) 成品版本。 -# 更新日期: 2026/06/26 10:28:36 +# 更新日期: 2026/06/30 12:13:04 # ============================================================================= # workflow 名稱,顯示於 Gitea Actions 介面。 diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index b90e67c..8013bc9 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -1,7 +1,7 @@ # ============================================================================= # 用途: calculate-version 專案的 CI workflow。 # 在 Pull Request 開啟或更新時,觸發 OpenCode AI 程式碼審查。 -# 更新日期: 2026/06/26 10:28:36 +# 更新日期: 2026/06/30 12:12:59 # ============================================================================= # workflow 名稱,顯示於 Gitea Actions 介面。 diff --git a/README.md b/README.md index 4ea412e..8d0b1a4 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # calculate-version -> 更新時間:2026/06/26 10:49:46 +> 更新時間:2026/06/30 12:32:40 -計算版本號的 Gitea Action。依現有 release 推算下一個穩定版或 beta 版本號,並將結果寫入 Action output `version`。核心邏輯以 Node.js 實作,置於 `app/`,由 `entrypoint.sh` 作為容器進入點啟動。 +計算版本號的 Gitea Action。依現有 release 推算下一個穩定版或 beta 版本號,並將結果寫入 Action output `version`。核心邏輯以 Node.js 實作,置於 `app/`,由 `entrypoint.sh` 作為容器進入點啟動;容器映像採多階段建置(build 階段 `node:latest`、runtime 階段 `node:slim`)。 版本進位規則:`patch + 1`;當 `patch` 達 10 進位至 `minor`,`minor` 達 10 進位至 `major`。beta 版本號形如 `-beta.`,其中 `` 為該版本既有 beta 標籤的最大序號加 1。 @@ -32,15 +32,15 @@ | 功能名稱 | 功能描述 | | --- | --- | -| [index.main](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/index.js#L23) | [Action 進入點:協調設定載入、release 取得、版本計算與輸出(支援相依注入)。](#indexmain) | +| [index.main](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/index.js#L27) | [Action 進入點:協調設定載入、release 取得、版本計算與輸出(支援相依注入)。](#indexmain) | ### logger(app/logger.js) | 功能名稱 | 功能描述 | | --- | --- | -| [logger.section](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/logger.js#L16) | [輸出帶標題的區塊段落至標準輸出,標題前後以分隔線包夾。](#loggersection) | -| [logger.info](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/logger.js#L26) | [輸出一般資訊層級的 log 訊息,自動加上 `[info]` 前綴。](#loggerinfo) | -| [logger.error](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/logger.js#L38) | [輸出錯誤訊息至 stderr(僅輸出,不終止行程)。](#loggererror) | +| [logger.section](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/logger.js#L45) | [輸出帶標題的區塊段落至標準輸出,標題前後以分隔線包夾。](#loggersection) | +| [logger.info](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/logger.js#L60) | [輸出 INF 層級 log 訊息,格式為 `[INF][時間]: 訊息`。](#loggerinfo) | +| [logger.error](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/logger.js#L77) | [輸出 ERR 層級訊息至 stderr(格式為 `[ERR][時間]: 訊息`,僅輸出不終止行程)。](#loggererror) | ### config(app/config.js) @@ -49,30 +49,30 @@ | [config.isUnset](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/config.js#L11) | [判斷環境變數值是否視為「未設定」。](#configisunset) | | [config.requireEnv](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/config.js#L23) | [驗證必填環境變數,未設定時拋出錯誤。](#configrequireenv) | | [config.normalizeBetaFlag](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/config.js#L38) | [將 beta 旗標正規化為布林值。](#confignormalizebetaflag) | -| [config.loadConfig](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/config.js#L68) | [從環境變數載入並驗證執行所需的設定。](#configloadconfig) | +| [config.loadConfig](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/config.js#L80) | [從環境變數載入並驗證執行所需的設定。](#configloadconfig) | ### version(app/version.js) | 功能名稱 | 功能描述 | | --- | --- | -| [version.compareVersionArrays](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/version.js#L12) | [逐區段比較兩個版本號數值陣列,較短者視為較小。](#versioncompareversionarrays) | -| [version.parseStableVersions](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/version.js#L36) | [從 release 清單解析出所有穩定版的版本號數值陣列。](#versionparsestableversions) | -| [version.latestStableVersion](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/version.js#L55) | [取得 release 清單中最新的穩定版版本號字串。](#versionlateststableversion) | -| [version.nextReleaseVersion](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/version.js#L74) | [依最新穩定版計算下一個發行版本號。](#versionnextreleaseversion) | -| [version.nextBetaNumber](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/version.js#L97) | [計算指定版本號的下一個 beta 流水號。](#versionnextbetanumber) | -| [version.calculateVersion](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/version.js#L122) | [計算最新穩定版與下一個版本號(支援 beta)。](#versioncalculateversion) | +| [version.compareVersionArrays](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/version.js#L14) | [逐區段比較兩個版本號數值陣列,較短者視為較小。](#versioncompareversionarrays) | +| [version.parseStableVersions](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/version.js#L38) | [從 release 清單解析出所有穩定版的版本號數值陣列。](#versionparsestableversions) | +| [version.latestStableVersion](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/version.js#L57) | [取得 release 清單中最新的穩定版版本號字串。](#versionlateststableversion) | +| [version.nextReleaseVersion](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/version.js#L78) | [依最新穩定版計算下一個發行版本號。](#versionnextreleaseversion) | +| [version.nextBetaNumber](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/version.js#L101) | [計算指定版本號的下一個 beta 流水號。](#versionnextbetanumber) | +| [version.calculateVersion](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/version.js#L126) | [計算最新穩定版與下一個版本號(支援 beta)。](#versioncalculateversion) | ### releases(app/releases.js) | 功能名稱 | 功能描述 | | --- | --- | -| [releases.fetchReleases](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/releases.js#L22) | [以分頁方式取得指定 Gitea repo 的所有 release。](#releasesfetchreleases) | +| [releases.fetchReleases](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/releases.js#L24) | [以分頁方式取得指定 Gitea repo 的所有 release。](#releasesfetchreleases) | ### output(app/output.js) | 功能名稱 | 功能描述 | | --- | --- | -| [output.writeOutput](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/output.js#L14) | [將一行 `name=value` 附加寫入 Action 的輸出檔。](#outputwriteoutput) | +| [output.writeOutput](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/output.js#L16) | [將一行 `name=value` 附加寫入 Action 的輸出檔。](#outputwriteoutput) | ## 使用範例 @@ -97,7 +97,7 @@ const version = await main({ ### logger.section -輸出帶標題的區塊段落至標準輸出:先一個換行,接著 50 個 `=` 的主分隔線、標題文字,最後 50 個 `-` 的次分隔線,用於在 log 中建立可視段落區隔。 +輸出帶標題的區塊段落至標準輸出:先一個換行,接著 50 個 `=` 的主分隔線、標題文字,最後 50 個 `-` 的次分隔線,用於在 log 中建立可視段落區隔。此為結構性段落標題,不套用 `[等級][時間]` 前綴。 ```js const logger = require('./logger'); @@ -113,25 +113,25 @@ logger.section('參數檢查'); ### logger.info -輸出一般資訊層級訊息至標準輸出,自動加上 `[info]` 前綴與換行;不會結束行程。 +輸出一般資訊(INF)層級訊息至標準輸出,格式統一為 `[INF][{時間}]: {訊息}`,時間使用台灣時區(Asia/Taipei)、格式 `yyyy/MM/dd HH:mm:ss`,並於結尾換行;不會結束行程。 ```js const logger = require('./logger'); logger.info('IS_BETA=false'); -// 輸出:[info] IS_BETA=false +// 輸出:[INF][2026/06/30 12:00:00]: IS_BETA=false ``` ### logger.error -輸出錯誤訊息至標準錯誤輸出(stderr),自動加上 `[error]` 前綴與換行。僅負責輸出,**不終止行程**;是否結束由呼叫端(進入點)決定,以利測試與錯誤復原。 +輸出錯誤(ERR)層級訊息至標準錯誤輸出(stderr),格式統一為 `[ERR][{時間}]: {訊息}`(時間為台灣時區)。僅負責輸出,**不終止行程**;是否結束由呼叫端(進入點)決定,以利測試與錯誤復原。 ```js const logger = require('./logger'); logger.error('GITEA_SERVER_URL 未設定'); -// 對 stderr 輸出:[error] GITEA_SERVER_URL 未設定 +// 對 stderr 輸出:[ERR][2026/06/30 12:00:00]: GITEA_SERVER_URL 未設定 ``` @@ -191,7 +191,7 @@ const config = loadConfig({ ### version.compareVersionArrays -逐區段(element-wise)比較兩個版本號數值陣列,較短的陣列視為較小。回傳值 `> 0` 表示 a 大於 b、`< 0` 表示 a 小於 b、`0` 表示相等。 +逐區段(element-wise)比較兩個版本號數值陣列,較短的陣列視為較小。回傳值 `> 0` 表示 a 大於 b、`< 0` 表示 a 小於 b、`0` 表示相等;相異區段回傳的是該段差值(非固定 ±1)。 ```js const { compareVersionArrays } = require('./version'); @@ -203,7 +203,7 @@ compareVersionArrays([1, 2], [1, 2, 0]); // < 0(較短者較小) ### version.parseStableVersions -從 release 清單解析出所有穩定版(排除 beta、排除格式不合法者)的版本號數值陣列;會去除 tag 開頭的 `v`。 +從 release 清單解析出所有穩定版(排除 beta、排除格式不合法者)的版本號數值陣列;會去除 tag 開頭的 `v`。傳入非陣列時回傳空陣列。 ```js const { parseStableVersions } = require('./version'); @@ -231,7 +231,7 @@ latestStableVersion([]); // "0.0.0" ### version.nextReleaseVersion -依最新穩定版字串計算下一個發行版本號:`patch + 1`,`patch` 達 10 進位至 `minor`,`minor` 達 10 進位至 `major`。 +依最新穩定版字串計算下一個發行版本號:`patch + 1`,`patch` 達 10 進位至 `minor`,`minor` 達 10 進位至 `major`(「逢 10 進位」為本專案自訂約定,非標準 SemVer)。 ```js const { nextReleaseVersion } = require('./version'); @@ -271,7 +271,7 @@ calculateVersion([{ tag_name: 'v1.2.3' }], true); ### releases.fetchReleases -以分頁方式取得指定 Gitea repo 的所有 release,並回傳合併後的陣列。使用全域 `fetch` 逐頁請求(每頁 limit 為 10);當某頁回傳空資料、`null` 或筆數少於上限時即停止。提供 `options.token` 時以授權方式請求。網路失敗、回應讀取失敗、非 2xx、無法解析或非陣列回應時拋出 `Error`(含頁碼)。 +以分頁方式取得指定 Gitea repo 的所有 release,並回傳合併後的陣列。使用全域 `fetch`(Node.js 18+)逐頁請求(每頁 limit 為 10);當某頁回傳空資料、`null` 或筆數少於上限時即停止。提供 `options.token` 時以授權方式請求。網路失敗、回應讀取失敗、非 2xx、無法解析或非陣列回應時拋出 `Error`(含頁碼)。 ```js const { fetchReleases } = require('./releases'); @@ -287,7 +287,7 @@ const releases = await fetchReleases( ### output.writeOutput -將一行 `name=value` 附加寫入 GitHub/Gitea Action 的輸出檔(預設取 `process.env.GITHUB_OUTPUT`)。輸出檔路徑為 falsy 時拋出 `Error`。 +將一行 `name=value` 附加寫入 GitHub/Gitea Action 的輸出檔(預設取 `process.env.GITHUB_OUTPUT`)。以 append 方式寫入、不覆蓋既有內容;輸出檔路徑為 falsy 時拋出 `Error`。 ```js const { writeOutput } = require('./output'); diff --git a/app/index.js b/app/index.js index 688a404..9cf09b7 100644 --- a/app/index.js +++ b/app/index.js @@ -19,6 +19,10 @@ const { writeOutput } = require('./output'); * @param {Function} [deps.writeOutput] - 寫出 output 的函式。 * @param {{section:Function, info:Function, error:Function}} [deps.log] - log 記錄器。 * @returns {Promise} 計算出的版本號。 + * @throws {Error} 當任一注入相依(loadConfig/fetchReleases/calculateVersion/writeOutput)拋出例外時, + * 原樣向外傳播,由呼叫端決定如何結束。 + * @remarks 由模組底部的 require.main 守衛在被直接執行時呼叫;失敗時頂層以模組層級 logger.error 輸出 + * 並 exit(1)。單元測試可透過 deps 注入替身以覆蓋成功與各失敗路徑。 */ async function main(deps = {}) { const { diff --git a/app/output.js b/app/output.js index f167cf0..44a2f9c 100644 --- a/app/output.js +++ b/app/output.js @@ -10,6 +10,8 @@ const fs = require('node:fs'); * @param {string} [file=process.env.GITHUB_OUTPUT] - 輸出檔路徑,預設取自環境變數 `GITHUB_OUTPUT`。 * @throws {Error} 當輸出檔路徑為 falsy(例如 `GITHUB_OUTPUT` 未設定)時拋出,無法寫入輸出。 * @returns {void} + * @remarks 由 main 於計算出版本號後呼叫,將 `version` 寫入 Action output 供後續 step 取用; + * 以 append 方式寫入、不覆蓋既有內容,且 value 僅支援單行字串(未處理換行或 `=`)。 */ function writeOutput(name, value, file = process.env.GITHUB_OUTPUT) { if (!file) { diff --git a/app/version.js b/app/version.js index f5562b4..49c973a 100644 --- a/app/version.js +++ b/app/version.js @@ -8,6 +8,8 @@ const SEGMENT_LIMIT = 10; * @param {number[]} a - 第一個版本號區段陣列,例如 [1, 2, 3]。 * @param {number[]} b - 第二個版本號區段陣列,例如 [1, 2, 0]。 * @returns {number} 大於 0 表示 a 大於 b;小於 0 表示 a 小於 b;0 表示兩者相等。 + * 相異區段回傳的是該段差值(非固定 ±1)。 + * @throws {TypeError} 當 a 或 b 非陣列(無 length 屬性)時拋出。 */ function compareVersionArrays(a, b) { const length = Math.max(a.length, b.length); @@ -70,6 +72,8 @@ function latestStableVersion(releases) { * 依最新穩定版字串計算下一個發行版本號:patch 加 1,patch 達 10 進位至 minor,minor 達 10 進位至 major。 * @param {string} latest - 最新穩定版版本號字串,例如 "1.2.9"。 * @returns {string} 下一個發行版本號字串,格式為 "major.minor.patch",例如 "1.3.0"。 + * @remarks 「逢 10 進位」為本專案自訂約定(非標準 SemVer);輸入會先 String() 轉字串, + * 缺段或非數字段一律補 0(如 null/undefined → "0.0.1"),major 無進位上限。 */ function nextReleaseVersion(latest) { const parts = String(latest).split('.').map((part) => Number(part) || 0);