2017年9月10日 星期日

在 Gitlab CI 查看測試覆蓋率(Coverage)與報告 (使用 PHPUnit)

幾年前,在不知道 Gitlab CI 的時期
都是自架 Jenkins 進行測試,產覆蓋率報告
雖然要處理一堆設定,還要裝一堆套件
不過客製化上比較方便

後來學長開始試用 Gitlab CI 後,發現比 Jenkins 好設定許多
主要是寫一個 .gitlab-ci.yml 設定

雖然方便,也能進版控,但是也缺了一些功能,像是線上查閱各種報告之類的
感覺也很難根據自己的需求客製化



幾年後,開始寫自己的網站,一時起意,想說再來研究看看能不能弄出覆蓋率報告
好增加自己寫測試的誘因 (明明就是藉口)



接下來有兩個目標

1. 讓 Gitlab Project 顯示覆蓋率的 Badge
    像這樣:coverage report



2. 可以直接在 Gitlab 上查閱覆蓋率報告 (使用 Gitlab Pages)
    https://hackersir.gitlab.io/VSDK/



不過本文的示範有幾個限制:

1. 必須使用 Gitlab CI
2. 使用 PHPUnit 作為示範,其他語言可能要自己摸索

提示:Gitlab Pages 無法設定存取權限,所以私有專案要小心覆蓋率報告會外洩程式碼



