Puppet git hooks

Since I have noticed an uptick in interest in my puppet-git-hooks, I thought I should dedicate some time to explaining myself (also, this is the first time anyone has ever written a book about anything that I’ve done).

The Goal

The highest level goal for these git hooks is to provide a programmatic mechanism for validating puppet code upon git commit/push.  A slightly lower level goal is to provide feedback to contributors to puppet projects and ensure that the code is in a good state and that style guides are being followed.  An even lower level goal is to use the same hooks for both client and server-side checks and wrap the logic around how git commit works vs how git receive works.  At the time of this writing, these hooks will test the following:

  1. Puppet manifest syntax
  2. Puppet template (erb) syntax
  3. Puppet manifest style guide compliance
  4. YAML (yaml, yml, eyaml, eyml) syntax
  5. Rspec-puppet tests

The Layout

If you don’t care about how the sausage is made, you can skip this section.  I will be detailing the directory and code layout and important workflow/codeflow points pertaining to these git hooks.

pre-commit

The pre-commit hook does what it sounds like: it’s the hook that runs on the client-side during the “git commit” process, but before your commit is actually staged.  This allows for the local commit to be denied before it is in history, which can be a little cumbersome to modify (at best).  Currently, the only asymmetric test between the server-side and client-side hooks is the rspec tests (more about rspec-puppet can be found here).

The git client looks for an executable file called “pre-commit” located in <git dir>/.git/.  If found, the git client will call this file and pass in it some git references (details).  Once the details are sorted out, this file iterates over the changed files and executes the shell scripts located in the commit-hooks directory.  All the tools required for the scripts in commit-hooks must be present on the client in order for these hooks to be successful, which means you might need to apt-get install a few packages..

pre-receive

This hook is run on the server side.  There is a fair bit of communication between the client and the server. In one of the steps, the client hands the changeset to the server.  The server must then verify acceptance of this changeset.  This pre-receive hook runs after the client hands the server it’s changeset and before the server tells the client that it did indeed accept the change set.  This is useful to centrally enforce standards (it also assumes you are using a central/canonical source for your git workflow).

Since these are all run server-side, all the tools required for the scripts in commit-hooks must be present on the server.

commit-hooks

This is the meat and potatoes of the actual puppet specific stuff.  There is logic in the pre-receive and pre-commit hooks to determine if a hook should be called (mostly by checking the file extension) and prepares/formats the data in a manner that these scripts are expecting to see it.  Once everything is ready, pre-receive or pre-commit will call the scripts located in this directory, usually with a single parameter being the filesystem location of the file the script is testing (for example: puppet_lint_checks.sh /tmp/foo.pp).

Conclusion

Git hooks are hard.  Which is why you should reuse work that someone else has already done.  And if these hooks don’t work for you, feel free to provide a patch (if you are comfortable doing so) or even just open an issue with a bug or feature request.