diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml index 30b1952..f6b4b47 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/cd.yaml @@ -1,12 +1,32 @@ +# 用途:本檔為 Gitea CD(持續部署)工作流程設定。 +# 當 master 分支有 push 時自動觸發,使用公司 Gitea 上的 +# composite action「release-tag-version」對建置成品進行釋出與版本標註(tag)。 +# 更新日期(台灣時區 Asia/Taipei):2026/06/30 16:44:09 + +# 工作流程名稱,顯示於 Gitea Actions 介面,用以辨識此 CD 流程 name: CD +# 定義觸發此工作流程的事件 on: + # 當有程式碼 push(推送)至指定分支時觸發 push: + # 限定僅特定分支的 push 才觸發 branches: + # 僅 master 分支(正式發布主線)push 時才執行此 CD 流程 - master +# 定義此工作流程包含的所有 job(工作) jobs: + # job 識別代號:release-tag-version(釋出並標註版本) release-tag-version: + # job 的顯示名稱,呈現於 Gitea Actions 執行畫面 name: Release Tag Version + # 指定此 job 執行所使用的 runner 標籤(ubuntu runner) runs-on: ubuntu + # 定義此 job 依序執行的步驟清單 steps: + # 步驟名稱:釋出並標註成品版本 - name: 釋出並標註成品版本 + # 引用公司 Gitea 上的 composite action「release-tag-version」執行釋出與打 tag。 + # 版本(@ 之後)由 Gitea 變數 vars.ACTION_RELEASE_TAG_VERSION 動態決定, + # 便於集中管理所引用 action 的版本,不需修改本檔即可切換版本。 + # 需人工確認:此 action 之具體釋出/標註行為與所需 secrets/權限,須參閱該 composite action 定義。 uses: https://gitea.jsc.idv.tw/composite-actions/release-tag-version@${{ vars.ACTION_RELEASE_TAG_VERSION }} diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index b9d4eed..e3b2487 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -1,19 +1,48 @@ +# =================================================================== +# 用途:Gitea CI workflow,於 Pull Request 開啟或更新時觸發 AI 程式碼審查。 +# 透過公司 Gitea 上的 composite action `opencode-code-review`, +# 對 PR 變更內容執行自動化 AI code review,並把審查結果以留言回貼到 PR。 +# 更新日期(台灣時區 Asia/Taipei):2026/06/30 16:44:09 +# =================================================================== + +# workflow 名稱,顯示於 Gitea Actions 介面 name: CI +# 觸發事件設定 on: + # 針對 Pull Request 事件觸發 pull_request: + # 目標分支過濾:忽略以下分支(即 master 不觸發本 workflow) branches-ignore: + # 排除 master 分支,避免對正式主線的 PR 執行 AI 審查 - master + # 僅在 PR 被「開啟(opened)」或「推送新 commit 同步(synchronize)」時觸發 types: [opened, synchronize] +# 定義所有 jobs jobs: + # job 識別碼:AI 程式碼審查 ai-code-review: + # job 顯示名稱 name: AI Code Review + # 指定執行環境(runner 標籤),使用 ubuntu runner runs-on: ubuntu + # 此 job 對 GITHUB_TOKEN 所需的權限範圍 permissions: + # 允許寫入 repository 內容(供 action 讀取/操作程式碼) contents: write + # 允許寫入 Pull Request(供 action 回貼審查留言) pull-requests: write + # 允許寫入 issues(PR 留言底層走 issue comment API,需此權限) issues: write + # 此 job 的執行步驟 steps: + # 步驟名稱:使用 OpenCode 進行 AI 程式碼審查 - name: AI 程式碼審查 by OpenCode + # 引用公司 Gitea 上的 composite action `opencode-code-review`, + # 版本由 repository/organization 變數 ACTION_OPENCODE_CODE_REVIEW_VERSION 指定, + # 便於集中控管所使用的 action 版本 uses: https://gitea.jsc.idv.tw/composite-actions/opencode-code-review@${{ vars.ACTION_OPENCODE_CODE_REVIEW_VERSION }} + # 傳遞給 composite action 的輸入參數 with: + # 留言用 token,從 secrets.COMMENT_TOKEN 取得, + # 供 action 以該身分將審查結果回貼到 PR 留言 comment_token: ${{ secrets.COMMENT_TOKEN }} diff --git a/README.md b/README.md index c229e66..9255268 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Release Cleanup -> 更新時間:2026/06/30 12:02:55(台灣時區 Asia/Taipei) +> 更新時間:2026/06/30 17:58:12(台灣時區 Asia/Taipei) 清理舊成品的 **Gitea / GitHub docker container action**。依保留數量清理 repo 的舊 release,並刪除沒有對應 release 的 tag;正式版與 beta 版各自獨立保留指定數量。 @@ -16,6 +16,18 @@ `GITEA_TOKEN` 為空時以匿名身分呼叫 API。取得分頁失敗或參數不合法則直接以 exit code 1 結束程序。 +## 日誌輸出格式 + +所有等級式輸出統一為 `[{等級}][{時間}]: {訊息}`(等級為 `INF`/`WRN`/`ERR`,時間為 Asia/Taipei 的 `yyyy/MM/dd HH:mm:ss`);`fail` 走 stderr,其餘走 stdout。例如: + +```text +[INF][2026/06/30 17:58:12]: RELEASE_COUNT=42 +[WRN][2026/06/30 17:58:12]: GITEA_TOKEN is empty; release API calls will be anonymous +[ERR][2026/06/30 17:58:12]: 刪除失敗: v1.0.0 (Release 1.0.0), HTTP 500 +``` + +> 註:`separator` / `section` 為純分隔線/標題輸出,不帶等級與時間戳。 + ## Action 輸入與環境變數 | 名稱 | 來源 | 必填 | 預設 | 說明 | @@ -44,7 +56,7 @@ jobs: | 專案名稱 | 專案描述 | | --- | --- | -| [release-cleanup](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app) | 清理 Gitea repo 舊 release 與孤兒 tag 的 docker container action;正式版與 beta 版各自保留指定數量 | +| [release-cleanup](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app) | 清理 Gitea repo 舊 release 與孤兒 tag 的 docker container action;正式版與 beta 版各自保留指定數量,並以統一等級式日誌輸出處理過程 | ### 參考專案 @@ -64,19 +76,22 @@ jobs: ### release-cleanup +> 說明:本專案為單一 Node 模組(`app/index.js`),下列為模組內可文件化的頂層函式(不含 `main` 內部的巢狀私有函式 `fetchAllPages` / `deleteUrl`)。 + | 功能名稱 | 功能描述 | | --- | --- | | [separator](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L10) | [在 stdout 輸出視覺分隔線](#separator) | | [section](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L21) | [輸出區段標題區塊](#section) | -| [info](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L33) | [以 \[INFO\] 前綴輸出資訊訊息](#info) | -| [success](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L43) | [以 \[OK\] 前綴輸出成功訊息](#success) | -| [warn](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L53) | [以 \[WARN\] 前綴輸出警告訊息](#warn) | -| [fail](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L64) | [以 \[ERR\] 前綴輸出錯誤訊息到 stderr](#fail) | -| [isEmptyOrNull](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L76) | [判斷值是否視為空 / 未設定](#isemptyornull) | -| [requireValue](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L89) | [檢查必填值,空值時結束程序](#requirevalue) | -| [requireInteger](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L106) | [驗證非負整數,不符時結束程序](#requireinteger) | -| [isBeta](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L120) | [判斷名稱是否為 beta 版本](#isbeta) | -| [main](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L140) | [Action 主流程:清理舊 release 與孤兒 tag](#main) | +| [timestamp](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L34) | [取得 Asia/Taipei 時間字串](#timestamp) | +| [info](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L46) | [以 \[INF\] 等級輸出資訊訊息](#info) | +| [success](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L57) | [以 \[INF\] 等級輸出成功訊息](#success) | +| [warn](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L67) | [以 \[WRN\] 等級輸出警告訊息](#warn) | +| [fail](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L78) | [以 \[ERR\] 等級輸出錯誤訊息到 stderr](#fail) | +| [isEmptyOrNull](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L90) | [判斷值是否視為空 / 未設定](#isemptyornull) | +| [requireValue](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L103) | [檢查必填值,空值時結束程序](#requirevalue) | +| [requireInteger](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L120) | [驗證非負整數,不符時結束程序](#requireinteger) | +| [isBeta](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L134) | [判斷名稱是否為 beta 版本](#isbeta) | +| [main](https://gitea.jsc.idv.tw/docker-actions/release-cleanup/src/branch/develop/app/index.js#L154) | [Action 主流程:清理舊 release 與孤兒 tag](#main) | ## 使用範例 @@ -105,43 +120,58 @@ section('參數檢查'); // -------------------------------------------------- ``` + +### timestamp + +取得目前 **Asia/Taipei** 時區的時間字串,格式為 `yyyy/MM/dd HH:mm:ss`。使用 Node 內建 `Intl`(`toLocaleString('sv-SE')` 輸出 24 小時制再把 `-` 換成 `/`),不需額外相依。供各等級式 log helper 組裝統一格式前綴使用。 + +```js +timestamp(); +// 例如回傳: '2026/06/30 17:58:12' +info(`RELEASE_COUNT=42`); +// 內部即以 timestamp() 組出: [INF][2026/06/30 17:58:12]: RELEASE_COUNT=42 +``` + +> 前置條件:執行環境須支援 `Intl`(Node 18+ 內建)。結果:回傳當下台灣時間字串,無副作用。 + ### info -以 `[INFO]` 前綴將一般資訊訊息輸出到 stdout(`console.log`)。 +以 `[INF][時間]:` 前綴將一般資訊訊息輸出到 stdout(`console.log`,時間為 Asia/Taipei)。 ```js info('RELEASE_COUNT=10'); -// 輸出:[INFO] RELEASE_COUNT=10 +// 輸出:[INF][2026/06/30 17:58:12]: RELEASE_COUNT=10 ``` ### success -以 `[OK]` 前綴將成功訊息輸出到 stdout。 +以 `[INF][時間]:` 前綴將成功訊息輸出到 stdout。規範等級碼無「成功」一項,故等級採 `INF`,成功語意保留於訊息文字。 ```js success('成功刪除: v1.0.0 (Release 1.0.0)'); -// 輸出:[OK] 成功刪除: v1.0.0 (Release 1.0.0) +// 輸出:[INF][2026/06/30 17:58:12]: 成功刪除: v1.0.0 (Release 1.0.0) ``` ### warn -以 `[WARN]` 前綴將警告訊息輸出到 stdout(非致命情況,程式會繼續執行)。 +以 `[WRN][時間]:` 前綴將警告訊息輸出到 stdout(非致命情況,程式會繼續執行)。 ```js warn('GITEA_TOKEN is empty; release API calls will be anonymous'); -// 輸出:[WARN] GITEA_TOKEN is empty; release API calls will be anonymous +// 輸出:[WRN][2026/06/30 17:58:12]: GITEA_TOKEN is empty; release API calls will be anonymous ``` ### fail -以 `[ERR]` 前綴將錯誤訊息輸出到 **stderr**(`console.error`)。僅負責輸出,不會結束程序;是否離開由呼叫端決定。 +以 `[ERR][時間]:` 前綴將錯誤訊息輸出到 **stderr**(`console.error`)。僅負責輸出,不會結束程序;是否離開由呼叫端決定。 ```js fail('刪除失敗: v0.1.0 (Release 0.1.0), HTTP 500'); +// 輸出(stderr):[ERR][2026/06/30 17:58:12]: 刪除失敗: v0.1.0 (Release 0.1.0), HTTP 500 process.exit(1); // 終止由呼叫端負責 ``` @@ -159,11 +189,11 @@ isEmptyOrNull('abc'); // false ### requireValue -檢查必填值。先以 `[INFO]` 印出 `name=value`,若值被判定為空則印出 `[ERR]` 並以 exit code 1 結束程序。 +檢查必填值。先以 `[INF]` 印出 `name=value`,若值被判定為空則以 `[ERR]` 輸出並以 exit code 1 結束程序。 ```js requireValue('GITEA_SERVER_URL', process.env.GITEA_SERVER_URL); -// 值為空 → 輸出 [ERR] GITEA_SERVER_URL is required,並 process.exit(1) +// 值為空 → 輸出 [ERR][時間]: GITEA_SERVER_URL is required,並 process.exit(1) ``` > 前置條件:應在程式啟動早期呼叫。注意此函式會將值原樣印到 stdout,故不用於機密值(程式對 `GITEA_TOKEN` 改以 redacted 方式輸出)。 @@ -171,11 +201,11 @@ requireValue('GITEA_SERVER_URL', process.env.GITEA_SERVER_URL); ### requireInteger -驗證值是否為非負整數字串(正則 `/^[0-9]+$/`,允許前導零、不允許負號或小數),不符合時印出 `[ERR]` 並以 exit code 1 結束程序。 +驗證值是否為非負整數字串(正則 `/^[0-9]+$/`,允許前導零、不允許負號或小數),不符合時以 `[ERR]` 輸出並以 exit code 1 結束程序。 ```js requireInteger('KEEP_COUNT', '2'); // 通過 -requireInteger('KEEP_COUNT', '-1'); // 輸出 [ERR] ... 並 process.exit(1) +requireInteger('KEEP_COUNT', '-1'); // 輸出 [ERR][時間]: ... 並 process.exit(1) ``` @@ -204,4 +234,4 @@ main().catch((err) => { }); ``` -> 前置條件:執行環境須提供必要環境變數,且可連線到 Gitea API。結果:清理符合條件的舊 release 與孤兒 tag,並輸出處理過程 log。 +> 前置條件:執行環境須提供必要環境變數,且可連線到 Gitea API。結果:清理符合條件的舊 release 與孤兒 tag,並以統一等級式日誌輸出處理過程。 diff --git a/app/index.js b/app/index.js index ab96512..83dc448 100644 --- a/app/index.js +++ b/app/index.js @@ -25,44 +25,58 @@ function section(title) { } /** - * 以 [INFO] 前綴將一般資訊訊息輸出到 stdout。 + * 取得目前 Asia/Taipei 時區的時間字串,格式為 `yyyy/MM/dd HH:mm:ss`。 + * 使用 Node 內建 Intl(`toLocaleString('sv-SE')` 天生輸出 24 小時制 + * `YYYY-MM-DD HH:mm:ss`,再把 `-` 換成 `/`),不需額外相依。 + * + * @returns {string} 例如 `2026/06/30 16:53:06`。 + */ +function timestamp() { + return new Date() + .toLocaleString('sv-SE', { timeZone: 'Asia/Taipei' }) + .replace(/-/g, '/'); +} + +/** + * 以 `[INF][時間]:` 前綴將一般資訊訊息輸出到 stdout(時間為 Asia/Taipei)。 * * @param {string} msg 要輸出的訊息內容。 * @returns {void} */ function info(msg) { - console.log(`[INFO] ${msg}`); + console.log(`[INF][${timestamp()}]: ${msg}`); } /** - * 以 [OK] 前綴將成功訊息輸出到 stdout。 + * 以 `[INF][時間]:` 前綴將成功訊息輸出到 stdout(時間為 Asia/Taipei)。 + * 規範等級碼無「成功」,故等級採 INF,成功語意保留於訊息文字。 * * @param {string} msg 要輸出的訊息內容。 * @returns {void} */ function success(msg) { - console.log(`[OK] ${msg}`); + console.log(`[INF][${timestamp()}]: ${msg}`); } /** - * 以 [WARN] 前綴將警告訊息輸出到 stdout。 + * 以 `[WRN][時間]:` 前綴將警告訊息輸出到 stdout(時間為 Asia/Taipei)。 * * @param {string} msg 要輸出的訊息內容。 * @returns {void} */ function warn(msg) { - console.log(`[WARN] ${msg}`); + console.log(`[WRN][${timestamp()}]: ${msg}`); } /** - * 以 [ERR] 前綴將錯誤訊息輸出到 stderr。 + * 以 `[ERR][時間]:` 前綴將錯誤訊息輸出到 stderr(時間為 Asia/Taipei)。 * 僅負責輸出,不會結束程序(是否離開由呼叫端決定)。 * * @param {string} msg 要輸出的錯誤訊息內容。 * @returns {void} */ function fail(msg) { - console.error(`[ERR] ${msg}`); + console.error(`[ERR][${timestamp()}]: ${msg}`); } /**