Using a local Renovate bot to manage Ansible collection dependencies
We wanted to use renovate bot to automatically update collection dependencies for one of our Ansible playbook repositories. This blog post describes the basics of renovate, how we configured it and how we actually run renovate locally.
Understanding renovate
As this was our first try of using renovate for dependency updates, we struggled to understand how renovate works and how it is configured.
Renovate is a bot that is able to scan multiple repositories for dependencies and create pull/merge requests with updated dependencies.
Configuration is split between a configuration for the bot and a local one for each repository.
So you basically have
One or more global configuration files that configure the bot (config.js) written in JavaScript or TypeScript
One configuration file per repository (renovate.json) written in JSON that contains local configuration options just for this repository.
Renovate is very flexible on how to structure the configuration. For more information see config-overview in the docs.
Renovate also supports multiple platforms, like GitHub, GitLab or Forgejo. For a complete list see renovate platforms.
The idea is that you run the bot once, it scans all configured repositories and creates pull requests in every repository with dependency updates.
If your projects are hosted on GitHub and you would like to use GitHub Actions for running renovate the straight forward solution is to follow Mend Renovate on GitHub Marketplace.
But we wanted more control and tried to
run renovate on a local machine. This should be migrated to a Job Template or Kubernetes CronJob later (might be worth another post)
use a private Automation Hub for hosting dependencies. So renovate should query collections on our Private Automation Hub for dependency updates
credentials should be made available via environment variables to the bot
Configuring and running renovate
As a first test we created a local bot configuration file config.js in our home directory. The GIT repository we used for testing is https://github.com/tosmi-ansible/aap-setup.
The first thing to be aware of is that the renovate bot by default always searches the repository configuration file (renovate.json) in the upstream repository. Changes to local files are ignored.
One way to avoid this is using --platform=local. This actually uses the local renovate.json file, but has the caveat that not all renovate functionality is available.
But in our case this was good enough as we just wanted to test AAP Hub authentication.
It is also helpful to run renovate with debugging enabled, this dumps the configuration currently used to STDOUT.
For example we had the following renovate.json config for testing:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:best-practices"
],
"timezone": "Europe/London",
"schedule": [
"at any time"
],
"packageRules": [
{
"matchDatasources": ["galaxy-collection"]
},
{
"matchDatasources": ["github-tags"],
"enabled": "false"
}
],
"hostRules": [
{
"matchHost": "aap.apps.hub.aws.tntinfra.net",
"token": "Token <the token>",
"authType": "Token-Only"
}
]
}But running renovate with LOG_LEVEL=debug set in the environment revealed the following settings:
DEBUG: Repository config (repository=tosmi-ansible/aap-setup)
"fileName": "renovate.json",
"config": {
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"]
}The configuration above is the configuration available in the remote GIT repository and not our local configuration.
| Renovate does not use a local renovate.json repository config by default. It always pulls the configuration from the remote repository except when you use _—platform=local. |
Furthermore renovate heavily relies on local caching. We wanted to test if renovate is using our hub token for connecting to the Hub, but we could not see any log entry in the AAP Hub container.
Renovate creates its cache files in a directory called baseDir. You can specify the location (and later wipe the cache) with the --base-dir option.
As we are using a self signed certificate in our AAP Hub test installation we had to specify NODE_TLS_REJECT_UNAUTHORIZED=0 to disable TLS verification.
To summarize our test configuration:
We used the following config.js global renovate configuration file:
module.exports = {
token: '<github token>',
platform: 'github',
onboardingConfig: {
extends: ['config:recommended'],
},
//repositories: ['tosmi-ansible/aap-setup'], (1)
};| 1 | Repository listing is not allowed when using --platform=local |
In the repository where we want to test automatic dependency updates we used the following renovate.json configuration:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:best-practices"
],
"timezone": "Europe/London",
"schedule": [
"at any time"
],
"packageRules": [
{
"matchDatasources": ["galaxy-collection"]
},
{
"matchDatasources": ["github-tags"],
"enabled": "false" (1)
}
],
"hostRules": [
{
"matchHost": "aap.apps.hub.aws.tntinfra.net",
"token": "Token <the token>",
"authType": "Token-Only"
}
]
}| 1 | We disabled GitHub tag lookup explicitly as renovate would find some of our dependencies on GitHub |
This is our collections/requirements.yaml file with a test dependency:
roles:
collections:
- name: kubernetes.core
version: 6.3.0
source: https://aap.apps.hub.aws.tntinfra.net/api/galaxy/content/rh-certified/On our AAP Private Automation Hub we had kubernetes.core version 6.4.0 available.
So to run and test renovate locally we used the following command line:
NODE_TLS_REJECT_UNAUTHORIZED=0 LOG_LEVEL=debug RENOVATE_CONFIG_FILE=~/config.js renovate --platform=github --repository-cache=disabled --base-dir=/tmp/cacheSecret management and configuration cleanup
The next step is to remove the hard-coded tokens from our configuration. We wanted to use environment variables, as this allows us to run renovate as:
A Kubernetes CronJob with a Pod. We could inject the token via a Secret
As a job template within AAP with tokens stored as AAP credentials or
A normal Unix cron job with environment variables set
As the global renovate configuration config.js is written in JavaScript we could leverage process.env to retrieve required tokens from environment variables.
Here is our modified config.js:
module.exports = {
platform: 'github',
onboardingConfig: {
extends: ['config:recommended'],
},
// repositories: ['tosmi-ansible/aap-setup'], (1)
secrets: {
AAP_HUB_TOKEN: process.env.AAP_HUB_TOKEN, (2)
},
hostRules: [
{
matchHost: "aap.apps.hub.aws.tntinfra.net",
token: "{{ secrets.AAP_HUB_TOKEN }}", (3)
authType: "Token" (4)
},
],
};| 1 | We disable repository listing for --platform=local. Otherwise renovate will raise an error. |
| 2 | We define a new secret AAP_HUB_TOKEN and read the value from the environment variable AAP_HUB_TOKEN |
| 3 | We use the secret as our token for authenticating to AAP Hub |
| 4 | The authType setting is a little bit special, see the following section |
For GitHub authentication renovate expects a GitHub token in the environment variable RENOVATE_TOKEN.
A few words about the authType setting. AAP Hub requires the following authorization header in the HTTP request for authentication:
Authorization: Token <the token>With renovate we have two options to achieve this:
Either set authType to "Token-Only" and specify the token as "Token <the token>". So with token-only renovate takes the token string verbatim
Or set the authType to the string we would like to prepend to the token as we did
We had to dig into the source code of renovate to understand how it functions.
And here is the renovate.json repository configuration that we used:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:best-practices"
],
"timezone": "Europe/London",
"schedule": [
"at any time"
],
"packageRules": [
{
"matchDatasources": ["galaxy-collection"]
},
{
"matchDatasources": ["github-tags"],
"enabled": "false"
}
]
}You could also move the hostRules to the repository local renovate.json file and still use secrets.AAP_HUB_TOKEN, but as this is going to be our global configuration for Ansible code base covering multiple repositories our current idea is to store the authentication in the global configuration.
To set the required environment variables containing our secrets we execute
$ export AAP_HUB_TOKEN=$(pass show other/ansible/aws-aap-tokens | awk '/hub/ {print $2}') (1)
$ export RENOVATE_TOKEN=$(pass show other/github/tosmi-rw-token | awk '/token/ {print $2}')| 1 | We use the pass utility for secret management. |
Integration with GitHub
So the last step is to store everything (the global and local configuration) on GitHub.
For the global repository we created the tosmi-ansible/renovate-config repository.
Here is our final config.js global configuration file in this repository:
module.exports = {
platform: 'github',
gitAuthor: "Renovate Bot <renovate-bot@stderr.at>",
dryRun: null,
onboardingConfig: {
extends: ['config:recommended'],
},
repositories: ['tosmi-ansible/aap-setup'], (1)
secrets: {
AAP_HUB_TOKEN: process.env.AAP_HUB_TOKEN,
},
hostRules: [
{
matchHost: "aap.apps.hub.aws.tntinfra.net",
token: "{{ secrets.AAP_HUB_TOKEN }}",
authType: "Token"
},
],
};| 1 | This time we tell renovate which repositories it should scan. |
The default configuration default.json, also stored in the global repository:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:best-practices"
],
"timezone": "Europe/London",
"schedule": [
"at any time"
],
"enabledManagers": ["ansible", "ansible-galaxy"], (1)
"packageRules": [
{
"matchDatasources": ["galaxy-collection"]
},
{
"matchDatasources": ["github-tags"],
"enabled": "false"
}
]
}| 1 | We only enable ansible and ansible-galaxy managers. Otherwise renovate would search for various other sources for dependencies. |
tosmi-ansible/aap-setup contains our local configuration:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"tosmi-ansible/renovate-config",
"config:best-practices"
]
}This only contains a reference to our global configuration and we would like to use the best-practices preset.
We can now run renovate from the renovate-config repository and it will scan the configured repository and create a pull request with updated dependencies if required.
$ git clone git@github.com:tosmi-ansible/renovate-config.git
$ cd renovate-config
$ NODE_TLS_REJECT_UNAUTHORIZED=0 renovate --platform=github --base-dir=/tmp/renovate-cache (1)| 1 | We still need to set NODE_TLS_REJECT_UNAUTHORIZED to 0, because our AAP Hub instance uses a private certificate |
One minor issue that we discovered is that if a pull request for an update already existed (even a closed one) Renovate would not open a new one. If you run renovate with LOG_LEVEL=debug you will see the following message:
DEBUG: Closed PR #19 already exists. Skipping branch. (repository=tosmi-ansible/aap-setup, branch=renovate/kubernetes.core-6.x)
"prTitle": "Update dependency kubernetes.core to v6.4.0"To convince Renovate to create a new pull request just rename the closed pull request on GitHub. We just added the prefix "RENAMED". After renaming the pull request, renovate will happily create a new one.
Tips and tricks
This section list various things we learning while running renovate locally
Renovate does not honor new dependencies in requirements.yaml
We had an issues with new dependencies in requirements.yaml. Wiping the renovate cache (/tmp/renovate_cache) in our case fixed this and renovate created new pull requests for the added dependencies.
Renovate does not open new PR (pull requests) for updated dependencies
We double checked AAP and our renovate configuration and there was clearly a newer version of a collection but renovate just did not open a new PR.
Running renovate with LOG_LEVEL=debug revealed the following message (we tried to update the redhat.openshift_virtualization collection):
{
"branchName": "renovate/redhat.openshift_virtualization-2.x",
"prNo": null,
"prTitle": "Update dependency redhat.openshift_virtualization to v2.2.4",
"result": "branch-limit-reached", (1)| 1 | renovate does not open a new branch because of "branch-limit-reached" |
We check our upstream repository on GitHub and there was just the main branch, hm…
Looking further up in the log we found:
DEBUG: prHourlyLimit of the upgrades present in this branch (repository=tosmi-ansible/aap-setup, branch=renovate/infra.aap_utilities-3.x)
"limits": [{"depName": "infra.aap_utilities", "prHourlyLimit": 2}]
DEBUG: Calculated lowest prHourlyLimit among the upgrades present in this branch is 2. (repository=tosmi-ansible/aap-setup, branch=renovate/infra.aap_utilities-3.x)
DEBUG: Hourly PRs limit reached (repository=tosmi-ansible/aap-setup, branch=renovate/infra.aap_utilities-3.x) (1)
"hourlyPrCount": 2,
"hourlyPrLimit": 2
DEBUG: Reached branch limit - skipping branch creation (repository=tosmi-ansible/aap-setup, branch=renovate/infra.aap_utilities-3.x)| 1 | There is a hourly branch limit of two in place |
As we just ran renovate to update another dependency, we seem to be hitting this hourly limit. The docs mention a default of 2.
The solution was to run renovate with the option --pr-hourly-limit=0:
NODE_TLS_REJECT_UNAUTHORIZED=0 renovate --platform=github --base-dir=/tmp/renovate-cache --pr-hourly-limit=0Copyright © 2020 - 2026 Toni Schmidbauer & Thomas Jungbauer



Discussion
Comments are powered by GitHub Discussions. To participate, you'll need a GitHub account.
By loading comments, you agree to GitHub's Privacy Policy. Your data is processed by GitHub, not by this website.