* test(versioning/aws-machine-image): cover the empty version guard `_parse()` returns null for a falsy version before it tries the AMI id regex, and no test passed one. Checking that an empty string is not valid closes the only branch the module was missing. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(datasource/buildpacks-registry): cover a response without a homepage `latest.homepage` is optional in the registry response, but every test supplied one, so the release result was never built without it. A buildpack whose latest entry carries no homepage now checks that the releases still come back and no source url is derived. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(datasource): cover optional-field branches in four datasources Each of these datasources builds its release result by attaching fields only when the registry supplies them, and the "not supplied" path was never exercised: - cdnjs: a library with neither homepage nor repository - cpan: a search result where no release is marked latest, so no tag - dart: a latest release carrying no pubspec - ruby-version: a release table row whose first column is not a version Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(datasource): cover missing-metadata branches in hex and pypi Two more datasources only attached fields when the registry supplied them, and the absent case was untested: a hex package with neither an html_url nor a github link in its meta, and a pypi response carrying no releases at all. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(datasource): cover galaxy and repology fallbacks, mark unreachable guards Adds a galaxy role with empty github fields, so no source url is derived, and a repology lookup where the api fallback after a 403 finds no matching package. Marks four guards that are not worth a test: cpan and dart both check a variable that is only null when the request threw, and `handleGenericErrors()` always rethrows; conan's registry url is always supplied by the datasource layer; and repology's resolver either returns a body or throws. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(datasource): cover pod CDN branches, mark the sbt listing guards Adds two pod lookups: an empty CDN body, and a CDN index that lists no matching pod. Marks the guards whose tests would need multi-level directory listing fixtures: both sbt datasources walk nested index pages, and pod's github helper checks a body that an empty json response never produces because parsing throws first. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(datasource): cover maven metadata without a latest tag Adds maven metadata carrying a release but no latest, so respectLatest is left alone. Marks the three deb guards, which would each need a crafted package index: a block missing a required key, a repeated package in the final block, and two component indexes whose meta agrees. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * test(datasource): cover npmrc registry fallback, mark cache-bound guards Adds a resolveRegistryUrl lookup for a package no npmrc rule matches. Marks the guards whose tests would need a primed cache or a specific blob shape: nuget's services index, deno's release cache, the docker hub cache window, docker's manifest and config handling, go's pseudo-version fallback, and both rubygems cache layers. Three implicit elses are left counted: a coverage-ignore hint does not attach to an `else if`, so the registry strategy chain, the npmrc reset and docker's digest-header branch carry a plain note instead. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> * fix(datasource/repology): pass the mock body as a string `ResponseMock.body` is typed as a string, and every other call in the spec passes `'[]'`. The new api fallback test passed an array literal, which tsc rejected. Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io> --------- Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
Maven Central rate limiting and caching
Maven Central, hosted by Sonatype, receives a very large number of requests and has implemented rate limiting measures to manage organizational overconsumption. If you're experiencing 429 (rate limited) responses from Maven Central, you may need to optimize your caching strategy.
Renovate includes Maven caching optimizations, but they rely on having a persistent datasource cache. By default, Renovate uses a file-based cache, which means:
- Persistent environments (like self-hosted runners with persistent storage) will benefit from cross-run caching
- Ephemeral environments (like GitHub Actions or other CI/CD with fresh containers each run) won't benefit from caching across runs
To maximize caching effectiveness and reduce Maven Central requests:
- Use Redis for persistent caching: Configure a Redis instance for your Renovate datasource cache
- Ensure cache persistence: If using file-based caching, ensure the cache directory persists between Renovate runs
- Monitor rate limit warnings: Renovate will log warnings when receiving 429 responses from Maven Central
If you continue to experience rate limiting issues after implementing persistent caching, you may need to:
- Reduce the frequency of Renovate runs
- Consider using a Maven repository proxy with its own caching layer
!!! note
Dependencies that appear to be Gradle plugins (where the groupId or artifactId ends with .gradle.plugin) will not be looked up in Maven Central.
Making your changelogs fetchable
In case you are publishing artifacts and you want to ensure that your changelogs are fetchable by Renovate, you need to configure the scm section on their pom.xml file.
For example:
<scm>
<url>scm:git:https://github.com/path_to_repository</url>
</scm>
This is what allows Renovate to determine the sourceUrl, that it then uses to fetch the changelogs.
!!! note
This also works for private repositories.
It can leverage the same token that you had to configure in order to be able to reach the private Artifactory.
Specifying your project homepage
When opening a Pull Request Renovate uses the top level url property to determine the homepage of your project and shows it inside the Pull Request.
To customize you can set it inside your pom.xml.
For example:
<url>https://project.example.com</url>
latest and release tags
When latest or release values are present in a package's maven-metadata.xml, Renovate will map these to its tags concept.
This enables the use of Renovate's followTag feature.
However, Renovate will set respectLatest=false whenever the latest tag is found, because many Maven registries have been found to populate the tag unreliably.
You should use packageRules to set respectLatest=true if you wish to use this feature.