這邊我們使用 VSDK (https://gitlab.com/HackerSir/VSDK) 這個專案作為示範
這是當初為學生會開發的開票直播平台
使用 Laravel framework 5.2

目前只會跑 PHPUnit
而且只會產出文字版的覆蓋率簡易報告,輸出在 Console

在這個專案底下,有一個檔案叫 .gitlab-ci.yml ,這是給 Gitlab CI 使用的
Gitlab CI 會根據這個檔案進行動作
以下是檔案的內容

before_script:
  # Project
  - composer install --prefer-dist --no-ansi --no-interaction --no-progress --no-scripts --no-suggest
  - cp .env.example .env
  - php artisan key:generate
  - php artisan config:clear
  - php artisan migrate:refresh --seed

after_script:
  # PHP Code Sniffier
  - ./vendor/bin/phpcs --config-set ignore_errors_on_exit 1
  - ./vendor/bin/phpcs --config-set ignore_warnings_on_exit 1
  - ./vendor/bin/phpcs --standard=style_ruleset.xml app

variables:
  # MySQL Service
  MYSQL_DATABASE: FCU_OIA
  MYSQL_ROOT_PASSWORD: root_password
  MYSQL_USER: db_user
  MYSQL_PASSWORD: secret
  # Connection Settings
  DB_DATABASE: FCU_OIA
  DB_USERNAME: db_user
  DB_PASSWORD: secret
  # Other settings for testing
  CACHE_DRIVER: array
  SESSION_DRIVER: array

phpunit:php7.0:mysql5.6:
  image: edbizarro/gitlab-ci-pipeline-php:7.0
  services:
    - mysql:5.6
  variables:
    DB_CONNECTION: mysql
    DB_HOST: mysql
    DB_PORT: '3306'
  script:
    - ./vendor/phpunit/phpunit/phpunit -v --coverage-text --stderr

phpunit:php7.0:mysql5.7:
  image: edbizarro/gitlab-ci-pipeline-php:7.0
  services:
    - mysql:5.7
  variables:
    DB_CONNECTION: mysql
    DB_HOST: mysql
    DB_PORT: '3306'
  script:
    - ./vendor/phpunit/phpunit/phpunit -v --coverage-text --stderr

先來簡單介紹一下
首先看到縮排最左邊的五行:
1. before_script: 在每一個 Job 之前執行的 script
2. after_script: 在每一個 Job 之後執行的 script
3. variables: 定義變數
4. phpunit:php7.0:mysql5.6: Job Name
5. phpunit:php7.0:mysql5.7: Job Name

可以看到,兩個 Job 使用不同版本的 mysql server,而每一個 Job 的 script 都會執行 phpunit
而 before_script 是網站的安裝步驟,像是 composer、php artisan migrate
而 after_script 則是對程式碼做靜態分析

(.gitlab-ci.yml詳細文件可以參考:https://docs.gitlab.com/ce/ci/yaml/README.html)



基本上只要有 .gitlab-ci.yml ,Gitlab 就會為每次 push 跑一次 CI
(預設應該會用共用的 Gitlab CI Runner,每個月有額度上限)
(當然有可以自己架一台,就不用排隊等機器)
(Plan 可以參考:https://about.gitlab.com/gitlab-com/)

那要到哪邊看執行結果,可以到專案的 Pipelines


點擊左邊的「passed」,或是 Pipeline 編號,可以看到更詳細的資料
之後在點 Job 可以看到 Coverage,不過是空的




OK,首先我們先讓 Gitlab 抓到覆蓋率是多少
之前提到,目前只會顯示在 Console 上,如果你點進 Job 的詳細資料
應該可以看到這樣 (可能需要點圖放大)


看一下白框倒數幾行,可以看到有一行是  Lines: 0.30% (9/3021)
可以得知覆蓋率是 0.30% (覆蓋率非常低,我知道)

確定 PHPUnit 會產出覆蓋率之後
接著到專案的 Settings > Pipelines


往下拉,找到如下圖的設定:
讓 Gitlab 去從 Console 找出覆蓋率是多少
這邊剛好有提供 PHPUnit 的範例
先將 「^\s*Lines:\s*\d+.\d+\%」填到上方的 Regular expression
按下 Save changes 存檔



接著修改 .gitlab-ci.yml 檔



「- ./vendor/phpunit/phpunit/phpunit -v --coverage-text --stderr」

修改成

「- ./vendor/phpunit/phpunit/phpunit -v --coverage-text --colors=never --stderr」

主要是要有 --coverage-text 以及 --colors=never

--coverage-text 是要輸出覆蓋率的資訊,原本我們就有加

--colors=never 是要關閉顏色輸出,顏色的控制字元會讓 Gitlab 抓不到,不然就是要修改剛剛的 Regular expression

記得有用到的地方都要改,以本文的例子是兩個都要改


完成後,commit & push 到 gitlab 上
等待 Job 跑完後,可以看到 Gitlab 已經抓出覆蓋率了

接下來,我們要在 Readme 上顯示覆蓋率的 badge
一樣到專案的 Settings > Pipelines
往下拉,找到如下圖的地方
複製你需要的 Code 到 Readme (本例是 Markdown)
完成後,回到 Project 頁,Readme 會出現 coverage badge




接著,下一個目標是要能夠在 Gitlab 上查閱詳細的覆蓋率報告
(註:這邊只使用在一個 Job 上,多Job 可能需要研究)

首先,先讓 PHPUnit 產出 html 報告

修改 .gitlab-ci.yml
橘色的部分是新增的部分

phpunit:php7.0:mysql5.7:
  image: edbizarro/gitlab-ci-pipeline-php:7.0
  services:
    - mysql:5.7
  variables:
    DB_CONNECTION: mysql
    DB_HOST: mysql
    DB_PORT: '3306'
  script:
    - ./vendor/phpunit/phpunit/phpunit -v --coverage-text --colors=never --coverage-html=coverage --stderr
  artifacts:
    paths:
      - coverage/


--coverage-html=coverage 是讓 PHPunit 輸出 html 版的報告到 coverage 資料夾

artifacts:
    paths:
      - coverage/

這段是讓 Gitlab CI 將 coverage 資料夾進行打包
commit & push 到 Gitlab 上,讓 CI 開始工作

完成後,可以看到右邊多了下載按鈕
可以把報告整個下載下來



或是到 Job 的 console 輸出
右邊也可以下載或瀏覽(Browse)



不過瀏覽(Browse)似乎只能列出檔案清單
沒辦法直接瀏覽,等等要來解決這個問題




為了能夠直接瀏覽報告,我們需要將內容發佈到 Gitlab Pages

提示:Gitlab Pages 無法設定存取權限,所以私有專案要小心覆蓋率報告會外洩程式碼

修改 .gitlab-ci.yml
在檔案最後新增一個 Job:
      
pages:
  stage: deploy
  dependencies:
    - phpunit:php7.0:mysql5.7
  before_script:
    - echo "before_script"
  script:
    - rm -r public
    - mv coverage/ public/
  after_script:
    - echo "after_script"
  artifacts:
    paths:
      - public
    expire_in: 30 days


這邊要注意的是,Job 名稱一定要是 pages
dependencies是設定此工作要等 phpunit:php7.0:mysql5.7 完成

另外 before_script 和 after_script 是要複寫全域的 before_script 和 after_script
(應該會有更好的做法.....,畢竟才剛開始用 Gitlab CI)

script 要做的工作是把 coverage 重新命名成 public
因為 Gitlab Pages 預設是抓取 public 資料夾
不過在 laravel 專案中已經有 public 資料夾了
所以我們先用 「rm -r public」移除 public 資料夾

最後再打包 public 資料夾

編輯後,commit & push 到 Gitlab 上,讓 CI 開始工作

Job 完成後


前往專案的 Gitlab Pages
(本例是:https://hackersir.gitlab.io/VSDK/)
(Group 或 Username + gitlab.io /專案名稱 )

這樣就可以線上看報告了 ^_^



參考資料:
https://about.gitlab.com/2016/11/03/publish-code-coverage-report-with-gitlab-pages/



1 則留言: