-
Notifications
You must be signed in to change notification settings - Fork 460
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Gradle 6+ #503
Fix Gradle 6+ #503
Conversation
Defining termsAn idealized view of dependency resolution is A gradle build needs to resolve dependencies for two purposes - for the buildscript (build plugins and tools), and for the project (transitive dependencies of the actual thing being built). For the rest of this issue, it is important to understand that dependency resolution for the buildscript and the project are completely independent, and it will be confusing if we accidentally use "project" to mean "buildscript and project". Gradle defaults and behavior
Spotless' unique use-caseWhen a user does Spotless does not resolve, or even declare, any dependencies during buildscript evaluation. However, after the buildscripts have been executed and gradle is calculating the up-to-date status, we have to declare and resolve these dependencies. I'm not sure of the precise definition of "configuration time" in the gradle docs, but I'm pretty sure that gradle/gradle#2298 (forbid dependency resolution at configuration time by default) doesn't apply to us. Spotless is a build tool, so it should resolve its dependencies from buildscript repositories, not project repositories. And by default, a subproject doesn't have any buildscript repositories. Our solution to this for a long time has been to resolve all of our dependencies from the root project's buildscript. This is kosher when we apply spotless to the root project, but when subprojects are evaluating their up-to-date status in parallel, then we're really abusing the root project. See #372 for the carnage. |
… constraints" This reverts commit d9397a1.
a9fb4f9
to
3b412df
Compare
Simple solutionsThe simplest solution is to stop abusing the root buildscript, and instead resolve dependencies from each project's buildscript individually. We would still get classloader caching across subprojects (caching is based only on the value of the resolved files), so there's no performance hit. The problem is that users will have to add The next solution is to instead abuse each project's project repositories. So long as the user has defined some We can even let the user pick which of these two workarounds they prefer. e3f9f67 above shows how easy this is to implement, but neither is a good user experience, so I reverted it to look for something better. |
…hich step is being configured.
…e Gradle 6+ deprecation warnings.
Resolving the conflictsI think it is wise for Gradle to push people to centralize their buildscript dependencies into the root project. I also think it is good that we let people grab a wide variety of formatters and versions without thinking about named configurations and the behind-the-scenes work. There is a conflict, but I don't think either side of the conflict should move very far. There is a simple (and definitely correct) solution, which combines these two pieces of the story above:
The solution is to require that if a step is used in a subproject, it must also be used (or at least declared) in the root project, even if it's not actually applied to a target. A more thorough look at the resolutionThe whole trick is inside one commit, 892203d, which is tested working on Gradle 2.14 and 6+. We create a new task in the root project called In subprojects, every For some projects, the
TODOdocs, changelog, fix the maven build (JitCI does everything except maven, and it's passing). This is a pretty complicated PR, and I'm in a bit of a hurry because there is other stuff I'd like to release which requires Gradle 6+ and thus is blocked on this. The only new user-facing API is |
…arations in root. We can infer them without a performance penalty by registering every subproject SpotlessTask with the RegisterDependenciesTask. When we eventually bump our minimum-required gradle to take advantage of task configuration avoidance, this workaround will still work - the only task we'll have to create eagerly is the registerDependencies task.
…est into RegisterDependenciesTask.
…re out which step is being configured." This reverts commit 28d8962.
The best way to understand the final change is the collapsed changes across the whole PR (files tab). The high level overview is: spotless/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/RegisterDependenciesTask.java Lines 38 to 43 in 7535906
|
Published in |
Gradle 6 has a couple things that I'm excited to use in other projects, but our dependency resolution technical debt throws a lot of deprecation warnings in Gradle 6. I don't want to break back-compat unless we have to, but it's possible that our hand will be forced soon. We just got a great comment on an old bug (still present in our latest versions). That user is stuck on Gradle 3.5 (!!!), but their insight broke the logjam and got it solved. So, let's see if we can fix this without breaking old users...