Byte Ebi's Logo

Byte Ebi 🍤

每天一小口,蝦米變鯨魚

使用 GrumPHP 做程式碼品質的守門員

檢查你的程式有沒有怪味道,在你犯錯前就制止你。一生只督你一人

Ray

多人一起開發的環境下,Code Review 是一件非常重要的事情
因為如果有人寫出一些不符合規則的程式,或是無法通過測試的程式時會造成專案出錯
而人工檢查語法或是手動執行測試耗時費力 no fashion,這種事情應該讓程式自動做
於是 GrumPHP 登場了

什麼是 GrumPHP

GrumPHP 是一個開源的 Composer 套件,藉由 git hook
當有人變更程式並且 commit 的時候,GrumPHP 將根據設定好的 tasks 去檢查程式內容
如果測試失敗,commit 會被中斷

並且 GrumPHP 內建了一組常見的任務,可以用最少的客製設定使用 GrumPHP
可以在官方文件中的 Tasks 頁面找到大部分你會用到的檢查任務
以下我們就分別從安裝到加入四個常用的任務來介紹

安裝 GrumPHP

一樣拿上次做一半的 LaraPeko 來做示範,以下說的「專案」指的都是這個套件包!

首先進入專案目錄下執行

composer require --dev phpro/grumphp

會跳出互動介面問你要不要建立設定檔grumphp.yml,然後給你一大堆選項
可以先隨便選一個,或是直接跳過
因為下一步要安裝的是yamllint,如果你在這邊選了 yamllint,下一步就沒事了

可以在專案根目錄執行指令來測試是否可以執行檢查

vendor/bin/grumphp run

若是執行

composer install

可以看到提示GrumPHP is sniffing your commits!代表 GrumPHP 已經在嗅探我們的 commit 了

grumphp composer install

加入檢查任務

這邊會逐步安裝並說明四個常用的基本檢查任務

  • yamllint
  • PHPLint
  • Phpunit
  • Phpcs

首先如果上一步沒建立grumphp.yml的話,在專案根目錄下建立檔案並建立內容

grumphp:
    tasks: {

    }

在官方 GitHub 上有一份範例的 grumphp.yml 設定檔
Parameters 文件 有參數的詳細說明和與設值介紹
在這邊為了減少設定上的步驟,我們都先用預設值就好

1. yamllint

檢查你專案中的 yaml 檔結構合法性,如果有 drone 或是其他需要使用 yaml 格式檔案配置的設定檔

根據文件中 YamlLint 我們不需要額外配置
只需要在 tasks 列表中加入 yamllint 即可

grumphp:
    tasks: {
        yamllint: null,
    }

2. PHPLint

檢查語法錯誤,多一個逗點之類會讓 IDE 有紅字的syntax error

照著官方文件的任務使用方法安裝:PHPLint
首先執行 composer 指令安裝依賴項目,因為這個檢查只有在測試環境需要被執行
所以只在測試環境require-dev中安裝

composer require --dev php-parallel-lint/php-parallel-lint

接著加入grumphp.yml中的任務

grumphp:
    tasks: {
        yamllint: null,
        phplint: ~,
    }

同樣的,在文件中有很多可以調整個規則
可以依照個人使用調整,而這邊我們依然使用預設值就好

3. Phpunit

指行指定路徑下的測試,如果失敗則視為任務失敗

照著官方文件的任務說明安裝在測試環境中:Phpunit

composer require --dev phpunit/phpunit

而文件中有說明,你必須建立phpunit.xml作為任務的設定檔
底下範例指定了測試檔案的資料夾目錄

  • Unit:./tests/Unit
  • Feature:./tests/Feature

如果缺少這個檔案,預設會是 null,執行下去會報錯
如果你的對應資料夾沒建立,在執行檢查的時候也會視為錯誤,記得要在專案中建立對應資料夾

phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true">
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>

        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
</phpunit>

來測試一下任務是否有執行上次套件包中的測試吧!
因為配合 phpunit.xml 的設定,所以把上次寫在 tests 資料夾內的測試搬到 tests/unit 內
執行指令vendor/bin/grumphp run可以看到通過的綠色的開心老頭

phpunit pass

若我們修改測試方法,讓測試無法通過

public function testGetAhoy()
{
    $larapeko = new LaraPeko();
    $this->assertEquals('ahoy', 'DD');
}

接著再一次執行指令便會看到一個生氣的紅色老頭,以及其錯誤訊息
透過提示訊息,我們可以清楚的知道是哪個測試沒有通過

phpunit fail phpunit fail

4. Phpcs

這個任務,可以檢查提交的 PHP 內容是不是符合 PSR 規則

首先安裝相關套件,參考:Phpcs 任務文件

composer require --dev squizlabs/php_codesniffer

接著一樣是需要建立配置文件phpcs.xml來設定我們需要檢查的規則,這邊以基本的 PSR-12 為例
可以看到我們設定了 PSR12 的檢查規則

<?xml version="1.0"?>
<ruleset name="PSR12">
    <description>The PSR12 coding standard.</description>
    <rule ref="PSR12"/>
    <file>app/</file>
    <file>config/</file>
    <file>routes/</file>
    <exclude-pattern>public/index.php</exclude-pattern>
    <exclude-pattern>server.php</exclude-pattern>
    <exclude-pattern>laravel-nova-*</exclude-pattern>
    <exclude-pattern>vendor</exclude-pattern>
    <exclude-pattern>resources</exclude-pattern>
    <exclude-pattern>database/</exclude-pattern>
    <exclude-pattern>storage/</exclude-pattern>
    <exclude-pattern>node_modules/</exclude-pattern>
    <exclude-pattern>tests</exclude-pattern>
</ruleset>

既然設定好了就執行看看吧

vendor/bin/grumphp run

phpcs pass

可以看到我們設定的測試都有通過了

那如果有一些不符合 PSR12 規則的東西會發生什麼事情呢?
為了測試,我們隨便找一段 PHP 程式,在分號後面再加一個分號
這麼做並不會觸發先前安裝的 phplint 檢查,因為這不屬於語法錯誤,但這麼做不符合 PSR12 規則

phpcs fail

於是我們又看到了生氣的老頭,指出哪裡有問題

自動監聽

以上都是我們手動執行套件的任務來測試程式碼的品質,好還要更好
最好可以讓程式自動執行測試,也就是一開頭我們說過的在 commit 時自動觸發 GrumPHP 的 tasks

這件事情想起來難,做起來倒是一點就通
透過修改專案的composer.json我們可以加入指令,參考 composer 官方文件
我們可以透過加入scripts區塊,讓指令在 composer 執行過程中被執行

在專案的composer.json中加入指令,在初始時就就開始嗅探

    "scripts": {
        "post-install-cmd": [
            "@php ./vendor/bin/grumphp git:init"
        ]
    },

這樣不論是在 CLI 執行git commit或是使用 GUI 操作,都可以在 commit 前觸發我們定義的 tasks
如下圖就是使用 GUI 觸發 phpcs 這個任務的失敗狀態跳出的訊息

grumphp gui fail

最新文章

Category

Tag