Slack! Hubot! Github!
At SuprNation we are using Slack as our primary communication tool. Slack is great, it has great search capabilities, allows rich messaging and most of all is able to integrate with other software components e.g. integrate Jenkins to post build updates to a slack channel. In this post we will integrate Slack with Hubot. Hubot is a virtual bot which will login to slack and provide some awesome and fun features e.g. automate deployment, language translation, integration with Google Maps, react to comments by posting an image from Imgr and so on. There are various scripts which you can add-on to hubot but the fun really starts when you create your own scripts to automate some of your own processes. Apart from our Slack integration with Hubot we will also create a plugin which integrates with GitHub to illustrate this idea.
Slack
Creating your slack team is simple - just head over to the slack homepage, click on Create New Team and follow the wizard. I have create a slack team called cloudmark
with a single user cloudmark
which I will use for the rest of this post. Once your team is created you should be presented with the following screen.
Now, let’s create a Hubot Slack Token which will enable Hubot to integrate with Slack. From the slack window click on the team name and click Apps and Custom Integrations.
Search for Hubot,
and click Install.
Now, select a name for your bot (in this case I typed down hubot
) and click on Add Hubot Integration.
You should now have your HUBOT_SLACK_TOKEN
. Copy this somewhere handy, we will need this in the next step. Yes! Yes! my API key is showing! I’ll change it afterwards so don’t you worry pal!
Hubot
Now let’s create our bot using a yeoman generator. Create an empty directory (I will use a directory named hubot
) and type in the following command to download the generator.
npm install -g generator-hubot
Next, type in yo hubot
. Make sure that you type in slack
when the wizard asks for the Bot Adapter.
After completion you should end up with a complete bot scaffold:
To start hubot
type in the following command.
HUBOT_SLACK_TOKEN=<your slack token> ./bin/hubot -a slack
Hubot is now integrated with Slack! To verify this go to your Slack window and you should see a new user named hubot
logged in :bowtie:
Github Plugin
Now that have Hubot and Slack setup let’s create a simple plugin which lists all Github issues on a particular repository labelled with the followup
label. To test this
plugin I will create a repository called hubot-plugin-test and create a couple of fake issues
To integrate with Github from Hubot we are going to make use of a wrapper library called githubot
. To install this Github API wrapper type:
npm install githubot --save
Next, we need to generate a Github API Token using the following request:
curl -i https://api.github.com/authorizations -d '{"note":"githubot","scopes":["repo"]}' -u <username>
You should receive an http response containing the token
value. We will pass in this token value to the hubot
process.
{
"id": 27406025,
"url": "https://api.github.com/authorizations/27406025",
"app": {
"name": "githubot",
"url": "https://developer.github.com/v3/oauth_authorizations/",
"client_id": "00000000000000000000"
},
"token": "b81ba1edaa85ccac51cf53251b792bab19c23455",
"hashed_token": "cc7bb462d9ce120a4e92c244fa8bf50ce86d5a9a4a62c4a97198e175c474385e",
"token_last_eight": "19c23455",
"note": "githubot",
"note_url": null,
"created_at": "2016-01-30T12:49:44Z",
"updated_at": "2016-01-30T12:49:44Z",
"scopes": [
"repo"
],
"fingerprint": null
}
Finally, we are ready to code the followup
plugin. The simplest way to create a plugin is to create a coffeescript file in the scripts folder <hubot-generated-code>/scripts
. The code for the followup plugin is listed below:
# Description:
# Show open issues from a Github repository
# Commands:
# hubot followup -- Shows all issues to follow up.
_ = require("underscore")
ASK_REGEX = /followup\s*/i
module.exports = (robot) ->
github = require("githubot")(robot)
issues = process.env.HUBOT_FOLLOWUP_LABELS;
robot.respond ASK_REGEX, (msg) ->
# Query Parameter
query_params = state: "open", sort: "created"
query_params.per_page=100
query_params.labels = 'followup'
base_url = process.env.HUBOT_GITHUB_API || 'https://api.github.com'
github.get "#{base_url}/repos/#{process.env.HUBOT_GITHUB_REPO}/issues", query_params, (issues) ->
if !_.isEmpty issues
for issue in issues
labels = ("`##{label.name}`" for label in issue.labels).join(" ")
msg.send "> [`#{issue.number}`] *#{issue.title} #{labels}* #{issue.html_url}"
else
msg.send "Congratulations! Nothing to followup!"
The code is pretty self explanatory; we retrieve all the issues from the repository and reply back to the source. One important thing to note is that we can use variables passed in from the environment through the process.env
object. In this case we retrieve the repository we are interested in by using process.env.HUBOT_GITHUB_REPO
.
Now, restart the hubot process with the following parameters:
HUBOT_SLACK_TOKEN=<hubot_slack_token> HUBOT_GITHUB_TOKEN=<github_api_token> HUBOT_GITHUB_USER=<github_username> HUBOT_GITHUB_REPO=<github_repo> ./bin/hubot -a slack
In my example this would translate to the following command:
HUBOT_SLACK_TOKEN=xoxb-19874712274-matxlL7HDPd1NRR81RD75MlO HUBOT_GITHUB_TOKEN=b81ba1edaa85ccac51cf53251b792bab19c23455 HUBOT_GITHUB_USER=cloudmark HUBOT_GITHUB_REPO=cloudmark/hubot-plugin-test ./bin/hubot -a slack
To verify that the plugin is operational type help
as a direct message to hubot and verify that the command hubot followup
is listed. Note that the list of commands is extracted directly from the comments.
# Commands:
# hubot followup -- Shows all issues to follow up.
Now let use our newly created command by typing followup
.
Pretty neat huh?! Alternatively we can invite hubot to a channel by typing /invite @hubot
and type @hubot: followup
.
Enjoy using Hubot! Just remember
- A robot may not injure a human being or, through inaction, allow a human being to come to harm.
- A robot must obey orders given it by human beings except where such orders would conflict with the First Law.
- A robot must protect its own existence as long as such protection does not conflict with the First or Second Law.