release: 將 AI 程式碼審查 action 發布到 master #2
@@ -1,272 +0,0 @@
|
|||||||
# Gitea Node Action 範本
|
|
||||||
|
|
||||||
Node(JavaScript)action 讓你用 JavaScript 撰寫 action 邏輯,直接跑在 runner 內建的 Node runtime 上。相較於 composite(純 YAML 組合 step)與 Docker(包 image)action,node 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 action(GitHub 沒有)。 |
|
|
||||||
| **表達式函式** | 依官方比較文件,**僅保證支援 `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)
|
|
||||||
Reference in New Issue
Block a user