HomeDrupalEnforcing Coding Standards with Git, PHPLint, and Drupal Code Sniffer

Enforcing Coding Standards with Git, PHPLint, and Drupal Code Sniffer

For a Drupal developer, there are several ways that you can use git hooks to speed up and improve your commits. This article will demonstrate three different pre-commit hooks that you can add to your git repository.

The first pre-commit hook uses PHPLint which will validate your PHP code looking for syntax errors and other things. It only runs the check on any files that have changed in the current commit. If validation fails, it will prevent the commit from completing until you fix it.

The second pre-commit hook will sniff your Drupal code for cases where your code doesn’t match Drupal Coding Standards. There are two types of messages that will be returned by the sniff: errors and warnings. By default, it will abort the commit if there are any errors. Warning messages will be displayed, but they won’t prevent the commit from going through. This can be easily modified to always allow the commit to go through by making $exit_code always equal 0.

The third pre-commit hook checks if you added any debugging code by accident. If it finds any debugging code, such as dpm, it will return an error and prevent the commit from completing. This hook specifically only checks lines that were added or modified in the current commit.

All of the pre-commit hooks will ignore changes made within the docroot folder and any files that are features related (since it’s auto generated by features). They also only check files with certain extensions. It is very simple to customize each hook to fit the structure of your codebase, which will be explained later. First, we need to make sure Composer and Coder are installed.

Install Composer

Check if you have composer enabled on your computer by opening your terminal and typing in ‘composer’.

If you have composer, skip this step. If you get a result that composer was not found, then run the following commands:

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('SHA384', 'composer-setup.php') === 'e115a8dc7871f15d853148a7fbac7da27d6c0030b848d9b3dc09e2a0388afed865e6a3d6b3c0fad45c48e2b5fc1196ae') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
mv composer.phar /usr/local/bin/composer

Install Coder

Now it’s time to install the coder module. Run in your terminal:

composer global require drupal/coder

This will install the Drupal Coder module in ~/.composer/vendor/drupal/coder.

Update PATH

Now you are going to need to update your path. Open your shell startup script (most likely ~/.bashrc or ~/.zshrc) in your favorite editor and add the following line to the file:

export PATH="$PATH:$HOME/.composer/vendor/bin"

To apply the changes to your current terminal section type the following in your terminal:

source ~/.zshrc (or source ~/.bashrc)

Register the Drupal and DrupalPractice Standards

Run the following in your terminal:

phpcs --config-set installed_paths ~/.composer/vendor/drupal/coder/coder_sniffer

If you are going to want to run phpcs on it’s own and want Drupal to be set as the default standard, then run the following command:

phpcs --config-set default_standard Drupal

Other potentially useful phpcs configuration settings can be seen here. If you want to see what php configuration settings are currently, you can run:

phpcs --config-show

Create Global Git Hooks

Do the following to set up a git-templates location and make sure the folder exists:

git config --global init.templatedir '~/.git-templates'
mkdir -p ~/.git-templates/hooks

Now we need to copy the hooks into ~/.git-templates/hooks. If you only want to use the hooks on specific projects then you can copy it to <projectdir>/.git/hooks instead.

Download the pre-commit hooks here and download them to ~/.git-templates/hooks. The first file is required, but you can choose to omit either the lint or phpcs files. Make the files executable:

chmod a+x ~/.git-templates/hooks/*

Add the hooks to your Git repos

Any new repos that you clone or init will automatically have these hooks copied over.

Any existing repos that you want these hooks added to, you can run ‘git init’ inside the repo directory and it will copy them over (assuming existing hooks don’t already exist – it won’t overwrite them). If you want to overwrite hooks that already exist in the repo, then you can copy this script and execute it from within the git repo directory. That script will remove any existing hooks in the .git/hooks directory, then run ‘git init’ which will copy hooks from ~/.git-templates/hooks.

Customizing the pre-commit hooks

All of the pre-commit hooks have a similar structure and can be modified as to which files to check.

First, there is the $file_exts array that specifies which types of files will be checked. If you don’t want to check ‘.class’ files, simply remove that entry from the array. Additionally, if there is a file extension that you want to check that isn’t included in the array, simply add that extension to the array. You don’t need to include the ‘.’ with the extension name, just the name itself.

Another array, $ignore_filename_strings, specifies strings within the filename that will be ignored. The string doesn’t have to match the entire filename to ignore the file, just any part of the filename. I set this up to specifically ignore features related files since those files are auto-generated and may fail coding standard tests, but you can’t do anything to fix them if they do. If you notice certain files being checked in your commits that you don’t want to be checked, you can add them here.

The third array, $ignore_file_path_strings, specifies entire directories to ignore. It is setup to ignore docroot and contrib folders so core and contrib modules don’t get checked by the hook. If your git repo is structured differently, you may need to change the directory names.

One additional array that is only in the debugging pre-commit hook is $debugging_searches. This specifies what debugging code to search for and prevent from being committed. I’ve included the standard devel debugging functions along with a few others. If there are other functions or debugging code that you don’t ever want committed, then you can add it to this array.

Acknowledgements

The inspiration for these git hooks started with this sandbox project. That project runs phpcs in a pre-commit hook. I just expanded on the customizability of that hook, and also added the PHPLint and debugging hooks as well.