This week I’ve been working automating some review tasks at SoundCloud with a tool called Danger from @orta and @krausefx. We had some linting tasks in CI that analyzed the code and stopped the whole build process notifying the affected developers about something not matching the project specs. Developers had to go into Jenkins (in our case), check out the build log, fix what was failing, commit and push the changes restarting the pipeline execution. What if we could report all that handy information and check results directly to GitHub? That’s exactly what Danger tool does. I first heard about it reading this very interesting article from Orta title “Being a Better Programmer When You’re Actually Lazy”. Just summarizing what Danger does:
- You include an extra step in your CI build process that executes danger
bundle exec danger
- Danger reads a file
Dangerfilethat contains the checks (ruby code).
- It exposes a set of useful environment variables like the PR title, the files that changed,… It also exposes methods to report the result of these checks
Dangercompletes it sends a comment to the opened PR with the results (as you can see in the screenshot below taken from the article mentioned).
The tool uses the user you specify through a DANGER_GITHUB_API_TOKEN environment variable
Creating “dangers” in multiple ruby files
When I tried the tool I felt that adding all the Ruby logic in a single
Dangerfile was going to turn the file into a big mess. What about having a
danger folder with all the tasks? Then we could require these tasks from
Dangerfile and execute them one after another.
The steps below show how I ended up doing it. It doesn’t mean it’s then only way. There’re probably some other alternatives. This is the one I tried and that worked with our project structure, keeping all the danger checks in their own folder.
- First create a folder
dangerwhere all the tasks/checks will be.
- Each of these checks represents a ruby file. Its structure would be like this one:
Where every check inherits from
Danger::Checks::Base. That base class defines a base constructor with taking a
Danger::Dangerfile instance that contains all the environment variables exposed from Danger, variables like the number of lines of your PR, the new files added,…:
If you want to use
failmethods and environment variables you can access them from the @dangerfile attribute.
Then the structure of your
Dangerfile would look like this one:
These are just some examples of checks that we’re using but the options are infinite:
- PRSize: Checks if the number of lines in the PR is over a given value.
- IncludeSpecs: Checks if any new
.mfile includes unit tests.
- Todo: Checks if the developer forgot any
// TODOsomewhere in the code.
- Ping: Analyzes modified files and notifies developers that might be directly concerned about these changes because they, for example, own the feature whose file has been modified.
There’re manual processes that are unavoidable, even though, tools like Fastlane & Danger are helping to automate the majority of them. When we’re so focused on our projects we don’t worry that much about the time we spend in repetitive tasks (since we only think about developin). The time that we can spend on these tasks can be huge and it’s worth to spend some time setting up either Danger, Fastlane and try to automate as many processes as you can.