Nikita from Taiga UI discusses the development of a Github App using Node.js to automate the comparison of screenshot tests in the CI pipeline for the "Tinkoff" company.
Abstract
In the article, Nikita, a frontend developer from Taiga UI at "Tinkoff", addresses the automation of routine tasks such as managing screenshot tests using Cypress. He explains the creation of a Github App from scratch to streamline the process of identifying and reviewing failed screenshot tests, which often involves downloading and comparing numerous images. The article covers the selection of an open-source solution, the use of the Probot framework to interact with Github API events, and the deployment of the app to a hosting platform. The developed bot, named Argus, attaches comments to pull requests with links to screenshot differences, and is configurable for different projects, demonstrating an efficient solution to a common development workflow issue.
Opinions
The author expresses the necessity for developers to automate repetitive tasks to improve efficiency.
While acknowledging existing tools like Cypress Dashboard and Sorry Cypress, the author opines that they are either too expensive or not ideal, leading to the development of a custom Github App.
The author recommends using vanilla JavaScript with community-approved frameworks for simplicity and effectiveness when monitoring webhook events and making Github API requests.
There is an emphasis on using strict typing with Typescript to minimize errors during the development of the Github App.
The author advocates for self-hosting solutions for better control and cost management, choosing Glitch as the platform for deploying the Github bot.
The author indicates a preference for open-source and community-driven tools like Probot and GitHub repositories, which help in creating cost-effective and flexible automation solutions.
The opinion is conveyed that automation not only saves time but also reduces the likelihood of human error during the code review process.
«Bots should work, developers should think»: Writing Github App with Node.js
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.