Conversation
WalkthroughUpdates the Error Prone version in gradle/libs.versions.toml (errorProne -> 2.45.0) and adds an errorProneJdk17 version entry (2.42.0). Adds a Gradle ext property and a new configuration/task ( Possibly related issues
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1401 +/- ##
=========================================
Coverage 88.19% 88.19%
Complexity 2616 2616
=========================================
Files 95 95
Lines 8675 8675
Branches 1743 1743
=========================================
Hits 7651 7651
Misses 510 510
Partials 514 514 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (5)
build.gradlebuildSrc/src/main/groovy/nullaway.java-test-conventions.gradlegradle/libs.versions.tomljmh/build.gradlenullaway/build.gradle
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-14T18:50:06.159Z
Learnt from: msridhar
Repo: uber/NullAway PR: 1245
File: guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java:101-102
Timestamp: 2025-08-14T18:50:06.159Z
Learning: In NullAway JSpecify tests, when JDK version requirements exist due to bytecode annotation reading capabilities, prefer failing tests over skipping them on unsupported versions to ensure CI catches regressions and enforces proper JDK version usage for developers.
Applied to files:
nullaway/build.gradlejmh/build.gradlebuildSrc/src/main/groovy/nullaway.java-test-conventions.gradle
📚 Learning: 2025-10-09T19:59:16.543Z
Learnt from: msridhar
Repo: uber/NullAway PR: 1243
File: jdk-annotations/astubx-generator/build.gradle:22-22
Timestamp: 2025-10-09T19:59:16.543Z
Learning: When disabling testJdk17 tasks for modules requiring JDK 21, use `onlyIf { false }` to skip the task:
```gradle
tasks.named("testJdk17").configure {
onlyIf { false }
}
```
Do not use `doFirst { throw new GradleException(...) }` as it will cause CI failures when the task is executed.
Applied to files:
jmh/build.gradlebuildSrc/src/main/groovy/nullaway.java-test-conventions.gradle
🔇 Additional comments (7)
build.gradle (1)
40-43: LGTM! Version constant properly exposed.The new
errorProneJdk17Versionext property follows the established pattern and correctly sources the version from the catalog, making it available to subprojects for JDK 17-specific Error Prone testing.nullaway/build.gradle (1)
85-87: LGTM! Dependency properly addresses transitive conflicts.The addition of JetBrains annotations to the
errorProneJdk17configuration is well-documented and prevents version conflicts during JDK 17 testing.jmh/build.gradle (1)
147-151: LGTM! Task correctly disabled for JMH module.The use of
onlyIf { false }properly skips the JDK 17 test task for the JMH module, which requires the latest Error Prone version. This approach aligns with established patterns.Based on learnings, this is the correct way to disable tasks without causing CI failures.
gradle/libs.versions.toml (1)
20-21: LGTM! Version catalog properly updated.The version updates correctly implement the dual-version strategy: Error Prone 2.45.0 for main builds (requiring JDK 21+) and 2.42.0 for JDK 17 testing.
buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle (3)
47-58: LGTM! Configuration properly set up for JDK 17 testing.The
errorProneJdk17configuration and dependencies are correctly wired to support testing with Error Prone 2.42.0 on JDK 17.
81-81: LGTM! Loop correctly adjusted to prevent task duplication.Removing JDK 17 from the loop prevents conflict with the dedicated
testJdk17task created below, while maintaining test coverage on JDK 25.
137-139: LGTM! Check task properly wired to include JDK 17 tests.The dependency ensures JDK 17 tests run as part of the standard verification workflow.
| // Create a task to test with JDK 17 and the supported version of Error Prone for that JDK | ||
| def epJdk17Test = tasks.register("testJdk17", Test) { | ||
| javaLauncher = javaToolchains.launcherFor { | ||
| languageVersion = JavaLanguageVersion.of(17) | ||
| } | ||
|
|
||
| description = "Runs the test suite using the oldest supported version of Error Prone" | ||
| group = LifecycleBasePlugin.VERIFICATION_GROUP | ||
|
|
||
| // Copy inputs from normal Test task. | ||
| def testTask = tasks.getByName("test") | ||
| // A bit of a hack: we add the dependencies of the JDK17-supporting Error Prone version to the _beginning_ of the | ||
| // classpath, so that they are used instead of the latest version. This exercises the scenario of building | ||
| // NullAway against the latest supported Error Prone version but then running on JDK 17. | ||
| classpath = configurations.errorProneJdk17 + testTask.classpath | ||
|
|
||
| testClassesDirs = testTask.testClassesDirs | ||
|
|
||
| jvmArgs += [ | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", | ||
| "--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", | ||
| "--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED", | ||
| // Accessed by Lombok tests | ||
| "--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED", | ||
| ] | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Clarify task description to reflect JDK 17 compatibility purpose.
The task description (line 109) states "oldest supported version of Error Prone" but actually uses the JDK 17-compatible version (2.42.0), not the oldest version (2.14.0, used by testErrorProneOldest). The description should clarify this distinction.
🔎 Proposed description fix
- description = "Runs the test suite using the oldest supported version of Error Prone"
+ description = "Runs the test suite on JDK 17 using Error Prone ${errorProneJdk17Version}"🤖 Prompt for AI Agents
In buildSrc/src/main/groovy/nullaway.java-test-conventions.gradle around lines
103 to 135, update the task description to accurately state that this task runs
the test suite with the JDK 17-compatible Error Prone version (used to exercise
running on JDK 17) rather than claiming it uses the "oldest supported version of
Error Prone"; change the description string to mention JDK 17 compatibility
(e.g., "Runs the test suite using the Error Prone version compatible with JDK
17") so it clearly distinguishes this task from the one that runs the oldest
Error Prone version.
NullAway has no automated dependency updates. Several entries in gradle/libs.versions.toml are pinned on purpose and must not move: errorProneOldest is the 2.36.0 minimum README.md documents, errorProneJdk17 is the newest Error Prone that runs on JDK 17 because 2.43.0 and later require JDK 21 (uber#1401), and guava is the version NullAway depends on while guava-latest tracks the newest release for guava-recent-unit-tests (uber#629). The obvious way to hold such an entry does not work. Renovate's gradle manager declares versioning "gradle", whose ranges are [a,b), 1.2.+ and [1.0]. There is no "<" form, so a bound of "< 2.43" in either matchCurrentVersion or allowedVersions parses as nothing and holds nothing back. The three Error Prone entries also resolve to the same com.google.errorprone artifacts, so matchPackageNames cannot tell them apart either. Each pinned entry therefore gets a rule that matches on sharedVariableName, the version-catalog alias Renovate records for a dependency, and bounds it with a Gradle range: [,2.37) for errorProneOldest, [,2.43) for errorProneJdk17, [,32) for guava. A patch release inside the pin stays available, and a groupName keeps each entry in a PR of its own, since group:monorepos, which config:recommended brings in, would otherwise collect every com.google.errorprone dependency into a single error-prone-monorepo PR. Everything else is grouped the way Renovate already groups it, by version-catalog entry or by upstream monorepo. Three sets take no updates at all: the 1.0-HEAD-SNAPSHOT marker that selects the current Error Prone snapshot, jmh/build.gradle, whose caffeine, autodispose and nullaway versions appear as literal substrings in its own classpath filters, and com.android.support, the legacy Android support library. PRs arrive every two weeks, except for Error Prone, which opens as soon as a release lands. A major update goes to the dependency dashboard for manual review instead of opening a PR. The workflow runs renovate-config-validator on renovate.json, following the model in pgjdbc. It passes --no-global, without which the validator treats the file as a self-hosted global config and accepts options a repository config may not carry. It carries no paths filter, because a workflow that filters itself out reports no status and so could never be a required check; the job runs on every pull request and every merge queue entry instead, and skips the validation step when neither renovate.json nor the workflow itself changed. One step carries no condition at all: it checks that every catalog alias the rules pin is still declared in gradle/libs.versions.toml, because a rename there disables a rule while the config goes on validating, and the change-detection step does not watch that file. Checked with renovate --platform=local --dry-run=full: every pinned entry is held, and widening each bound by hand produces the separate branches the rules name. Renaming a catalog entry by hand fails the alias check and names the entry. Assisted-by: Claude Code (claude-opus-5)
NullAway has no automated dependency updates. uber#1817 proposed Dependabot and was closed in favor of Renovate for its configuration options: grouping every GitHub Actions bump into one pull request, and custom regex managers for versions the standard managers do not reach. Several versions in this build are pinned on purpose, and a bot that bumped every one of them would break the test matrix: * `errorProneOldest` holds the minimum Error Prone that `README.md` documents, 2.36.0, and `testErrorProneOldest` runs the suite against it. Raising that floor is a decision rather than maintenance, so the entry takes 2.36.x only. * `errorProneJdk17` holds the newest Error Prone that runs on JDK 17, since 2.43.0 and later require JDK 21 (uber#1401), and `testJdk17` puts its jars in front of the test classpath. The entry takes 2.42.x only. * `guava` is the version NullAway itself depends on, and it reaches a user's annotation processor path, so it stays on 31.x. The separate `guava-latest` entry that `guava-recent-unit-tests` uses keeps taking updates (uber#629). * `errorProneLatestSnapshot` asks for the literal `1.0-HEAD-SNAPSHOT` marker, which Renovate reads as version 1.0 and would replace with a release. * `jmh/build.gradle` pins the versions each benchmark was built with, and spells three of them as literal substrings in its classpath filters, so a bump would leave a filter matching nothing. * `com.android.support` is the superseded Android support library, used only by `sample-app`. The three Error Prone catalog entries resolve to the same `com.google.errorprone` artifacts, and `guava` and `guava-latest` both resolve to `com.google.guava:guava`, so `matchPackageNames` cannot tell them apart. Those rules match on `sharedVariableName`, the catalog alias Renovate reports for a dependency, under both spellings Renovate uses: the bare alias, and the `libs.versions.` prefixed form it keeps for an entry that `build.gradle` reads through an `ext` property. Each bound is a Gradle range such as `[,2.37)`, because that versioning accepts `[a,b)`, `1.2.+` and `[1.0]` and has no `<` form, so a bound written as `< 2.37` would parse as nothing and hold nothing back. Each pinned entry also carries a `groupName`, because otherwise `group:monorepos`, which `config:recommended` brings in, would collect a pinned entry and an unpinned one into one monorepo pull request. Everything else is grouped the way Renovate already groups it, by version-catalog entry or by upstream monorepo. The rest is policy. Updates arrive every two weeks, labeled `dependencies`, with no semantic-commit prefix, since this repository writes plain subjects. A major update goes to the dependency dashboard for manual approval instead of opening a pull request. Error Prone is exempt from the schedule and opens as soon as a release is published: NullAway compiles against Error Prone internals such as `ASTHelpers`, and `testErrorProneLatestSnapshot` exists to catch such a change while it is still a snapshot (uber#1555). `renovate-config-validator` catches a malformed config and nothing else, so the workflow also checks that every alias a rule pins is still declared in `gradle/libs.versions.toml`; a rename there would leave the rule matching nothing while the config still validated. That step carries no `if:` condition, because the catalog is not one of the two files the workflow watches for changes. The workflow itself carries no `paths:` filter, so that its status is always reported and it can be made a required check; the validation step is skipped instead when neither `renovate.json` nor the workflow changed. The validator runs with `--no-global`, without which it accepts self-hosted global options such as `onboarding` that a repository config may not carry. The `on:`, `concurrency:` and `permissions:` blocks are the ones uber#1818 settled on for `continuous-integration.yml`. This is configuration, so there are no unit tests. Checked with `renovate --platform=local --dry-run=full` over this worktree, which matched every rule against the real dependency set: each pinned entry is held, and widening a bound by hand produces the separate branch its rule names. Renaming a catalog entry by hand fails the alias check and names the entry. Left out, following the plan in uber#1792 to start with an initial version and tune the rules later: automerge stays off, no custom regex manager is configured yet, and the versions `jmh/build.gradle` and `sample-app` pin are disabled outright rather than bounded. Merging this file does not start Renovate; the app still has to be enabled for `uber/NullAway`. Fixes uber#1792 Assisted-by: Claude Code (claude-opus-5)
NullAway has no automated dependency updates. uber#1817 proposed Dependabot and was closed in favor of Renovate for its configuration options: grouping every GitHub Actions bump into one pull request, and custom regex managers for versions the standard managers do not reach. Several versions in this build are pinned on purpose, and a bot that bumped every one of them would break the test matrix: * `errorProneOldest` holds the minimum Error Prone that `README.md` documents, 2.36.0, and `testErrorProneOldest` runs the suite against it. Raising that floor is a decision rather than maintenance, so the entry takes 2.36.x only. * `errorProneJdk17` holds the newest Error Prone that runs on JDK 17, since 2.43.0 and later require JDK 21 (uber#1401), and `testJdk17` puts its jars in front of the test classpath. The entry takes 2.42.x only. * `guava` is the version NullAway itself depends on, and it reaches a user's annotation processor path, so it stays on 31.x. The separate `guava-latest` entry that `guava-recent-unit-tests` uses keeps taking updates (uber#629). * `errorProneLatestSnapshot` asks for the literal `1.0-HEAD-SNAPSHOT` marker, which Renovate reads as version 1.0 and would replace with a release. * `jmh/build.gradle` pins every version it names, and spells three of them as literal substrings in its classpath filters, so a bump would leave a filter matching nothing. * `com.android.support` is the superseded Android support library, used only by `sample-app`. The three Error Prone catalog entries resolve to the same `com.google.errorprone` artifacts, and `guava` and `guava-latest` both resolve to `com.google.guava:guava`, so `matchPackageNames` cannot tell them apart. Those rules match on `sharedVariableName`, the catalog alias Renovate reports for a dependency, under both spellings Renovate uses: the bare alias, and the `libs.versions.` prefixed form it keeps for an entry that `build.gradle` reads through an `ext` property. Each bound is a Gradle range such as `[,2.37)`, because that versioning accepts `[a,b)`, `1.2.+` and `[1.0]` and has no `<` form, so a bound written as `< 2.37` would parse as nothing and hold nothing back. Each pinned entry also carries a `groupName`, because otherwise `group:monorepos`, which `config:recommended` brings in, would collect a pinned entry and an unpinned one into one monorepo pull request. Everything else is grouped the way Renovate already groups it, by version-catalog entry or by upstream monorepo. The rest is policy. Updates arrive every two weeks, labeled `dependencies`, with no semantic-commit prefix, since this repository writes plain subjects. A major update goes to the dependency dashboard for manual approval instead of opening a pull request. Error Prone is exempt from the schedule and opens as soon as a release is published: NullAway compiles against Error Prone internals such as `ASTHelpers`, and `testErrorProneLatestSnapshot` (uber#1555) runs the suite against Error Prone snapshots, so such a change shows up before the release does. `renovate-config-validator` checks the config's shape, not whether a rule still matches anything, so the workflow also checks that every alias a rule pins is still declared in `gradle/libs.versions.toml`; a rename there would leave the rule matching nothing while the config still validated. That step carries no `if:` condition, because the catalog is not one of the two files the workflow watches for changes. The workflow itself carries no `paths:` filter, so that its status is always reported and it can be made a required check; the validation step is skipped instead when neither `renovate.json` nor the workflow changed. The validator runs with `--no-global`, without which it accepts self-hosted global options such as `onboarding` that a repository config may not carry. The `merge_group` trigger and the `concurrency` group are the ones uber#1818 settled on for `continuous-integration.yml`. This is configuration, so there are no unit tests. Checked with `renovate --platform=local --dry-run=full` over this worktree, which matched every rule against the real dependency set: each pinned entry is held, and widening a bound by hand produces the separate branch its rule names. Renaming a catalog entry by hand fails the alias check and names the entry. Left out, following the plan in uber#1792 to start with an initial version and tune the rules later: automerge stays off, no custom regex manager is configured yet, and `jmh/build.gradle` and `com.android.support` are disabled outright rather than bounded. Merging this file does not start Renovate; the app still has to be enabled for `uber/NullAway`. Fixes uber#1792 Assisted-by: Claude Code (claude-opus-5)
NullAway has no automated dependency updates. uber#1817 proposed Dependabot and was closed in favor of Renovate for its configuration options: grouping every GitHub Actions bump into one pull request, and custom regex managers for versions the standard managers do not reach. Several versions in this build are pinned on purpose, and a bot that bumped every one of them would break the test matrix: * `errorProneOldest` holds the minimum Error Prone that `README.md` documents, 2.36.0, and `testErrorProneOldest` runs the suite against it. Raising that floor is a decision rather than maintenance, so the entry takes 2.36.x only. * `errorProneJdk17` holds the newest Error Prone that runs on JDK 17, since 2.43.0 and later require JDK 21 (uber#1401), and `testJdk17` puts its jars in front of the test classpath. The entry takes 2.42.x only. * `guava` is the version NullAway itself depends on, and it reaches a user's annotation processor path, so it stays on 31.x. The separate `guava-latest` entry that `guava-recent-unit-tests` uses keeps taking updates (uber#629). * `errorProneLatestSnapshot` asks for the literal `1.0-HEAD-SNAPSHOT` marker, which Renovate reads as version 1.0 and would replace with a release. * `jmh/build.gradle` pins every version it names, and spells three of them as literal substrings in its classpath filters, so a bump would leave a filter matching nothing. * `com.android.support` is the superseded Android support library, used only by `sample-app`. The three Error Prone catalog entries resolve to the same `com.google.errorprone` artifacts, and `guava` and `guava-latest` both resolve to `com.google.guava:guava`, so `matchPackageNames` cannot tell them apart. Those rules match on `sharedVariableName`, the catalog alias Renovate reports for a dependency, under two spellings. Renovate reports the bare alias for every entry in this repository; the `libs.versions.` prefixed form is insurance, for an entry that `build.gradle` reads through an `ext` property and that a refactor leaves with a single dependency. Each bound is a Gradle range such as `[,2.37)`, because that versioning accepts `[a,b)`, `1.2.+` and `[1.0]` and has no `<` form, so a bound written as `< 2.37` would parse as nothing and hold nothing back. Each pinned entry also carries a `groupName`, because otherwise `group:monorepos`, which `config:best-practices` pulls in through `config:recommended`, would collect a pinned entry and an unpinned one into one monorepo pull request. Everything else is grouped the way Renovate already groups it, by version-catalog entry or by upstream monorepo. The rest is policy. Updates arrive every two weeks, labeled `dependencies`, with no semantic-commit prefix, since this repository writes plain subjects. A major update goes to the dependency dashboard for manual approval instead of opening a pull request. Error Prone is exempt from the schedule and opens as soon as a release is published: NullAway compiles against Error Prone internals such as `ASTHelpers`, and `testErrorProneLatestSnapshot` (uber#1555) runs the suite against Error Prone snapshots, so such a change shows up before the release does. `renovate-config-validator` checks the config's shape, not whether a rule still matches anything, so the workflow also checks that every alias a rule pins is still declared in `gradle/libs.versions.toml`; a rename there would leave the rule matching nothing while the config still validated. That step carries no `if:` condition, because the catalog is not one of the two files the workflow watches for changes. The workflow itself carries no `paths:` filter, so that its status is always reported and it can be made a required check; the validation step is skipped instead when neither `renovate.json` nor the workflow changed. The validator runs with `--no-global`, without which it accepts self-hosted global options such as `onboarding` that a repository config may not carry. The `merge_group` trigger and the `concurrency` group are the ones uber#1818 settled on for `continuous-integration.yml`. This is configuration, so there are no unit tests. Checked with `renovate --platform=local --dry-run=full` over this worktree, which matched every rule against the real dependency set: each pinned entry is held, and widening a bound by hand produces the separate branch its rule names. Renaming a catalog entry by hand fails the alias check and names the entry. Left out, following the plan in uber#1792 to start with an initial version and tune the rules later. Automerge stays off and no custom regex manager is configured yet. The GitHub Actions grouping covers `actions/*` and `github/*`, not the other publishers this repository uses, so a `codecov`, `gradle/actions` or `zizmorcore` bump still arrives on its own. The older test fixtures in `gradle/libs.versions.toml` are not excluded either: nothing in the repository records which of them are held on purpose, so their majors need dashboard approval and their minors will open pull requests until someone names the ones to pin. `jmh/build.gradle` and `com.android.support` are disabled outright rather than bounded. Merging this file does not start Renovate; the app still has to be enabled for `uber/NullAway`. Fixes uber#1792 Assisted-by: Claude Code (claude-opus-5)
NullAway has no automated dependency updates. uber#1817 proposed Dependabot and was closed in favor of Renovate for its configuration options: grouping every GitHub Actions bump into one pull request, and custom regex managers for versions the standard managers do not reach. Several versions in this build are pinned on purpose, and a bot that bumped every one of them would break the test matrix: * `errorProneOldest` holds the minimum Error Prone that `README.md` documents, 2.36.0, and `testErrorProneOldest` runs the suite against it. Raising that floor is a decision rather than maintenance, so the entry takes 2.36.x only. * `errorProneJdk17` holds the newest Error Prone that runs on JDK 17, since 2.43.0 and later require JDK 21 (uber#1401), and `testJdk17` puts its jars in front of the test classpath. The entry takes 2.42.x only. * `guava` is the version NullAway itself depends on, and it reaches a user's annotation processor path, so it stays on 31.x. The separate `guava-latest` entry that `guava-recent-unit-tests` uses keeps taking updates (uber#629). * `errorProneLatestSnapshot` asks for the literal `1.0-HEAD-SNAPSHOT` marker, which Renovate reads as version 1.0 and would replace with a release. * `jmh/build.gradle` pins every version it names, and spells three of them as literal substrings in its classpath filters, so a bump would leave a filter matching nothing. * `com.android.support` is the superseded Android support library, used only by `sample-app`. The three Error Prone catalog entries resolve to the same `com.google.errorprone` artifacts, and `guava` and `guava-latest` both resolve to `com.google.guava:guava`, so `matchPackageNames` cannot tell them apart. Those rules match on `sharedVariableName`, the catalog alias Renovate reports for a dependency, under two spellings. Renovate reports the bare alias for every entry in this repository; the `libs.versions.` prefixed form is insurance, for an entry that `build.gradle` reads through an `ext` property and that a refactor leaves with a single dependency. Each bound is a Gradle range such as `[,2.37)`, because that versioning accepts `[a,b)`, `1.2.+` and `[1.0]` and has no `<` form, so a bound written as `< 2.37` would parse as nothing and hold nothing back. Each pinned entry also carries a `groupName`, because otherwise `group:monorepos`, which `config:best-practices` pulls in through `config:recommended`, would collect a pinned entry and an unpinned one into one monorepo pull request. Everything else is grouped the way Renovate already groups it, by version-catalog entry or by upstream monorepo. The rest is policy. Updates arrive every two weeks, labeled `dependencies`, with no semantic-commit prefix, since this repository writes plain subjects. A major update goes to the dependency dashboard for manual approval instead of opening a pull request, Error Prone included; only the schedule and the cooldown below treat Error Prone differently. It is exempt from the schedule and opens as soon as a release is published: NullAway compiles against Error Prone internals such as `ASTHelpers`, and `testErrorProneLatestSnapshot` (uber#1555) runs the suite against Error Prone snapshots, so such a change shows up before the release does. A release less than seven days old does not reach a pull request: `minimumReleaseAge` holds it back, so that a broken or compromised publish has time to be found and pulled. Where an older release above the current version is itself old enough, Renovate targets that one rather than waiting. Error Prone and the actions GitHub publishes are exempt, because a broken Error Prone release breaks this build rather than reaching users and `testErrorProneLatestSnapshot` has already exercised it as a snapshot, and because an action GitHub publishes is not the supply-chain risk a third-party one is. A security update bypasses the cooldown through Renovate's own `vulnerabilityAlerts` defaults. `renovate-config-validator` checks the config's shape, not whether a rule still matches anything, so the workflow also checks that every alias a rule pins is still declared in `gradle/libs.versions.toml`; a rename there would leave the rule matching nothing while the config still validated. That step carries no `if:` condition, because the catalog is not one of the two files the workflow watches for changes. The workflow itself carries no `paths:` filter, so that its status is always reported and it can be made a required check; the validation step is skipped instead when neither `renovate.json` nor the workflow changed. The validator runs with `--no-global`, without which it accepts self-hosted global options such as `onboarding` that a repository config may not carry. The `merge_group` trigger and the `concurrency` group are the ones uber#1818 settled on for `continuous-integration.yml`. This is configuration, so there are no unit tests. Checked with `renovate --platform=local --dry-run=full` over this worktree, which matched every rule against the real dependency set: each pinned entry is held, and widening a bound by hand produces the separate branch its rule names. Renaming a catalog entry by hand fails the alias check and names the entry. The cooldown was measured the same way: at seven days two updates are held as pending and three retarget to an older release that is old enough, and raising it to 365 days holds twenty while the exempt Error Prone update still comes through. No run covers GitHub Actions: a local Renovate has no token, so all 21 action dependencies come back `github-token-required`. Left out, following the plan in uber#1792 to start with an initial version and tune the rules later. Automerge stays off and no custom regex manager is configured yet. The GitHub Actions grouping covers `actions/*` and `github/*`, not the other publishers this repository uses, so a `codecov`, `gradle/actions` or `zizmorcore` bump still arrives on its own. The older test fixtures in `gradle/libs.versions.toml` are not excluded either: nothing in the repository records which of them are held on purpose, so their majors need dashboard approval and their minors will open pull requests until someone names the ones to pin. `jmh/build.gradle` and `com.android.support` are disabled outright rather than bounded. Merging this file does not start Renovate; the app still has to be enabled for `uber/NullAway`. Fixes uber#1792 Assisted-by: Claude Code (claude-opus-5)
NullAway has no automated dependency updates. #1817 proposed Dependabot and was closed in favor of Renovate for its configuration options: grouping every GitHub Actions bump into one pull request, and custom regex managers for versions the standard managers do not reach. Several versions in this build are pinned on purpose, and a bot that bumped every one of them would break the test matrix: * `errorProneOldest` holds the minimum Error Prone that `README.md` documents, 2.36.0, and `testErrorProneOldest` runs the suite against it. Raising that floor is a decision rather than maintenance, so the entry takes 2.36.x only. * `errorProneJdk17` holds the newest Error Prone that runs on JDK 17, since 2.43.0 and later require JDK 21 (#1401), and `testJdk17` puts its jars in front of the test classpath. The entry takes 2.42.x only. * `guava` is the version NullAway itself depends on, and it reaches a user's annotation processor path, so it stays on 31.x. The separate `guava-latest` entry that `guava-recent-unit-tests` uses keeps taking updates (#629). * `errorProneLatestSnapshot` asks for the literal `1.0-HEAD-SNAPSHOT` marker, which Renovate reads as version 1.0 and would replace with a release. * `jmh/build.gradle` pins every version it names, and spells three of them as literal substrings in its classpath filters, so a bump would leave a filter matching nothing. * `com.android.support` is the superseded Android support library, used only by `sample-app`. The three Error Prone catalog entries resolve to the same `com.google.errorprone` artifacts, and `guava` and `guava-latest` both resolve to `com.google.guava:guava`, so `matchPackageNames` cannot tell them apart. Those rules match on `sharedVariableName`, the catalog alias Renovate reports for a dependency, under two spellings. Renovate reports the bare alias for every entry in this repository; the `libs.versions.` prefixed form is insurance, for an entry that `build.gradle` reads through an `ext` property and that a refactor leaves with a single dependency. Each bound is a Gradle range such as `[,2.37)`, because that versioning accepts `[a,b)`, `1.2.+` and `[1.0]` and has no `<` form, so a bound written as `< 2.37` would parse as nothing and hold nothing back. Each pinned entry also carries a `groupName`, because otherwise `group:monorepos`, which `config:best-practices` pulls in through `config:recommended`, would collect a pinned entry and an unpinned one into one monorepo pull request. Everything else is grouped the way Renovate already groups it, by version-catalog entry or by upstream monorepo. The rest is policy. Updates arrive every two weeks, labeled `dependencies`, with no semantic-commit prefix, since this repository writes plain subjects. A major update goes to the dependency dashboard for manual approval instead of opening a pull request, Error Prone included; only the schedule and the cooldown below treat Error Prone differently. It is exempt from the schedule and opens as soon as a release is published: NullAway compiles against Error Prone internals such as `ASTHelpers`, and `testErrorProneLatestSnapshot` (#1555) runs the suite against Error Prone snapshots, so such a change shows up before the release does. A release less than seven days old does not reach a pull request: `minimumReleaseAge` holds it back, so that a broken or compromised publish has time to be found and pulled. Where an older release above the current version is itself old enough, Renovate targets that one rather than waiting. Error Prone and the actions GitHub publishes are exempt, because a broken Error Prone release breaks this build rather than reaching users and `testErrorProneLatestSnapshot` has already exercised it as a snapshot, and because an action GitHub publishes is not the supply-chain risk a third-party one is. A security update bypasses the cooldown through Renovate's own `vulnerabilityAlerts` defaults. `renovate-config-validator` checks the config's shape, not whether a rule still matches anything, so the workflow also checks that every alias a rule pins is still declared in `gradle/libs.versions.toml`; a rename there would leave the rule matching nothing while the config still validated. That step carries no `if:` condition, because the catalog is not one of the two files the workflow watches for changes. The workflow itself carries no `paths:` filter, so that its status is always reported and it can be made a required check; the validation step is skipped instead when neither `renovate.json` nor the workflow changed. The validator runs with `--no-global`, without which it accepts self-hosted global options such as `onboarding` that a repository config may not carry. The `merge_group` trigger and the `concurrency` group are the ones #1818 settled on for `continuous-integration.yml`. This is configuration, so there are no unit tests. Checked with `renovate --platform=local --dry-run=full` over this worktree, which matched every rule against the real dependency set: each pinned entry is held, and widening a bound by hand produces the separate branch its rule names. Renaming a catalog entry by hand fails the alias check and names the entry. The cooldown was measured the same way: at seven days two updates are held as pending and three retarget to an older release that is old enough, and raising it to 365 days holds twenty while the exempt Error Prone update still comes through. No run covers GitHub Actions: a local Renovate has no token, so all 21 action dependencies come back `github-token-required`. Left out, following the plan in #1792 to start with an initial version and tune the rules later. Automerge stays off and no custom regex manager is configured yet. The GitHub Actions grouping covers `actions/*` and `github/*`, not the other publishers this repository uses, so a `codecov`, `gradle/actions` or `zizmorcore` bump still arrives on its own. The older test fixtures in `gradle/libs.versions.toml` are not excluded either: nothing in the repository records which of them are held on purpose, so their majors need dashboard approval and their minors will open pull requests until someone names the ones to pin. `jmh/build.gradle` and `com.android.support` are disabled outright rather than bounded. Merging this file does not start Renovate; the app still has to be enabled for `uber/NullAway`. Fixes #1792 Assisted-by: Claude Code (claude-opus-5) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Chores** - Added automated Renovate configuration to regularly identify and group dependency updates. - Dependency updates now follow release-age safeguards, version constraints, and approval requirements for major changes. - Added validation checks to ensure Renovate configuration remains consistent and valid across pull requests, merge queues, and pushes. - GitHub Actions updates are grouped together to simplify maintenance. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Fixes #1397
Auto-fix violations of https://errorprone.info/bugpattern/FormatStringShouldUsePlaceholders. For testing on JDK 17 we still use Error Prone 2.42.0, as 2.43.0+ require JDK 21.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.