-
Notifications
You must be signed in to change notification settings - Fork 134
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
Lazy exact dependencies #2639
Lazy exact dependencies #2639
Conversation
Generate changelog in
|
// \-- testCompile extendsFrom(compile) | ||
// We therefore want to look at only the dependencies _directly_ declared in the implementation | ||
// and compile configurations (belonging to our source set) | ||
Configuration implCopy = project.getConfigurations() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had originally tried to put this in a beforeResolve
, where it makes most sense to live. But this causes GCV to have ConcurrentModificationException
s, as it iterates over all the Configuration
s and then resolves them while this section of code creates more Configuration
s, meaning I had to keep it in afterEvaluate
Object value = | ||
compileClasspath.get().getAttributes().getAttribute(attribute); | ||
conf.getAttributes().attribute((Attribute<Object>) attribute, value); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no way to lazily add a Map
of attributes (aka lazily conditionally add an attribute). So it too must unfortunately live in an afterEvaluate
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can get around this particular usage of afterEvaluate
since we don't actually need to copy the map, just the attribute from the compileClasspath
=> we know the attribute we want and can do use the attribute provider method for a single attribute key.
Additionally, I think this code is only really effective for gradle versions < 5.6? => if our min version is high enough, this bit of code is redundant as it's already covered by
Lines 112 to 116 in 36e20de
if (GradleVersion.current().compareTo(GradleVersion.version("5.6")) >= 0) { | |
attributes.attribute( | |
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, | |
project.getObjects().named(LibraryElements.class, LibraryElements.CLASSES)); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was the first thing I tried and it didn't work. Sometimes the library elements attribute does not exist on source configuration. This then causes attribute(Attribute, Provider<T>)
to throw as per the javadoc:
This method can NOT be used to discard the value of an property. Specifying a null provider will result in an IllegalArgumentException being thrown. When the provider has no value at finalization time, an IllegalStateException - regardless of whether or not a convention has been set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not everything is actionable, or necessarily for this PR, but would be interesting to see, as it could simplify the class a lot
@@ -21,7 +21,7 @@ | |||
|
|||
public final class GradleTestVersions { | |||
public static final ImmutableList<String> VERSIONS = | |||
ImmutableList.of(Baseline.MIN_GRADLE_VERSION.getVersion(), "7.1.1", "7.3"); | |||
ImmutableList.of(Baseline.MIN_GRADLE_VERSION.getVersion(), "7.6.2", "8.4"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you want this to be 8.4 or 8.3?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might as well use 8.4 as that is latest.
...e-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineExactDependencies.java
Outdated
Show resolved
Hide resolved
@@ -61,6 +61,7 @@ tasks.test.dependsOn tasks.publishToMavenLocal | |||
test { | |||
environment 'CIRCLE_ARTIFACTS', "${buildDir}/artifacts" | |||
environment 'CIRCLE_TEST_REPORTS', "${buildDir}/circle-reports" | |||
systemProperty 'ignoreDeprecations', 'true' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how come?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we discussed this internally some time ago - I actually want to set it on everything:
should we just ignoreDeprecations for every gradle project? Some reasons why:
- Deprecations often come from other repos we end up running as part of tests. For example, in [internal-repo] there are some tests that run tasks from [other-internal-repo], that then fail with deprecations warnings due to [other-internal-repo]'s tasks. Since we can’t fix them in the [internal-repo], we end up adding
--warning-mode=none
to every test, losing deprecation warnings anyway. Or worse, people addSystem.setProperty('ignoreDeprecations', 'true')
to individual tests as nebula suggests, making the build flake.- It’s impossible to see what caused deprecation warnings using nebula-test. The only way I found out to get good info is to add the buildscan plugin to the test.
- We don’t tend to fix deprecations until a major version remove the feature anyway.
- This leads to our gradle plugin repos being super out of date for their own gradle wrapper, meaning they get wrecked by stuff like not supporting jackson 2.15.2's java 20 code.
In this case, we get deprecation warnings about GCV not working with Gradle 9 when running in 8.3/8.4 - something we can't even fix in this repo.
...e-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineExactDependencies.java
Outdated
Show resolved
Hide resolved
// Specifically, we need to pick up the LIBRARY_ELEMENTS_ATTRIBUTE, which is being configured on | ||
// compileClasspath in JavaBasePlugin.defineConfigurationsForSourceSet, but we can't reference | ||
// it | ||
// directly because that would require us to depend on Gradle 5.6. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably not for this PR, but surely we can raise the min gradle version? does the concern here still hold without it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose it just comes down to directly referencing the attribute like we did in line 117? instead of copying all the attributes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could probably aim to do some cleanup of minimum gradle versions (including the horrifying GradleWorkarounds
files that exist in many repos) once we move to Gradle 8.
...e-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineExactDependencies.java
Show resolved
Hide resolved
Object value = | ||
compileClasspath.get().getAttributes().getAttribute(attribute); | ||
conf.getAttributes().attribute((Attribute<Object>) attribute, value); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can get around this particular usage of afterEvaluate
since we don't actually need to copy the map, just the attribute from the compileClasspath
=> we know the attribute we want and can do use the attribute provider method for a single attribute key.
Additionally, I think this code is only really effective for gradle versions < 5.6? => if our min version is high enough, this bit of code is redundant as it's already covered by
Lines 112 to 116 in 36e20de
if (GradleVersion.current().compareTo(GradleVersion.version("5.6")) >= 0) { | |
attributes.attribute( | |
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, | |
project.getObjects().named(LibraryElements.class, LibraryElements.CLASSES)); | |
} |
// For Gradle 6 and below, the compile configuration might still be used. | ||
maybeCompile.ifPresent(compile -> { | ||
Configuration compileCopy = compile.copy(); | ||
// Ensure it's not resolvable, otherwise plugins that resolve all configurations might have | ||
// a bad time resolving this with GCV, if you have direct dependencies without corresponding | ||
// entries in | ||
// versions.props, but instead rely on getting a version for them from the lock file. | ||
compileCopy.setCanBeResolved(false); | ||
compileCopy.setCanBeConsumed(false); | ||
|
||
project.getConfigurations().add(compileCopy); | ||
|
||
conf.extendsFrom(compileCopy); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
redundant? our min version is effectively 7.0 if you apply all the plugins, I think it's 6.7 if you don't apply javaversions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, tbh I'd rather just leave it while we still have some repos on Gradle 6 (which I should burn down as part of this work).
AtomicBoolean projectsEvaluated = new AtomicBoolean(); | ||
project.getGradle().projectsEvaluated(g -> projectsEvaluated.set(true)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an aside, do you want some sort of similar check in the flattener?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, it's a bit redundant given GCV does the same thing
|
||
TaskProvider<CheckUnusedDependenciesTask> sourceSetUnusedDependencies = project.getTasks() | ||
.register( | ||
checkUnusedDependenciesNameForSourceSet(sourceSet), CheckUnusedDependenciesTask.class, task -> { | ||
task.dependsOn(sourceSet.getClassesTaskName()); | ||
task.setSourceClasses(sourceSet.getOutput().getClassesDirs()); | ||
task.dependenciesConfiguration(explicitCompile); | ||
task.getDependenciesConfigurations().add(explicitCompile); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wacky idea, not actually sure, but can't we just use the getHierarchy()
method of the configuration we're initially copying? and then take the first one? do we actually need/want a copy, or did we only take a copy because that was the only way to get the first level without the other dependencies from super configurations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because with that, you can just do a conf.map(c -> Iterables.getFirst(c.getHierarchy()))
, it's also a LinkedSet
populated in DFS manner so in theory it should have what we want assuming we don't want/need a separate copy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really sure I follow here, the first time I saw this plugin was this PR. I'd like to focus on getting this to work at all with Gradle 8 first, if we want to improve it/change it in some way it seems less risky to spend time on that intentionally in another change.
👍 |
Released 5.24.0 |
Before this PR
Repo upgrades to Gradle 8 are failing because of errors when using
baseline-java-versions
andbaseline-exact-dependencies
together:The source of the problem is that in Gradle 8.3, the values of various Java toolchain related attributes are finalised for a
Configuration
the moment thatConfiguration
is created.baseline-exact-dependencies
was usinggetConfigurations().getByName(...)
when configuring source sets, which means that it was forcing the creation ofConfiguration
s and so finalising the values of these attributes beforebaseline-java-versions
had a chance to configure thelanguageVersion
etc.After this PR
==COMMIT_MSG==
baseline-exact-dependencies
is now far more lazy aroundConfiguration
creation in order to support Gradle 8.==COMMIT_MSG==
Possible downsides?