Files
JefferyandClaude Fable 5 98a447beb1
docker-actions/template: CI / BUILD (pull_request) Successful in 3s
docs(README): 補充 v 前綴 tag 支援與範例、修正功能列表行號連結
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 11:26:57 +08:00

11 KiB
Raw Permalink Blame History

Calculate Next Version

從 git tag 取得最新版號,依 is_beta 計算下一個正式版或 beta 版號(各號碼滿 9 進位)並輸出為 value 的 Gitea/GitHub Docker container action。

  • 更新時間:2026/07/16 11:26:21

action 使用方式

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.ZX.Y.Z-beta.N,可帶小寫 v 前綴如 v1.2.3,解析時只取 v 之後的版本號),取最大版號;無任何版號 tag 時從 0.0.1beta 為 0.0.1-beta.1)起算。輸出的 value 一律不帶前綴。
  • git tag 讀取失敗(例如 workspace 不是 git repository、workflow 未先執行 actions/checkout)時不會中止:輸出 ERR 說明原因後,改以起始版號 0.0.1beta 為 0.0.1-beta.1)作為預設值繼續輸出。
  • is_beta=false:最新為正式版 → patch +11.2.31.2.4);最新為 beta → 去掉 beta 尾碼轉正式(1.2.4-beta.31.2.4)。
  • is_beta=true:最新為正式版 → patch +1 加 -beta.1;最新為 beta → beta 號 +1beta.9beta.10,無上限)。
  • major/minor/patch 各上限 9,滿 9 進位(1.2.91.3.01.9.92.0.0);9.9.9 再進位則報錯並以非零 exit code 結束。

日誌格式:所有輸出訊息統一為 [階段][等級][時間]: 訊息階段 選填;等級INF/WRN/ERR/TRC/DBG時間 為 Asia/Taipei 時區的 yyyy/MM/dd HH:mm:ss)。

專案列表

專案描述表

專案名稱 專案描述
calculate-next-version Docker container action:提供版號解析/比較/進位計算(version 模組)與統一格式日誌輸出(logger 模組),從 git tag 計算下一個正式版或 beta 版號並寫出為 action 輸出 value

參考專案表

專案名稱 參考專案列表
calculate-next-version

NuGet 套件表

專案名稱 NuGet 套件列表
calculate-next-version 無(Node.js 專案,僅使用 node 內建模組,無外部相依)

功能列表

calculate-next-version

功能名稱 功能描述
logger.inf 輸出 INF(一般資訊)等級的日誌訊息到 stdout
logger.wrn 輸出 WRN(警告)等級的日誌訊息到 stdout
logger.err 輸出 ERR(錯誤)等級的日誌訊息到 stderr
logger.trc 輸出 TRC(細部追蹤)等級的日誌訊息到 stdout
logger.dbg 輸出 DBG(除錯)等級的日誌訊息到 stdout
version.parse 解析版號字串為版號物件(可帶 v 前綴),不符格式回傳 null
version.stringify 將版號物件轉換為版號字串
version.compare 比較兩個版號物件的大小,正式版大於同號 beta
version.next 依最新版號與 is_beta 旗標計算下一版號

使用範例

logger.inf

輸出 INF(一般資訊)等級的日誌訊息到 stdout,格式為 [階段][等級][時間]: 訊息(時間為 Asia/Taipei 時區的 yyyy/MM/dd HH:mm:ss);stage 選填,省略時訊息不含 [階段] 區塊。用於記錄流程中的正常進度,例如讀到的輸入、計算結果、寫出的輸出。

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]: 計算完成

logger.wrn

輸出 WRN(警告)等級的日誌訊息到 stdout,格式與參數同 logger.inf。用於非致命的異常狀況,例如找不到任何版號 tag、需注意的邊界條件。

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,將從起始版號計算

logger.err

輸出 ERR(錯誤)等級的日誌訊息到 stderr(console.error),格式與參數同 logger.inf。用於可預期錯誤與未捕捉例外的回報;呼叫端通常在輸出後以非零 exit code 結束。

const logger = require('./logger');

logger.err('找不到環境變數 GITHUB_OUTPUT,無法寫出輸出', '寫出結果');
// [寫出結果][ERR][2026/07/16 09:23:47]: 找不到環境變數 GITHUB_OUTPUT,無法寫出輸出
process.exit(1);

logger.trc

輸出 TRC(細部追蹤)等級的日誌訊息到 stdout,格式與參數同 logger.inf。用於記錄低層次操作的細節,例如實際執行的外部指令、逐筆解析的中間結果。

const logger = require('./logger');

logger.trc('執行指令:git tag --list', '讀取版號');
// [讀取版號][TRC][2026/07/16 09:23:47]: 執行指令:git tag --list

logger.dbg

輸出 DBG(除錯)等級的日誌訊息到 stdout,格式與參數同 logger.inf。用於協助開發者追蹤程式流程與詳細狀態,例如被略過的不符格式 tag。

const logger = require('./logger');

logger.dbg('略過不符合版號格式的 tagnot-a-version', '讀取版號');
// [讀取版號][DBG][2026/07/16 09:23:47]: 略過不符合版號格式的 tagnot-a-version

version.parse

解析版號字串為版號物件 { major, minor, patch, beta };支援正式版(X.Y.Z)與 beta 版(X.Y.Z-beta.N)兩種格式,皆可帶小寫 v 前綴(解析時忽略前綴、只取 v 之後的版本號),betanull 表示正式版。不符合格式(含 null、非字串轉出的值)時回傳 null、不拋出例外,適合逐一解析 git tag 並過濾非版號 tag。

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(不符合格式)

version.stringify

將版號物件轉換為版號字串;betanull 時輸出 X.Y.Z,否則輸出 X.Y.Z-beta.N。為 version.parse 的反向操作,用於日誌輸出與最終寫出 action 的 value

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'

version.compare

比較兩個版號物件的大小,回傳正數(a > b)、0(相等)或負數(a < b)。依 major → minor → patch → beta 的順序比較;同號碼時正式版大於 beta 版(1.2.4 > 1.2.4-beta.3),beta 版之間依號碼比較。用於在所有 git tag 中挑出最大(最新)的版號。

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')); // => 2beta 依號碼比較)
compare(parse('2.0.0'), parse('1.9.9'));               // => 1

version.next

依最新版號與 is_beta 旗標計算下一版號。latestnull 時起算 0.0.1beta 為 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 結束)。

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'