DEV Community

Cover image for Automating merge request reviews with Danger on GitLab
Yoriiis
Yoriiis

Posted on • Edited on

Automating merge request reviews with Danger on GitLab

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 if package.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.

Danger review comment on a merge request


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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

To ensure that Danger has access to your entire GIT repository history, with GitLab it is best to override the settings GIT_STRATEGY and GIT_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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
  )
}
Enter fullscreen mode Exit fullscreen mode

💡 To simplify version upgrades in the danger repository, use branch names like v1 instead of main. This allows multiple versions, such as v1 and v2, 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

Resources


Top comments (1)

Collapse
 
gromnan profile image
Jérôme TAMARELLE

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.