Gwooks
A DSL for quickly creating endpoints for GitHub post-receive webhooks. It makes it easy to trigger an action whenever one of your GitHub repos receives a push matching some custom conditions.
Installation
Add this line to your application's Gemfile:
gem 'gwooks'
And then execute:
$ bundle
Or install it yourself as:
$ gem install gwooks
Usage
First extend the Gwooks::Base
class and use its DSL to create actions to be
performed in response to a code push:
class MyActions < Gwooks::Base
# Do something when GitHub receives a push to a repository
# named "my_cool_project":
repository_name "my_cool_project" do
# You can nest matchers. The following block for example is executed
# when GitHub receives a push to 'my_cool_project' repo's 'master' branch:
branch "master" do
# You have also access to the payload sent by GitHub, parsed to a hash:
contributors = payload[:commits].map {|c| c[:author][:email] }
contributors.uniq.each do |email|
send_email email, "Thanks for your contribution :)"
end
end
# You can match with regular exceptions too. E.g. the next block gets
# called when GitHub receives a push with at least one commit message
# matching the given Regexp:
commit_message /Bump new version v(\d+\.\d+\.\d+)/ do |matches|
matches.each do |match|
send_email("someone@email.com", "New version released: #{match[1]}")
end
end
end
private
def send_email(to, msg)
# assume we define here a method to send an email
end
end
Then provide an endpoint for the GitHub post-receive webhook making use of the class you created:
require "sinatra"
post "/webhook" do
MyActions.call(params[:payload])
end
Alternatively, you can use the Sinatra application provided by the class
Gwooks::App
, which is already setup for you:
# In your config.ru
require "gwooks"
# Tell Gwooks::App to use your class
Gwooks::App.use_webhook MyActions
# Gwooks::App responds to "POST /"
run Gwooks::App
Finally set up your GitHub repo to trigger a post-receive hook pointing to your endpoint. Whenever GitHub receives a push, your endpoint will be notified, and all the matching actions will be performed.
Matcher methods (DSL)
Each of the DSL methods matches a corresponding property in the
payload
object (e.g. repository_owner_email
matches
payload["repository"]["owner"]["email"]
). The payload is accessible through
the payload
method, parsed into a hash.
Note that all the methods starting with commits
are also aliased with the
singular commit
, and those starting with repository
are aliased with
repo
to improve code readability.
The signature is identical for all matcher methods:
repository_owner_email(pattern, &block)
pattern can be any object. If it is a Regexp, it is matched against the target property in the payload, otherwise it is checked for equality.
block is called once if there is at least one match, and it gets passed
the match, or an array of matches if the target property is an array (all
commits
methods match against the array of commits and their properties). The
match is a MatchData object when regexp matching is used, or the matched
pattern otherwise. The block is evaluated in the instance scope, and thus can
access the payload
object.
Here is the full list of DSL methods:
after
before
branch
commits_added (alias: commit_added)
commits_author_email (alias: commit_author_email)
commits_author_name (alias: commit_author_name)
commits_id (alias: commit_id)
commits_message (alias: commit_message)
commits_modified (alias: commit_modified)
commits_removed (alias: commit_removed)
commits_timestamp (alias: commit_timestamp)
commits_url (alias: commit_url)
ref
repository_description (alias: repo_description)
repository_forks (alias: repo_forks)
repository_homepage (alias: repo_homepage)
repository_name (alias: repo_name)
repository_owner_email (alias: repo_owner_email)
repository_owner_name (alias: repo_owner_name)
repository_pledgie (alias: repo_pledgie)
repository_private (alias: repo_private)
repository_url (alias: repo_url)
repository_watchers (alias: repo_watchers)
Each of them matches a corresponding field in the payload sent by GitHub,
except branch
, which is a shortcut to match the branch using info in the
ref
(e.g. branch "master"
is a shortcut for ref "refs/heads/master"
)
Payload
The payload sent by GitHub is parsed into a hash-like object and is available
through the payload
instance method. For convenience, a branch
property is
added to it, indicating the branch that received the push (extrapolated from
the ref
). The payload property can be indifferently accessed using symbol or
string keys.
The payload
object also has a resolve
method that takes a string key and
returns the matched property (or array of matched properties) or nil
if the
property or one of its parents is not set:
payload.resolve "repository.owner.name"
# returns the repo owner name, or nil if either payload["repository"],
# payload["repository"]["owner"] or payload["repository"]["owner"]["name"] are
# not set.
payload.resolve "commits.author.name"
# returns the array of each commit's author name
# Equivalent to `payload["commits"].map {|c| c["author"]["name"]}`, but it
# does not raise errors if some property is not set.
Alpha release
Please take into consideration that this is an alpha release, and as such the API may change frequently.
Changelog
v0.0.6 - Add possibility to nest matcher methods
v0.0.5 - Add branch
payload property and corresponding DSL method
v0.0.4 - Payload with indifferent access
v0.0.3 - Alias repository_
methods to repo_
v0.0.2 - Alias commits_
methods to commit_
v0.0.1 - First release