How to create a chatbot to talk with your GitHub repos
Tags: chatbots, bot, slack, github
Published: 2019-09-17 22:13:30

<a href="https://sustainoss.org/" target="_blank" rel="noopener noreferrer">Sustainability of open source</a> is a huge problem. There are many ways to <a href="https://livablesoftware.com/5-ways-to-thank-open-source-maintainers/" target="_blank" rel="noopener noreferrer">help the maintainers </a> but one growing trend is the <a href="https://livablesoftware.com/bots-open-source-sustainability/" target="_blank" rel="noopener noreferrer"> creation of bots that automate some of the tasks</a>. See a good list of <a href="https://livablesoftware.com/best-bots-software-development/" target="_blank" rel="noopener noreferrer">existing bots you can add to your OSS project</a>.

In this post, we'll show you how you could easily build your own bot for GitHub. Not just a "simple" bot, but a chatbot!. Once we're done you'll be able to **chat with your GitHub repositories**. To make things even more interesting, we'll deploy the **chatbot as a Slack app**. As example bots, we'll create two chatbots:

1. (for users) A bot that helps your users write good bug reports so that you don't waste your time trying to reproduce their bugs with incomplete information
2. (for maintainers) A bot that pings you on Slack when a new issue is created and lets you assign labels and developers to it. 

