Programmatically Remind Your Teammates on Slack to Review GitHub PRs
Tags: opensource, github, slack, reshuffle
Published: 2020-12-17 17:50:56

The Github integration for Slack is great for team productivity. Having the ability to give Slack channels full visibility into Github projects, for real-time notifications, is an amazing way to keep the development team on the same page. However, this can become a double-edged sword. Developers may decide to ignore these messages being sent because it may be information overload. 

I’ve been in a similar situation where pull requests needed approval from reviewers but they wouldn’t check the channels or their emails. The only thing that got their attention were direct messages. This hindered delivery and having to ping the reviewer myself was becoming a pain.

As great as the Github app for Slack is, I wanted something more custom that would suit my needs. For example, whenever a pull request is made with reviewers, only send direct messages to those who have been requested.

In this article, we will use Github, Slack, and [Reshuffle](https://dev.reshuffle.com/) to create the workflow to directly message the reviewers on a pull request.

##How to Build It

Before getting started with the code, we’ll need to get credentials set up with Github and Slack.

__Github__
  - Log in and generate a token [here](https://github.com/settings/tokens)
  - Save the token somewhere, as you''ll need it soon

__Slack__
  - Create a new Slack App [here](https://api.slack.com/apps)
  - Enter the App name and select the workspace
  - Click on `Create App`
  - Click on your new App
  - The signing secret is under `Basic Information` > `App Credentials`
  - The token is under `Settings` > `Install App` > `OAuth Access Token`
  - Save the token and signing secret somewhere, as you''ll need it soon

See links for full documentation: 
  - [Reshuffle](https://github.com/reshufflehq/reshuffle)
  - [Slack Connector](https://github.com/reshufflehq/reshuffle-slack-connector)
  - [Github Connector](https://github.com/reshufflehq/reshuffle-github-connector)
  - [Cron Connector](https://github.com/reshufflehq/reshuffle/blob/master/doc/CronConnector.md)

With the credentials saved somewhere safe, we can begin by instantiating a Reshuffle app and configuring the connectors.

_Note: The Github Connector requires a runTimeBaseUrl. A tool like [ngrok](https://ngrok.com/) can be used to generate a url that exposes your localhost over SSL._

```javascript
const { Reshuffle, CronConnector } = require("reshuffle");
const { GitHubConnector } = require("reshuffle-github-connector");
const { SlackConnector } = require("reshuffle-slack-connector");
 
const app = new Reshuffle();
// Cron config
const cronConnector = new CronConnector(app);
//Github Config
const githubConnector = new GitHubConnector(app, {
 token: process.env.GITHUB_TOKEN,
 runtimeBaseUrl: process.env.RUNTIME_BASE_URL,
});
const slackConnector = new SlackConnector(app, {
 token: process.env.SLACK_TOKEN,
 signingSecret: process.env.SLACK_SIGN_SECRET
});
 
 // Code listed further down
 // will be inserted here
 
app.start();
```
Reshuffle Connectors provide events and actions that allow developers to easily build custom workflows and integrations. We’re now able to take advantage of what they can do.

We’ll continue by getting a list of the user’s Github handles and their Slack IDs. In order to get this data, we use a method on Slack Connector that exposes [Slack's web client](https://slack.dev/bolt-js/concepts#web-api) actions.

_Note: In this example, display_name is being assumed to be the same as the Github handle. You can definitely add your own profile fields that suit your team._

```javascript
const slackUsers = await (async () => {
 const webClient = await slackConnector.getWebClient();
 const { members } = await webClient.users.list();
 let usersHash = {};
 members.forEach((member) => {
   usersHash[member.profile.display_name] = member.id;
 });
 return usersHash;
})();
```
Next, we’ll write a helper function to handle the event when a pull request is created, this will take in a list of reviewers from Github, the user list from Slack, and the link url to the pull request. If there are no reviewers, we’ll simply post to the general channel, otherwise, we match the reviewers to the slack members list and send them a direct message.

```javascript
const messageHelper = async (
 ghReviewers,
 slackList,
 prLink,
 pending = false
) => {
 if (ghReviewers.length == 0) {
   await slackConnector.postMessage(
     "general",
     `${pending ? "Pending pull request" : "New pull request"} - ${prLink}`
   );
 } else {
   ghReviewers.forEach(async ({ login }) => {
     if (slackList.hasOwnProperty(login)) {
       await slackConnector.postMessage(
         slackList[login],
         `${
           pending ? "* Pending review *" : "* New review requested *"
         } ${prLink}`
       );
     }
   });
 }
};
```

To tie everything together, we configure the Github Connector to trigger an event anytime a pull request is created.

_Note: See the full list of available events [here](https://github.com/reshufflehq/reshuffle-github-connector#connector-events)_

We can get the list of requested reviewers from the event object, passing onto our helper, which is only called if the event action matches “opened” or “reopened”.

```javascript
githubConnector.on(
 {
   owner: process.env.GITHUB_OWNER,
   repo: process.env.GITHUB_REPO,
   githubEvent: "pull_request",
 },
 async (event, app) => {
   const {
     pull_request: { requested_reviewers },
     pull_request: { html_url },
   } = event;
   if (["opened", "reopened"].includes(event.action)) {
     const reviewers = requested_reviewers.map((reviewer) => reviewer);
     await messageHelper(reviewers, slackUsers, html_url);
   }
 }
);
```
_Note: For more information on the parameters of postMessage check the [docs](https://github.com/reshufflehq/reshuffle-slack-connector#postMessage)._

With that, we’re finished, any time a pull requests is created with reviewers, they are directly messaged.

As a bonus, if the reviewers forget about the pull request, we can use the Cron Connector as a scheduler to check for any open PRs on the repository and message the reviewers. 

```javascript
cronConnector.on({ expression: "0 12 * * 3 *" }, async (event, app) => {
 const { data } = await githubConnector.sdk().pulls.list({
   owner: process.env.GITHUB_OWNER,
   repo: process.env.GITHUB_REPO,
   state: "open",
 });
 data.forEach(async ({ html_url, requested_reviewers: reviewers }) => {
   await messageHelper(reviewers, slackUsers, html_url, true);
 });
});
```

This example provides a good starting point to how you can easily create a custom workflow for your team's needs using Reshuffle.

##Now, Make it Happen

As your developers and project management teams experience the ease of working with integrated applications, we encourage you to consider where else integrating workflows would benefit your teams. With so many different tools, the more you can consolidate them into one common interface, the easier people can get work done. 

Reshuffle is continually listening to what our customers need and desire. Don’t see a Connector to a service you’d like to integrate? Send a tweet to [@ReshuffleHQ](https://twitter.com/reshufflehq) to let us know which Connector you’d like us to develop next.