As developers, we spend a lot of time writing code, but also reviewing it, particularly during code review phases between teams.
Sometimes, certain comments are repetitive and could be automated to save developers time. Furthermore, just like unit tests that check our code, we could add tests that check merge requests content (metadata or GIT changes).
This is where Danger comes in. The same tool GitLab itself uses in its open-source projects.
What is Danger
Danger is a tool to automate code review tasks, available on several source code management like GitHub, GitLab or BitBucket.
First, you define rules in a configuration file that run in CI process. Then, when a merge request is created or updated, Danger analyzes the changes and posts comments with warnings or errors into the merge request.
There are two main versions of Danger, Ruby and JavaScript, see Which Danger should I use.
At Prisma Media, we have chosen the Ruby version because it is more mature and stable, and because we wanted to draw inspiration from the configuration files used by the GitLab teams. There is no point in reinventing rules, especially if some of them work within a project as important and global as GitLab.
Danger can perform several types of actions, such as:
- Checking changes made to a specific file (GIT changes)
- Checking merge request metadata (title, assignee, reviewer, label, etc.)
- Using the platform's API directly to extend its scope
See details about Danger reference.
Our Danger rules
To ease adoption, we began by adding a simple rule to every project: checking the CHANGELOG. Because updating the CHANGELOG was sometimes forgotten or incorrectly formatted. A simple, automated rule made this process more reliable and encouraged the use of Danger.
Over time, we added more rules, focusing on recurring feedback that could be automated with Danger.
Here are some examples of the rules we have in place.
- Merge request title must contain a Jira ticket
- Merge request title should be less than 72 characters
- Merge request must have assignees
- Merge request must have reviewers if marked as ready
- Filenames and directories must not contain uppercase letters or underscores
- Changelog must be updated and contain a link to the merge request
- Unit tests should be updated if
.js
,.ts
,.tsx
files are modified -
package-lock.json
should be updated ifpackage.json
changes
Depending on your requirements, the rules can be a warning or an error if you want the job to fail. Exceptions can also be added, for example if the change is trivial or concerns a part of the code that does not require a new version, the rule is skipped.
We also pay particular attention to the wording of Danger's messages to ensure they are easy to understand.
In addition, if at least one comment has been created, a link allowing Danger to be replayed is displayed. This is very useful if, for example, the feedback concerns metadata from the merge request that can be corrected with just a retry on the job.
At Prisma Media, we call our Danger review bot Alfred.
GitLab CI integration
Create a Dangerfile
at the root of the repository. The rule will analyze the metadata of the merge request.
if gitlab.mr_json['title'].length > 72
warn 'Merge request title should be less than 72 characters.'
end
if gitlab.mr_json['assignees'].empty?
fail 'Merge request must have assignee(s).'
end
Then, add a job danger-review
in the .gitlab-ci.yaml
file
danger-review:
image: ruby:3.3.0
variables:
GIT_STRATEGY: fetch
GIT_DEPTH: 0
script:
- gem install danger --version 9.5.1
- gem install danger-gitlab --version 8.0.0
- danger --verbose --fail-on-errors=true --dangerfile=Dangerfile
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
To ensure that Danger has access to your entire GIT repository history, with GitLab it is best to override the settings
GIT_STRATEGY
andGIT_DEPTH
.
The job rules above is important to limit the execution of Danger to merge request pipelines. Because if you run it on a branch pipeline, you could end up in a scenario where the job runs even though the merge request does not yet exist, which would skip the job even though there may be feedback. See details for merge request pipeline.
Authentication
For Danger to comment on merge requests, the pipeline needs a token to perform actions on the merge request.
Create a Project Access Tokens with the API scope, Developer permission, and no expiration date. Add the token as a CI/CD project variable named DANGER_GITLAB_API_TOKEN
.
Use CI and Danger as templates
To simplify deployment across multiple projects, CI templates and Danger rules can be hosted in a dedicated repository and imported into consumer projects. This keeps the code centralized and lets it evolve independently.
Create a repository named danger
with the following structure:
ci/
danger-review.yaml
danger/
changelog
Dangerfile
README.md
metadata/
Dangerfile
README.md
Each Danger rule is stored into a dedicated directory with its own documentation.
Transform the danger-review
job above into a template CI with variables for personalization.
ci/danger-review.yaml
.danger-review:
image: ruby:3.3.0
variables:
CONFIG_PATH: 'Dangerfile'
GIT_STRATEGY: fetch
GIT_DEPTH: 0
script:
- gem install danger --version 9.5.1
- gem install danger-gitlab --version 8.0.0
- danger --verbose --fail-on-errors=true --dangerfile=${CONFIG_PATH}
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
Create the Danger rules for the changelog.
danger/changelog/Dangerfile
files = (git.added_files + git.modified_files)
if files.include?('CHANGELOG.md')
diff = git.diff_for_file('CHANGELOG.md')
unless diff.patch.include?("[##{gitlab.mr_json["iid"]}](#{gitlab.mr_json["web_url"]})")
fail 'Changelog entry must include the merge request link.'
end
else
fail '"CHANGELOG.md" file is missing in GIT diff, version needs to be bump.'
end
Create the Danger rules for the metadata.
danger/metadata/Dangerfile
if gitlab.mr_json['title'].length > 72
warn 'Merge request title should be less than 72 characters.'
end
if gitlab.mr_json['assignees'].empty?
fail 'Merge request must have assignee(s).'
end
In a consumer project, import the CI template created above.
.gitlab-ci.yaml
include:
- { project: 'danger', file: '/ci/danger-review.yaml', ref: 'main' }
danger-review:
extends: .danger-review
Import the Danger rules into our root Danger file.
Dangerfile
dangerfiles = [
'changelog',
'metadata'
]
dangerfiles.each { |file|
danger.import_dangerfile(
gitlab: 'danger',
branch: 'main',
path: "danger/#{file}/Dangerfile"
)
}
💡 To simplify version upgrades in the
danger
repository, use branch names likev1
instead ofmain
. This allows multiple versions, such asv1
andv2
, to be maintained in parallel.
Each project can still create specific rules for its own needs by adding them to its local Dangerfile
.
Conclusion
Using Danger in CI has dramatically improved merge request quality and consistency across our projects:
- Feedback appears directly in merge request threads
- Rules are reusable, documented, and shared across multiple projects
- Teams spend less time checking trivial issues
- Custom project-specific rules are easy to implement
Formulating messages clearly is key. A well-written warning or error guides developers without frustration. With the retry feature and merge request pipelines, the process becomes smooth and almost mandatory.
If your team hasn't tried Danger yet, it's worth exploring. You can start small, automate common rules, and expand gradually to cover project-specific needs.
The complete example is available on GitHub for you to try out! 🧑💻
Discover Danger Review on GitHub
Top comments (1)
Nice tool!
Instead of reinstalling the ruby gems on every job run, you should use the gitlab cache or a docker image with all the dependencies pre-installed. That saves bandwidth, server resources for ruby gems and speedups the jub run.