Capturing Commits for Sentry Using Envoyer

Written By Jesse Schutt
Posted on

At Zaengle we use an error tracking tool called Sentry to keep our apps humming along. One of the more handy features it offers is the ability to associate a series of git commits to a release. This helps us track down potential problems by identifying when certain bugs may have been introduced.

With the standard Sentry-Laravel implementation, the package will inspect the .git repository to determine which commits belong to a given release. However, our deployment tool, Envoyer, does things a bit different and doesn't include the .git repository in the deployment directory. That leaves us without the ability to utilize the built-in commit grouping.

How Envoyer Works

Envoyer provides zero-downtime deployments by cloning a new directory for each release and at the very last second updating a symlink to the "current" directory. Effectively, it swaps one release for another as fast as a symlink can be updated.

Deployment Hooks to the Rescue!

Fortunately, by using Envoyer's "deployment hooks" we are able to capture the starting/ending hashes and send them to Sentry for commit collection!

All Sentry needs is a commit hash that references the first commit in the release and a second hash that references the last commit. Let's look at how we can get those values.

Since we know how Envoyer clones deployments we can create some dotfiles that contain the hashes we need to send to Sentry. The first step is to save the current release hash to a .commit_hash file so it is available for future reference.

Add a deployment hook with the following content and run a release. If it runs successfully you will now have a file in your release directory named .commit_hash which will contain the hash of the current commit.

# Deployment Hooks -> Activate New Release -> AFTER

echo "{{ sha }}" > {{release}}/.commit_hash

Once that file has been created you should add the following two deployment hooks, which is where the magic happens. In the "Write Previous SHA" hook we are grabbing the .commit_hash value from the previous release and saving it into a new .commit_hash_previous file. Then we write the current SHA into a new .commit_hash file.

# Deployment Hooks -> Clone New Release -> AFTER

yes | cp -f {{project}}/current/.commit_hash {{release}}/.commit_hash_previous
echo "{{ sha }}" > {{release}}/.commit_hash

At this point we have both the starting and ending hash of our commit range and just need to notify Sentry of the release and commit range. This is done by a curl request to the Sentry API with our specific values:

# Purge Old Releases : AFTER

export SENTRY_BEARER_TOKEN="MyBearerToken"
export SENTRY_PROJECT="my-sentry-project-name"
export ENVIRONMENT="develop"
export PREVIOUS_SHA=`tail {{release}}/.commit_hash_previous`

cd {{ release }}
curl \
-H "Authorization: Bearer ${SENTRY_BEARER_TOKEN}" \
-H "Content-Type:application/json" \
-d "{
        \"previousCommit\": \"${PREVIOUS_SHA}\"
    \"projects\": [\"my-sentry-project-name\"]

curl{{sha}}/deploys/ \
-H "Authorization: Bearer ${SENTRY_BEARER_TOKEN}" \
-H 'Content-Type: application/json' \
-d "
    \"environment\": \"${ENVIRONMENT}\",
    \"name\": \"{{release}}\"

That's it! We now automatically get release and commit tracking data piped into Sentry every time we initiate an Envoyer deployment.

Bonus - Sending Release Information to Sentry When Errors Occur

Now that we have commit information attached to our releases, we need to tell our Sentry implementation which release we are using when the application encounters an error. As we saw before, Sentry would automatically determine which release we were using if we had a valid .git repository alongside the deployment. However, due to how Envoyer deploys code we don't have one.

We've put together a simple package based on this and this so that Sentry will either look for a .commit_hash file or a .git repository and include the hash when reporting errors.

Take a look at the package readme for more details!

  1. Hero Image