
最近研究了一下用 Github Actions 做 Rails 的 CI ,分享一下經驗 : )
Github Actions 是 Github 的自動化工具。
Github Actions 只要在你的專案根目錄新增.github/workflows
,再新增任意名稱的 Yaml 檔。
Git push 到 Github 後,即會根據你寫的 workflow 的內容自動執行了。
可以直接看下面分享的 YAML 檔,不過建議還是先看一下 Github Action 的文檔Introduction to GitHub Actions - GitHub Docs ,會比較有概念喔(常常更新的也滿快的)
先分享.github/workflows/ci.yml
,後面會再說明每一列是代表什麼意思
name:CIon:[push,pull_request]jobs:build:runs-on:ubuntu-lateststeps:-uses:actions/checkout@v1-name:Setup Rubyuses:ruby/setup-ruby@v1with:ruby-version:2.7.2bundler-cache:true-name:Install Nodeuses:actions/setup-node@v2with:node-version:'12.16.x'-name:Restore cached ./node_modulesuses:actions/cache@v2with:path:./node_moduleskey:${{ runner.os }}-yarn-lock-${{ hashFiles('./yarn.lock') }}restore-keys:|${{ runner.os }}-yarn-lock--name:Yarn Installrun:yarn installtest:needs:buildruns-on:ubuntu-latestservices:mysql:image:mysql:8ports:['3306:3306']env:MYSQL_ROOT_PASSWORD:'my-root-pw'MYSQL_DATABASE:test_dbMYSQL_USER:username_you_likeMYSQL_PASSWORD:password_you_likeoptions:--health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3redis:image:redisports:['6379:6379']options:--entrypoint redis-serversteps:-uses:actions/checkout@v1-name:Setup Rubyuses:ruby/setup-ruby@v1with:ruby-version:2.7.2bundler-cache:true-name:Install Nodeuses:actions/setup-node@v2with:node-version:'12.16.x'-name:Restore cached ./node_modulesuses:actions/cache@v2with:path:./node_moduleskey:${{ runner.os }}-yarn-lock-${{ hashFiles('./yarn.lock') }}restore-keys:|${{ runner.os }}-yarn-lock--name:Yarn Installrun:yarn install-name:Prepare Databaseenv:RAILS_ENV:testRAILS_MASTER_KEY:${{ secrets.RAILS_MASTER_KEY }}run:bundle exec rails db:prepare-name:Run testsenv:REDIS_URL:redis://localhost:6379/1RAILS_ENV:testRAILS_MASTER_KEY:${{ secrets.RAILS_MASTER_KEY }}run:|bundle exec rspec --format RspecJunitFormatter --out ./reports/rspec.xml-name:Publish Test Reportuses:mikepenz/action-junit-report@v2with:report_paths:'./reports/rspec.xml'
說明版
# 此 workflow 的名稱,可任意取,到時會出現在 Github Actions 中name:CI# on 是控制何時要執行這個 workflow# * push: 有 commit push 時# * pull_request: PR 更新時on:[push,pull_request]# 一個 workflow 可以有很多jobs 組成,它們通常是同時(平行)執行的,#不過可以設定先後順序,下面一點會提到。#job 的名稱可任意取名,我這裡叫它 build# `runs-on` 是 job 要在什麼 OS 上執行, github 上的 Github Actions 好像得用 ubuntu-latest,我也是照教學沿用了jobs:build:runs-on:ubuntu-latest# `step` 是 Github Actions 的最小單位# steps 裡每個 step 可以執行一或多個指令或一個 Action# 要執行指令,則使用 `run`# `run: echo "hello world!"`# 要執行 Action,用 `uses`# `uses: actions的名字`# 每個 step 的 name 並不是必填,但填了就像註解一樣,方便理解steps:# Action 其實就預先寫好的腳本# GitHub Marketplace 上有一堆,可以想像是想把自動化的腳本當成在 App Store 上賣# [GitHub Marketplace · Actions to improve your workflow · GitHub](https://github.com/marketplace?type=actions)#`actions/checkout@v1` 就是一個常用的 Action,可以把你的 git repository 下載下來-uses:actions/checkout@v1# ruby/setup-ruby@v1 是用來安裝 Ruby 的 Action# 下載的 ruby-version: 2.7.2 是要裝 2.7.2 的 Ruby# bundler-cache: true 是要快取 bundler 下載的 gem,下面再說明快取# 基本上這些 Action 都可以在 Github Marketplace 上查到用法# [Setup Ruby, JRuby and TruffleRuby · Actions · GitHub Marketplace · GitHub](https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby)-name:Setup Rubyuses:ruby/setup-ruby@v1with:ruby-version:2.7.2bundler-cache:true# 同上,安裝 Node-name:Install Nodeuses:actions/setup-node@v2with:node-version:'12.16.x'# `actions/cache@v2` 是專門來做快取的 Action# 這裡寫 path: ./node_modules 就是要把 ./node_modules 下的檔案全 cache 起來# 快取的結果會用 key 的設定去命名。# 這個 action 會先依照 restore-keys 去找可以回復的快取# 最後的 step 純粹就是跑 yarn install# 如果光看這個 順序應該有人會疑惑:# 快取的 action 是放在 yarn install 前,或更上方 ruby 的部分有 bundle install 前,# 在安裝依賴前,先「讀取」快取好理解,# 但重要的是「存」快取的時機怎麼沒看到?# 執行一次就知道,這類快取的 Action 都有掛個動作在 PostJob 的 callback,# 當這個 job 結束後會把該快取的 path 存起來# 另外,每個倉庫有 5GB 的快取空間,正常來說應該是用不完啦。# 所以 gems, npm 這種安裝的程式庫都把它們快取起來吧-name:Restore cached ./node_modulesuses:actions/cache@v2with:path:./node_moduleskey:${{ runner.os }}-yarn-lock-${{ hashFiles('./yarn.lock') }}restore-keys:|${{ runner.os }}-yarn-lock--name:Yarn Installrun:yarn install# 這是第二個 job ,我命名為 test,因為準備要跑 rspec 了# 上面說 job 其實是平行執行的,`needs` 可以控制先後順序,needs: build 的意思就是 build 跑完才會跑 test# 雖然以目前這個 workflow 來看,其實可以把steps 全寫在同一個 job ,沒什麼差別。# 但寫成這樣,可以方便未來加入不同類的 test,比如 js 的 test, capybara 的 test,可以在 build 後,所有的 test 同時執行。test:needs:buildruns-on:ubuntu-latest# `services` 可以用 docker image 架起需要用的服務,設定好 port mapping# 我這裡架了 mysql 和 redis# 那些 env 是去 DockerHub 上去找官方的 image 的說明才知道有什麼可以加的# 順帶一提,CI 時 `config/database.yml` 可以兩種處理方式# * 直接加入 git,內容再用 ENV 去替換# * 新增一個 database.yml.ci ,在 workflow 裡加一個 step 去 `run: cp config/database.yml.ci config/database.yml`services:mysql:image:mysql:8ports:['3306:3306']env:MYSQL_ROOT_PASSWORD:'my-root-pw'MYSQL_DATABASE:test_dbMYSQL_USER:test_userMYSQL_PASSWORD:test_pwoptions:--health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3redis:image:redisports:['6379:6379']options:--entrypoint redis-server# 下面這段到 yarn install 跟 build 是做完全一模一樣的事,執行時會直接取 build 快取的結果,所以很快就會跑完。# 看起來很冗,不過如果未來可以用 YAML 的 Anchor 功能,這一塊可以直接寫成一個可複用的 block,# 目前就直接重複吧!steps:-uses:actions/checkout@v1-name:Setup Rubyuses:ruby/setup-ruby@v1with:ruby-version:2.7.2bundler-cache:true-name:Install Nodeuses:actions/setup-node@v2with:node-version:'12.16.x'-name:Restore cached ./node_modulesuses:actions/cache@v2with:path:./node_moduleskey:${{ runner.os }}-yarn-lock-${{ hashFiles('./yarn.lock') }}restore-keys:|${{ runner.os }}-yarn-lock--name:Yarn Installrun:yarn install# 如果要開始跑 rails 的指令時,要帶一些`環境變數`時,例如我這樣會用 RAILS_ENV 跟 RAILS_MASTER_KEY# 是密碼類的字串可以存在Github倉庫 >Settings>Secrets 裡,workflow 裡可以直接 `${{ secrets.RAILS_MASTER_KEY }}` 去讀取-name:Prepare Databaseenv:RAILS_ENV:testRAILS_MASTER_KEY:${{ secrets.RAILS_MASTER_KEY }}run:bundle exec rails db:prepare# 這邊是跑 rspec# 有裝 rspec_junit-formatter ,所以可以產生一個 XML 檔紀錄測試結果-name:Run testsenv:REDIS_URL:redis://localhost:6379/1RAILS_ENV:testRAILS_MASTER_KEY:${{ secrets.RAILS_MASTER_KEY }}run:bundle exec rspec --format RspecJunitFormatter --out ./reports/rspec.xml-name:Publish Test Reportuses:mikepenz/action-junit-report@v2with:report_paths:'./reports/rspec.xml'
最後用mikepenz/action-junit-report@v2
去讀取 XML 的測試結果並秀出在頁面上
心得
我覺得自動化最煩的就是一堆小細節要顧,
比如說也可以完全不快取硬讓它跑,但就會很慢。
像 CircleCI 的orb
就是把每個語言、框架常用的自動化指令整理起來變成一組指令集。
但 Github Actions 直接更進一步讓社群製作指令集,並準備好市集,方便搜尋跟分享,野心勃勃要幹掉其它 CI。
整體上還滿容易用,連 Rails 都能輕易導入(回想一下把 Rails 裝進 Docker 的夜晚),滿推薦試試看的。
而且Github(微軟)滿佛的,每個月給2000小時,個人練習或小型專案應該是用不完啦,可以去帳號 Billing & Plans 下查用量。
參考資料
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse