Files
ai-code-review/README.md
T
2026-07-02 07:23:43 +00:00

273 lines
13 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.
# Gitea Node Action 範本
NodeJavaScriptaction 讓你用 JavaScript 撰寫 action 邏輯,直接跑在 runner 內建的 Node runtime 上。相較於 composite(純 YAML 組合 step)與 Docker(包 imageactionnode action 適合需要**程式邏輯、呼叫 API、跨平台**的情境,且啟動速度比 Docker action 快。
本文件整理 node action 的 `action.yml` 中**所有可用參數、說明與限制**,並特別標出 **Gitea 與 GitHub Actions 的差異**。範例皆對應本 repo 的 [`action.yml`](./action.yml) 與 [`src/index.js`](./src/index.js)。
> 語法基準:Gitea Actions 以相容 GitHub Actions metadata 語法為目標,但兩者有明確差異(見「Gitea vs GitHub」章節)。Gitea 端的行為亦受底層 [`act`](https://gitea.com/gitea/act) runner 版本影響——尤其**支援的 Node 版本**——實作前建議以測試機驗證。
---
## 目錄
- [完整結構總覽](#完整結構總覽)
- [頂層參數](#頂層參數)
- [`inputs`(輸入參數)](#inputs輸入參數)
- [`outputs`(輸出)](#outputs輸出)
- [`runs`(執行設定)](#runs執行設定)
- [在 JavaScript 內取值 / 設值](#在-javascript-內取值--設值)
- [建置與打包(相依套件)](#建置與打包相依套件)
- [Node action 的限制與注意事項](#node-action-的限制與注意事項)
- [Gitea vs GitHub Actions 差異](#gitea-vs-github-actions-差異)
- [本 repo 範例對照](#本-repo-範例對照)
- [參考來源](#參考來源)
---
## 完整結構總覽
```yaml
name: 'Gitea Node Template' # 必填
description: 'Gitea Node 範本' # 必填
author: 'Jeffery' # 選填
inputs: # 選填,定義輸入參數
message:
description: '輸入訊息'
required: false
default: 'Hello, World!'
outputs: # 選填,定義輸出
message:
description: '輸出訊息' # node action 只需 description,不需 value
runs: # 必填
using: 'node24' # 必填,node runtime(最新版;見版本說明)
main: 'src/index.js' # 必填,進入點 JS 檔
pre: 'setup.js' # 選填,main 之前執行
pre-if: "always()" # 選填,pre 的條件,預設 always()
post: 'cleanup.js' # 選填,main 之後執行
post-if: "always()" # 選填,post 的條件,預設 always()
branding: # 選填(Marketplace 用,Gitea 內部可省略)
icon: 'activity'
color: 'blue'
```
> 📌 檔名**只能**是 `action.yml` 或 `action.yaml`,放在 action repo 根目錄。
---
## 頂層參數
| 參數 | 必填 | 說明 |
|------|------|------|
| `name` | ✅ | Action 名稱。 |
| `description` | ✅ | Action 簡短說明。 |
| `author` | ❌ | 作者名稱。 |
| `inputs` | ❌ | 輸入參數定義(見下)。 |
| `outputs` | ❌ | 輸出定義(見下)。 |
| `runs` | ✅ | 執行設定;node action 用 `using: 'node24'` + `main`。 |
| `branding` | ❌ | Marketplace 顯示用的 `icon``color`。 |
---
## `inputs`(輸入參數)
每個 input 是 `inputs.<input_id>` 底下的一組設定。`<input_id>` 必須以字母或底線開頭,只能含英數、`-``_`
| 欄位 | 必填 | 說明 |
|------|------|------|
| `description` | ✅ | 參數說明。 |
| `required` | ❌ | 是否必填,布林值,預設 `false`。 |
| `default` | ❌ | 預設值;呼叫端沒傳時採用。**只能是字串**。 |
| `deprecationMessage` | ❌ | 標記此 input 已棄用,使用時記錄警告訊息。 |
**呼叫端傳值**(用 `with`):
```yaml
- uses: ./
with:
message: 'Hi there'
```
> ✅ **與 composite 的關鍵差異**node action **會**自動把每個 input 轉成 `INPUT_<NAME>` 環境變數——名稱**轉大寫**、**空白換成底線**(例:input `my message` → `INPUT_MY_MESSAGE`)。在 JS 內即可用 `process.env.INPUT_MESSAGE` 或 `core.getInput('message')` 取值。
>
> ⚠️ `required: true` **不會**在缺值時自動報錯——runner 只是標記語意,實際檢查要自己在程式裡做(或用 `core.getInput('x', { required: true })`)。
>
> input 值一律是**字串**;數字、布林傳進來也會變字串(例如 `"true"`),比較時要留意。
---
## `outputs`(輸出)
node action 的 output **只需要 `description`**,**不需要**(也不該有)composite 那種 `value` 欄位——實際的值是在**執行時**由程式寫入:
| 欄位 | 必填 | 說明 |
|------|------|------|
| `description` | ✅ | 輸出說明。 |
**在 JS 內設定 output** → 寫入 `$GITHUB_OUTPUT` 檔案(或用 `core.setOutput`):
```js
const fs = require('fs');
const os = require('os');
fs.appendFileSync(process.env.GITHUB_OUTPUT, `message=Hello${os.EOL}`);
// 或(需要 @actions/core): core.setOutput('message', 'Hello');
```
**呼叫端取用 output**
```yaml
- id: node-template
uses: ./
- run: echo "${{ steps.node-template.outputs.message }}"
```
> 📏 **大小限制**:單一 job 的 outputs 上限 1 MB;一次 workflow run 全部 outputs 合計上限 50 MB。大量資料請改用 artifact。
---
## `runs`(執行設定)
node action 的 `runs` 欄位:
| 欄位 | 必填 | 說明 |
|------|------|------|
| `using` | ✅ | Node runtime。最新為 `node24`(本 repo 採用);亦可用 `node20` / `node16`。實際可用版本取決於 runner(見下方 Gitea 差異)。 |
| `main` | ✅ | 進入點 JS 檔(例:`src/index.js` 或打包後的 `dist/index.js`)。 |
| `pre` | ❌ | 在 `main` **之前**、job 開始時執行的 JS 檔(可做前置設定)。 |
| `pre-if` | ❌ | 決定 `pre` 是否執行的條件,預設 `always()`。 |
| `post` | ❌ | 在 `main` **之後**執行的 JS 檔(可做清理、即使 main 失敗仍會跑)。 |
| `post-if` | ❌ | 決定 `post` 是否執行的條件,預設 `always()`。 |
> ⚠️ **`pre` 不支援 local action**:直接放在同一 repo、用 `uses: ./` 呼叫的 local action **無法**使用 `runs.pre`。`pre` / `post` 也是 **node action 專屬**composite / Docker 沒有)。
---
## 在 JavaScript 內取值 / 設值
node action 進入點是一支普通的 Node 程式。兩種常見寫法:
**A) 零相依(本 repo 採用)**——直接讀環境變數、寫檔案,無需 `npm install`
```js
const message = process.env.INPUT_MESSAGE ?? 'Hello, World!'; // 讀 input
fs.appendFileSync(process.env.GITHUB_OUTPUT, `message=${message}\n`); // 寫 output
console.log(`message=${message}`); // 日誌
process.exit(1); // 讓 step 失敗
```
**B) 使用官方 toolkit `@actions/core`**——語意更清楚,處理跳脫與多行值較穩:
```js
const core = require('@actions/core');
const message = core.getInput('message'); // 讀 input(等同 INPUT_MESSAGE
core.setOutput('message', message); // 設 output
core.info('...'); // 日誌
core.setFailed('錯誤訊息'); // 記錄失敗並以非零碼結束
```
需要呼叫 Gitea / GitHub API 時再加 `@actions/github`(提供已驗證的 REST client 與 `github.context`)。
---
## 建置與打包(相依套件)
- **沒有相依套件**(如本 repo):`main` 直接指向原始 `src/index.js` 即可,Gitea **不需要** build 步驟。
- **有相依套件**(用了 `@actions/core` 等):runner **不會**幫你 `npm install`,你必須把相依一起帶進 repo。二選一:
1. **打包(建議)**:用 [`@vercel/ncc`](https://github.com/vercel/ncc) 把原始碼與相依編成單一檔,再把 `main` 指到它:
```bash
npm i -D @vercel/ncc
npx ncc build src/index.js -o dist # 產生 dist/index.js
```
並改 `action.yml``main: 'dist/index.js'`。**打包後的 `dist/` 要 commit 進 repo。**
2. **直接 commit `node_modules`**:可行但體積大、易出問題,一般不建議。
> 用打包方式時,記得每次改 code 都重新 `ncc build` 並把 `dist/` 一起提交,否則 action 跑的是舊版。
---
## Node action 的限制與注意事項
1. **相依不會自動安裝**
runner 不會在 action repo 內跑 `npm install`。要嘛零相依,要嘛把相依打包 / commit 進 repo(見上一節)。
2. **`required: true` 不會自動擋**
缺少必填 input 時 runner 不會報錯,要自己在程式裡驗證。
3. **input 一律是字串**
`INPUT_*` / `core.getInput` 拿到的都是字串,數字與布林需自行轉型。
4. **output 有大小上限**
單 job 1 MB、單次 run 合計 50 MB;超量請用 artifact。
5. **`main` 路徑相對於 action 根目錄**
`main: src/index.js` 指的是相對於 action repo 根目錄的路徑,不受呼叫端工作目錄影響。要讀 action 自帶的其他檔案時,用 `__dirname` 或 `process.env.GITHUB_ACTION_PATH` 定位,不要用相對於呼叫端的路徑。
6. **`pre` 不支援 local action、且 `pre`/`post` 為 node 專屬**
見 `runs` 章節。
7. **Node 版本要對得上 runner**
`using` 指定的版本必須是該 runner 支援的版本,否則 action 直接被拒(見下方 Gitea 差異)。
8. **跨 step 共享環境變數 / PATH**
在程式內寫入 `$GITHUB_ENV`、`$GITHUB_PATH` 指向的檔案,可讓**後續 step**取得對應的環境變數 / PATH。
---
## Gitea vs GitHub Actions 差異
Gitea Actions **不是** GitHub Actions 的 100% 複製品。撰寫 node action 時特別注意:
| 項目 | Gitea 行為 |
|------|-----------|
| **支援的 Node 版本** | `runs.using` 可用的 node 版本**取決於 act runner 版本**`node20` 需 runner ≥ v0.2.6**`node24`(最新,本 repo 採用)需較新的 runner**。若 runner 太舊,會報錯 `The runs.using key in action.yml must be one of: [composite docker node12 node16 node20 go], got node24`——此時請**升級 act runner**,或暫時退回 `node20`。GitHub 端自 2026/03 起 `node24` 已為 JS action 預設。 |
| **`using: 'go'`** | Gitea 額外支援 `using: 'go'` 寫 Go actionGitHub 沒有)。 |
| **表達式函式** | 依官方比較文件,**僅保證支援 `always()`**`success()` / `failure()` / `cancelled()` / `hashFiles()` 等其他函式視 `act` runner 版本而定,不保證可用——寫 `if:`(含 `pre-if` / `post-if`)前先在測試機驗證。 |
| **`uses` 支援絕對 URL** | 可寫 `uses: https://github.com/actions/checkout@v4` 或 `uses: http://your_gitea/owner/repo@branch`,不限同站 action。 |
| **context 檢查較寬鬆** | Gitea 不檢查 context 可用性,`env` context 可用在比 GitHub 更多的位置(但不代表可攜,跨到 GitHub 會失敗)。 |
| **被忽略的 job 欄位** | `jobs.<job_id>.timeout-minutes`、`jobs.<job_id>.continue-on-error`、`jobs.<job_id>.environment` 會被忽略。 |
| **`runs-on`** | 只接受簡單格式 `runs-on: xyz` 或 `runs-on: [xyz]`,不支援複雜表達式。 |
| **annotations / problem matchers** | 不支援,會被忽略。 |
| **`permissions` scope** | 支援 `permissions`,但沒有 GitHub 專屬的 `statuses` / `checks` / `deployments` / `id-token` / `security-events` / `pages`Gitea 有自己的 `code` / `releases` / `wiki` / `projects`。 |
> 上表以 Gitea 官方文件為準;`act` runner 持續更新,部分限制(尤其表達式函式與 Node 版本)可能隨版本放寬,仍以你環境的實測為準。
---
## 本 repo 範例對照
- Action 定義:[`action.yml`](./action.yml)`using: node24` + `main: src/index.js`
- 進入點程式:[`src/index.js`](./src/index.js)(零相依:讀 `INPUT_MESSAGE`、寫 `$GITHUB_OUTPUT`
- 專案設定:[`package.json`](./package.json)
- CI 呼叫範例:[`.gitea/workflows/ci.yaml`](./.gitea/workflows/ci.yaml)
CI 的 `BUILD` job 呼叫本 action、後續 job 取用其 output
```yaml
build:
outputs:
message: ${{ steps.build.outputs.message }}
steps:
- uses: actions/checkout@${{ vars.ACTION_CHECKOUT_VERSION }}
- id: build
uses: ./
result:
needs: [build, test]
steps:
- run: echo "${{ needs.build.outputs.message }}"
```
---
## 參考來源
- [GitHub Actions — Metadata syntax for actions](https://docs.github.com/en/actions/reference/workflows-and-actions/metadata-syntax)
- [GitHub Actions — Creating a JavaScript action](https://docs.github.com/en/actions/tutorials/create-actions/create-a-javascript-action)
- [Gitea — Compared to GitHub Actions](https://docs.gitea.com/usage/actions/comparison)
- [Gitea Blog — Gitea Actions now Supports Node20 based actions](https://blog.gitea.com/node-20-actions-support/)
- [Gitea — Act Runner](https://docs.gitea.com/usage/actions/act-runner)
- [@actions/core toolkit](https://github.com/actions/toolkit/tree/main/packages/core)
- [@vercel/ncc — 打包工具](https://github.com/vercel/ncc)