To create such a chatbot you'll need to interact with the [Slack API](https://api.slack.com/), the [GitHub API](https://developer.github.com/v3/) and at least a Natural Language Understanding (NLU) component, like [DialogFlow](https://dialogflow.com/). Instead of manually doing all this work ourselves, we will rely on <a href="https://xatkit.com/" target="_blank" rel="noopener noreferrer">Xatkit</a> platform (an open-source low-code chatbot development framework). Xatkit already provides an abstraction of these three elements, heavily simplifying the development of chatbots, as you'll see in a moment (for the TL;DR people, check the [Xatkit organization in GitHub](https://github.com/xatkit-bot-platform) and take a look at the <a href="https://github.com/xatkit-bot-platform/xatkit-examples/tree/master/GithubBot">code of the example bot</a>). 

In Xatkit, you <a href="https://github.com/xatkit-bot-platform/xatkit-releases/wiki/Getting-Started" target="_blank" rel="noopener noreferrer">define the bot behaviour via two different files</a>: the <em>intent</em> library (that specifies the potential intentions of the user when talking to the chatbot) and the <em>execution</em> model (that defines how to react to the user intentions or other events directly received by the bot). Let's see how we can use Xatkit to create our two bots. 

## Filing a bug report from Slack
If you look at any OSS project, the firsts iterations in any new bug report consist in the maintainer trying to get from the user who submitted the report all the information needed to reproduce it. This is a huge waste of time for both sides. And one that delays significantly the bug fixing since the communication is not synchronous so depending on the respective availability and time zones, it can go on for a few days.

I'll show you how a chatbot can make sure a bug report has all the basic information a maintainer needs. In the example, we assume the project is a WordPress plugin. Typically, to debug a potential error there we always need to know the WP version and the PHP version the website is running. So to illustrate the capabilities of our chatbot approach for GitHub we'll make sure the chatbot collects this information.

We start by defining the intents. Note that some of the intents are only possible after a previous intent has been matched. Some of the intents store conversation data that we'll use to open the bug at the end.
<pre lang="Xtext" line="1">intent OpenBug {
	inputs {
		"The plugin is not working"
		"I have a problem with the plugin"
		"I'd like to report an error"
		"I want to open a bug"
		"I want to report a bug"
		"There is an error in the plugin"
	}
	
}

intent DescribeBug follows OpenBug {
	inputs {
		"My error is Error"
		"The problem is Error"
		"I get this error: Error"
		"My error is that Error"
		"The problem is that Error"
		"I get the error Error"
	}
	creates context bug {
		sets parameter title from fragment Error (entity any)
	}
}

intent TellWPVersion follows DescribeBug {
	requires context bug
	inputs {
		"My version number is WPVersion"
		"I use number WPVersion"
		"It's version WPVersion"
	}
	creates context bug {
		sets parameter wpversion from fragment WPVersion (entity number)
	}
}

intent TellPHPVersion follows TellWPVersion {
	requires context bug
	inputs {
		"My version is PHPVersion"
		"I use PHPVersion"
		"It's version PHPVersion"
		"The server is on php version PHPVersion"
	}
	creates context bug {
		sets parameter phpversion from fragment PHPVersion (entity number)
	}
}
</pre>
This is an example dialog with this chatbot.

<a href="http://livablesoftware.com/wp-content/uploads/2019/09/OpeningGitHubIssueFromSlack.png"><img class="wp-image-118713 aligncenter" src="https://livablesoftware.com/wp-content/uploads/2019/09/OpeningGitHubIssueFromSlack-1024x719.png" alt="Chatbot to fill a bug report from Slack" width="569" height="400" /></a>

And once all the error info has been gathered, we just need to put it all together and open an issue with it. As you can see in the following code excerpt, once the last intent has been matched we ask GitHub to create a new issue with the title and body parameters we collected along the way. We end up labeling the new issue as a bug.
<pre lang="Xtext" line="1">on intent TellPHPVersion do
	action SlackPlatform.Reply(message : "Thanks for your detailed info")	
	def newissue = action GithubPlatform.OpenIssue(user : "jcabot", repository : "xatkit-tests", issueTitle : context(bug).get("title") , 
			issueContent : "WP version is " + context(bug).get("wpversion") + " PHP version is " + context(bug).get("phpversion") 
	)
	action GithubPlatform.SetLabel(issue : newissue, label : "bug")
</pre>
This generates as end result the following issue created from the above dialog.
<a href="http://livablesoftware.com/wp-content/uploads/2019/09/GitHubIssue.png"><img class="alignnone size-large wp-image-118716" src="https://livablesoftware.com/wp-content/uploads/2019/09/GitHubIssue-1024x494.png" alt="" width="1024" height="494" /></a>

<h2>From GitHub to Slack: receiving and reacting to GitHub notifications</h2>
Let's now how we can get notified in Slack of things happening in GitHub. In this example, we'll just look at "New issue" notifications. The bot should be able to:
<ol>
 	<li>Receive New Issue notifications from GitHub</li>
 	<li>Save time to the maintainer by enabling her to assign a label to the issue and a potential developer that could follow-up on it</li>
</ol>

To process the <em>OpenIssue </em>notification and forward it to Slack, we just need to write this piece of code
<pre lang="Xtext" line="1">on event Issue_Opened do
	action SlackPlatform.PostMessage(message : "An issue has been opened with the title " + context(issue).get("issue-&gt;title"), channel: config(slack.channel))
	def issue = action GithubPlatform.GetIssue(user : config(github.repository.username), repository : config(github.repository.name), issueNumber : context(issue).get("issue-&gt;number"))
	session.store("issue", issue)
</pre>
where we get the issue information from the event and post it to Slack (SlackPlatform is part of the predefined <a href="https://github.com/xatkit-bot-platform/xatkit-slack-platform" target="_blank" rel="noopener noreferrer">Slack platform in Xatkit</a>). The issue itself is also stored in the session for further use.

Once the maintainer gets the notification, the chatbot starts listening to see if the maintainer expresses any intention to add a label or assign a user to it. These intents definitions will try to match whatever the maintaner writes in Slack to these two potential actions.
<pre lang="Xtext" line="1">intent SetLabel {
	requires context issue
	inputs {
		"Set label Label"
		"Give label Label"
	}
	creates context  issue {
		sets parameter issueLabel from fragment Label (entity any)
	}
}

intent AssignUser {
	requires context issue
	inputs {
		"Assign user Username"
		"Username will take care of it"
	}
	creates context  issue {
		sets parameter assignedUsername from fragment Username (entity any)
	}
}
</pre>
Note that, as for the previous bot, intents are defined via a set of training sentences. Training sentences try to represent the different ways a maintainer can express that intention (e.g. set label or give label). Thanks to our DialogFlow integration, additional variations will also be recognized: see the following dialog, where I write "Add label" instead of Set or Give.

<a href="http://livablesoftware.com/wp-content/uploads/2019/09/SlackNotificationsFromGitHub.png"><img class="alignnone size-large wp-image-118714" src="https://livablesoftware.com/wp-content/uploads/2019/09/SlackNotificationsFromGitHub-1024x288.png" alt="" width="1024" height="288" /></a>

After this chat, the new issue gets properly tagged and assigned in the GitHub repo. No need for the maintainer to move out of Slack to do so. The execution actions associated with the intents take care of this.
<pre lang="Xtext" line="1">on intent SetLabel do
	action GithubPlatform.SetLabel(issue : session.get("issue"), label : context(issue).get("issueLabel"))
	action SlackPlatform.Reply(message : "Done!")
</pre>
<a href="http://livablesoftware.com/wp-content/uploads/2019/09/NewIssueFromSlack.png"><img class="alignnone size-large wp-image-118712" src="https://livablesoftware.com/wp-content/uploads/2019/09/NewIssueFromSlack-1024x407.png" alt="GitHub issue created from Slack" width="1024" height="407" /></a>

## Summary: chatting with GitHub 

To sum up, in a few lines of code we've been able to create a bidirectional *Slack-GitHub chatbot* to help open source maintainers. This was just an example but I hope it's a good enough example to showcase the potential of (chat)bots to significantly improve the sustainability of open-source.