Building slack bot using Github actions

Problem

In PushOwl we have a support channel in slack where unclear or urgent support questions are raised and are usually answered by developers. To avoid chaos and make things more manageable we have weekly support owners for the channel. Where developers from backend and frontend teams are made owners of the channel on a round-robin schedule. The owner gets changed every week on Monday. It becomes hard to track who becomes the next owner of the channel and do this every week on Monday morning.

Building a slack bot

To avoid this issue we decided to build a Slack bot that:

  1. chooses one developer each from backend and frontend from a list of developers, for the current week
  2. puts a message on a Slack channel about the chosen support owners every Monday morning

Bots need to be hosted on a server. But instead of hosting a separate server, we decided to use Github actions to do this. Because we are already using Github Actions, so why not!

Iterating through the list

To pick the next person on the list every week we need to store the index of the last owner.

But Github action does not provide a way to store data so we need a way to pick the next person in the list. Luckily for us, we can use the week number of the year to deal with this. So to pick up the next person for the week we can do

Index of new owner = The week of the year % Number of people on the list

This will give us a number from 0 to the length of the list iterating every week. This allows us to loop through the list every week easily

Show me the code

This is how our Github action looks now. We use a separate node script for readability but this could be done in the single workflow file

name: Channel owner
on:
  push:
  schedule:
    - cron: "30 3 * * MON"
jobs:
  tech-support-owner:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - run: npm i
      - uses: actions/github-script@v3
        with:
          script: |
            const script = require(`${process.env.GITHUB_WORKSPACE}/scripts/owner.js`)
            const val = await script()
        env:
          SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }}

and the node script owner.js looks as follows

Date.prototype.getWeek = function () {
  const onejan = new Date(this.getFullYear(), 0, 1);
  const today = new Date(this.getFullYear(), this.getMonth(), this.getDate());
  const dayOfYear = (today - onejan + 86400000) / 86400000;
  return Math.ceil(dayOfYear / 7);
};

module.exports = async () => {
  const client = new WebClient(process.env.SLACK_TOKEN);

  const frontendOwner =
    owners.frontend[Math.floor(new Date().getWeek() % owners.frontend.length)];
  const backendOwner =
    owners.backend[Math.floor(new Date().getWeek() % owners.backend.length)];

  await client.conversations.setTopic({
    channel: CHANNEL,
    topic: `Current assigned owners
      Frontend: <@${frontendOwner.id}>
      Backend: <@${backendOwner.id}>
      `,
  });
};

Things we could improve

  • We could read the google calendar availability for the developer before setting them as the channel owner if they are on leave we could skip them for the week. That would be cool! 🔥