«Bots should work, developers should think»: Writing Github App with Node.js

Nikita Barsukov
IT’s Tinkoff
Published in
5 min readNov 29, 2021

Undoubtedly, software developers are creative and pretty busy people — they do not have enough time to take care of routine tasks. However, machines can do all the monotonous tasks and, occasionally, even more effectively than humans. That is why everything should be automated to a large extent.

Hi! My name is Nikita. I am a frontend developer from Taiga UI. It is an Angular UI-Kit library that is actively used in the “Tinkoff” company. I will speak about solving one of such routine tasks in our project by writing a Github App in Node.js from scratch.

Problem statement — Lost in the forest of screenshots

In our project, we actively write screenshot tests using the framework Cypress.

After committing all code changes and opening pull request, a new Github CI Workflow runs every test. It saves our upcoming releases from introducing new bugs into our awesome UI-Kits components. If any test fails, all screenshots are attached as the zip-archive artifact to this workflow. The developer can download it and look into the screenshots. Unfortunately, we do not live in the perfect world where developers never make mistakes, and tests sometimes fail. Developers should download the archive and compare screenshots with “before” and “after” states. If there are too many tests, such simple action becomes an exhausting task. As I mentioned, this can be automated!

Cypress offers an official paid tool — Dashboard, which costs an arm and a leg. I bet that all developers need their limbs, so an alternative is unofficial, but a somewhat popular tool — Sorry Cypress. This open-source solution proposes almost the same dashboard but with lower prices and the possibility of hosting the entire infrastructure on your servers.

Even though this bootleg alternative is a better option, we still decided to write a simple Github bot.

How Github App works

To cut a long story short, the Github App is a set of callback-functions. They are called when the watched webhook-event is triggered in the repository. A list of all events is available on this Github Doc page. The callback-functions usually make Github API requests, leading to the creation of new commits, branches, files, and other changes in the repository.

We can monitor the necessary webhook-event and send the required API requests using only vanilla Javascript. However, it is much simpler to use community-approved solutions, which provide some abstraction over the vanilla JS. We will use the popular framework Probot for writing Github Apps.

You can initialize a new app using cli-commands. It is well described in the framework’s documentation and will not be repeated here. We recommend using a Typescript template during the app’s creation: strict typing prevents you from making random mistakes.

Listening to repository events

Our bot should listen to only three types of events: when the workflow begins (1), completes (2), and closes the pull request (3). Open the generated by cli index.ts file and add the following code:

Reminder: do not forget to give permissions to the bot to monitor workflow_run and pull_request events on the Github App’s settings page.

In the code, each callback-function to the repository event takes a context argument. This context contains much helpful information about the “watched” event. For example, it is the selector-function to get the name of the workflow that triggered the given webhook-event:

The context.payload also contains other required information: the id of the workflow run, the name of the branch on which this workflow was triggered, the number of the opened pull request, and a lot of other information.

Using the Github API

The framework Probot uses Node.js module @octokit/rest. It helps to use Github REST API methods via context.octokit…. See the list of all available methods here.

Our bot requires the following methods to create comments on pull requests:

  • context.octokit.issues.createComment (create a new PR’s comment).
  • context.octokit.rest.issues.updateComment (edit an already existing PR’s comment).

Do not be confused that we use methods from the issue object. Pull request is the same issue containing code. Github docs claims: “Every pull request is an issue, but not every issue is a pull request”. Therefore, all issue’s methods are applicable to the pull requests as well.

To download artifacts with screenshots of failed tests, we use the following methods:

  • context.octokit.actions.listWorkflowRunArtifacts (a list of meta-information about the all artifacts of a given workflow).
  • context.octokit.actions.downloadArtifact (downloading an artifact-archive by its id).

So, we have screenshot files and an understanding of how to create comments. Github’s comments support Markdown, and Markdown allows to insert images as base64 strings. It seems that it is a home stretch… but it is not. The Markdown’s version used by Github does not support this feature. You can insert an image into a Github’s comment only by an external link.

But this problem can be solved too. You can upload the required file (which we plan to attach to the failed tests’ report) to a separate repository branch and access it later via https://raw.githubusercontent.com/…. The code will be as follows:

After the PR’s closing, uploaded images can always be deleted. @octokit/rest library has API methods for it.

Deployment

Deployment is a compulsory part of every application life. The official documentation of the Probot framework offers detailed tutorials on how to deploy Github App using popular services. We deployed our Node.js application to Glitch. This platform provides free hosting, and the limitations of a free account are negligible for a simple application like a Github bot.

The final source code of our bot can be found on this Github repository:

We already actively use it in our project. The repository with the application was named Argus (a many-eyed “all-seeing” giant in Greek mythology). It was developed much more resounding than described in this article, but the application’s core was described above.

Wrapping up — Getting out of the woods

The development of a Github App is easy. It requires neither deep knowledge of the programming language nor framework. You should just look through the list of the repository webhooks-events and look into Github REST API methods to find the necessary ones and apply them for your task.

In this article, we have built a Github application that watches workflows with tests. If any tests fail, the bot downloads artifacts, finds screenshots with the differences between the “before” / “after” states and then attaches them as a comment to the PR.

We deployed the code as a Github bot called Lumberjack. It is already actively following our Taiga UI project. But the bot has configurable parameters, and you can easily customize it for your project. Just invite it to your repository and show workflow to watch.

--

--