Renovate: Fully automatic dependency updates

At Release Engineers, when we think we've seen it all when it comes to repositories, developers continue to surprise us. Teams move fast and manage lots of code, microservice projects grow to gigabytes of dependencies in no time at all. Dependencies can transform into technical debt, with some even becoming vulnerabilities and a few leading to production incidents. So what can we do? Dependabot and Renovate to the rescue! These tools keep dependencies up to date for us, but can become their own class of problem due to the volume of pull requests they generate:



The author's GitHub notifications. How many Dependabot PRs? Nobody knows; it stops counting at 1000.

Let's take a look at Renovate, with the idea of avoiding as much pull request noise as possible. Or if you'd like; Skip this guide, and check out the reference implementation on GitHub.

Abstract

This is a step-by-step process on how to get 100% fully automated dependency updates. Public dependencies will be automatically updated in your project's default branch after successfully passing checks that you define.

Check

Make sure you have the following ready:

  • A GitHub repository that you own.
  • A GitHub personal access token* with access to this repository.
  • Minimal familiarity with GitHub Actions.

* As of the time of writing, "Fine-grained (Beta)" tokens do not work for this guide. Please use "Classic" tokens.

Step 1: Validate with GitHub Actions

While Renovate can auto-merge changes, it still requires our input on whether those changes should be merged. For this purpose it can use status checks of GitHub Actions. We'll validate each commit made to the repository with a workflow by running our usual builds and tests. Ensure your project has a GitHub Actions workflow that runs on push events. (This can be existing CI.) Use the following as a template;

# .github/workflows/validate.yml
on:
  push:
    branches:
      - '**'

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Validate Dockerfile
        run: |
          # your CI commands go here; builds, tests, etc.

In our reference implementation:

Note that this workflow runs on every branch. You can choose to restrict this to only renovate/**, but we recommend treating changes by Renovate the same as you would any other change to your repository.

Step 2: Run Renovate

Renovate is available as a Node.js package which you can run locally from your favorite CLI using npx like so:

GITHUB_TOKEN="$(gh auth token)"
GITHUB_REPOSITORY=release-engineers/reference-renovate
GIT_AUTHOR="$(git config user.name) <$(git config user.email)>"

npx renovate --token "$GITHUB_TOKEN" \
    --onboarding=false \
    --dependency-dashboard=false \
    --git-author="$GIT_AUTHOR" \
    --branch-prefix='renovate/' \
    --semantic-commits=enabled \
    --require-config=optional \
    --automerge=true \
    --automerge-type=branch \
    --pr-creation='not-pending' \
    "${GITHUB_REPOSITORY}"

After executing this on our own reference implementation repository, we can see Renovate created a renovate/python-3.x which includes a single change.

Looks like it found a dependency, and updated it. Renovate can't merge it immediately as it requires our validation to kick off first. The moment this completes we can run Renovate a second time.

Step 3: Run Renovate Again

Upon completion of our validate workflow, the commit in GitHub receives a successful check;

This indicates to Renovate that the branch is ready to be merged. To try this out, we run the exact same Renovate script again. This will merge the renovate/python-3.x branch into the default branch (i.e. master, main) as shown:

The dependency update is complete. Renovate analyzed our dependencies, patched files where it should have, made changes on our behalf and even merged it upon seeing it was a success. Let's go one step further and schedule this Renovate script with GitHub Actions to ensure that this dependency remains up to date.

Step 4: Automate with GitHub Actions

Create a GitHub Actions secret in your repository named RENOVATE_GITHUB_TOKEN and set it to the GitHub API token you used to run Renovate. Next, create a GitHub Actions workflow to run the Renovate script on a schedule.

# .github/workflows/renovate.yml
on:
  schedule:
    - cron: '0 0 * * 0' # Every Sunday at 00:00
    - cron: '0 2 * * 0' # Every Sunday at 02:00
  workflow_dispatch:

jobs:
  test_schedule:
    runs-on: ubuntu-latest
    steps:
      - shell: bash
        env:
          LOG_LEVEL: debug
          TOKEN: ${{ secrets.RENOVATE_GITHUB_TOKEN }}
          GITHUB_REPOSITORY: ${{ github.repository }}
        run: |
          npx renovate --token "${TOKEN}" \
            --onboarding=false \
            --dependency-dashboard=false \
            --git-author='Philipp Gayret <philipp@release-engineers.com>' \
            --branch-prefix='renovate/' \
            --semantic-commits=enabled \
            --require-config=optional \
            --automerge=true \
            --automerge-type=branch \
            --pr-creation='not-pending' \
            "${GITHUB_REPOSITORY}"

Be sure to reference your own email, and your own GitHub Actions secret. This sets up GitHub Actions to run twice weekly; once to create update branches and commits, and a second time to merge the first successful commit. If you have a large amount of dependencies or repositories, you may want to consider running it more frequently. Note that you can also customize Renovate to bundle multiple updates into a single branch.

In our reference implementation:

  • This GitHub Actions workflow runs Renovate on a schedule.
  • We've added on.workflow_dispatch, so that the workflow can also be started manually.

Results

You now have a fully automated dependency update workflow. Renovate updates dependencies on a schedule and merges them into the default branch only when all checks pass. Your projects should now remain consistently up-to-date and well-maintained.

Thanks for reading!

Thinking big about dependencies? Don't hesitate to contact us.

Previous
Previous

GitHub API Tokens