Summary
It took me quite a while to piece together from the sparse examples I was able to find, so I figure I'll share what I've come up with as well.
Basically here's what you need to do:
- use an
update
hook (similar to pre-receive
)
- inspect the branch and commit
- checkout the bare repo to a temp folder
- run the formatter (Prettier, in this case) on the temp folder
- exit non-zero if files are / would be changed
- (either from the tool's output or a
git status --work-tree=... --git-dir=...
)
Example: Prettier + 'update' Hook
Although the pre-receive
hook is much more googleable, I find that the update
hook is both easier to use and more flexible. I'm using Prettier in this example, but I tried to write to be easy to adapt to any linter / vetter / formatter.
In my case my git user's home directory is /srv/git-repositories
and the hooks for the project I've set up are at:
/srv/git-repositories/my-project.git/hooks/update
I've actually tested this, so I know that it works, although it's a bit watered down from what I'm really using.
That said, it covers the basics:
ref_name=$1
new_rev=$3
# only check branches, not tags or bare commits
if [ -z $(echo $ref_name | grep "refs/heads/") ]; then
exit 0
fi
# don't check empty branches
if [ "$(expr "${new_rev}" : '0*$')" -ne 0 ]; then
exit 0
fi
# Checkout a copy of the branch (but also changes HEAD)
my_work_tree=$(mktemp -d -t git-work-tree.XXXXXXXX) 2>/dev/null
git --work-tree="${my_work_tree}" --git-dir="." checkout $new_rev -f >/dev/null
# Do the formatter check
echo "Checking code formatting..."
pushd ${my_work_tree} >/dev/null
prettier './**/*.{js,css,html,json,md}' --list-different
my_status=$?
popd >/dev/null
# reset HEAD to master, and cleanup
git --work-tree="${my_work_tree}" --git-dir="." checkout master -f >/dev/null
rm -rf "${my_work_tree}"
# handle error, if any
if [ "0" != "$my_status" ]; then
echo "Please format the files listed above and re-commit."
echo "(and don't forget your .prettierrc, if you have one)"
exit 1
fi
Although I typically use gitea for git hosting, I've tested this particular hook with a simple automated git deploy with ssh, and it should work just as well with GitLab, Gogs, and the like.
More Info
I offer a little more detail in the blog post I wrote on the matter:
Even more...
You may also benefit from some of these other resources: