GitHub offers a great feature called WebHook URLs. You can add a url to take advantage of git’s post-receive hook and get a POST request containing data related to a repository push (e.g., commits, tags, and head-resets). While the data is very detailed and thorough, its complexity and focus on mimicking the git operations make it harder to use. For example, files added are listed per commit instead of a complete array spanning all commits. Also, retreiving if a tag was added requires checking three different properties.

When using GitHub payloads to determine your own server behavior, different payload data from GitHub may require different actions to be taken. For example, you wouldn’t need to pull from your master branch and update a website’s content if someone pushed a new branch. But you might want to stage that branch somewhere, which would be a completely different operation.

Deployment With Git Hooks

We use the post-receive hooks GitHub provides for many of our websites, including bocoup.com. All of us work on the Bocoup.com website collaboratively, and so when any of us commits to our website’s repository, GitHub sends that action to our web server. We have some scripts in place to pull that repository into a staging area, which allows all of us to preview the changes. When it’s time to go live, there is a separate page we can access that lets us deploy the current staging commit to the live site. It’s all pretty basic, but it saves us an incredible amount of time.

I wanted to build and share a tool that addresses the problems of complexity and filtering the raw GitHub payload, and I was able to go above and beyond my normal open source time here at Bocoup to go ahead and do that! Cool, eh?

Introducing gith

The result of this work is gith , short for “githooks”. It provides an easy-to-use API that simplifies the process of utilizing GitHub’s payloads in a number of ways:

Listen on a specified port for WebHook payloads from github.com using node

Filter the payloads by payload type: repository, branch, file or tag

Subscribe to events based on the payload information, such as all , file:add , tag:add or file:delete

, , or Provide a simpler payload object that has things like the branch name and all of the files added, removed, or deleted in an array

gith accomplishes this very well. For example, if I wanted to do something when a file was added to a particular repository, I can write a small node script to handle it:

var gith = require( 'gith' ).create( 9001 ); gith({ repo: 'danheberden/gith' }).on( 'file:add', function( payload ) { console.log( 'these files were added', payload.files.added ); });

or if I wanted to find files added in a particular directory:

var gith = require( 'gith' ).create( 1337 ); gith({ repo: 'danheberden/gith', file: /^test/payloads/ }).on( 'file:add', function( payload ) { /* files were added to /test/payloads in danheberden/gith */});

or even more simply, get alerted when anything happens:

var gith = require( 'gith' ).create( 9001 ); gith().on( 'all', function( payload ) { /* update the website! */});

There’s a lot more information at the project’s repository: https://github.com/danheberden/gith

Moving Forward

gith is the result of refining the development and deployment workflow for bocoup.com and many of our other projects, and it will continue to be an important part of our operations going forward.

There are more features planned and unit tests to write, but we wanted you to see it as soon as possible and have an opportunity to get involved and give feedback. This is what I’m planning to attack in the immediate future:

Supporting github API calls with OAuth

Getting a list of files that were added/removed/modified in a tagging operation or head reset

Polling an account for new repositories and automatically subscribing them to the WebHook url

Specifying a secret query-string-argument in the url (e.g., ?secret=password) to prevent the server from receiving false payloads