From fbbc26e0852965d7e2cbc1190bb7f18960cfdfc0 Mon Sep 17 00:00:00 2001 From: Tad Fisher Date: Mon, 3 Jun 2019 15:41:44 -0700 Subject: [PATCH] Migrate tests to stutter; bring compat down to 4.4.1 --- app/build.gradle.kts | 2 +- plugin/.stutter/java11.lock | 7 + plugin/.stutter/java8.lock | 2 + plugin/build.gradle.kts | 32 +-- .../kotlin/org/nixos/gradle2nix/BasicTest.kt | 97 +++++--- .../org/nixos/gradle2nix/SubprojectsTest.kt | 226 ++++++++++++++++++ .../kotlin/org/nixos/gradle2nix/TestUtil.kt | 105 ++++++++ .../org/nixos/gradle2nix/Gradle2NixPlugin.kt | 20 +- .../org/nixos/gradle2nix/PluginResolver.kt | 15 +- 9 files changed, 434 insertions(+), 72 deletions(-) create mode 100644 plugin/.stutter/java11.lock create mode 100644 plugin/src/compatTest/kotlin/org/nixos/gradle2nix/SubprojectsTest.kt create mode 100644 plugin/src/compatTest/kotlin/org/nixos/gradle2nix/TestUtil.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 69ca255..2f4796d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -40,7 +40,7 @@ application { } tasks { - named("startScripts") { + startScripts { doLast { unixScript.writeText(unixScript.readText().replace("@APP_HOME@", "\$APP_HOME")) windowsScript.writeText(windowsScript.readText().replace("@APP_HOME@", "%APP_HOME%")) diff --git a/plugin/.stutter/java11.lock b/plugin/.stutter/java11.lock new file mode 100644 index 0000000..2dbe61e --- /dev/null +++ b/plugin/.stutter/java11.lock @@ -0,0 +1,7 @@ +# DO NOT MODIFY: Generated by Stutter plugin. +5.0 +5.1.1 +5.2.1 +5.3.1 +5.4.1 +5.5-rc-1 diff --git a/plugin/.stutter/java8.lock b/plugin/.stutter/java8.lock index c66434a..3c9cb20 100644 --- a/plugin/.stutter/java8.lock +++ b/plugin/.stutter/java8.lock @@ -1,4 +1,5 @@ # DO NOT MODIFY: Generated by Stutter plugin. +4.4.1 4.5.1 4.6 4.7 @@ -10,3 +11,4 @@ 5.2.1 5.3.1 5.4.1 +5.5-rc-1 diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index ed44674..621fc91 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -25,8 +25,15 @@ dependencyLocking { lockAllConfigurations() } +configurations { + compile { + dependencies.remove(project.dependencies.gradleApi()) + } +} + dependencies { implementation(project(":model")) + shadow(gradleApi()) compileOnly("org.gradle:gradle-tooling-api:${gradle.gradleVersion}") implementation("org.apache.maven:maven-model:latest.release") implementation("org.apache.maven:maven-model-builder:latest.release") @@ -56,7 +63,7 @@ kotlinDslPluginOptions { stutter { java(8) { - compatibleRange("4.5") + compatibleRange("4.4") } java(11) { compatibleRange("5.0") @@ -64,26 +71,11 @@ stutter { } tasks { + pluginUnderTestMetadata { + pluginClasspath.setFrom(files(shadowJar)) + } + withType { useJUnitPlatform() } - -// gradleTestGenerator { -// dependsOn(shadowJar) -// doLast { -// file(gradleTest.get().initScript).bufferedWriter().use { out -> -// out.append(""" -// initscript { -// dependencies { -// classpath fileTree('file:${buildDir.absolutePath}/libs'.toURI()) { -// include '*.jar' -// } -// } -// } -// -// apply plugin: org.nixos.gradle2nix.Gradle2NixPlugin -// """.trimIndent()) -// } -// } -// } } diff --git a/plugin/src/compatTest/kotlin/org/nixos/gradle2nix/BasicTest.kt b/plugin/src/compatTest/kotlin/org/nixos/gradle2nix/BasicTest.kt index 6ba9945..f337ea5 100644 --- a/plugin/src/compatTest/kotlin/org/nixos/gradle2nix/BasicTest.kt +++ b/plugin/src/compatTest/kotlin/org/nixos/gradle2nix/BasicTest.kt @@ -1,9 +1,5 @@ package org.nixos.gradle2nix -import org.gradle.internal.classpath.DefaultClassPath -import org.gradle.testkit.runner.internal.PluginUnderTestMetadataReading -import org.gradle.tooling.GradleConnector -import org.gradle.tooling.internal.consumer.DefaultModelBuilder import org.junit.jupiter.api.Test import org.junit.jupiter.api.io.TempDir import java.io.File @@ -11,32 +7,11 @@ import kotlin.test.assertEquals class BasicTest { - companion object { - @JvmStatic @TempDir lateinit var projectDir: File - - val initScript: File by lazy { - projectDir.resolve("init.gradle").also { - it.writer().use { out -> -// val classpath = DefaultClassPath.of(PluginUnderTestMetadataReading.readImplementationClasspath()) -// .asFiles.joinToString(prefix = "'", postfix = "'") -// out.appendln(""" -// initscript { -// dependencies { -// classpath files($classpath) -// } -// } -// -// apply plugin: org.nixos.gradle2nix.Gradle2NixPlugin -// """.trimIndent()) - out.appendln("apply plugin: org.nixos.gradle2nix.Gradle2NixPlugin") - } - } - } - } + @TempDir lateinit var projectDir: File @Test fun `builds basic project with kotlin dsl`() { - projectDir.resolve("build.gradle.kts").writeText(""" + val model = projectDir.buildKotlin(""" plugins { java } @@ -51,20 +26,48 @@ class BasicTest { } """.trimIndent()) - val connection = GradleConnector.newConnector() - .useGradleVersion(System.getProperty("compat.gradle.version")) - .forProjectDirectory(projectDir) - .connect() + assertEquals(model.gradle.version, System.getProperty("compat.gradle.version")) - val model = (connection.model(Build::class.java) as DefaultModelBuilder) - .withArguments( - "--init-script=$initScript", - "--stacktrace" + with(model.rootProject.projectDependencies) { + with(repositories) { + assertEquals(1, maven.size) + assertEquals(maven[0].urls[0], "https://jcenter.bintray.com/") + } + + assertArtifacts( + pom("com.squareup.moshi:moshi-parent:1.8.0"), + jar("com.squareup.moshi:moshi:1.8.0"), + pom("com.squareup.moshi:moshi:1.8.0"), + jar("com.squareup.okio:okio:2.2.2"), + pom("com.squareup.okio:okio:2.2.2"), + jar("org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60"), + pom("org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60"), + jar("org.jetbrains.kotlin:kotlin-stdlib:1.2.60"), + pom("org.jetbrains.kotlin:kotlin-stdlib:1.2.60"), + jar("org.jetbrains:annotations:13.0"), + pom("org.jetbrains:annotations:13.0"), + pom("org.sonatype.oss:oss-parent:7"), + actual = artifacts ) - .withInjectedClassPath(DefaultClassPath.of(PluginUnderTestMetadataReading.readImplementationClasspath())) - .setStandardOutput(System.out) - .setStandardError(System.out) - .get() + } + } + + @Test + fun `builds basic project with groovy dsl`() { + val model = projectDir.buildGroovy(""" + plugins { + id("java") + } + + repositories { + jcenter() + } + + dependencies { + implementation 'com.squareup.okio:okio:2.2.2' + implementation 'com.squareup.moshi:moshi:1.8.0' + } + """.trimIndent()) assertEquals(model.gradle.version, System.getProperty("compat.gradle.version")) @@ -73,6 +76,22 @@ class BasicTest { assertEquals(1, maven.size) assertEquals(maven[0].urls[0], "https://jcenter.bintray.com/") } + + assertArtifacts( + pom("com.squareup.moshi:moshi-parent:1.8.0"), + jar("com.squareup.moshi:moshi:1.8.0"), + pom("com.squareup.moshi:moshi:1.8.0"), + jar("com.squareup.okio:okio:2.2.2"), + pom("com.squareup.okio:okio:2.2.2"), + jar("org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60"), + pom("org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60"), + jar("org.jetbrains.kotlin:kotlin-stdlib:1.2.60"), + pom("org.jetbrains.kotlin:kotlin-stdlib:1.2.60"), + jar("org.jetbrains:annotations:13.0"), + pom("org.jetbrains:annotations:13.0"), + pom("org.sonatype.oss:oss-parent:7"), + actual = artifacts + ) } } } diff --git a/plugin/src/compatTest/kotlin/org/nixos/gradle2nix/SubprojectsTest.kt b/plugin/src/compatTest/kotlin/org/nixos/gradle2nix/SubprojectsTest.kt new file mode 100644 index 0000000..159f87c --- /dev/null +++ b/plugin/src/compatTest/kotlin/org/nixos/gradle2nix/SubprojectsTest.kt @@ -0,0 +1,226 @@ +package org.nixos.gradle2nix + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir +import java.io.File +import kotlin.test.assertEquals + +class SubprojectsTest { + @TempDir + lateinit var root: File + + @Test + fun `builds multi-module project with kotlin dsl`() { + root.resolve("child-a").also { it.mkdirs() } + .resolve("build.gradle.kts").writeText(""" + plugins { + java + } + + dependencies { + implementation("com.squareup.okio:okio:2.2.2") + } + """.trimIndent()) + + root.resolve("child-b").also { it.mkdirs() } + .resolve("build.gradle.kts").writeText(""" + plugins { + java + } + + dependencies { + implementation("com.squareup.moshi:moshi:1.8.0") + } + """.trimIndent()) + + root.resolve("settings.gradle.kts").writeText(""" + include(":child-a", ":child-b") + """.trimIndent()) + + val model = root.buildKotlin(""" + plugins { + java + } + + allprojects { + repositories { + jcenter() + } + } + + dependencies { + testImplementation("junit:junit:4.12") + } + """.trimIndent()) + + with(model.rootProject) { + with(projectDependencies) { + assertEquals(listOf(DefaultMaven(urls = listOf("https://jcenter.bintray.com/"))), + repositories.maven) + + assertArtifacts( + jar("junit:junit:4.12"), + pom("junit:junit:4.12"), + jar("org.hamcrest:hamcrest-core:1.3"), + pom("org.hamcrest:hamcrest-core:1.3"), + pom("org.hamcrest:hamcrest-parent:1.3"), + actual = artifacts) + } + + assertEquals(2, children.size) + + with(children[0]) { + assertEquals("child-a", name) + assertEquals(root.resolve("child-a").toRelativeString(root), projectDir) + + with(projectDependencies) { + assertEquals( + listOf(DefaultMaven(urls = listOf("https://jcenter.bintray.com/"))), + repositories.maven + ) + + assertArtifacts( + jar("com.squareup.okio:okio:2.2.2"), + pom("com.squareup.okio:okio:2.2.2"), + jar("org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60"), + pom("org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60"), + jar("org.jetbrains.kotlin:kotlin-stdlib:1.2.60"), + pom("org.jetbrains.kotlin:kotlin-stdlib:1.2.60"), + jar("org.jetbrains:annotations:13.0"), + pom("org.jetbrains:annotations:13.0"), + actual = artifacts + ) + } + } + + with(children[1]) { + assertEquals("child-b", name) + assertEquals(root.resolve("child-b").toRelativeString(root), projectDir) + + with(projectDependencies) { + assertEquals( + listOf(DefaultMaven(urls = listOf("https://jcenter.bintray.com/"))), + repositories.maven + ) + + assertArtifacts( + pom("com.squareup.moshi:moshi-parent:1.8.0"), + jar("com.squareup.moshi:moshi:1.8.0"), + pom("com.squareup.moshi:moshi:1.8.0"), + pom("com.squareup.okio:okio-parent:1.16.0"), + jar("com.squareup.okio:okio:1.16.0"), + pom("com.squareup.okio:okio:1.16.0"), + pom("org.sonatype.oss:oss-parent:7"), + actual = artifacts + ) + } + } + } + } + + @Test + fun `builds multi-module project with groovy dsl`() { + root.resolve("child-a").also { it.mkdirs() } + .resolve("build.gradle").writeText(""" + plugins { + id 'java' + } + + dependencies { + implementation 'com.squareup.okio:okio:2.2.2' + } + """.trimIndent()) + + root.resolve("child-b").also { it.mkdirs() } + .resolve("build.gradle").writeText(""" + plugins { + id 'java' + } + + dependencies { + implementation 'com.squareup.moshi:moshi:1.8.0' + } + """.trimIndent()) + + root.resolve("settings.gradle").writeText(""" + include ':child-a', ':child-b' + """.trimIndent()) + + val model = root.buildGroovy(""" + plugins { + id 'java' + } + + allprojects { + repositories { + jcenter() + } + } + + dependencies { + testImplementation 'junit:junit:4.12' + } + """.trimIndent()) + + with(model.rootProject) { + with(projectDependencies) { + assertEquals(listOf(DefaultMaven(urls = listOf("https://jcenter.bintray.com/"))), + repositories.maven) + + assertArtifacts( + jar("junit:junit:4.12"), + pom("junit:junit:4.12"), + jar("org.hamcrest:hamcrest-core:1.3"), + pom("org.hamcrest:hamcrest-core:1.3"), + pom("org.hamcrest:hamcrest-parent:1.3"), + actual = artifacts) + } + + assertEquals(2, children.size) + + with(children[0]) { + assertEquals("child-a", name) + assertEquals(root.resolve("child-a").toRelativeString(root), projectDir) + + with(projectDependencies) { + assertEquals( + listOf(DefaultMaven(urls = listOf("https://jcenter.bintray.com/"))), + repositories.maven + ) + + assertArtifacts( + jar("com.squareup.okio:okio:2.2.2"), + pom("com.squareup.okio:okio:2.2.2"), + jar("org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60"), + pom("org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60"), + jar("org.jetbrains.kotlin:kotlin-stdlib:1.2.60"), + pom("org.jetbrains.kotlin:kotlin-stdlib:1.2.60"), + jar("org.jetbrains:annotations:13.0"), + pom("org.jetbrains:annotations:13.0"), + actual = artifacts + ) + } + } + + with(children[1]) { + assertEquals("child-b", name) + assertEquals(root.resolve("child-b").toRelativeString(root), projectDir) + + with(projectDependencies) { + assertEquals(listOf(DefaultMaven(urls = listOf("https://jcenter.bintray.com/"))), + repositories.maven) + + assertArtifacts( + pom("com.squareup.moshi:moshi-parent:1.8.0"), + jar("com.squareup.moshi:moshi:1.8.0"), + pom("com.squareup.moshi:moshi:1.8.0"), + pom("com.squareup.okio:okio-parent:1.16.0"), + jar("com.squareup.okio:okio:1.16.0"), + pom("com.squareup.okio:okio:1.16.0"), + pom("org.sonatype.oss:oss-parent:7"), + actual = artifacts) + } + } + } + } +} diff --git a/plugin/src/compatTest/kotlin/org/nixos/gradle2nix/TestUtil.kt b/plugin/src/compatTest/kotlin/org/nixos/gradle2nix/TestUtil.kt new file mode 100644 index 0000000..8152ef4 --- /dev/null +++ b/plugin/src/compatTest/kotlin/org/nixos/gradle2nix/TestUtil.kt @@ -0,0 +1,105 @@ +package org.nixos.gradle2nix + +import org.gradle.api.internal.artifacts.dsl.ParsedModuleStringNotation +import org.gradle.internal.classpath.DefaultClassPath +import org.gradle.testkit.runner.internal.PluginUnderTestMetadataReading +import org.gradle.tooling.GradleConnector +import java.io.File +import kotlin.test.assertTrue + +private fun File.initscript() = resolve("init.gradle").also { + it.writer().use { out -> + val classpath = DefaultClassPath.of(PluginUnderTestMetadataReading.readImplementationClasspath()) + .asFiles.joinToString(prefix = "'", postfix = "'") + out.appendln(""" + initscript { + dependencies { + classpath files($classpath) + } + } + + apply plugin: org.nixos.gradle2nix.Gradle2NixPlugin + """.trimIndent()) + } +} + +fun File.buildGroovy(script: String): DefaultBuild { + resolve("build.gradle").writeText(script) + return build() +} + +fun File.buildKotlin(script: String): DefaultBuild { + resolve("build.gradle.kts").writeText(script) + return build() +} + +private fun File.build(): DefaultBuild { + return GradleConnector.newConnector() + .useGradleVersion(System.getProperty("compat.gradle.version")) + .forProjectDirectory(this) + .connect() + .model(Build::class.java) + .withArguments( + "--init-script=${initscript()}", + "--stacktrace" + ) + .setStandardOutput(System.out) + .setStandardError(System.out) + .get() + .let { DefaultBuild(it) } +} + +fun jar(notation: String, sha256: String = ""): DefaultArtifact = + artifact(notation, sha256, "jar") + +fun pom(notation: String, sha256: String = ""): DefaultArtifact = + artifact(notation, sha256, "pom") + +private fun artifact(notation: String, sha256: String, type: String): DefaultArtifact { + val parsed = ParsedModuleStringNotation(notation, type) + return DefaultArtifact( + groupId = parsed.group ?: "", + artifactId = parsed.name ?: "", + version = parsed.version ?: "", + classifier = parsed.classifier ?: "", + extension = type, + sha256 = sha256 + ) +} + +private fun artifactEquals(expected: DefaultArtifact, actual: DefaultArtifact): Boolean { + return with (expected) { + groupId == actual.groupId && + artifactId == actual.artifactId && + version == actual.version && + classifier == actual.classifier && + extension == actual.extension && + (sha256.takeIf { it.isNotEmpty() }?.equals(actual.sha256) ?: true) + } +} + +fun assertArtifacts(vararg expected: DefaultArtifact, actual: List) { + val mismatches = mutableListOf() + val remaining = mutableListOf().also { it.addAll(actual) } + expected.forEachIndexed { i: Int, exp: DefaultArtifact -> + val act = actual[i] + if (!artifactEquals(exp, act)) { + mismatches += Mismatch(i, exp, act) + } else { + remaining -= act + } + } + assertTrue(mismatches.isEmpty() && remaining.isEmpty(), """ + Artifact mismatches: + ${mismatches.joinToString("\n ", prefix = " ")} + + Missing artifacts: + ${remaining.joinToString("\n ", prefix = " ")} + """) +} + +data class Mismatch( + val index: Int, + val expected: DefaultArtifact, + val actual: DefaultArtifact +) diff --git a/plugin/src/main/kotlin/org/nixos/gradle2nix/Gradle2NixPlugin.kt b/plugin/src/main/kotlin/org/nixos/gradle2nix/Gradle2NixPlugin.kt index d4c12da..0cd1ef3 100644 --- a/plugin/src/main/kotlin/org/nixos/gradle2nix/Gradle2NixPlugin.kt +++ b/plugin/src/main/kotlin/org/nixos/gradle2nix/Gradle2NixPlugin.kt @@ -4,14 +4,15 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.artifacts.dsl.RepositoryHandler import org.gradle.api.artifacts.repositories.MavenArtifactRepository +import org.gradle.api.internal.GradleInternal import org.gradle.api.invocation.Gradle import org.gradle.api.tasks.wrapper.Wrapper -import org.gradle.kotlin.dsl.named -import org.gradle.kotlin.dsl.newInstance +import org.gradle.kotlin.dsl.getByName import org.gradle.kotlin.dsl.support.serviceOf import org.gradle.plugin.management.PluginRequest import org.gradle.tooling.provider.model.ToolingModelBuilder import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry +import org.gradle.util.GradleVersion import java.net.URL import java.util.* import org.nixos.gradle2nix.Gradle as NixGradle @@ -64,12 +65,12 @@ private class NixToolingModelBuilder( } private fun Project.buildGradle(): DefaultGradle = - with(tasks.named("wrapper").get()) { + with(tasks.getByName("wrapper")) { DefaultGradle( version = gradleVersion, type = distributionType.name.toLowerCase(Locale.US), url = distributionUrl, - sha256 = distributionSha256Sum ?: fetchDistSha256(distributionUrl), + sha256 = sha256, nativeVersion = gradle.gradleHomeDir?.resolve("lib")?.listFiles() ?.firstOrNull { f -> nativePlatformJarRegex matches f.name }?.let { nf -> nativePlatformJarRegex.find(nf.name)?.groupValues?.get(1) @@ -85,7 +86,7 @@ private fun Project.buildGradle(): DefaultGradle = } private fun Project.buildPlugins(pluginRequests: List): DefaultDependencies = - with(objects.newInstance(pluginRequests)) { + with(PluginResolver(gradle as GradleInternal, pluginRequests)) { DefaultDependencies(repositories.repositories(), artifacts()) } @@ -151,3 +152,12 @@ internal fun RepositoryHandler.repositories() = DefaultRepositories( DefaultMaven(listOf(repo.url.toString()) + repo.artifactUrls.map { it.toString() }) } ) + +private val Wrapper.sha256: String + get() { + return if (GradleVersion.current() < GradleVersion.version("4.5")) { + fetchDistSha256(distributionUrl) + } else { + distributionSha256Sum ?: fetchDistSha256(distributionUrl) + } + } diff --git a/plugin/src/main/kotlin/org/nixos/gradle2nix/PluginResolver.kt b/plugin/src/main/kotlin/org/nixos/gradle2nix/PluginResolver.kt index d84804f..6186f3b 100644 --- a/plugin/src/main/kotlin/org/nixos/gradle2nix/PluginResolver.kt +++ b/plugin/src/main/kotlin/org/nixos/gradle2nix/PluginResolver.kt @@ -1,8 +1,10 @@ package org.nixos.gradle2nix import org.gradle.api.artifacts.ExternalModuleDependency +import org.gradle.api.internal.GradleInternal import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionSelectorScheme import org.gradle.api.internal.plugins.PluginImplementation +import org.gradle.kotlin.dsl.support.serviceOf import org.gradle.plugin.management.PluginRequest import org.gradle.plugin.management.internal.PluginRequestInternal import org.gradle.plugin.use.PluginId @@ -11,22 +13,21 @@ import org.gradle.plugin.use.resolve.internal.ArtifactRepositoriesPluginResolver import org.gradle.plugin.use.resolve.internal.PluginResolution import org.gradle.plugin.use.resolve.internal.PluginResolutionResult import org.gradle.plugin.use.resolve.internal.PluginResolveContext -import javax.inject.Inject -open class PluginResolver @Inject constructor( - private val pluginDependencyResolutionServices: PluginDependencyResolutionServices, - versionSelectorScheme: VersionSelectorScheme, +internal class PluginResolver( + gradle: GradleInternal, private val pluginRequests: Collection ) { - val repositories by lazy { - pluginDependencyResolutionServices.resolveRepositoryHandler - } + private val pluginDependencyResolutionServices = gradle.serviceOf() + private val versionSelectorScheme = gradle.serviceOf() private val artifactRepositoriesPluginResolver = ArtifactRepositoriesPluginResolver( pluginDependencyResolutionServices, versionSelectorScheme ) + val repositories = pluginDependencyResolutionServices.resolveRepositoryHandler + private val resolver by lazy { DependencyResolver( pluginDependencyResolutionServices.configurationContainer,