docker-actions/template: CI / BUILD (pull_request) Successful in 3s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
197 lines
11 KiB
Markdown
197 lines
11 KiB
Markdown
# Calculate Next Version
|
||
|
||
從 git tag 取得最新版號,依 `is_beta` 計算下一個正式版或 beta 版號(各號碼滿 9 進位)並輸出為 `value` 的 Gitea/GitHub Docker container action。
|
||
|
||
- 更新時間:2026/07/16 11:26:21
|
||
|
||
## action 使用方式
|
||
|
||
```yaml
|
||
jobs:
|
||
release:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0 # 需要完整 tag 歷史才能計算版號
|
||
- id: version
|
||
uses: docker-actions/calculate-next-version@master
|
||
with:
|
||
is_beta: 'false'
|
||
sha: ${{ gitea.sha }} # 該 commit 已有版號 tag 時直接輸出該版號
|
||
- run: echo "下一版號:${{ steps.version.outputs.value }}"
|
||
```
|
||
|
||
| 類型 | 名稱 | 必填 | 預設值 | 說明 |
|
||
| --- | --- | --- | --- | --- |
|
||
| input | `is_beta` | 否 | `false` | 是否為 beta 版(true 時產生 X.Y.Z-beta.N 版號) |
|
||
| input | `sha` | 否 | (空) | 要檢查的 commit SHA(建議傳入 `${{ gitea.sha }}`);該 commit 已有版號 tag 時直接輸出該版號。未提供時自動改用 `GITHUB_SHA` |
|
||
| output | `value` | — | — | 計算出的下一版號 |
|
||
|
||
版號規則:
|
||
|
||
- 已標記檢查:先以 `sha` 輸入(未提供則用 `GITHUB_SHA`)確認該 commit 是否已有符合格式的版號 tag;已有時直接輸出該 tag 內容(多個取最大、忽略 `is_beta`),不再計算下一版。檢查失敗(如 sha 不存在)輸出 WRN 後改走一般計算流程。
|
||
- 版號來源為 repo 的 git tag(格式 `X.Y.Z` 或 `X.Y.Z-beta.N`,可帶小寫 `v` 前綴如 `v1.2.3`,解析時只取 `v` 之後的版本號),取最大版號;無任何版號 tag 時從 `0.0.1`(beta 為 `0.0.1-beta.1`)起算。輸出的 `value` 一律不帶前綴。
|
||
- git tag 讀取失敗(例如 workspace 不是 git repository、workflow 未先執行 `actions/checkout`)時不會中止:輸出 ERR 說明原因後,改以起始版號 `0.0.1`(beta 為 `0.0.1-beta.1`)作為預設值繼續輸出。
|
||
- `is_beta=false`:最新為正式版 → patch +1(`1.2.3` → `1.2.4`);最新為 beta → 去掉 beta 尾碼轉正式(`1.2.4-beta.3` → `1.2.4`)。
|
||
- `is_beta=true`:最新為正式版 → patch +1 加 `-beta.1`;最新為 beta → beta 號 +1(`beta.9` → `beta.10`,無上限)。
|
||
- major/minor/patch 各上限 9,滿 9 進位(`1.2.9` → `1.3.0`、`1.9.9` → `2.0.0`);`9.9.9` 再進位則報錯並以非零 exit code 結束。
|
||
|
||
日誌格式:所有輸出訊息統一為 `[階段][等級][時間]: 訊息`(`階段` 選填;`等級` 為 `INF`/`WRN`/`ERR`/`TRC`/`DBG`;`時間` 為 Asia/Taipei 時區的 `yyyy/MM/dd HH:mm:ss`)。
|
||
|
||
## 專案列表
|
||
|
||
### 專案描述表
|
||
|
||
| 專案名稱 | 專案描述 |
|
||
| --- | --- |
|
||
| [calculate-next-version](https://gitea.jsc.idv.tw/docker-actions/calculate-next-version/src/branch/master) | Docker container action:提供版號解析/比較/進位計算(version 模組)與統一格式日誌輸出(logger 模組),從 git tag 計算下一個正式版或 beta 版號並寫出為 action 輸出 `value`。 |
|
||
|
||
### 參考專案表
|
||
|
||
| 專案名稱 | 參考專案列表 |
|
||
| --- | --- |
|
||
| [calculate-next-version](https://gitea.jsc.idv.tw/docker-actions/calculate-next-version/src/branch/master) | 無 |
|
||
|
||
### NuGet 套件表
|
||
|
||
| 專案名稱 | NuGet 套件列表 |
|
||
| --- | --- |
|
||
| [calculate-next-version](https://gitea.jsc.idv.tw/docker-actions/calculate-next-version/src/branch/master) | 無(Node.js 專案,僅使用 node 內建模組,無外部相依) |
|
||
|
||
## 功能列表
|
||
|
||
### calculate-next-version
|
||
|
||
| 功能名稱 | 功能描述 |
|
||
| --- | --- |
|
||
| [logger.inf](https://gitea.jsc.idv.tw/docker-actions/calculate-next-version/src/branch/master/src/logger.js#L86) | [輸出 INF(一般資訊)等級的日誌訊息到 stdout](#loggerinf) |
|
||
| [logger.wrn](https://gitea.jsc.idv.tw/docker-actions/calculate-next-version/src/branch/master/src/logger.js#L101) | [輸出 WRN(警告)等級的日誌訊息到 stdout](#loggerwrn) |
|
||
| [logger.err](https://gitea.jsc.idv.tw/docker-actions/calculate-next-version/src/branch/master/src/logger.js#L116) | [輸出 ERR(錯誤)等級的日誌訊息到 stderr](#loggererr) |
|
||
| [logger.trc](https://gitea.jsc.idv.tw/docker-actions/calculate-next-version/src/branch/master/src/logger.js#L131) | [輸出 TRC(細部追蹤)等級的日誌訊息到 stdout](#loggertrc) |
|
||
| [logger.dbg](https://gitea.jsc.idv.tw/docker-actions/calculate-next-version/src/branch/master/src/logger.js#L146) | [輸出 DBG(除錯)等級的日誌訊息到 stdout](#loggerdbg) |
|
||
| [version.parse](https://gitea.jsc.idv.tw/docker-actions/calculate-next-version/src/branch/master/src/version.js#L28) | [解析版號字串為版號物件(可帶 v 前綴),不符格式回傳 null](#versionparse) |
|
||
| [version.stringify](https://gitea.jsc.idv.tw/docker-actions/calculate-next-version/src/branch/master/src/version.js#L54) | [將版號物件轉換為版號字串](#versionstringify) |
|
||
| [version.compare](https://gitea.jsc.idv.tw/docker-actions/calculate-next-version/src/branch/master/src/version.js#L74) | [比較兩個版號物件的大小,正式版大於同號 beta](#versioncompare) |
|
||
| [version.next](https://gitea.jsc.idv.tw/docker-actions/calculate-next-version/src/branch/master/src/version.js#L138) | [依最新版號與 is_beta 旗標計算下一版號](#versionnext) |
|
||
|
||
## 使用範例
|
||
|
||
<a id="loggerinf"></a>
|
||
### logger.inf
|
||
|
||
輸出 INF(一般資訊)等級的日誌訊息到 stdout,格式為 `[階段][等級][時間]: 訊息`(時間為 Asia/Taipei 時區的 `yyyy/MM/dd HH:mm:ss`);`stage` 選填,省略時訊息不含 `[階段]` 區塊。用於記錄流程中的正常進度,例如讀到的輸入、計算結果、寫出的輸出。
|
||
|
||
```javascript
|
||
const logger = require('./logger');
|
||
|
||
logger.inf('下一版號:1.2.4', '計算版號');
|
||
// [計算版號][INF][2026/07/16 09:23:47]: 下一版號:1.2.4
|
||
|
||
logger.inf('計算完成');
|
||
// [INF][2026/07/16 09:23:47]: 計算完成
|
||
```
|
||
|
||
<a id="loggerwrn"></a>
|
||
### logger.wrn
|
||
|
||
輸出 WRN(警告)等級的日誌訊息到 stdout,格式與參數同 `logger.inf`。用於非致命的異常狀況,例如找不到任何版號 tag、需注意的邊界條件。
|
||
|
||
```javascript
|
||
const logger = require('./logger');
|
||
|
||
logger.wrn('找不到任何符合 X.Y.Z 或 X.Y.Z-beta.N 格式的 tag,將從起始版號計算', '讀取版號');
|
||
// [讀取版號][WRN][2026/07/16 09:23:47]: 找不到任何符合 X.Y.Z 或 X.Y.Z-beta.N 格式的 tag,將從起始版號計算
|
||
```
|
||
|
||
<a id="loggererr"></a>
|
||
### logger.err
|
||
|
||
輸出 ERR(錯誤)等級的日誌訊息到 stderr(`console.error`),格式與參數同 `logger.inf`。用於可預期錯誤與未捕捉例外的回報;呼叫端通常在輸出後以非零 exit code 結束。
|
||
|
||
```javascript
|
||
const logger = require('./logger');
|
||
|
||
logger.err('找不到環境變數 GITHUB_OUTPUT,無法寫出輸出', '寫出結果');
|
||
// [寫出結果][ERR][2026/07/16 09:23:47]: 找不到環境變數 GITHUB_OUTPUT,無法寫出輸出
|
||
process.exit(1);
|
||
```
|
||
|
||
<a id="loggertrc"></a>
|
||
### logger.trc
|
||
|
||
輸出 TRC(細部追蹤)等級的日誌訊息到 stdout,格式與參數同 `logger.inf`。用於記錄低層次操作的細節,例如實際執行的外部指令、逐筆解析的中間結果。
|
||
|
||
```javascript
|
||
const logger = require('./logger');
|
||
|
||
logger.trc('執行指令:git tag --list', '讀取版號');
|
||
// [讀取版號][TRC][2026/07/16 09:23:47]: 執行指令:git tag --list
|
||
```
|
||
|
||
<a id="loggerdbg"></a>
|
||
### logger.dbg
|
||
|
||
輸出 DBG(除錯)等級的日誌訊息到 stdout,格式與參數同 `logger.inf`。用於協助開發者追蹤程式流程與詳細狀態,例如被略過的不符格式 tag。
|
||
|
||
```javascript
|
||
const logger = require('./logger');
|
||
|
||
logger.dbg('略過不符合版號格式的 tag:not-a-version', '讀取版號');
|
||
// [讀取版號][DBG][2026/07/16 09:23:47]: 略過不符合版號格式的 tag:not-a-version
|
||
```
|
||
|
||
<a id="versionparse"></a>
|
||
### version.parse
|
||
|
||
解析版號字串為版號物件 `{ major, minor, patch, beta }`;支援正式版(`X.Y.Z`)與 beta 版(`X.Y.Z-beta.N`)兩種格式,皆可帶小寫 `v` 前綴(解析時忽略前綴、只取 `v` 之後的版本號),`beta` 為 `null` 表示正式版。不符合格式(含 `null`、非字串轉出的值)時回傳 `null`、不拋出例外,適合逐一解析 git tag 並過濾非版號 tag。
|
||
|
||
```javascript
|
||
const { parse } = require('./version');
|
||
|
||
parse('1.2.3'); // => { major: 1, minor: 2, patch: 3, beta: null }
|
||
parse('v1.2.3'); // => { major: 1, minor: 2, patch: 3, beta: null }(忽略 v 前綴)
|
||
parse('1.2.3-beta.5'); // => { major: 1, minor: 2, patch: 3, beta: 5 }
|
||
parse('v1.2'); // => null(不符合格式)
|
||
```
|
||
|
||
<a id="versionstringify"></a>
|
||
### version.stringify
|
||
|
||
將版號物件轉換為版號字串;`beta` 為 `null` 時輸出 `X.Y.Z`,否則輸出 `X.Y.Z-beta.N`。為 `version.parse` 的反向操作,用於日誌輸出與最終寫出 action 的 `value`。
|
||
|
||
```javascript
|
||
const { stringify } = require('./version');
|
||
|
||
stringify({ major: 1, minor: 2, patch: 3, beta: null }); // => '1.2.3'
|
||
stringify({ major: 1, minor: 2, patch: 3, beta: 5 }); // => '1.2.3-beta.5'
|
||
```
|
||
|
||
<a id="versioncompare"></a>
|
||
### version.compare
|
||
|
||
比較兩個版號物件的大小,回傳正數(a > b)、0(相等)或負數(a < b)。依 major → minor → patch → beta 的順序比較;同號碼時正式版大於 beta 版(`1.2.4` > `1.2.4-beta.3`),beta 版之間依號碼比較。用於在所有 git tag 中挑出最大(最新)的版號。
|
||
|
||
```javascript
|
||
const { parse, compare } = require('./version');
|
||
|
||
compare(parse('1.2.4'), parse('1.2.4-beta.3')); // => 1(正式版較大)
|
||
compare(parse('1.2.4-beta.5'), parse('1.2.4-beta.3')); // => 2(beta 依號碼比較)
|
||
compare(parse('2.0.0'), parse('1.9.9')); // => 1
|
||
```
|
||
|
||
<a id="versionnext"></a>
|
||
### version.next
|
||
|
||
依最新版號與 `is_beta` 旗標計算下一版號。`latest` 為 `null` 時起算 `0.0.1`(beta 為 `0.0.1-beta.1`);最新為 beta 版時,`isBeta=false` 去尾碼轉正式、`isBeta=true` 則 beta 號 +1(無上限);最新為正式版時 patch 進位(各位數滿 9 進位),`isBeta=true` 再加 `-beta.1`。最新正式版已達 `9.9.9` 需再進位時拋出 `Error`(呼叫端輸出 ERR 後以非零 exit code 結束)。
|
||
|
||
```javascript
|
||
const { parse, next, stringify } = require('./version');
|
||
|
||
stringify(next(parse('1.2.3'), false)); // => '1.2.4'
|
||
stringify(next(parse('1.2.3'), true)); // => '1.2.4-beta.1'
|
||
stringify(next(parse('1.2.4-beta.3'), false)); // => '1.2.4'(轉正式)
|
||
stringify(next(parse('1.2.9'), false)); // => '1.3.0'(滿 9 進位)
|
||
stringify(next(null, true)); // => '0.0.1-beta.1'
|
||
```
|