Skip to content

Commit 930e9c7

Browse files
feat: DSL option that opts-in source sets to requiring explicit dependencies.
This can help with a migration from Kotlin 1 to Kotlin 2, as the latter no longer automatically adds all main dependencies to testFixtures (for example). It is also generally useful if you believe all (or some) source sets should explicitly declare their dependencies and not rely on Configuration inheritance.
1 parent f7a6ce5 commit 930e9c7

File tree

19 files changed

+1031
-231
lines changed

19 files changed

+1031
-231
lines changed

src/functionalTest/groovy/com/autonomousapps/AbstractProject.groovy

+28-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import com.autonomousapps.kit.AbstractGradleProject
66
import com.autonomousapps.kit.GradleProject
77
import com.autonomousapps.kit.gradle.GradleProperties
88
import com.autonomousapps.kit.gradle.Plugin
9+
import com.autonomousapps.kit.gradle.dependencies.DependencyProvider
10+
import com.autonomousapps.kit.gradle.dependencies.PluginProvider
911
import com.autonomousapps.kit.gradle.dependencies.Plugins
1012
import com.autonomousapps.utils.DebugAware
1113

@@ -24,6 +26,28 @@ abstract class AbstractProject extends AbstractGradleProject {
2426
/** Applies the 'java-library' and 'com.autonomousapps.dependency-analysis' plugins. */
2527
protected static final List<Plugin> javaLibrary = [Plugin.javaLibrary, Plugins.dependencyAnalysisNoVersion]
2628

29+
protected final DependencyProvider dependencies
30+
protected final PluginProvider plugins
31+
32+
static String getKotlinVersion() {
33+
return System.getProperty("com.autonomousapps.test.versions.kotlin")
34+
}
35+
36+
AbstractProject() {
37+
this(getKotlinVersion(), null)
38+
}
39+
40+
AbstractProject(
41+
String kotlinVersion,
42+
String agpVersion
43+
) {
44+
dependencies = new DependencyProvider(kotlinVersion)
45+
plugins = new PluginProvider(
46+
kotlinVersion,
47+
agpVersion,
48+
)
49+
}
50+
2751
@Override
2852
protected GradleProject.Builder newGradleProjectBuilder(
2953
GradleProject.DslKind dslKind = GradleProject.DslKind.GROOVY
@@ -38,7 +62,7 @@ abstract class AbstractProject extends AbstractGradleProject {
3862
.withRootProject { r ->
3963
r.gradleProperties += additionalProperties
4064
r.withBuildScript { bs ->
41-
bs.plugins(Plugins.dependencyAnalysis, Plugins.kotlinJvmNoApply)
65+
bs.plugins(plugins.dependencyAnalysis, plugins.kotlinJvmNoApply)
4266
}
4367
}
4468
}
@@ -63,16 +87,16 @@ abstract class AbstractProject extends AbstractGradleProject {
6387
additionalProperties += GradleProperties.enableConfigurationCache()
6488
}
6589

66-
def plugins = [Plugins.buildHealth]
90+
def appliedPlugins = [plugins.buildHealth]
6791
if (withKotlin) {
68-
plugins.add(Plugins.kotlinJvmNoApply)
92+
appliedPlugins.add(plugins.kotlinJvmNoApply)
6993
}
7094

7195
return super.newGradleProjectBuilder(dslKind)
7296
.withRootProject { r ->
7397
r.gradleProperties += additionalProperties
7498
r.withSettingsScript { s ->
75-
s.plugins(plugins)
99+
s.plugins(appliedPlugins)
76100
}
77101
}
78102
}

src/functionalTest/groovy/com/autonomousapps/android/projects/AbstractAndroidProject.groovy

+2-5
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,12 @@ abstract class AbstractAndroidProject extends AbstractProject {
2525

2626
protected final String agpVersion
2727
protected final AgpVersion version
28-
protected final PluginProvider pluginProvider
2928

3029
AbstractAndroidProject(String agpVersion) {
30+
super(getKotlinVersion(), agpVersion)
31+
3132
this.agpVersion = agpVersion
3233
this.version = AgpVersion.version(agpVersion)
33-
this.pluginProvider = new PluginProvider(
34-
System.getProperty("com.autonomousapps.test.versions.kotlin"), // TODO: inject
35-
agpVersion,
36-
)
3734
}
3835

3936
protected AndroidBlock defaultAndroidAppBlock(

src/functionalTest/groovy/com/autonomousapps/android/projects/AbstractVariantProject.groovy

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,14 @@ abstract class AbstractVariantProject extends AbstractAndroidProject {
5454
a.styles = AndroidStyleRes.DEFAULT
5555
a.colors = AndroidColorRes.DEFAULT
5656
a.withBuildScript { bs ->
57-
bs.plugins = plugins
57+
bs.plugins = appliedPlugins
5858
bs.android = defaultAndroidAppBlock()
5959
bs.dependencies = dependencies
6060
}
6161
}.write()
6262
}
6363

64-
protected final List<Plugin> plugins = [
64+
protected final List<Plugin> appliedPlugins = [
6565
Plugins.androidApp,
6666
Plugins.kotlinAndroidNoVersion,
6767
Plugins.dependencyAnalysisNoVersion,

src/functionalTest/groovy/com/autonomousapps/android/projects/SettingsProject.groovy

+8-8
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ abstract class SettingsProject {
3636
.withAndroidSubproject('app') { app ->
3737
app.withBuildScript { bs ->
3838
bs.plugins = [
39-
pluginProvider.androidAppNoVersion,
40-
pluginProvider.kotlinAndroidNoVersion,
39+
plugins.androidAppNoVersion,
40+
plugins.kotlinAndroidNoVersion,
4141
]
4242
bs.android = defaultAndroidAppBlock()
4343
bs.dependencies = [
@@ -64,15 +64,15 @@ abstract class SettingsProject {
6464
}
6565
.withAndroidLibProject('lib', 'com.example.lib') { lib ->
6666
lib.withBuildScript { bs ->
67-
bs.plugins = [pluginProvider.androidLibNoVersion]
67+
bs.plugins = [plugins.androidLibNoVersion]
6868
bs.android = defaultAndroidLibBlock(false, 'com.example.lib')
6969
}
7070
lib.colors = AndroidColorRes.DEFAULT
7171
lib.manifest = libraryManifest('com.example.lib')
7272
}
7373
.withAndroidLibProject('lib2', 'com.example.lib2') { lib2 ->
7474
lib2.withBuildScript { bs ->
75-
bs.plugins = [pluginProvider.androidLibNoVersion]
75+
bs.plugins = [plugins.androidLibNoVersion]
7676
bs.android = defaultAndroidLibBlock(false, 'com.example.lib2')
7777
}
7878
lib2.manifest = AndroidManifest.defaultLib('com.example.lib2')
@@ -126,15 +126,15 @@ abstract class SettingsProject {
126126
.withRootProject { r ->
127127
r.withBuildScript { bs ->
128128
bs.buildscript = null
129-
bs.plugins(pluginProvider.dependencyAnalysis)
129+
bs.plugins(plugins.dependencyAnalysis)
130130
}
131131
}
132132
.withAndroidSubproject('app') { app ->
133133
app.withBuildScript { bs ->
134134
bs.plugins = [
135-
pluginProvider.androidApp,
136-
pluginProvider.kotlinAndroid,
137-
pluginProvider.dependencyAnalysisNoVersion,
135+
plugins.androidApp,
136+
plugins.kotlinAndroid,
137+
plugins.dependencyAnalysisNoVersion,
138138
]
139139
bs.android = defaultAndroidAppBlock()
140140
}

src/functionalTest/groovy/com/autonomousapps/jvm/CustomSourceSetSpec.groovy

+1-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ final class CustomSourceSetSpec extends AbstractJvmSpec {
191191
)
192192
}
193193
194-
def "don't suggest moving a dependency from one feature variant to another"() {
194+
def "don't suggest moving a dependency from one feature variant to another (#gradleVersion)"() {
195195
given:
196196
def project = new FeatureVariantInConsumerTestProject()
197197
gradleProject = project.gradleProject
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.autonomousapps.jvm
2+
3+
import com.autonomousapps.jvm.projects.Kotlin2Migration
4+
5+
import static com.autonomousapps.utils.Runner.build
6+
import static com.autonomousapps.utils.Runner.buildAndFail
7+
import static com.google.common.truth.Truth.assertThat
8+
9+
final class Kotlin2MigrationSpec extends AbstractJvmSpec {
10+
11+
def "buildHealth passes without testFixtures dependencies with Kotlin 1.9 (#gradleVersion)"() {
12+
given:
13+
def project = new Kotlin2Migration.CompilesWithoutTestFixturesDependencies()
14+
gradleProject = project.gradleProject
15+
16+
when:
17+
build(gradleVersion, gradleProject.rootDir, 'buildHealth')
18+
19+
then:
20+
assertThat(project.actualBuildHealth()).containsExactlyElementsIn(project.expectedBuildHealth)
21+
22+
where:
23+
gradleVersion << gradleVersions()
24+
}
25+
26+
def "buildHealth fails without testFixtures dependencies with Kotlin 1.9 (#gradleVersion)"() {
27+
given:
28+
def project = new Kotlin2Migration.BuildHealthFailsWithoutTestFixturesDependencies()
29+
gradleProject = project.gradleProject
30+
31+
when:
32+
build(gradleVersion, gradleProject.rootDir, 'buildHealth')
33+
34+
then:
35+
assertThat(project.actualBuildHealth()).containsExactlyElementsIn(project.expectedBuildHealth)
36+
37+
where:
38+
gradleVersion << gradleVersions()
39+
}
40+
41+
def "buildHealth passes with testFixtures dependency with Kotlin 2.0 (#gradleVersion)"() {
42+
given:
43+
def project = new Kotlin2Migration.CompilesWithTestFixturesDependency()
44+
gradleProject = project.gradleProject
45+
46+
when:
47+
build(gradleVersion, gradleProject.rootDir, 'buildHealth')
48+
49+
then:
50+
assertThat(project.actualBuildHealth()).containsExactlyElementsIn(project.expectedBuildHealth)
51+
52+
where:
53+
gradleVersion << gradleVersions()
54+
}
55+
56+
def "compilation fails without testFixtures dependency with Kotlin 2.0 (#gradleVersion)"() {
57+
given:
58+
def project = new Kotlin2Migration.CompilationFailsWithoutTestFixturesDependencies()
59+
gradleProject = project.gradleProject
60+
61+
when:
62+
def result = buildAndFail(gradleVersion, gradleProject.rootDir, ':consumer:compileTestFixturesKotlin')
63+
64+
then:
65+
assertThat(result.output).contains("Unresolved reference 'producer'.")
66+
assertThat(result.output).contains("Unresolved reference 'Person'.")
67+
68+
where:
69+
gradleVersion << gradleVersions()
70+
}
71+
}

src/functionalTest/groovy/com/autonomousapps/jvm/projects/ApplicationProject.groovy

+4-4
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,19 @@ import static com.autonomousapps.kit.gradle.dependencies.Dependencies.*
1919
*/
2020
final class ApplicationProject extends AbstractProject {
2121

22-
private final List<Plugin> plugins
22+
private final List<Plugin> appliedPlugins
2323
private final SourceType sourceType
2424
private final boolean forced
2525
private final commonsMath = commonsMath('implementation')
2626

2727
final GradleProject gradleProject
2828

2929
ApplicationProject(
30-
List<Plugin> plugins = [Plugin.application],
30+
List<Plugin> appliedPlugins = [Plugin.application],
3131
SourceType sourceType = SourceType.JAVA,
3232
boolean forced = false
3333
) {
34-
this.plugins = plugins + Plugins.dependencyAnalysisNoVersion
34+
this.appliedPlugins = appliedPlugins + Plugins.dependencyAnalysisNoVersion
3535
this.sourceType = sourceType
3636
this.forced = forced
3737
this.gradleProject = build()
@@ -42,7 +42,7 @@ final class ApplicationProject extends AbstractProject {
4242
.withSubproject('proj') { s ->
4343
s.sources = sources()
4444
s.withBuildScript { bs ->
45-
bs.plugins = plugins
45+
bs.plugins = appliedPlugins
4646
bs.dependencies = dependencies()
4747

4848
// TODO(tsr): put this somewhere else. It's only for TestKit-Truth

src/functionalTest/groovy/com/autonomousapps/jvm/projects/FeatureVariantInConsumerTestProject.groovy

+21-27
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import com.autonomousapps.AbstractProject
66
import com.autonomousapps.kit.GradleProject
77
import com.autonomousapps.kit.Source
88
import com.autonomousapps.kit.SourceType
9-
import com.autonomousapps.kit.gradle.Feature
109
import com.autonomousapps.kit.gradle.Java
1110
import com.autonomousapps.kit.gradle.Plugin
1211
import com.autonomousapps.model.Advice
@@ -24,27 +23,26 @@ final class FeatureVariantInConsumerTestProject extends AbstractProject {
2423
}
2524

2625
private GradleProject build() {
27-
def builder = newGradleProjectBuilder()
28-
builder.withSubproject('producer') { s ->
29-
s.sources = producerSources
30-
s.withBuildScript { bs ->
31-
bs.plugins = javaLibrary
26+
return newGradleProjectBuilder()
27+
.withSubproject('producer') { s ->
28+
s.sources = producerSources
29+
s.withBuildScript { bs ->
30+
bs.plugins = javaLibrary
31+
}
3232
}
33-
}
34-
builder.withSubproject('consumer') { s ->
35-
s.sources = consumerSources
36-
s.withBuildScript { bs ->
37-
bs.plugins = javaLibrary + Plugin.javaTestFixtures
38-
bs.java = Java.ofFeatures(Feature.ofName('extra'))
39-
bs.dependencies = [
40-
project('api', ':producer'),
41-
project('testFixturesImplementation', ':producer'),
42-
project('extraImplementation', ':consumer')
43-
]
33+
.withSubproject('consumer') { s ->
34+
s.sources = consumerSources
35+
s.withBuildScript { bs ->
36+
bs.plugins = javaLibrary + Plugin.javaTestFixtures
37+
bs.java = Java.ofFeatures('extra')
38+
bs.dependencies = [
39+
project('api', ':producer'),
40+
project('testFixturesImplementation', ':producer'),
41+
project('extraImplementation', ':consumer')
42+
]
43+
}
4444
}
45-
}
46-
47-
return builder.write()
45+
.write()
4846
}
4947

5048
private producerSources = [
@@ -95,19 +93,15 @@ final class FeatureVariantInConsumerTestProject extends AbstractProject {
9593
private Producer p;
9694
private Consumer c;
9795
}""".stripIndent()
98-
, "extra")
96+
, "extra")
9997
]
10098

10199
Set<ProjectAdvice> actualBuildHealth() {
102100
return actualProjectAdvice(gradleProject)
103101
}
104102

105-
private final Set<Advice> expectedConsumerAdvice = [
106-
Advice.ofAdd(projectCoordinates(':producer'), 'extraImplementation')
107-
]
108-
109103
final Set<ProjectAdvice> expectedBuildHealth = [
110-
projectAdviceForDependencies(':consumer', expectedConsumerAdvice),
111-
projectAdviceForDependencies(':producer', [] as Set)
104+
emptyProjectAdviceFor(':consumer'),
105+
emptyProjectAdviceFor(':producer')
112106
]
113107
}

0 commit comments

Comments
 (0)