snare recipes

This page contains some example configurations and per-repo programs that may help you think of how snare can best be applied to your situation. The per-repo programs in this page happen to be written in shell script for easy deployment, but note that you can write per-repo programs in whatever language/system you wish.

Perform a command on a pull request merge

This per-repo program shows how to:

  1. Interpret GitHub’s JSON file to only execute commands after a pull request is merged.
  2. Perform a git checkout that requests only the minimal amount of data to get access to the repository at the point of the pull request.
#! /bin/sh

set -efux

# Ignore everything except pull request events
if [ $1 != "pull_request" ]; then
    exit 0
fi

# Ignore pull request events that aren't closing a pull request
if [ "X`jq .action $2 | tr -d '\"'`" != "Xclosed" ]; then
    exit 0
fi

# Ignore close events unless they merged changes in
if [ "X`jq .pull_request.merged $2 | tr -d '\"'`" != "Xtrue" ]; then
    exit 0
fi

# What is the hash of the pull request's merge commit?
hash=$(jq -r .pull_request.merge_commit_sha "$2")

git init
git remote add origin https://github.com/owner/repo
git fetch --depth 1 origin "${hash}"
git checkout FETCH_HEAD

# Commands here are only executed when a pull request is merged.

Reduce unnecessary builds of a website

Imagine you have a webhook which builds a website on each push event: we can only safely build and deply the website one event at a time. If multiple push events come in quick succession, we may then have a lengthy queue of build and deploy jobs to work through. Rather than doing each, we can use queue = evict to make sure that the most recent job on the queue evicts any predecessor, thus reducing the amount of work, and deploying the newest version of the site sooner.

Because queue = evict discards jobs without running them, it is not recommended to use it as a blanket setting: instead, it is recommended to set it explicitly for each individual repository it applies to e.g.:

github {
  match "user/repo" {
    queue = evict;
  }
}

Send full email diffs

This per-repo program sends full email diffs of all changes pushed to a repository to someone@something.com.

#! /bin/sh

set -efux

EMAIL="someone@something.com"

if [ "$1" != "push" ]; then
    exit 0
fi

repo_fullname=`jq .repository.full_name "$2" | tr -d '\"'`
repo_url=`jq .repository.html_url "$2" | tr -d '\"'`
before_hash=`jq .before "$2" | tr -d '\"'`
after_hash=`jq .after "$2" | tr -d '\"'`

git clone "$repo_url" repo
cd repo
git log --reverse -p "$before_hash..$after_hash" | mail -s "Push to $repo_fullname" "$EMAIL"