Streamlining Software Dependency Management with Dependabot

Streamlining Software Dependency Management with Dependabot

Charly Laurent

Software development is a complex process that relies heavily on dependencies to provide essential functionality. However, managing these dependencies can be a significant challenge, as they require regular updates to fix bugs and security vulnerabilities. This can be a time-consuming and labor-intensive task for development teams. Fortunately, tools like Dependabot can help streamline the process and ensure that software dependencies are up-to-date and secure. This blog post will explore how we use Dependabot to manage our software dependencies. You'll see that Dependabot introduces new challenges that need to be addressed, and we want to share our solutions with you.

About Dependabot

Dependabot is an automated dependency management tool that helps developers keep their software projects up to date with the latest security patches and software updates. It was originally created as a standalone service and was later acquired by GitHub, which integrated it into its platform.

Dependabot according to Midjourney

Dependabot scans a project's dependencies and identifies outdated or vulnerable packages. It then automatically creates pull requests to update these dependencies to their latest versions, allowing developers to quickly and easily update their projects without manually reviewing and updating each package.

Setting up Dependabot is as easy as adding a dependabot.yml configuration file in your repository. The configuration file specifies the location of the manifest, or other package definition files, stored in your repository.

To give you an example, below is our configuration file:

version: 2
updates:
  - package-ecosystem: pip
    directory: "/"
    schedule:
      interval: daily
      time: "08:00"
      timezone: Europe/Paris
    open-pull-requests-limit: 10
    allow:
      - dependency-name: "*"
        dependency-type: "all"
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: daily
      time: "08:00"
      timezone: Europe/Paris

Dependabot uses this information to check for outdated dependencies. We rely on Dependabot to update our Python, JavaScript, and GitHub Actions dependencies.

When Dependabot identifies an outdated dependency, it creates a pull request to update the manifest to the latest version of the dependency. In our case, Dependabot can create up to 10 pull requests per manifest every morning.

Ordinarily, a developer would have to open each pull request, check that the tests pass, and merge it manually. This is a lot of work, especially on Python and JavaScript projects. For example, Dependabot has opened more than 50 pull requests on our main repository for the past week alone and more than 200 pull requests for the past month!

This can lead to pull request fatigue for a team. If a project has many dependencies or dependency updates are frequent, Dependabot may create many pull requests, which can be overwhelming for developers to review and merge.

Automatic Merge

The best solution to avoid pull request fatigue would be automatically merging Dependabot’s pull request. For this to work effectively, you need two things:

  1. a good test suite;
  2. a merge queue.

Updates to dependencies can sometimes create compatibility issues with other project parts, resulting in errors. However, having a reliable test suite that runs in your CI system can prevent such problems.

Even with a great test suite, you may still encounter issues merging multiple Dependabot pull requests. Passing the test suite on two pull requests separately does not guarantee they will pass when merged.

This is very important to understand: you cannot merge all your dependabot pull request in a single click without a merge queue.

Why You Need a Merge Queue

When merging dependency updates automatically in a software project, it's important to remember that even with a great test suite, issues may arise when merging multiple Dependabot pull requests. This is because passing the test suite on two pull requests separately does not guarantee they will pass when merged. Here are some reasons why:

  1. Conflicting dependencies: Two separate dependency updates might have conflicting requirements or incompatible versions. When the pull requests are merged together, the dependencies might not be compatible with each other, leading to issues in the software project.
  2. Order of merging: The order in which the dependency updates are merged might affect the outcome. One update might rely on another being in place or introduce a breaking change that causes issues with other dependencies.
  3. Interdependent functionality: The functionality of the updated dependencies might be interdependent, meaning that changes in one dependency might affect the behavior of another. The test suite might pass when tested separately, but these dependencies might cause issues or unintended consequences when combined.
  4. Test suite limitations: No test suite can cover all possible scenarios, especially regarding interactions between multiple dependencies. The test suite might not catch all potential issues, so even if each pull request passes the tests individually, issues could arise when merging them together.
What is a Merge Queue?
Do you happen to know the common point between the open-source Node.js and Rustprojects, the sporty social network Strava, the e-commerce company Shopify andthe ride-hailing company Uber? Their engineering team all rely on a merge queue. Well, if you never heard of such a concept, you might

This is where Mergify's Merge Queue comes in. It ensures that each pull request waits in line to be merged. Once a pull request is merged, the next one in line must pass the test suite again before being merged. You can also test multiple pull requests simultaneously, saving valuable CI time.

A simple Mergify configuration to merge Dependabot’s pull requests automatically looks like this.

queue_rules:
  - name: lowprio
    conditions:
      - check-success=test
    batch_size: 10
    batch_max_wait_time: 5min

pull_request_rules:
  - name: automatic merge from dependabot
    conditions:
      - check-success=test
      - author=dependabot[bot]
    actions:
      queue:
        name: lowprio

By configuring Mergify in this way, all of Dependabot's pull requests will be placed in the lowprio queue after passing the test suite. The queue will then test the merge of 10 pull requests with the main branch. If the tests are successful, all the pull requests are merged simultaneously. However, if the tests fail, Mergify will split the pull request batch until it finds the failing pull request.

The batch_max_wait_time parameter will add some time before starting a batch, allowing as many pull requests as possible to enter the queue.

The Rebase Hell

You might notice that Dependabot rebases all its pull requests once the first ones are merged, particularly on projects that use a lock file for their dependencies. Consequently, all the embarked pull requests leave the queue and their test procedure restart. The reason for this is the default rebase strategy of Dependabot. When Dependabot detects that one of its pull requests is in conflict, especially on the lock file, Dependabot rebases it.

Rebase Hell

What can you do about this? There are two possible solutions.

  1. Either you deactivate the default behavior. Dependabot allows you to deactivate it in the configuration file. You can then implement your own rebase strategy in case of conflict.
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    # Disable rebasing for npm pull requests
    rebase-strategy: "disabled"

2. Leverage the Mergify queue_branch_merge_method parameter. If set to fast-forward, Mergify will merge its test branch by merging the draft pull request it creates, instead of merging the original pull requests. The fast-forward method will preserve the commit tree, and Dependabot will not detect any conflict.

Our main branch before the fast-forward merge
Our main branch after the fast-forward merge

With this configuration, you don't have to worry about Dependabot anymore. Every Dependabot pull request is merged automatically without unnecessary CI run. As a developer, you have to check which Dependabot pull request remains at the end of the day. Those pull requests probably have failed the tests because of a breaking change in the dependency.

Demo video

Automate and Conquer: The Future of Dependency Management

In conclusion, harnessing the power of Dependabot and Mergify together can supercharge your software development process! Say goodbye to the days of manually reviewing and updating dependencies, and embrace the automation revolution.

Dependabot ensures your project stays up-to-date with the latest security patches and software updates, while Mergify's Merge Queue keeps your codebase tidy and conflict-free. Don't let dependency management bog down your team any longer; dive into this dynamic duo and watch your productivity soar.

Happy coding!