diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 992fff0..60e3632 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -1,51 +1,117 @@ +# ============================================================================= +# CI Workflow(Gitea Actions) +# 用途:在 Pull Request 開啟或更新時觸發的持續整合流程,依序執行三個 job: +# 1. BUILD - 發佈 Gitea Release(beta 版本號取自 run_number)。 +# 2. TEST - checkout 原始碼,執行本 composite action(setup-codex), +# 再用 codex exec 產生「自我介紹」文字,透過 heredoc 寫入 job output。 +# 3. RESULT - 顯示 TEST job 輸出的 message,用於驗證整條流程串接成功。 +# 更新日期:2026/07/03 11:41:20 +# ============================================================================= + +# workflow 名稱,會顯示在 Gitea Actions 的執行清單中。 name: CI +# 觸發條件設定區塊。 on: + # 監聽 Pull Request 事件。 pull_request: + # 僅在 PR「開啟」(opened) 或「有新 commit 推送 / 更新」(synchronize) 時觸發, + # 避免 closed / reopened 等其他事件也啟動整條 CI。 types: [opened, synchronize] +# 定義本 workflow 的所有 job。 jobs: + # ---- Job 1:BUILD(發佈 Release)---- build: + # job 顯示名稱(前綴數字用於在 UI 中排序閱讀)。 name: 1. BUILD + # 指定執行環境(runner label),使用 ubuntu runner。 runs-on: ubuntu + # 此 job 專屬的環境變數。 env: + # 版本號規則:固定 0.0.0-beta. 前綴 + Gitea 的執行流水號 run_number, + # 讓每次 CI 產生遞增且唯一的 beta 版本字串。 VERSION: "0.0.0-beta.${{ gitea.run_number }}" + # 此 job 的執行步驟。 steps: + # 步驟:發佈 Release。 - name: Publishing Release + # 使用第三方 action 建立 Gitea Release;版本號由 repo variable 控制, + # 便於集中管理 action 版本、避免硬編碼。 uses: akkuman/gitea-release-action@${{ vars.ACTION_GITEA_RELEASE_VERSION }} + # 傳入該 action 的參數。 with: + # Release 顯示名稱:「儲存庫名稱 v版本號」。 name: "${{ gitea.event.repository.name }} v${{ env.VERSION }}" + # Release 對應的 tag 名稱,前綴 v + 版本號。 tag_name: "v${{ env.VERSION }}" + # tag 指向的 commit,使用本次觸發事件的 commit SHA。 target_commitish: ${{ gitea.sha }} + # 是否標記為「預發佈」(prerelease):當 PR 目標分支 base_ref 為 develop 時為 true, + # 代表流向 develop 的變更視為預發佈版本。 prerelease: ${{ gitea.base_ref == 'develop' }} + # ---- Job 2:TEST(執行 setup-codex 並產生自我介紹)---- test: + # job 顯示名稱。 name: 2. TEST + # 指定 ubuntu runner。 runs-on: ubuntu + # 相依關係:需等 build job 成功後才執行。 needs: [build] + # 定義此 job 對外輸出,供後續 job(result)取用。 outputs: + # 將名為 execute 的步驟輸出的 message,暴露為 job 層級的 message 輸出。 message: ${{ steps.execute.outputs.message }} + # 此 job 的執行步驟。 steps: + # 步驟:取出原始碼。 - name: Source Code Checkout + # 使用官方 checkout action 將 repo 內容拉到 runner;版本由 repo variable 控制。 uses: actions/checkout@${{ vars.ACTION_CHECKOUT_VERSION }} + # 步驟:執行本 repo 的 composite action(setup-codex)。 - name: Run Setup Codex + # 指定步驟 id,方便後續引用其輸出。 id: setup-codex + # 「./」代表使用當前 repo 根目錄的 action(即本專案自身這個 composite action)。 uses: ./ + # 傳入該 action 的參數。 with: + # 從 secrets 帶入 CODEX_OAUTH 授權憑證,供 codex 登入 / 認證使用(機密不外顯)。 oauth: ${{ secrets.CODEX_OAUTH }} + # 步驟:實際呼叫 codex 產生自我介紹並寫入 job output。 - name: Execute Codex + # 指定步驟 id 為 execute,對應上方 outputs.message 的來源。 id: execute + # 明確指定以 bash 執行下方 run 腳本。 shell: bash + # 多行 shell 腳本(run: | 表示保留換行的區塊字面值)。 run: | + # 執行 codex exec 送出提示「請你進行自我介紹」,取得回覆文字存入 MESSAGE 變數; + # 2>/dev/null 將 stderr 丟棄,避免非結果訊息污染輸出內容。 MESSAGE=$(codex exec "請你進行自我介紹" 2>/dev/null) + # 用大括號將多個 echo 群組化,統一把整段輸出一次重導向到 $GITHUB_OUTPUT。 { + # 宣告輸出鍵 message 並使用 heredoc 分隔符 CODEX_EOF,以支援「多行值」的寫法。 echo "message<>) 到 $GITHUB_OUTPUT 檔,登記為此步驟的 output。 } >> "$GITHUB_OUTPUT" + # ---- Job 3:RESULT(顯示 TEST 的 message)---- result: + # job 顯示名稱。 name: 3. RESULT + # 指定 ubuntu runner。 runs-on: ubuntu + # 相依關係:需等 build 與 test 兩個 job 都完成後才執行。 needs: [build,test] + # 此 job 專屬的環境變數。 env: + # 從 test job 的輸出取得 message,供下方步驟印出。 MESSAGE: ${{ needs.test.outputs.message }} + # 此 job 的執行步驟。 steps: + # 步驟:印出訊息。 - name: Show Message + # 將環境變數 MESSAGE 的內容輸出到 log,用於確認整條流程串接與 codex 回覆結果。 run: echo "$MESSAGE" diff --git a/.gitea/workflows/master.yaml b/.gitea/workflows/master.yaml index cfce70f..c9c7545 100644 --- a/.gitea/workflows/master.yaml +++ b/.gitea/workflows/master.yaml @@ -1,21 +1,53 @@ +# ============================================================================= +# 用途說明: +# 本 workflow 為「CD(持續部署)」流程,於程式碼 push 到 master 分支時觸發。 +# 主要工作為 checkout 完整原始碼、依指定 commit 反查其所屬的 git tag, +# 並將該 tag 輸出顯示,供後續部署或版本追蹤使用。 +# 更新日期:2026/07/03 11:41:20 (Asia/Taipei) +# ============================================================================= + +# workflow 名稱,顯示於 Gitea Actions 介面 name: CD +# 觸發條件設定 on: + # 監聽 push 事件 push: + # 僅限定下列分支 branches: + # 只有 push 到 master 分支時才會觸發本 workflow - master +# 定義所有工作(jobs) jobs: + # 部署工作,job 識別鍵為 deploy deploy: + # 此 job 的顯示名稱 name: DEPLOY + # 指定執行環境(runner label)為 ubuntu runs-on: ubuntu + # job 層級環境變數 env: + # 取事件 commits 陣列的第二筆(索引 1)之 commit id 作為要處理的 SHA + # 需人工確認:使用索引 1 而非 0,取的是事件中「第二個」commit; + # 當一次 push 只包含單一 commit 時,索引 1 可能取不到值(為空)。 COMMIT_SHA: ${{ gitea.event.commits[1].id }} + # 依序執行的步驟 steps: + # 步驟一:取出原始碼 - name: Source Code Checkout + # 使用 actions/checkout,版本由 repo/organization 變數 ACTION_CHECKOUT_VERSION 決定 uses: actions/checkout@${{ vars.ACTION_CHECKOUT_VERSION }} with: + # fetch-depth: 0 代表抓取完整 git 歷史(含所有 tag), + # 以利後續 git describe 能正確反查 tag(淺層 clone 會導致查不到)。 fetch-depth: 0 + # 步驟二:取得該 commit 所屬的 tag - name: Get Commit Tag + # 設定步驟 id 為 commit,供後續步驟以 steps.commit.outputs 取得輸出 id: commit + # git describe --contains 會找出「包含」指定 commit 的最近 tag, + # 並將結果以 tag=... 寫入 $GITEA_OUTPUT,成為此步驟的輸出參數 tag。 run: echo "tag=$(git describe --contains ${{ env.COMMIT_SHA }})" >> $GITEA_OUTPUT + # 步驟三:顯示取得的 tag - name: Show Tag + # 印出上一步(id=commit)輸出的 tag 值,方便於 log 確認結果 run: echo "${{ steps.commit.outputs.tag }}" diff --git a/README.md b/README.md new file mode 100644 index 0000000..a208728 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# setup-codex + +> 更新時間:2026/07/03 11:45:51 + +`setup-codex` 是一個 **Gitea composite action**,用於在 Gitea Actions runner 上安裝並登入 [Codex CLI](https://chatgpt.com/codex),讓後續 workflow 步驟能直接呼叫已完成 OAuth 登入的 `codex` 指令。本 repo 由 action 定義(`action.yml`)與示範用的 CI/CD workflow 組成,內容皆為 YAML 與少量 shell/Node,**不含可列入 README 的公開程式方法**。 + +## 專案列表 + +### 專案描述 + +| 專案名稱 | 專案描述 | +| --- | --- | +| [setup-codex](https://gitea.jsc.idv.tw/actions/setup-codex/src/branch/develop) | Gitea composite action:安裝 Codex CLI、以 base64 編碼的 OAuth 驗證檔完成登入,並顯示目前登入帳號;另附 CI(PR 發佈 Release + 執行 action)與 CD(push master 反查 commit tag)示範 workflow。 | + +### 參考專案 + +| 專案名稱 | 參考專案列表 | +| --- | --- | +| [setup-codex](https://gitea.jsc.idv.tw/actions/setup-codex/src/branch/develop) | 無 | + +### NuGet 套件 + +| 專案名稱 | NuGet 套件列表 | +| --- | --- | +| [setup-codex](https://gitea.jsc.idv.tw/actions/setup-codex/src/branch/develop) | 無 | + +## 功能列表 + +本專案為 Gitea composite action(YAML + shell/Node),未公開任何可列入 README 的程式方法(public method/constructor/extension method/operator)。 + +| 功能名稱 | 功能描述 | +| --- | --- | +| (無) | 此專案未公開可列入 README 的功能。 | + +## 使用範例 + +> 說明:本專案無公開程式方法,以下改以「如何在 workflow 中使用此 composite action」作為使用範例。 + +### 在 workflow 中引用 action + +在同一個 repo 內,可用相對路徑 `./` 引用本 action;跨 repo 則以 `owner/repo@版本` 引用。此 action 需要一個必填參數 `oauth`(透過 OAuth 登入 ChatGPT 產生、並經 base64 編碼的驗證檔內容,建議存放於 secrets)。 + +```yaml +jobs: + demo: + runs-on: ubuntu + steps: + - name: Source Code Checkout + uses: actions/checkout@v4 + # 引用本 repo 根目錄的 composite action + - name: Run Setup Codex + uses: ./ + with: + oauth: ${{ secrets.CODEX_OAUTH }} + # 登入完成後即可直接呼叫 codex + - name: Execute Codex + shell: bash + run: codex exec "請你進行自我介紹" +``` + +**前置條件與注意事項** + +- `oauth`:必填。內容為 Codex/ChatGPT OAuth 驗證檔(`auth.json`)先經 base64 編碼後的字串,請存於 secret(例如 `CODEX_OAUTH`)避免外洩。 +- action 會在 runner 家目錄產生 `~/.codex/auth.json`(含機敏憑證),並將 Codex 執行檔目錄加入 `PATH`。 +- action 內建的 `Show Codex Account` 步驟會將登入帳號的 email 輸出到 workflow log,請留意 log 的存取權限與隱私。 + +### 對應的 workflow 檔案 + +| 檔案 | 觸發時機 | 用途 | +| --- | --- | --- | +| [action.yml](https://gitea.jsc.idv.tw/actions/setup-codex/src/branch/develop/action.yml) | 被其他 workflow 以 `uses` 引用 | 定義安裝/登入 Codex 的 composite action。 | +| [.gitea/workflows/ci.yaml](https://gitea.jsc.idv.tw/actions/setup-codex/src/branch/develop/.gitea/workflows/ci.yaml) | Pull Request `opened`/`synchronize` | 發佈 beta Release、執行本 action 並以 `codex exec` 產生自我介紹、顯示結果。 | +| [.gitea/workflows/master.yaml](https://gitea.jsc.idv.tw/actions/setup-codex/src/branch/develop/.gitea/workflows/master.yaml) | push 至 `master` | 反查指定 commit 所屬的 git tag 並顯示。 | diff --git a/action.yml b/action.yml index ff4d942..30309b8 100644 --- a/action.yml +++ b/action.yml @@ -1,27 +1,68 @@ +# ============================================================================= +# 指令檔用途:Gitea composite action —「Setup Codex CLI」 +# 本檔定義一個組合式(composite)action,負責在 CI/CD runner 上: +# 1) 下載並安裝 Codex CLI 工具,並將其執行檔目錄加入 PATH。 +# 2) 使用外部傳入、經 base64 編碼的 OAuth 驗證檔完成 Codex 登入。 +# 3) 解析登入驗證檔中的 id_token,輸出目前登入的帳號 email 以供確認。 +# 使用情境:讓後續 workflow 步驟可直接呼叫已登入的 Codex CLI。 +# 更新日期:2026/07/03 11:41:20 +# ============================================================================= + +# action 名稱:顯示於 Gitea/GitHub Actions UI 上的識別名稱 name: 'Setup Codex CLI' +# action 說明:簡述此 action 的功能(安裝 Codex CLI 工具) description: '安裝 Codex CLI 工具' +# 作者資訊 author: 'Jeffery' +# inputs:定義呼叫此 action 時可傳入的參數 inputs: + # 參數 oauth:ChatGPT OAuth 登入後產生的驗證檔內容 oauth: + # 參數說明:透過 OAuth 登入 ChatGPT 產生的驗證檔,內容須先經 base64 編碼再傳入 description: '透過 OAuth 登入 ChatGPT 產生驗證檔,經過 base64 編碼' + # required: true 表示此參數為必填,未提供時 action 會失敗 required: true +# outputs:定義此 action 執行後對外輸出的值 outputs: + # 輸出 message:供呼叫端取用的訊息輸出 message: + # 輸出說明 description: '輸出訊息' + # 【需人工確認】此 output 參照名為 `exchange` 的 step 之 outputs.message, + # 但本 action 的 steps 中並不存在 id 為 `exchange` 的步驟, + # 因此此 output 很可能取不到值(會是空字串)。此處僅標註,未修改該行內容。 value: ${{ steps.exchange.outputs.message }} +# runs:定義此 action 的執行方式與步驟 runs: + # using: 'composite' 表示這是組合式 action,由下方多個 shell step 組成 using: 'composite' + # steps:依序執行的步驟清單 steps: + # 步驟一:安裝 Codex CLI - name: Setup Codex + # env:此步驟專用的環境變數 env: + # CODEX_NON_INTERACTIVE=1:讓 Codex 以非互動模式執行,避免安裝過程等待輸入而卡住 CI CODEX_NON_INTERACTIVE: 1 + # run:以 shell 執行的安裝指令(多行) run: | + # 從官方網址下載安裝腳本並直接以 sh 執行(-f 失敗即報錯、-s 靜默、-S 顯示錯誤、-L 跟隨轉址) curl -fsSL https://chatgpt.com/codex/install.sh | sh + # 將 Codex 執行檔安裝目錄寫入 $GITHUB_PATH,使後續步驟能直接呼叫 codex 指令 echo "$HOME/.local/bin" >> "$GITHUB_PATH" + # shell: bash 指定以 bash 執行上方 run 內容(composite step 需明確指定 shell) shell: bash + # 步驟二:使用 OAuth 驗證檔登入 Codex - name: Login Codex with OAuth + # env:此步驟專用環境變數 env: + # 將呼叫端傳入的 oauth 參數(base64 字串)帶入環境變數 OAUTH OAUTH: ${{ inputs.oauth }} + # run:將 base64 字串解碼後還原成 auth.json 驗證檔,供 Codex CLI 讀取登入狀態 + # 副作用:會在 runner 家目錄產生 ~/.codex/auth.json(含機敏憑證),請勿外洩或輸出其內容 run: echo $OAUTH | base64 --decode > ~/.codex/auth.json + # 步驟三:顯示目前登入的 Codex 帳號 - name: Show Codex Account - run: node -e 'console.log(JSON.parse(Buffer.from(JSON.parse(require("fs").readFileSync(process.env.HOME+"/.codex/auth.json")).tokens.id_token.split(".")[1],"base64")).email)' \ No newline at end of file + # run:以 node 讀取 auth.json,解析 tokens.id_token(JWT)的 payload(第 2 段 base64)取出 email 並印出 + # 副作用【重要】:此行會將登入帳號的 email 輸出到 workflow log,log 內會出現帳號 email,請留意隱私與存取權限 + run: node -e 'console.log(JSON.parse(Buffer.from(JSON.parse(require("fs").readFileSync(process.env.HOME+"/.codex/auth.json")).tokens.id_token.split(".")[1],"base64")).email)'