Hi. Meet VarCI. The bot that …

Jad Bitar
VarCI
Published in
4 min readNov 23, 2016

Automates workflows for GitHub & GitLab teams.

It all started as an experiment. Back when the GitHub open-letter was published.

You’ve certainly heard of Mark Zuckerberg’s famous deal with H&M:

One less thing to think about every morning.

Mark believes that:

… making even the easiest decisions consumes mental energy and gets in the way of doing more important things.

Imagine, for one second, being able to not have to think about:

  • labelling issues
  • enforcing guidelines
  • making sure CLAs are signed
  • protecting files from changes

Boring. Time-consuming. Error-prone. I hear you.

Now, imagine automating all this using IFTTT. Just configure some rules and let it do the rest.

That would be awesome, right?

Sad reality is they don’t support doing the above. Even less what you are about to see next:

This was a pull request to the Awesome PHP list with multiple added links.

Let’s break it up a bit, shall we?

  • extracted link and description in a new comment
  • detected multiple links and notified the contributor

The best part is all that happened instantly; which allowed the contributor to make fixes right away and the pull request was ready to merge by the time maintainers got to it.

Let’s look under the hood to understand how this was made possible. For that, we’ll need to look at the webhook event’s payload and the repository’s .varci.yml configuration. More particularly, the first rule:

body_link:
name: "Pull requests that add links ... them in the body"
events: [ pull_request ]
when:
- action = "opened"
- files = ["README.md"]
- deletions = 0
- not (body_links.added contains diff_links.added)
comment: |
This pull request adds the following suggestion:

{{ diff.added.0 }}

This rule triggers when the event is for a pull request and all conditions are met. It posts a comment with the first added link found. To better understand the when section (conditions), let’s look at a sample payload received from GitHub for this repository:

{
"action": "opened",
"number": 1,
"pull_request": {
"url": "...",
"id": 34778301,
"html_url": "...",
"diff_url": "...",
"patch_url": "...",
"issue_url": "...",
"number": 1,
"state": "open",
"locked": false,
"title": "Update the README with new information",
"user": {
"login": "baxterthehacker",
"id": 6752317,
...
"type": "User",
"site_admin": false
},
"body": "This is a pretty simple change that we need to pull into master.",
"created_at": "2015-05-05T23:40:27Z",
...
"merged": false,
"mergeable": null,
"mergeable_state": "unknown",
"merged_by": null,
"comments": 0,
"review_comments": 0,
"commits": 1,
"additions": 1,
"deletions": 0,
"changed_files": 1
}
}

As you can notice, in the original payload, some fields are present while other are not (i.e. action is but body_links is not). The missing data (a.k.a. attachments) is populated only when accessed by a rule.

In our case, a list of links obtained by extracting the URLs from the pull request’s body (author’s comment) and diff (referred to as body_links and diff_links respectively) and the list of files (added or modified):

{
"action": "opened",
"number": 1,
"pull_request": {
...
},
"deletions": 0,
"files": [
"README.md"
],
"body_links": [],
"diff_links": {
"added": [
"...",
"..."
],
"broken": [],
"suggested": []
}
}

If we look back at our conditions, it’s now easier to understand what it does:

when:
- action = "opened"
- files = ["README.md"]
- deletions = 0
- not (body_links.added contains diff_links.added)

This translates to trigger only if action is opened, files only include README.md, no deletions are made and the new suggested link in Markdown format has not already been included in the pull request’s body.

Now that we’ve covered how the first comment was automated, let’s quickly look at the rule that triggered the second one:

multiple_additions:
name: "Pull request should only suggest one addition at a time"
events: [ pull_request ]
comment: |
@{{ user.login }}, it looks like you are trying to add multiple suggestions in a single pull request.

If so, please split these into multiple pull requests so each item's inclusion in the list can be discussed separately.
when:
- action = "opened"
- files = ["README.md"]
- deletions = 0
- count(grep("/^\* /", diff.added)) > 1

Similarly to the first rule, this one will populate the missing data. No body_links this time.

The last condition will check if there is more than one added line in the diff that starts with an asterisk (*); which on this repository denotes a new suggested link.

Easy, right?

In the coming days and weeks, I will be sharing more of these examples and ways to automate the most tedious and boring chores in your software team.

Until then, you can discover more by yourself at https://var.ci.

If you liked what you just saw, please help us out with a 💚 below and follow us to not miss any of the upcoming examples. 🙌

--

--