How To Build a Github Bot for Discord using Val.town
Background
On our team at DXOS we use Discord for both community and team chat and we also use Github for code collaboration. Both of these services work well for us, but unfortunately they don’t work very well together. Unfortunately the options for notifications from Github are not the best. The email notifications aren’t bad but if you’re not on top of your inbox they can quickly get lost and buried. Additionally, perhaps I don’t understand how to use them but, the web notifications are just not useful in my experience. Other than this, the only notifications integration for Github that I’m aware of is their Slack integration. I haven’t used it in a number of years but I remember it being quite useful at a previous job. This is the experience we were hoping to emulate inside Discord.
Unfortunately, the Github API doesn’t make this easy. In order to get a coherent stream of relevant information you’d need to make several api calls and figure out how to join all the relevant data. At that point you probably want some caching so you’re not making tons of repeat api calls and now you’ve got a full blown service on your hands. Not to mention the cost of running something like that, my general feeling about “dev ops” is that I don’t want to do it, so this didn’t seem like a path we wanted to go down. It was at this point that we had an idea: the notifications that we want are available from Github via email without putting any data together ourselves, but we want to just be able to send emails to Discord. Enter Val.town.
The heading on the Val.town landing page is:
If GitHub Gists could run and AWS Lambda were fun
Not only that, but one of the types of “vals” is Email
:
Email handler vals get their own email address that you can send email to, and when Val Town receives that email, it triggers the val with the email as its first argument. Ever wanted a robot that you could forward emails to, or to be able to control something via an email trigger? With email handler vals it’s simple: they get their own, unique address.
Now we’re cooking!
So to summarize the solution we’re going to build:
- We need a Discord bot to be able to send DMs on Discord.
- We need an email Val in order to send Github emails to and forward to Discord.
- We need to configure our Github account to send notifications to the Val instead of our regular email address.
Setup a Discord Bot
The first step here is to create an “application” on Discord, you can do that via this link.
Once there you can optionally name your bot, give it an avatar, and hide it from public lists.
One important setting to remember to turn is the SERVER MEMBERS INTENT
on the Bot
settings page. This will allow it to look at the members of the servers it is in to be able to send them DMs. While you’re on this page, grab the token for your bot for later.
After that got the OAuth2 > URL Generator
page, check off the Bot
permission and grab the url it generates for you. Paste the url into a web browser and choose the server you want the bot to live on.
The last thing you need to do with Discord is get your user id so that your bot knows who the forward the messages to. Discord has a helpful guide for how to do that if you don’t already have it.
Setup an Email Val
I’ve already written some Vals which accomplish this, all you need to do is create a new email Val and then paste in the following code:
import { email } from "https://esm.town/v/std/email";
import { noteToSelf } from "https://esm.town/v/wittjosiah/discord_note_to_self";
import { parse } from "https://esm.town/v/wittjosiah/parse_github_email";
export default async function(message: Email) {
console.log(JSON.stringify(message, null, 2));
if (!message.from.endsWith("<notifications@github.com>")) {
return;
}
try {
const { title, description, url, name, bot, reason } = parse(message);
if (bot) {
return;
}
const body = {
embeds: [{
title,
description,
url,
author: {
name,
},
footer: {
text: reason,
},
}],
};
const { status, dmId } = await noteToSelf({
body,
dmId: Deno.env.get("DISCORD_DM_ID"),
userId: Deno.env.get("DISCORD_USER_ID"),
token: Deno.env.get("DISCORD_GH_BOT_TOKEN"),
});
if (dmId) {
Deno.env.set("DISCORD_DM_ID", dmId);
}
} catch (err) {
console.error(err);
email({ text: message.text });
}
}
Now take your Discord user id and bot token from before and add them as env vars in Val.town.
Connect Github to Val.town
The last step is to get Github to send emails to your val. Before you do this, I’d recommend temporarily adding console.log(message.text)
to the beginning of your Val to be able to more easily grab the verification link.
Now, grab the email of your val, go to your Github email settings and add it to your account. Once you’ve verified the email, you’ll then be able to set it up to route notifications to it based on the organization it originates from in the custom routing settings.
That’s it! You’ve now got a custom Discord Github bot which will forward you all your email notifications.
One last thing that might help this be more useful depending on your needs is to tune the notification settings themselves. The setting called Customize email updates
is the key one here and I find it most useful to have only notifications for Reviews
and Comments
turned on.
You can make sure that the author wrote this post by copy-pasting this signature into this Keybase page.