Call us Toll-Free:
Email us


Mercurial Hook: PHP Syntax Check

Mike Peters, 06-15-2010
In a previous post, we wrote about PHP real time syntax checking. A method to send email alerts when any critical scripts on your live servers fail to pass PHP syntax validation.

The problem with this approach is that it alerts you of a problem after-the-fact.

Someone uploads a bad PHP script which breaks a critical module, you are alerted, but by that time users are already affected.

Today we'll take it this concept one step further by writing a hook for the Mercurial version control system, preventing developers from checking-in scripts that don't pass syntax-checking.

Installing PHP Syntax Check Mercurial hook

Step 1: The shell script

Save this shell script under your Mercurial folder, calling it:

# create a random temp file
temp_file=`/usr/bin/mktemp -t php_syntax_files`

# get all modified files and remove duplicate's
#note: use file_mods,file_adds instead
hg log -r $HG_NODE:tip --template "{files}\n" | sort | uniq > $temp_file

# Walk through each line
#for line in "$temp_file"; do
for line in $(< $temp_file); do
# Make sure it is a php file
if [ `echo $line | grep -E "\.(php)|(php4)|(php5)$"` ]
# create a random temp file
php_file=`/usr/bin/mktemp -t php_syntax_check`

# save the contents of this file (latest commit) to the temp file
hg cat -r tip $line > $php_file

# check the syntax
php_syntax_output=`/usr/local/bin/php-cgi -l -d display_errors=1 -d error_reporting=4 -d html_errors=0 < $php_file`;

# remove the temp file
rm -f $php_file;

test_syntax=`echo $php_syntax_output | grep "Parse error"`
if [ "$test_syntax" ];then
exit 1;

rm -f "$temp_file"

Step 2: Add hook to Mercurial config file

Update your Mercurial hgweb.config, adding the new hook under the 'hooks' section, like this:

pretxnchangegroup.syntax_check = /usr/home/mercurial/


Replace '/usr/home/mercurial' with the path where you saved

Attempting to push changes to the repository that don't pass php-syntax check, are now blocked.

Users will be presented with an error message and the transaction rolled back, until the user fixes the problem and pushes changes again.

optik, 09-07-2010
Nice, but storing results in temporary strings can be better, because we need to use this approach for more repositories, and there can be race conditions with writing temp files from these repositories.

Mike Peters, 09-08-2010
Optik -

We're using mktemp to create a truly unique temp file. Where do you see a potential race condition?

optik, 09-08-2010
Sorry, you are right, I read man mktemp :). Your solution is good at all. Using string variables can be little bit quicker and more "programming" like, then scripting like.

Lapoz, 02-03-2011
A more elegant way (IMHO) to achieve the same goal without temporary files :


### Configuration

### PHP syntax check
phpFiles=(`hg log -r $HG_NODE:tip --template "{files}\n" | grep -E "\.php[3-5]?$" | sort | uniq`)
for f in ${phpFiles[@]} ; do
res=`hg cat -r tip $f | $phpPath -l`
if [ $? -ne 0 ] ; then
echo $res 1>&2
exit 1

Lapoz, 02-05-2011
Oops, made my tests in a too straight forward situation.
I found out that filenames are printed in a single line for each changeset so due to how templating works in Mercurial we will need one temporary file after all :

### Configuration

### PHP syntax check
cat > tmpstyle << EOF
changeset = "{files}\n"
file = "{file}\n"
for f in `hg log -r $HG_NODE:tip -I "re:.+\.php[3-5]?$" --style tmpstyle | grep -E "\.php[3-5]?$" | sort | uniq` ; do
res=`hg cat -r tip $f | $phpPath -l`
if [ $? -ne 0 ] ; then
echo $res 1>&2
exit 1
rm tmpstyle
Enjoyed this post?

Subscribe Now to receive new posts via Email as soon as they come out.

Post your comments

Note: No link spamming! If your message contains link/s, it will NOT be published on the site before manually approved by one of our moderators.

About Us  |  Contact us  |  Privacy Policy  |  Terms & Conditions