8 years ago
Automating iOS review tasks with Danger
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
Dangerfile
that 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
warn()
,fail()
,message()
. -
Once
Danger
completes 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
danger
where all the tasks/checks will be. - Each of these checks represents a ruby file. Its structure would be like this one:
require 'danger'
module Danger
module Checks
# This Danger step checks if the number of line is over a maximum value.
# In that case it warns the developer
class PRSize < Base
def initialize(dangerfile, max_lines)
@max_lines = max_lines
@dangerfile = dangerfile
end
def execute
@dangerfile.warn("This PR is over #{@max_lines} lines of code. Make it smaller or create multiple PRs.") if @dangerfile.lines_of_code > @max_lines
end
end
end
end
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,…:
require 'danger'
module Danger
module Checks
class Base
attr_accessor :dangerfile
def initialize(dangerfile)
@dangerfile = dangerfile
end
def execute
raise "-execute method must be overriden"
end
end
end
end
If you want to use
warn
,message
,fail
methods and environment variables you can access them from the @dangerfile attribute.
Then the structure of your Dangerfile
would look like this one:
Dir["./danger/*.rb"].each {|file| require file }
## Constants
MAX_PR_LINES = 500
PINGEABLE_RESOURCES = [
{ regex: /SoundCloud\/Classes\/Player/, username: "pepibumur", name: "Player"}
]
# Checks
Danger::Checks::PRSize.new(self, MAX_PR_LINES).execute()
Danger::Checks::IncludeSpecs.new(self).execute()
Danger::Checks::Todo.new(self).execute()
Danger::Checks::Ping.new(self, PINGEABLE_RESOURCES).execute()
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
.m
file includes unit tests. -
Todo: Checks if the developer forgot any
// TODO
somewhere 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.
Conclusion
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.