Files
calculate-version/README.md
T
JefferyandClaude Opus 4.8 fb760004fd docs(calculate-version): 更新 README 對齊錯誤處理重構
logger.fail 改為 logger.error、新增 index.main 公開函式說明,並更新對應行號與使用範例。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 10:52:19 +08:00

298 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# calculate-version
> 更新時間:2026/06/26 10:49:46
計算版本號的 Gitea Action。依現有 release 推算下一個穩定版或 beta 版本號,並將結果寫入 Action output `version`。核心邏輯以 Node.js 實作,置於 `app/`,由 `entrypoint.sh` 作為容器進入點啟動。
版本進位規則:`patch + 1`;當 `patch` 達 10 進位至 `minor``minor` 達 10 進位至 `major`。beta 版本號形如 `<next>-beta.<n>`,其中 `<n>` 為該版本既有 beta 標籤的最大序號加 1。
## 專案列表
### 專案描述
| 專案名稱 | 專案描述 |
| --- | --- |
| [calculate-version](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app) | 計算版本號的 Gitea Action:載入並驗證環境設定、分頁抓取 Gitea release、計算下一個穩定版或 beta 版本號,並寫出 Action output。 |
### 參考專案
| 專案名稱 | 參考專案列表 |
| --- | --- |
| [calculate-version](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app) | 無 |
### NuGet 套件
| 專案名稱 | NuGet 套件列表 |
| --- | --- |
| [calculate-version](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app) | 無(zero-dependency;僅使用 Node.js 內建模組與全域 fetch |
## 功能列表
### indexapp/index.js
| 功能名稱 | 功能描述 |
| --- | --- |
| [index.main](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/index.js#L23) | [Action 進入點:協調設定載入、release 取得、版本計算與輸出(支援相依注入)。](#indexmain) |
### loggerapp/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) |
### configapp/config.js
| 功能名稱 | 功能描述 |
| --- | --- |
| [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) |
### versionapp/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) |
### releasesapp/releases.js
| 功能名稱 | 功能描述 |
| --- | --- |
| [releases.fetchReleases](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/releases.js#L22) | [以分頁方式取得指定 Gitea repo 的所有 release。](#releasesfetchreleases) |
### outputapp/output.js
| 功能名稱 | 功能描述 |
| --- | --- |
| [output.writeOutput](https://gitea.jsc.idv.tw/docker-actions/calculate-version/src/branch/develop/app/output.js#L14) | [將一行 `name=value` 附加寫入 Action 的輸出檔。](#outputwriteoutput) |
## 使用範例
<a id="indexmain"></a>
### index.main
Action 進入點:依序協調設定載入、release 取得、版本計算與輸出寫出,回傳計算出的版本號。失敗時向外拋出例外(由進入點頂層攔截並以狀態碼 1 結束)。相依模組可透過 `deps` 注入,便於測試。模組僅在被直接執行(`node app/index.js`)時自動啟動。
```js
const { main } = require('./index');
// 測試或自訂情境:注入假的相依
const version = await main({
loadConfig: () => ({ serverUrl: 'https://gitea.example.com', repository: 'owner/repo', token: null, isBeta: false }),
fetchReleases: async () => ([{ tag_name: 'v1.2.3' }]),
writeOutput: () => {},
log: { section() {}, info() {}, error() {} },
});
// version === '1.2.4'
```
<a id="loggersection"></a>
### logger.section
輸出帶標題的區塊段落至標準輸出:先一個換行,接著 50 個 `=` 的主分隔線、標題文字,最後 50 個 `-` 的次分隔線,用於在 log 中建立可視段落區隔。
```js
const logger = require('./logger');
logger.section('參數檢查');
// 輸出:
//
// ==================================================
// 參數檢查
// --------------------------------------------------
```
<a id="loggerinfo"></a>
### logger.info
輸出一般資訊層級訊息至標準輸出,自動加上 `[info]` 前綴與換行;不會結束行程。
```js
const logger = require('./logger');
logger.info('IS_BETA=false');
// 輸出:[info] IS_BETA=false
```
<a id="loggererror"></a>
### logger.error
輸出錯誤訊息至標準錯誤輸出(stderr),自動加上 `[error]` 前綴與換行。僅負責輸出,**不終止行程**;是否結束由呼叫端(進入點)決定,以利測試與錯誤復原。
```js
const logger = require('./logger');
logger.error('GITEA_SERVER_URL 未設定');
// 對 stderr 輸出:[error] GITEA_SERVER_URL 未設定
```
<a id="configisunset"></a>
### config.isUnset
判斷環境變數值是否視為「未設定」。`undefined``null`、空字串、字面字串 `"null"` 皆視為未設定。
```js
const { isUnset } = require('./config');
isUnset(undefined); // true
isUnset('null'); // true
isUnset('false'); // false
```
<a id="configrequireenv"></a>
### config.requireEnv
驗證必填環境變數;未設定時拋出 `Error`(訊息為 `${name} 未設定`),已設定時原樣回傳值。
```js
const { requireEnv } = require('./config');
const url = requireEnv('GITEA_SERVER_URL', process.env.GITEA_SERVER_URL);
// 未設定時拋出:Error: GITEA_SERVER_URL 未設定
```
<a id="confignormalizebetaflag"></a>
### config.normalizeBetaFlag
將 beta 旗標正規化為布林值。未設定時預設為 `false`;僅當值嚴格等於字面字串 `"true"` 時回傳 `true`
```js
const { normalizeBetaFlag } = require('./config');
normalizeBetaFlag('true'); // true
normalizeBetaFlag('TRUE'); // false(嚴格比較,不做大小寫轉換)
normalizeBetaFlag(undefined); // false
```
<a id="configloadconfig"></a>
### config.loadConfig
從環境變數載入並驗證執行所需的設定。`GITEA_SERVER_URL``GITEA_REPOSITORY` 為必填(未設定即拋錯),且 `GITEA_SERVER_URL` 須為合法的 http/https URL`GITEA_TOKEN` 非必填(未設定為 `null`);`IS_BETA` 會正規化為布林值。
```js
const { loadConfig } = require('./config');
const config = loadConfig({
GITEA_SERVER_URL: 'https://gitea.example.com',
GITEA_REPOSITORY: 'owner/repo',
IS_BETA: 'true',
});
// => { serverUrl: 'https://gitea.example.com', repository: 'owner/repo', token: null, isBeta: true }
```
<a id="versioncompareversionarrays"></a>
### version.compareVersionArrays
逐區段(element-wise)比較兩個版本號數值陣列,較短的陣列視為較小。回傳值 `> 0` 表示 a 大於 b、`< 0` 表示 a 小於 b、`0` 表示相等。
```js
const { compareVersionArrays } = require('./version');
compareVersionArrays([1, 10], [1, 2, 3]); // > 01.10 > 1.2.3
compareVersionArrays([1, 2], [1, 2, 0]); // < 0(較短者較小)
```
<a id="versionparsestableversions"></a>
### version.parseStableVersions
從 release 清單解析出所有穩定版(排除 beta、排除格式不合法者)的版本號數值陣列;會去除 tag 開頭的 `v`
```js
const { parseStableVersions } = require('./version');
parseStableVersions([
{ tag_name: 'v1.2.3' },
{ tag_name: '2.0.0' },
{ tag_name: 'v1.0.0-beta.1' }, // 被排除
]);
// => [[1, 2, 3], [2, 0, 0]]
```
<a id="versionlateststableversion"></a>
### version.latestStableVersion
取得 release 清單中最新(最大)的穩定版版本號字串,固定格式化為三段 `major.minor.patch`;查無穩定版時回傳 `"0.0.0"`
```js
const { latestStableVersion } = require('./version');
latestStableVersion([{ tag_name: 'v1.2.3' }, { tag_name: 'v1.9.9' }]); // "1.9.9"
latestStableVersion([]); // "0.0.0"
```
<a id="versionnextreleaseversion"></a>
### version.nextReleaseVersion
依最新穩定版字串計算下一個發行版本號:`patch + 1``patch` 達 10 進位至 `minor``minor` 達 10 進位至 `major`
```js
const { nextReleaseVersion } = require('./version');
nextReleaseVersion('1.2.8'); // "1.2.9"
nextReleaseVersion('1.2.9'); // "1.3.0"
nextReleaseVersion('1.9.9'); // "2.0.0"
```
<a id="versionnextbetanumber"></a>
### version.nextBetaNumber
計算指定版本號的下一個 beta 流水號:取現有相符 beta 標籤(`v<version>-beta.<n>`)的最大序號加 1,查無時回傳 `1``version` 參數不應含前綴 `v`
```js
const { nextBetaNumber } = require('./version');
nextBetaNumber([{ tag_name: 'v1.3.0-beta.1' }, { tag_name: 'v1.3.0-beta.3' }], '1.3.0'); // 4
nextBetaNumber([], '1.3.0'); // 1
```
<a id="versioncalculateversion"></a>
### version.calculateVersion
計算最新穩定版與下一個版本號;`isBeta``true` 時產生 beta 版本號。回傳物件 `{ latest, version }`
```js
const { calculateVersion } = require('./version');
calculateVersion([{ tag_name: 'v1.2.3' }], false);
// => { latest: '1.2.3', version: '1.2.4' }
calculateVersion([{ tag_name: 'v1.2.3' }], true);
// => { latest: '1.2.3', version: '1.2.4-beta.1' }
```
<a id="releasesfetchreleases"></a>
### releases.fetchReleases
以分頁方式取得指定 Gitea repo 的所有 release,並回傳合併後的陣列。使用全域 `fetch` 逐頁請求(每頁 limit 為 10);當某頁回傳空資料、`null` 或筆數少於上限時即停止。提供 `options.token` 時以授權方式請求。網路失敗、回應讀取失敗、非 2xx、無法解析或非陣列回應時拋出 `Error`(含頁碼)。
```js
const { fetchReleases } = require('./releases');
const logger = require('./logger');
const releases = await fetchReleases(
'https://gitea.example.com/api/v1/repos/owner/repo/releases',
{ token: process.env.GITEA_TOKEN, logger },
);
// => 所有 release 物件合併後的陣列
```
<a id="outputwriteoutput"></a>
### output.writeOutput
將一行 `name=value` 附加寫入 GitHub/Gitea Action 的輸出檔(預設取 `process.env.GITHUB_OUTPUT`)。輸出檔路徑為 falsy 時拋出 `Error`
```js
const { writeOutput } = require('./output');
writeOutput('version', '1.2.4');
// 對 $GITHUB_OUTPUT 附加一行:version=1.2.4
```