前言

會想自己弄一個 Github Action 除了自己有需求目前找不到既有的服務可以滿足之外,就是很想自己也動手玩玩看這個便利的工具。這個需求的產生主要是因為近年在跟團隊合作時,有發現要讓團隊成員養成保持專案的分支整潔的這件事情上面實在有點困難,主因是開發常常多頭進行之外,就是沒有一個時間是可以讓大家喘口氣好好整理目前的 Codebase,既然連 Code 都沒時間整理了,專案的分支就更不用講了。只是這樣長久下來實在有太多無意義的分支殘留,在搜尋時與管理時會有些麻煩,因此若有一個小幫手能夠自動自發的幫忙清理分支那就好很多了。

起步走

想直接看最終成品的可以到這邊看最後完成的樣子跟使用方式。但要先提醒急著用的人,這個 action 會把符合條件的 branch 砍掉,基本上屬於不可逆操作,所以使用說明需要先看仔細。

目前 Github action 主流是用 nodejs 開發,因為相關的 ecosystem 還滿完整豐富的開發起來還滿快的,所以這個指南就用 nodejs 來做簡易教學。會順手使用 volta 和本機端測試 Github action 的好用工具 act

volta 的使用可以參考這篇文章。

  • 初始設定
1
mkdir {your-project-path} && cd {your-project-path}
  • 設定專案初始值

專案使用 typescript 但因為只有開發階段需要所以只須裝在開發階段,另外再安裝一些開發階段才會需要的套件。

1
2
npm init
npm install --save-dev typescript @types/node @vercel/ncc @types/jest jest ts-jest gts

安裝後可以用以下指令測試 typescript 是否安裝成功

npx tsc -v

安裝完上述開發環境的套件後有一些套件需要初始化設定,像是 typescript、gts 跟 jest。 初始化 typescript。裡面有很多可以設定的參數,可以參考這裡。而初始化 jest 可以參考這裡,另外 gts 的相關資訊能在這邊看看。

在 jest 的設定方面有一個小撇步,那就是不要使用 typescript,讓它用一般的 javascript 檔案格式就好,不然編譯的時候預設會往 tsconfig.json 裡的 rootDir 位置去找 jest.config.ts ,該位置找不到檔案的話就會編譯失敗。

1
2
3
npx tsc --init
npx gts init
npx jest --init

你也是可以用全域安裝 typescript,雖然這樣做剛開始很方便,不過對於多個專案同時處理時版本有不一致的需求時會滿麻煩的

1
2
3
# 可全域安裝 typescript 但個人不建議這樣裝
volta install typescript
tsc -v

初始化設定好後可以接著設定專案所相依的版本,這個時候可以用 Volta 來幫忙做設定。

1
2
volta pin node@20.11.1
volta pin npm@10.4.0

這樣之後切到該資料夾 Volta 就會幫忙自動幫忙切換 NodeJS 跟 npm 的版本不需要自己切換了。

實做客製化的 Github action

目前這樣開發 Github action 事前的準備工作就算完成了,基本上跟一個簡易的 nodejs 專案沒有區別,剩下來的就是實做的部份。

若要開發 Github action 的話,有兩個套件是很推薦使用的:

  • @actions/core
    • 基本上要取得傳入的參數以及為 action 寫上 log 都可以用這個套件完成
  • @actions/github
    • 若有需要操作 Github rest API 就可以用這個
1
2
npm update
npm install @actions/core @actions/github @octokit/plugin-rest-endpoint-methods

PS 這邊會特別引入 @octokit/plugin-rest-endpoint-methods 套件單純是因為內部處理的時候我需要使用 Github rest API 的回應格式。若你沒有這個需求可以不用安裝。

設定 action 入口

Github action 需要有一份設定幫忙闡明該 action 的 input/output、action 的進入函式,與該 action 的執行環境(是 nodejs 還是其他 container 環境)。而這個關鍵的設定以 Github action 來說就是 action.yml 或是 action.yaml 檔案(檔名務必要是這兩個其中一個)。檔案裡面所接受的設定格式可以參考這裡

