---
# System prepended metadata

title: Using Renovate for automatic dependency version upgrades
tags: [sharing]

---

# Using Renovate on Azure DevOps for automatic Nuget packages version upgrades

# Overview

[Renovate Bot](https://docs.renovatebot.com/) is an automated tool that helps keep software dependencies up to date. It scans repositories, detects outdated dependencies, and creates pull requests to update them, reducing the risk of security vulnerabilities and compatibility issues. Renovate supports multiple package managers, integrates with platforms like GitHub and GitLab, and offers customization options for scheduling and update rules.

In this article, we will focus on integrating Renovate bot to Azure DevOps services for Nuget packages upgrade.

# Setup Renovate Bot

Despite of lacking some [features](https://docs.renovatebot.com/faq/#major-platform-features-not-supported-by-renovate) on Azure DevOps, Renovate is still well integrated and is a wonderful choice for the dependency upgrades use case, compares to other options like [Dependabot](https://github.com/dependabot) (mostly tied to Github)

The official doc for integrating Azure DevOps can be found [here](https://docs.renovatebot.com/modules/platform/azure/), but it's a bit ambigious and confusing to follow. In the next sections, we will walk through a detail implementation and production ready configuration of Renovate bot.

## Prepare Azure Pipelines for running Renovate

The initial step is defining a place to store Renovate config and pipeline definition, we can create a new repo in Azure Repos, in my case, I will call it: `Tools_Pipeline_Renovate-DependencyUpgrader`

### Creating Azure DevOps PAT
This is a mandatory step for authorizing Renovate to work. In general, you must create a PAT with these permissions:
- Code (Read & Write)
- Packaging (read) - in case you use the private feed from Azure Artifacts

![image](https://hackmd.io/_uploads/SyKYfgrFyl.png)


### Grant permission for pipeline

Make sure that the "Project Collection Build Service (YOUR-PROJECT)" user has the following permissions on the repositories:

- Contribute
- Contribute to pull requests
- Create branch
- Read

### Define the pipeline

For Azure DevOps, Renovate can either run on Azure Pipelines or [self-hosted](https://docs.renovatebot.com/examples/self-hosting/) depending on your use case. Anyways, for some small, mid size organizations, running it on Azure Pipelines is sufficient.

Below is the pipeline definition for running Renovate

```yaml
schedules:
  - cron: '45 1 * * 1-5'
    displayName: 'Every weekday at 1:45 AM (UTC) - 8:45 AM GMT+7'
    branches:
      include: [master]
    always: true
  - cron: '45 5 * * 1-5'
    displayName: 'Every weekday at 5:45 AM (UTC) - 12:45 PM GMT+7'
    branches:
      include: [master]
    always: true

trigger: none

pool:
  vmImage: ubuntu-latest

steps:
  - task: NuGetToolInstaller@1
    displayName: 'Use NuGet 6.12'
    inputs:
      versionSpec: 6.12

  - task: NuGetAuthenticate@1
    displayName: 'NuGet Authenticate'
    inputs:
      forceReinstallCredentialProvider: true

  - task: UseNode@1
    inputs:
      version: '20.x'

  - powershell: |
      git config --global user.email 'renovate-bot@gmail.com'
      git config --global user.name 'renovate'
      npx renovate
    env:
      GITHUB_COM_TOKEN: $(GITHUB_COM_TOKEN)
      RENOVATE_PLATFORM: azure
      RENOVATE_ENDPOINT: $(System.CollectionUri)
      RENOVATE_TOKEN: $(RENOVATE_TOKEN)
      RENOVATE_BASE_DIR: $(Agent.TempDirectory)
      LOG_LEVEL: debug

```

We will break down the detail and configuration of this pipeline:
- The job is scheduled (cron) daily before work and at lunch time so the developers will not be disturbed with a bunch of PR notifications, the PRs will be ready as soon as the developers come back to work, 15 minutes is sufficient for an organization with less than 50 repositories
- The Nuget tasks are used to authenticate and install needed packages for working with Nuget
- Renovate uses many different environment variables for configuring it's behavior:
    - [GITHUB_COM_TOKEN](https://docs.renovatebot.com/getting-started/running/#githubcom-token-for-changelogs) is used for fetching changelog of packages from Github
    - RENOVATE_PLATFORM for specifying the platform Renovate running on.
    - RENOVATE_ENDPOINT can be override for self hosted servers
    - RENOVATE_TOKEN is the PAT we've created above, the token will be used for fetching repos

## Configure Renovate

Renovate has a well written [documention](https://docs.renovatebot.com/config-overview/) and detail explaination for configuration options. They also includes many different kind of [presets](https://docs.renovatebot.com/config-presets/) for pre made recommended and best-practies configuration, we will use the best-practices preset in this article.

Below is the sample configuration for Renovate with Nuget packages, written in `config.js`

```javascript
module.exports = {
    hostRules: [
        {
            hostType: 'nuget',
            matchHost: 'https://pkgs.dev.azure.com/',
            username: 'nuget',
            password: process.env.RENOVATE_TOKEN
        }
    ],
    extends: [
        "config:best-practices"
    ],
    repositories: [
        '<PROJECT>/<REPO NAME>'
    ],
    enabledManagers: [
        'nuget'
    ],
    packageRules: [
        {
            groupName: 'dotnet-sdk',
            description: 'Enable non-major updates for .NET SDK and runtime (global.json)',
            matchPackageNames: [
            'dotnet-sdk',
            'mcr.microsoft.com/dotnet/sdk',
            'mcr.microsoft.com/dotnet/aspnet',
            'mcr.microsoft.com/dotnet/runtime',
            'mcr.microsoft.com/dotnet/runtime-deps'
            ],
            extends: [
            ':disableMajorUpdates',
            ':pinDigestsDisabled'
            ],
        },
        {
            groupName: "all-minor-and-patch-updates",
            description: "Group all minor and patch updates together",
            matchUpdateTypes: ["minor", "patch"],
            groupSlug: "minor-and-patch-updates"
        },
        {
            matchUpdateTypes: ["major"],
            separateMajorReleases: true
        }
    ],
    gitAuthor: "renovate <renovate-bot@gmail.com>",
    prHourlyLimit: 3,
    prConcurrentLimit: 3,
    nuget: {
        registryUrls: [
            "https://api.nuget.org/v3/index.json",
            "https://pkgs.dev.azure.com/<ORGANIZATION>/<PROJECT>/_packaging/<feed name>/nuget/v3/index.json"
        ]
    },
    additionalReviewers: ["Dependencies Upgrade Reviewers"],
    commitMessageAction: "Renovate daily update"
};

```

We will walk through the configuration mentioned in the file
- `hostRules` for authenticating with private feeds if needed
- The `config:best-practices` preset is used, this [preset](https://docs.renovatebot.com/presets-config/#configbest-practices) includes many different built in configs from Renovate
- Nuget package manager is enabled in this config
- The `packageRules` config defines groups of packages that will be upgraded, let's break them down:
    - The first group `dotnet-sdk` specifies packages related to dotnet SDK, these packages will be upgraded separately from other packages, within the same branch or PR
    - By default, for each dependency, Renovate will create a branch and PR for upgrading them. The `all-minor-and-patch-updates` group is useful for grouping all the minor and patch updates of every packages, this will reduce the number of PRs and branches created.
    - The last config separate the major upgrade of each dependency, this config makes the PRs easier to review, with one major upgrade per PR
- `prHourlyLimit` and `prConcurrentLimit` are for rate limiting the number of PRs created
- `nuget` block is dedicated for Nuget PM configuration, in this case, we are fetching packages from the public Nuget API and our private feed inside Azure Artifacts
- `additionalReviewers` adds optional groups or users to PRs reviewers, we can have on-call/rotation mechanism for developers to review the PRs.
- `commitMessageAction` overrides default PR title, easier for filtering PR names.

This is the file structure after finishing configurating

![image](https://hackmd.io/_uploads/S1tGrgrFJx.png)


# Running Renovate

After everything is ready, we can create a new pipeline from the pipeline definition above. 

![image](https://hackmd.io/_uploads/SJP87gBKye.png)

The first pipeline run will create onboarding PRs on the repos in `config.js`. This PR will add a file name `renovate.json` to the target repository, by default, this file will only contains the link to the schema for Renovate config. You can add repo-local config to this file.

![image](https://hackmd.io/_uploads/r1ZTXgSYke.png)

After merging the onboarding repo. Next runs of Renovate pipeline will create PRs for upgrading the packages. Done!

![image](https://hackmd.io/_uploads/BJIKEeStJg.png)

![image](https://hackmd.io/_uploads/ryepNgBt1e.png)


# Conclusions
We have successfully implemented Renovate across all 50 of our repositories, including internal libraries and core services. So far, everything has been running smoothly, with automated dependency updates significantly streamlining our workflow. While we still need to manually review changelogs and pull requests to ensure compatibility and stability, Renovate has greatly reduced the time and effort required for upgrading packages. By automating version checks and update processes, it has helped us maintain up-to-date dependencies, minimize security risks, and ensure our codebase remains maintainable.

