From 7a89f4087a2e2d9ae73e6d7065bf03dcf4b29f9a Mon Sep 17 00:00:00 2001 From: Sebastian Sellmair Date: Wed, 7 Dec 2022 15:51:51 +0100 Subject: [PATCH] [Gradle] Implement IdeSourcesAndDocumentationResolutionTest ^KT-55289 Verification Pending --- .../IdeaBinaryCoordinatesInstanceMatcher.kt | 22 +++ .../tcs/ideaDependencyMatcherBuilders.kt | 2 + ...ionQuerySourcesAndDocumentationResolver.kt | 11 +- ...deSourcesAndDocumentationResolutionTest.kt | 147 ++++++++++++++++++ 4 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-idea/src/testFixtures/kotlin/org/jetbrains/kotlin/gradle/idea/testFixtures/tcs/IdeaBinaryCoordinatesInstanceMatcher.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/ide/IdeSourcesAndDocumentationResolutionTest.kt diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/testFixtures/kotlin/org/jetbrains/kotlin/gradle/idea/testFixtures/tcs/IdeaBinaryCoordinatesInstanceMatcher.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/testFixtures/kotlin/org/jetbrains/kotlin/gradle/idea/testFixtures/tcs/IdeaBinaryCoordinatesInstanceMatcher.kt new file mode 100644 index 00000000000..aa315beba89 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/testFixtures/kotlin/org/jetbrains/kotlin/gradle/idea/testFixtures/tcs/IdeaBinaryCoordinatesInstanceMatcher.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.idea.testFixtures.tcs + +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryCoordinates +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryDependency +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency + +internal class IdeaBinaryCoordinatesInstanceMatcher( + private val coordinates: IdeaKotlinBinaryCoordinates +) : IdeaKotlinDependencyMatcher { + override val description: String + get() = "coordinates:$coordinates" + + override fun matches(dependency: IdeaKotlinDependency): Boolean { + if (dependency !is IdeaKotlinBinaryDependency) return false + return coordinates == dependency.coordinates + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-idea/src/testFixtures/kotlin/org/jetbrains/kotlin/gradle/idea/testFixtures/tcs/ideaDependencyMatcherBuilders.kt b/libraries/tools/kotlin-gradle-plugin-idea/src/testFixtures/kotlin/org/jetbrains/kotlin/gradle/idea/testFixtures/tcs/ideaDependencyMatcherBuilders.kt index 5404e1a8a58..a7603d3742a 100644 --- a/libraries/tools/kotlin-gradle-plugin-idea/src/testFixtures/kotlin/org/jetbrains/kotlin/gradle/idea/testFixtures/tcs/ideaDependencyMatcherBuilders.kt +++ b/libraries/tools/kotlin-gradle-plugin-idea/src/testFixtures/kotlin/org/jetbrains/kotlin/gradle/idea/testFixtures/tcs/ideaDependencyMatcherBuilders.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.gradle.idea.testFixtures.tcs import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryCoordinates import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinSourceDependency @@ -13,6 +14,7 @@ fun buildIdeaKotlinDependencyMatchers(notation: Any?): List return emptyList() is IdeaKotlinDependency -> listOf(IdeaKotlinDependencyInstanceMatcher(notation)) + is IdeaKotlinBinaryCoordinates -> listOf(IdeaBinaryCoordinatesInstanceMatcher(notation)) is IdeaKotlinDependencyMatcher -> listOf(notation) is Iterable<*> -> notation.flatMap { buildIdeaKotlinDependencyMatchers(it) } else -> error("Can't build ${IdeaKotlinSourceDependencyMatcher::class.java.simpleName} from $notation") diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeArtifactResolutionQuerySourcesAndDocumentationResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeArtifactResolutionQuerySourcesAndDocumentationResolver.kt index e7d7240d671..89e2a614e54 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeArtifactResolutionQuerySourcesAndDocumentationResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeArtifactResolutionQuerySourcesAndDocumentationResolver.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers +import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.component.ModuleComponentIdentifier import org.gradle.api.artifacts.result.ArtifactResolutionResult import org.gradle.api.artifacts.result.ResolvedArtifactResult @@ -14,9 +15,11 @@ import org.gradle.language.base.artifact.SourcesArtifact import org.gradle.language.java.artifact.JavadocArtifact import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinBinaryCoordinates +import org.jetbrains.kotlin.gradle.plugin.mpp.internal import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration import org.jetbrains.kotlin.gradle.plugin.sources.internal import org.jetbrains.kotlin.gradle.plugin.sources.project @@ -32,7 +35,7 @@ import org.jetbrains.kotlin.gradle.plugin.sources.project internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeDependencyResolver { override fun resolve(sourceSet: KotlinSourceSet): Set { val project = sourceSet.project - val configuration = sourceSet.internal.resolvableMetadataConfiguration + val configuration = selectConfiguration(sourceSet) val resolutionResult = project.dependencies.createArtifactResolutionQuery() .forComponents(configuration.incoming.resolutionResult.allComponents.map { it.id }) .withArtifacts(JvmLibrary::class.java, SourcesArtifact::class.java, JavadocArtifact::class.java) @@ -58,4 +61,10 @@ internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeD } }.toSet() } + + private fun selectConfiguration(sourceSet: KotlinSourceSet): Configuration { + val platformCompilation = sourceSet.internal.compilations.singleOrNull { it.platformType != KotlinPlatformType.common } + return platformCompilation?.internal?.configurations?.compileDependencyConfiguration + ?: sourceSet.internal.resolvableMetadataConfiguration + } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/ide/IdeSourcesAndDocumentationResolutionTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/ide/IdeSourcesAndDocumentationResolutionTest.kt new file mode 100644 index 00000000000..46fa1fafc8a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/ide/IdeSourcesAndDocumentationResolutionTest.kt @@ -0,0 +1,147 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("FunctionName", "DuplicatedCode") + +package org.jetbrains.kotlin.gradle.ide + +import org.jetbrains.kotlin.gradle.applyMultiplatformPlugin +import org.jetbrains.kotlin.gradle.buildProject +import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension +import org.jetbrains.kotlin.gradle.enableDefaultStdlibDependency +import org.jetbrains.kotlin.gradle.enableDependencyVerification +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency +import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency +import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.assertMatches +import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.binaryCoordinates +import org.jetbrains.kotlin.gradle.kpm.idea.mavenCentralCacheRedirector +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers.IdeNativeStdlibDependencyResolver +import org.jetbrains.kotlin.gradle.plugin.ide.kotlinIdeMultiplatformImport +import kotlin.test.Test +import kotlin.test.fail +import kotlin.text.Regex.Companion.escape + +class IdeSourcesAndDocumentationResolutionTest { + + @Test + fun `test - MVIKotlin`() { + val project = buildProject { + enableDefaultStdlibDependency(false) + enableDependencyVerification(false) + applyMultiplatformPlugin() + repositories.mavenCentralCacheRedirector() + } + + val kotlin = project.multiplatformExtension + kotlin.targetHierarchy.default() + kotlin.jvm() + kotlin.linuxX64() + kotlin.linuxArm64() + + val commonMain = kotlin.sourceSets.getByName("commonMain") + val commonTest = kotlin.sourceSets.getByName("commonTest") + val nativeMain = kotlin.sourceSets.getByName("nativeMain") + val nativeTest = kotlin.sourceSets.getByName("nativeTest") + val linuxX64Main = kotlin.sourceSets.getByName("linuxX64Main") + val linuxX64Test = kotlin.sourceSets.getByName("linuxX64Test") + + commonMain.dependencies { + implementation("com.arkivanov.mvikotlin:mvikotlin:3.0.2") + } + + project.evaluate() + + fun resolveDependencySources(sourceSet: KotlinSourceSet): List = + project.kotlinIdeMultiplatformImport.resolveDependencies(sourceSet) + .filterIsInstance() + .filter { it.binaryType == IdeaKotlinDependency.SOURCES_BINARY_TYPE } + + + /* Check commonMain&commonTest */ + run { + val expectedDependencies = listOf( + binaryCoordinates("com.arkivanov.mvikotlin:mvikotlin:3.0.2"), + binaryCoordinates("com.arkivanov.essenty:lifecycle:0.4.2"), + binaryCoordinates("com.arkivanov.essenty:instance-keeper:0.4.2"), + + /* sources.jar resolution using ArtifactResolutionQuery will resolve those additionally */ + binaryCoordinates("org.jetbrains:annotations:13.0"), + binaryCoordinates(Regex(escape("org.jetbrains.kotlin:kotlin-stdlib") + ".*")) + ) + + val resolvedDependencies = resolveDependencySources(commonMain) + resolvedDependencies.assertMatches(expectedDependencies) + resolveDependencySources(commonTest).assertMatches(resolvedDependencies) + resolvedDependencies.assertFilesEndWith("-sources.jar") + } + + /* Check nativeMain&nativeTest */ + run { + val expectedDependencies = listOf( + binaryCoordinates("com.arkivanov.mvikotlin:mvikotlin:3.0.2"), + binaryCoordinates("com.arkivanov.essenty:lifecycle:0.4.2"), + binaryCoordinates("com.arkivanov.essenty:instance-keeper:0.4.2"), + IdeNativeStdlibDependencyResolver.nativeStdlibCoordinates(project), + + /* sources.jar resolution using ArtifactResolutionQuery will resolve those additionally */ + binaryCoordinates("org.jetbrains:annotations:13.0"), + binaryCoordinates(Regex(escape("org.jetbrains.kotlin:kotlin-stdlib") + ".*")) + ) + + val resolvedDependencies = resolveDependencySources(nativeMain) + resolvedDependencies.assertMatches(expectedDependencies) + resolveDependencySources(nativeTest).assertMatches(resolvedDependencies) + resolvedDependencies.assertFilesEndWith("-sources.jar", "-sources.zip") + } + + /* Check linuxX64Main and linuxX64Test */ + run { + val expectedDependencies = listOf( + /* Artifact Query is 'over providing' */ + listOf( + binaryCoordinates("com.arkivanov.mvikotlin:mvikotlin:3.0.2"), + binaryCoordinates("com.arkivanov.mvikotlin:utils-internal:3.0.2"), + binaryCoordinates("com.arkivanov.mvikotlin:rx:3.0.2"), + binaryCoordinates("com.arkivanov.mvikotlin:rx-internal:3.0.2"), + binaryCoordinates("com.arkivanov.essenty:utils-internal:0.4.2"), + binaryCoordinates("com.arkivanov.essenty:lifecycle:0.4.2"), + binaryCoordinates("com.arkivanov.essenty:instance-keeper:0.4.2") + ), + + /* Required dependencies */ + listOf( + binaryCoordinates("com.arkivanov.mvikotlin:rx-internal-linuxx64:3.0.2"), + binaryCoordinates("com.arkivanov.mvikotlin:rx-linuxx64:3.0.2"), + binaryCoordinates("com.arkivanov.mvikotlin:utils-internal-linuxx64:3.0.2"), + binaryCoordinates("com.arkivanov.mvikotlin:mvikotlin-linuxx64:3.0.2"), + binaryCoordinates("com.arkivanov.essenty:utils-internal-linuxx64:0.4.2"), + binaryCoordinates("com.arkivanov.essenty:lifecycle-linuxx64:0.4.2"), + binaryCoordinates("com.arkivanov.essenty:instance-keeper-linuxx64:0.4.2") + ), + + /* Stdlib */ + listOf( + binaryCoordinates("org.jetbrains:annotations:13.0"), + IdeNativeStdlibDependencyResolver.nativeStdlibCoordinates(project), + binaryCoordinates(Regex(escape("org.jetbrains.kotlin:kotlin-stdlib") + ".*")) + ) + ) + + val resolvedDependencies = resolveDependencySources(linuxX64Main) + resolvedDependencies.assertMatches(expectedDependencies) + resolveDependencySources(linuxX64Test).assertMatches(resolvedDependencies) + resolvedDependencies.assertFilesEndWith("-sources.jar", "-sources.zip") + } + } +} + +private fun Iterable.assertFilesEndWith(vararg suffixes: String) { + forEach { dependency -> + if (suffixes.none { suffix -> dependency.binaryFile.path.endsWith(suffix) }) { + fail("Expected binaryFile to end with one of ${suffixes.toList()}. Found: ${dependency.binaryFile}") + } + } +} \ No newline at end of file