From c3c236cc6a61585f2b412c21a26395f2f3446391 Mon Sep 17 00:00:00 2001 From: GITEA ACTIONS Date: Thu, 2 Jul 2026 07:23:43 +0000 Subject: [PATCH] Initial commit --- .gitea/workflows/ci.yaml | 39 +++++ .gitea/workflows/master.yaml | 21 +++ .gitea/workflows/readme.md | 9 ++ README.md | 272 +++++++++++++++++++++++++++++++++++ action.yml | 14 ++ package.json | 11 ++ src/index.js | 16 +++ 7 files changed, 382 insertions(+) create mode 100644 .gitea/workflows/ci.yaml create mode 100644 .gitea/workflows/master.yaml create mode 100644 .gitea/workflows/readme.md create mode 100644 README.md create mode 100644 action.yml create mode 100644 package.json create mode 100644 src/index.js diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml new file mode 100644 index 0000000..0639499 --- /dev/null +++ b/.gitea/workflows/ci.yaml @@ -0,0 +1,39 @@ +name: CI +on: + pull_request: + types: [opened, synchronize] +jobs: + build: + name: 1. BUILD + runs-on: ubuntu + env: + VERSION: "0.0.0-beta.${{ gitea.run_number }}" + steps: + - name: Publishing Release + uses: akkuman/gitea-release-action@${{ vars.ACTION_GITEA_RELEASE_VERSION }} + with: + name: "${{ gitea.event.repository.name }} v${{ env.VERSION }}" + tag_name: "v${{ env.VERSION }}" + target_commitish: ${{ gitea.sha }} + prerelease: ${{ gitea.base_ref == 'develop' }} + test: + name: 2. TEST + runs-on: ubuntu + needs: [build] + outputs: + message: ${{ steps.composite-template.outputs.message }} + steps: + - name: Source Code Checkout + uses: actions/checkout@${{ vars.ACTION_CHECKOUT_VERSION }} + - name: Run Composite Template + id: composite-template + uses: ./ + result: + name: 3. RESULT + runs-on: ubuntu + needs: [build,test] + env: + MESSAGE: ${{ needs.test.outputs.message }} + steps: + - name: Show Message + run: echo "$MESSAGE" diff --git a/.gitea/workflows/master.yaml b/.gitea/workflows/master.yaml new file mode 100644 index 0000000..cfce70f --- /dev/null +++ b/.gitea/workflows/master.yaml @@ -0,0 +1,21 @@ +name: CD +on: + push: + branches: + - master +jobs: + deploy: + name: DEPLOY + runs-on: ubuntu + env: + COMMIT_SHA: ${{ gitea.event.commits[1].id }} + steps: + - name: Source Code Checkout + uses: actions/checkout@${{ vars.ACTION_CHECKOUT_VERSION }} + with: + fetch-depth: 0 + - name: Get Commit Tag + id: commit + run: echo "tag=$(git describe --contains ${{ env.COMMIT_SHA }})" >> $GITEA_OUTPUT + - name: Show Tag + run: echo "${{ steps.commit.outputs.tag }}" diff --git a/.gitea/workflows/readme.md b/.gitea/workflows/readme.md new file mode 100644 index 0000000..c376ad2 --- /dev/null +++ b/.gitea/workflows/readme.md @@ -0,0 +1,9 @@ +# GITEA NODE ACTION 的工作流列表 + +- CI + - BUILD + - TEST + - RESULT +- CD + - BUILD + - DEPLOY diff --git a/README.md b/README.md new file mode 100644 index 0000000..5bf3300 --- /dev/null +++ b/README.md @@ -0,0 +1,272 @@ +# 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.` 底下的一組設定。`` 必須以字母或底線開頭,只能含英數、`-`、`_`: + +| 欄位 | 必填 | 說明 | +|------|------|------| +| `description` | ✅ | 參數說明。 | +| `required` | ❌ | 是否必填,布林值,預設 `false`。 | +| `default` | ❌ | 預設值;呼叫端沒傳時採用。**只能是字串**。 | +| `deprecationMessage` | ❌ | 標記此 input 已棄用,使用時記錄警告訊息。 | + +**呼叫端傳值**(用 `with`): + +```yaml +- uses: ./ + with: + message: 'Hi there' +``` + +> ✅ **與 composite 的關鍵差異**:node action **會**自動把每個 input 轉成 `INPUT_` 環境變數——名稱**轉大寫**、**空白換成底線**(例: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..timeout-minutes`、`jobs..continue-on-error`、`jobs..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) diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..b9b7ec7 --- /dev/null +++ b/action.yml @@ -0,0 +1,14 @@ +name: 'Gitea Node Template' +description: 'Gitea Node (JavaScript) action 範本' +author: 'Jeffery' +inputs: + message: + description: '輸入訊息' + required: false + default: 'Hello, World!' +outputs: + message: + description: '輸出訊息' +runs: + using: 'node24' + main: 'src/index.js' diff --git a/package.json b/package.json new file mode 100644 index 0000000..396a6f4 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "node-template", + "version": "1.0.0", + "description": "Gitea Node (JavaScript) action 範本", + "main": "src/index.js", + "scripts": { + "build": "ncc build src/index.js -o dist" + }, + "author": "Jeffery", + "license": "MIT" +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..a3cba04 --- /dev/null +++ b/src/index.js @@ -0,0 +1,16 @@ +const fs = require('fs'); +const os = require('os'); + +// 讀取 input:node action 會把每個 input 轉成 INPUT_ 環境變數 +// (名稱大寫、空白換成底線)。action.yml 有設 default 時,runner 會先帶入 default。 +const message = process.env.INPUT_MESSAGE ?? 'Hello, World!'; + +// 設定 output:把 name=value 附加寫進 $GITHUB_OUTPUT 指向的檔案。 +// node action 的 output 不像 composite 需要在 action.yml 宣告 value。 +const githubOutput = process.env.GITHUB_OUTPUT; +if (githubOutput) { + fs.appendFileSync(githubOutput, `message=${message}${os.EOL}`); +} + +// 一般日誌輸出。若要讓 step 失敗,改用非零結束碼:process.exit(1)。 +console.log(`message=${message}`);