Guarding Code Quality with GrumPHP
Check if your code smells before you make a mistake.
In a collaborative development environment, Code Review is a crucial process.
If someone writes code that violates rules or fails tests, it can lead to project errors.
Manual syntax checks or running tests manually are time-consuming and not fashionable.
These tasks should be automated, and that’s where GrumPHP
comes in.
What is GrumPHP
GrumPHP is an open-source Composer package that utilizes git hooks.
When someone changes the code and commits it, GrumPHP checks the code content based on predefined tasks.
If the tests fail, the commit is aborted.
GrumPHP comes with a set of common tasks built-in, allowing you to use it with minimal custom configuration.
You can find most of the tasks you might need on the Tasks
page in the official documentation.
Let’s go through the installation process and add four commonly used tasks.
Installing GrumPHP
Let’s use the partially developed LaraPeko package as an example.
The term “project” mentioned here refers to this package.
First, navigate to the project directory and execute:
composer require --dev phpro/grumphp
An interactive prompt will appear, asking if you want to create the configuration file grumphp.yml
with various options.
You can choose any option or skip this step. The next step involves installing yamllint
.
If you chose yamllint in the previous step, you’re good to go.
You can test if the checks are working by running:
vendor/bin/grumphp run
If you run:
composer install
and see the message “GrumPHP is sniffing your commits!” it means GrumPHP is now sniffing your commits.
Adding Check Tasks
Let’s gradually install and explain four basic check tasks:
- yamllint
- PHPLint
- Phpunit
- Phpcs
If you didn’t create grumphp.yml
in the previous step, create the file in the project root directory with the following content:
grumphp:
tasks: {
}
You can find an example grumphp.yml
configuration file on the official GitHub page, and the Parameters file
provides detailed explanations and settings.
1. yamllint
Checks the validity of the yaml file structure in your project, useful for configuration files in formats such as Drone.
According to the YamlLint documentation
, no additional configuration is required.
Just add yamllint to the tasks list in grumphp.yml
:
grumphp:
tasks: {
yamllint: null,
}
2. PHPLint
Checks for syntax errors, such as missing commas that might result in red syntax error warnings in IDEs.
Follow the official documentation for the PHPLint task: PHPLint
.
Start by installing the required dependency only in the test environment:
composer require --dev php-parallel-lint/php-parallel-lint
Add the phplint task to grumphp.yml
:
grumphp:
tasks: {
yamllint: null,
phplint: ~,
}
Refer to the documentation for many adjustable rules. For simplicity, we’ll stick with the default values.
3. Phpunit
Runs tests in a specified path. Fails the task if any tests fail.
Follow the documentation for the Phpunit task: Phpunit . Install Phpunit in the test environment:
composer require --dev phpunit/phpunit
Create the phpunit.xml
configuration file as required:
<?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>
Test if the tasks are executed by running the following command.
Since we configured Phpunit to look for tests in specific folders, ensure those folders exist in the project.
vendor/bin/grumphp run
You should see a green happy face indicating that the tests passed.
If we modify a test method to make it fail:
public function testGetAhoy()
{
$larapeko = new LaraPeko();
$this->assertEquals('ahoy', 'DD');
}
And run the command again, you will see a red sad face along with an error message, making it clear which test failed.
4. Phpcs
Checks if the submitted PHP code adheres to PSR standards .
Install the required dependency following the Phpcs task documentation: Phpcs .
composer require --dev squizlabs/php_codesniffer
Create a phpcs.xml
configuration file to set the rules you want to check. Here, we use the basic PSR-12 rules:
<?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>
Now, run the check:
vendor/bin/grumphp run
You should see that all configured tests have passed.
If there are issues violating PSR-12, you will see a frowning face and details about the problems.
Automatic Listening
All the tasks we did above were manual executions. It would be better if the code quality check happens automatically.
To achieve this, we can modify the composer.json
file by adding scripts that run during the Composer process.
Add the following script to the composer.json
file to initialize GrumPHP during the post-installation command:
"scripts": {
"post-install-cmd": [
"@php ./vendor/bin/grumphp git:init"
]
},
This way, whether you run git commit
in the command line or perform the commit through a GUI, the defined GrumPHP tasks will be triggered before the commit.
Below is an example of a failure status message triggered by the phpcs task through a GUI.