Git hooks to improve code quality (grumphp, phpcs, phpcpd and phpstan)

This article is part of series that we created to have a common knowledge/rule base among our IT teams

As an Atlassian explained in their tutorial:

Git hooks are scripts that run automatically every time a particular event occurs in a Git repository. They let you customize Git’s internal behavior and trigger customizable actions at key points in the development life cycle.

Git hooks are scripts that Git executes before or after events such as commit, push, and receive. Git hooks are a built-in feature — no need to download anything. Git hooks are run locally.

These hook scripts are only limited by a developer’s imagination. Some example hook scripts include:

  • pre-commit: Check the commit message for spelling errors.
  • pre-receive: Enforce project coding standards.
  • post-commit: Email/SMS team members of a new commit.
  • post-receive: Push the code to production.

Every git repository has a .git/hooks folder with a script for each hook you can bind to. You’re free to change or update these scripts as necessary, and Git will execute them when those events occur.

Calling Grumphp with a Git hook

Grumphp is a code quality tool that can be shared among developers. We’re going to set a Git pre-commit hook to grumPHP to inspect code quality before committing the code.

You first need to install grumphp in your machine via composer using the command:

composer require --dev phpro/grumphp

Grumphp comes shipped with a configuration tool. Run the following command to create a basic configuration file with PHP command line:

php ./vendor/bin/grumphp configure

Inside grumphp.ymlconfiguration file set the standard to PSR12 with phpcs:

parameters:
ascii:
failed: ~
succeeded: ~
tasks:
phplint: ~
behat: ~
phpunit: ~
phpcs:
standard:
- 'PSR12'

Now we can add the hook, to add a pre-commit hook with grumphp we the following command in PHP:

php ./vendor/bin/grumphp git:pre-commit

A new pre-commit file will be added to your .git/hooks directory. This hook will be called before every commit run. We can verify this configuration by adding a new commit with code violations, grumphp should stop the commit with an error message.

$ git commit -m "test grumpphp hook"
GrumPHP detected a pre-commit command.
GrumPHP is sniffing your code!
Running task 1/2: Phpcs ...
running task 2/2: Phpunit ...
FILE: /path/to/code/myfile.php
--------------------------------------------------------------------------------
FOUND 5 ERRORS AFFECTING 4 LINES
--------------------------------------------------------------------------------
2 | ERROR | [ ] Missing file doc comment
3 | ERROR | [x] TRUE, FALSE and NULL must be lowercase; expected "false" but
| | found "FALSE"
5 | ERROR | [x] Line indented incorrectly; expected at least 4 spaces, found 1
8 | ERROR | [ ] Missing function doc comment
8 | ERROR | [ ] Opening brace should be on a new line
--------------------------------------------------------------------------------
PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY
--------------------------------------------------------------------------------

Some marked sniffs can be automatically fixed with PHP code beautifier and fixed (phpcbf) by running the phpcbf on a specific file(s) or an entire repository.

$ phpcs /path/to/code/myfile.php

FILE: /path/to/code/myfile.php
--------------------------------------------------------------------------------
FOUND 5 ERRORS AFFECTING 4 LINES
--------------------------------------------------------------------------------
2 | ERROR | [ ] Missing file doc comment
3 | ERROR | [x] TRUE, FALSE and NULL must be lowercase; expected "false" but
| | found "FALSE"
5 | ERROR | [x] Line indented incorrectly; expected at least 4 spaces, found 1
8 | ERROR | [ ] Missing function doc comment
8 | ERROR | [ ] Opening brace should be on a new line
--------------------------------------------------------------------------------
PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY
--------------------------------------------------------------------------------

PHP scripts to detect violations

We mentioned that we configure grumphp to PSR12 standards and that was under the line of phpcs, let’s understand what phpcs and what are other PHP scripts that we can use to detect violations in the code.

PHPCS

Phpcs (PHP code sniffer) is one of the scripts offered by PHP_CodeSniffer (the second script is the phpcbf), phpcs job is to tokenized PHP, Javascript, and CSS files to detect violations of a defined coding standard.

You can install PHP_CodeSniffer in your project using composer via the command:

$ composer require "squizlabs/php_codesniffer=*"

You will have two scripts added to your project

/vendor/bin/phpcs
/vendor/bin/phpcbf

To run the sniffer directly on a directory or file you can simply run

$ ./vendor/bin/phpcs /path/to/code-directory

When phpcs is run via grumphp via the pre-commit hook it only analyzes the changed files within that commit.

PHPCPD

Another script that we can use to detect violation is the phpcpd (PHP copy/past detector), this task will sniff your code for duplicated lines. To add it to your project you can use composer via command:

composer require --dev sebastian/phpcpd

You also need to configure it under the grumphp.yml configuration file:

# grumphp.yml
grumphp:
tasks:
phpcpd:
directory: ['.']
exclude: ['vendor']
fuzzy: false
min_lines: 5
min_tokens: 70
triggered_by: ['php']

Remember to change the directory to the directory that you wish to sniff.

PHPStan

PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs even before you write tests for the code. It moves PHP closer to compiled languages in the sense that the correctness of each line of the code can be checked before you run the actual line. To add it to your project you can use composer via command:

composer require --dev phpstan/phpstan

You also need to configure it under the grumphp.yml configuration file:

# grumphp.yml
grumphp:
tasks:
phpstan:
autoload_file: ~
configuration: ~
level: null
force_patterns: []
ignore_patterns: []
triggered_by: ['php']
memory_limit: "-1"
use_grumphp_paths: true

To let PHPStan analyze your codebase, you have to use the analyse command and point it to the right directories. So, for example, if you have your classes in directories src and tests, you can run PHPStan like this:

$ vendor/bin/phpstan analyse src tests

With the pre-commit configuration, grumphp will automatically launch phpcs, phpcpd, and phpstan scripts. There is unlimited usage of Git hooks, here we presented some basics that we use in our Symfony projects.

Enjoy 🖖.

References:

Software Engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store