A proper Git pre-commit hook for PHP-CS-Fixer

Hello,

I was getting tired of all the example pre-commit git hooks to execute php-cs-fixer. So I took a few minutes to write a small, generic pre-commit hook for PHP based executables. Though with some small modifications you could use this for other kinds of executables as well.

I'll explain what I did. First, as probably most if not all bash scripts, I started with what's called a shebang line.

#!/usr/bin/env bash

Next up, define some variables so we can easily edit this script to work for other hooks you want to define as well. This part of the script is up to you to change as needed.

EXECUTABLE_NAME=php-cs-fixer  
EXECUTABLE_COMMAND=fix

CONFIG_FILE=.php_cs  
CONFIG_FILE_PARAMETER='--config-file'

ROOT=`pwd`  

Now we'll define some locations where our executable might possibly hide. These are ordered by priority. If the executable is found in the first location, the script will use this and not look for the other locations.

# possible locations ordered by priority
locations=(  
  $ROOT/bin/$EXECUTABLE_NAME
  $ROOT/vendor/bin/$EXECUTABLE_NAME
  `which $EXECUTABLE_NAME`
)

This is where all generic stuff starts. You should not have to edit anything after this line. This will iterate over all possible locations and set the EXECUTABLE variable to the location a valid executable was found.

for location in ${locations[*]}  
do  
  if [[ -x $location ]]; then
    EXECUTABLE=$location
    break
  fi
done  

If no executable is found, it'll exit with some message. As explained in the echo statement; if no executable can be found, and you're sure it's there, make sure it's executable. If it's not executable, chmod it (e.g. chmod +x bin/php-cs-fixer). If the executable is found, the script will echo which one of the locations it's using, and display the version message.

if [[ ! -x $EXECUTABLE ]]; then  
  echo "executable $EXECUTABLE_NAME not found, exiting..."
  echo "if you're sure this is incorrect, make sure they're executable (chmod +x)"
  exit
fi

echo "using \"$EXECUTABLE_NAME\" located at $EXECUTABLE"  
$EXECUTABLE --version

Now we'll try to find a config file in the defined location. If it's found, it'll set a variable for it.

if [[ -f $ROOT/$CONFIG_FILE ]]; then  
  CONFIG=$ROOT/$CONFIG_FILE
  echo "config file located at $CONFIG loaded"
fi  

The git status line is ripped from some other script, so excuse me to whoever wrote it exactly this way. The git status line will show all modified files, pipe it through some filtering, and read it in a while statement setting the location of the modified file to the $line variable. Now it'll execute the command defined at the top of this script, with or without config depending on whether a config file was found. Finally it'll add the file back to git, which will then actually commit it.

git status --porcelain | grep -e '^[AM]\(.*\).php$' | cut -c 3- | while read line; do  
  if [[ -f $CONFIG ]]; then
    $EXECUTABLE $EXECUTABLE_COMMAND $CONFIG_FILE_PARAMETER=$CONFIG $line;
  else
    $EXECUTABLE $EXECUTABLE_COMMAND $line;
  fi

  git add $line;
done  

Want to use what I wrote? These two commands will get you up and running with this script, with php-cs-fixer pre-defined in it.

$ wget https://gist.githubusercontent.com/YP28/527415377bbaa212467088f85b752136/raw/pre-commit -O .git/hooks/pre-commit
$ chmod +x .git/hooks/pre-commit

The full script can be found on Github Gist.

Yordi Pauptit

Read more posts by this author.

Subscribe to Yordi Pauptit

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!