實做 action 邏輯

這個 action 主要會利用 Github rest API 提供的功能來實做(基本上也就只要用到他們自家的 rest API 就能完成該 action 所需要的一切)。

以下就是這四個重要的 API:

流程非常簡單,也就三個步驟:

  • 抓出該 repo 所有的 branch(除了 protected branch & default branch)
  • 分別取得 branch 的最新 commit 時間
  • 時間已經超過一定時間再去看看是否不論有 commit ahead 都要砍掉。

給予 Action 權限

因為這個 Github action 會針對 repo 做操作,所以需要給予相對應的權限讓它做事,我們可以利用 Github 提供的 fine-grained token 給予它最低限度的權限來做事,因為這個 action 會有情境要砍 branch 所以需要給予 content 類型 read-write 權限。權限細節可以看這邊

關於測試

Ruddy 老師說過類似以下的話:「要相信雲端的程式,還是 Local 端的程式?都不是,應該要相信測試過的程式」

基本上只要是程式就能寫測試,測看看本身的業務邏輯的執行是否都符合我們的需求,商業邏輯部份我們可以用 jest 來幫助我們,就跟在一般的 Nodejs 專案中使用一樣。不過因為 Github action 最強大的是可以跟生態系裡眾多的 actions 搭配運作,偏偏這種事情若不放去正式環境就測試不了,但真的就沒有辦法提早知道了嘛?專案 act 為這個問題提出了解答。

這個工具可以讓你在本機測試已經寫好了 Github action 讓他實際跑跑看,這樣就不用每次都要在 UI 界面點來點去,然後還要把兩邊的異動都推上去才能看看是否成功,對於 action 點對點測試的簡化很有幫助。

在本機端測試你的 Github action

在使用 act 之前需要先確定你的本機有裝好 docker,畢竟他做的事情跟 aws-sam-cli 有點像,都是把 image 拉下來去跑你的 action,而且跟其他 container 的整合很爛,基本上只支援 docker,所以若你不是使用 docker (像是 podman )的話,就需要另外安裝好 docker,不然官方式不保證程式可以順利運作,可以參考官方的討論串

呼叫端如何使用

  1. 首先確保目標 Github action 有確實存在 Github 上面。

這邊的範例是:branch-cleaner-action

  1. 給目標 repo 一個 workflow YAML 檔案。因為接下來 act 要吃這個 YAML 檔案的設定去執行 action。

新增如下檔案,但不用 commit,可以讓你測到通過後再入版控,不需要花時間整理 commit。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# C:\your_path\your_repo\.github\workflows\cleaner.yml
cleaner:
  runs-on: ubuntu-latest
  permissions:
    contents: write
  steps:
    - name: Clean Branches
      uses: RiceBen/branch-cleaner-action@v1.0.0
      with:
        secToken: ${{ secrets.GITHUB_TOKEN }}
        protect-branch-name: |
          main
          master          
        expiry-period-in-days: 5
        is-force-delete: true

基本上 secToken 是一定要提供給 action 畢竟會需要依靠這個 token 來打 Github rest API,然後 permission 一定要給 contents 有讀寫權限。 protect-branch-name 這邊是 Optional 欄位,若沒有給東西的話,預設行為(無法調整)會將 repo 的 default branch 塞入(避免 default branch 沒有 protect 被誤砍)。

做好上述準備後就可以來執行 act 工具了。

  1. 開啟 Terminal 執行 act ,看著畫面中的 fedback 除錯。

以下就是我們測試時會用到的語法:

act -W {your-workflow-full-path} -j {job-name-in-workflow} -s GITHUB_TOKEN="{your-git-hub-token}"

若是在根目錄下只打 act 的話,預設行為會將該 repo 的 workflow 全部執行完。若只是想測試單一一個 job 或是 workflow 的話就可以像這樣做,可以讓測試情境簡化不少。 執行之後就可以看到相關的 log 或是 debug 資訊。

Reference