Fix publishing dependencies of Android libraries (KT-29476)
* Add the extendsFrom relation between the Kotlin MPP compilation's
configurations (`*Api`, `*Implementation`, `*RuntimeOnly`) and
the Android variant's `*Elements` configurations, as those
dependencies currently are not added to the Android source sets and
are thus missing from the published dependencies.
* Fix a `this is KotlinCompilationToRunnableFiles` check that
mistakenly referenced the Project receiver of `whenEvaluated { ... }`
Issue #KT-29476 Fixed
This commit is contained in:
+33
-3
@@ -140,6 +140,8 @@ class KotlinAndroid32GradleIT : KotlinAndroid3GradleIT(androidGradlePluginVersio
|
|||||||
|
|
||||||
// Convert the 'app' project to a library, publish the two without metadata,
|
// Convert the 'app' project to a library, publish the two without metadata,
|
||||||
// check that the dependencies in the POMs are correctly rewritten:
|
// check that the dependencies in the POMs are correctly rewritten:
|
||||||
|
val appGroupDir = "app/build/repo/com/example/"
|
||||||
|
|
||||||
gradleSettingsScript().modify { it.replace("enableFeaturePreview", "//") }
|
gradleSettingsScript().modify { it.replace("enableFeaturePreview", "//") }
|
||||||
gradleBuildScript("app").modify {
|
gradleBuildScript("app").modify {
|
||||||
it.replace("com.android.application", "com.android.library")
|
it.replace("com.android.application", "com.android.library")
|
||||||
@@ -152,19 +154,47 @@ class KotlinAndroid32GradleIT : KotlinAndroid3GradleIT(androidGradlePluginVersio
|
|||||||
}
|
}
|
||||||
build("publish") {
|
build("publish") {
|
||||||
assertSuccessful()
|
assertSuccessful()
|
||||||
val appGroupDir = "app/build/repo/com/example/"
|
|
||||||
listOf("foobar", "foobaz").forEach { flavor ->
|
listOf("foobar", "foobaz").forEach { flavor ->
|
||||||
listOf("-debug", "").forEach { buildType ->
|
listOf("-debug", "").forEach { buildType ->
|
||||||
assertFileExists(appGroupDir + "app-androidapp-$flavor$buildType/1.0/app-androidapp-$flavor$buildType-1.0.aar")
|
assertFileExists(appGroupDir + "app-androidapp-$flavor$buildType/1.0/app-androidapp-$flavor$buildType-1.0.aar")
|
||||||
assertFileExists(appGroupDir + "app-androidapp-$flavor$buildType/1.0/app-androidapp-$flavor$buildType-1.0-sources.jar")
|
assertFileExists(appGroupDir + "app-androidapp-$flavor$buildType/1.0/app-androidapp-$flavor$buildType-1.0-sources.jar")
|
||||||
val pomText = projectDir.resolve(
|
val pomText = projectDir.resolve(
|
||||||
appGroupDir + "app-androidapp-$flavor$buildType/1.0/app-androidapp-$flavor$buildType-1.0.pom"
|
appGroupDir + "app-androidapp-$flavor$buildType/1.0/app-androidapp-$flavor$buildType-1.0.pom"
|
||||||
).readText()
|
).readText().replace("\\s+".toRegex(), "")
|
||||||
assertTrue { "<artifactId>lib-androidlib-$flavor$buildType</artifactId>" in pomText }
|
assertTrue {
|
||||||
|
"<artifactId>lib-androidlib-$flavor$buildType</artifactId><version>1.0</version><scope>runtime</scope>" in pomText
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
projectDir.resolve(groupDir).deleteRecursively()
|
projectDir.resolve(groupDir).deleteRecursively()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also check that api and runtimeOnly MPP dependencies get correctly published with the appropriate scope, KT-29476:
|
||||||
|
gradleBuildScript("app").modify {
|
||||||
|
it.replace("implementation project(':lib')", "api project(':lib')") + "\n" + """
|
||||||
|
kotlin.sourceSets.commonMain.dependencies {
|
||||||
|
runtimeOnly(kotlin('reflect'))
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
build("publish") {
|
||||||
|
assertSuccessful()
|
||||||
|
listOf("foobar", "foobaz").forEach { flavor ->
|
||||||
|
listOf("-debug", "").forEach { buildType ->
|
||||||
|
val pomText = projectDir.resolve(
|
||||||
|
appGroupDir + "app-androidapp-$flavor$buildType/1.0/app-androidapp-$flavor$buildType-1.0.pom"
|
||||||
|
).readText().replace("\\s+".toRegex(), "")
|
||||||
|
assertTrue {
|
||||||
|
"<artifactId>lib-androidlib-$flavor$buildType</artifactId><version>1.0</version><scope>compile</scope>" in pomText
|
||||||
|
}
|
||||||
|
assertTrue {
|
||||||
|
val kotlinVersion = defaultBuildOptions().kotlinVersion
|
||||||
|
"<artifactId>kotlin-reflect</artifactId><version>$kotlinVersion</version><scope>runtime</scope>" in pomText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
+10
@@ -146,6 +146,16 @@ class Android25ProjectHandler(
|
|||||||
// We should request such API in the Android plugin
|
// We should request such API in the Android plugin
|
||||||
val apiElementsConfigurationName = "${variant.name}ApiElements"
|
val apiElementsConfigurationName = "${variant.name}ApiElements"
|
||||||
val runtimeElementsConfigurationName = "${variant.name}RuntimeElements"
|
val runtimeElementsConfigurationName = "${variant.name}RuntimeElements"
|
||||||
|
|
||||||
|
// KT-29476, the Android *Elements configurations need Kotlin MPP dependencies:
|
||||||
|
if (project.configurations.findByName(apiElementsConfigurationName) != null) {
|
||||||
|
project.addExtendsFromRelation(apiElementsConfigurationName, compilation.apiConfigurationName)
|
||||||
|
}
|
||||||
|
if (project.configurations.findByName(runtimeElementsConfigurationName) != null) {
|
||||||
|
project.addExtendsFromRelation(runtimeElementsConfigurationName, compilation.implementationConfigurationName)
|
||||||
|
project.addExtendsFromRelation(runtimeElementsConfigurationName, compilation.runtimeOnlyConfigurationName)
|
||||||
|
}
|
||||||
|
|
||||||
listOf(apiElementsConfigurationName, runtimeElementsConfigurationName).forEach { outputConfigurationName ->
|
listOf(apiElementsConfigurationName, runtimeElementsConfigurationName).forEach { outputConfigurationName ->
|
||||||
project.configurations.findByName(outputConfigurationName)?.usesPlatformOf(compilation.target)
|
project.configurations.findByName(outputConfigurationName)?.usesPlatformOf(compilation.target)
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-25
@@ -104,35 +104,33 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
|
|||||||
|
|
||||||
override fun source(sourceSet: KotlinSourceSet) {
|
override fun source(sourceSet: KotlinSourceSet) {
|
||||||
if (kotlinSourceSets.add(sourceSet)) {
|
if (kotlinSourceSets.add(sourceSet)) {
|
||||||
with(target.project) {
|
//TODO possibly issue with forced instantiation
|
||||||
//TODO possibly issue with forced instantiation
|
target.project.whenEvaluated {
|
||||||
whenEvaluated {
|
sourceSet.getSourceSetHierarchy().forEach { sourceSet ->
|
||||||
sourceSet.getSourceSetHierarchy().forEach { sourceSet ->
|
val isCommonSource =
|
||||||
val isCommonSource =
|
CompilationSourceSetUtil.sourceSetsInMultipleCompilations(project)?.contains(sourceSet) ?: false
|
||||||
CompilationSourceSetUtil.sourceSetsInMultipleCompilations(project)?.contains(sourceSet) ?: false
|
|
||||||
|
|
||||||
addSourcesToCompileTask(sourceSet, addAsCommonSources = isCommonSource)
|
addSourcesToCompileTask(sourceSet, addAsCommonSources = isCommonSource)
|
||||||
|
|
||||||
// Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like
|
// Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like
|
||||||
// old Java & Android projects:
|
// old Java & Android projects:
|
||||||
addExtendsFromRelation(apiConfigurationName, sourceSet.apiConfigurationName, forced = false)
|
addExtendsFromRelation(apiConfigurationName, sourceSet.apiConfigurationName, forced = false)
|
||||||
addExtendsFromRelation(implementationConfigurationName, sourceSet.implementationConfigurationName, forced = false)
|
addExtendsFromRelation(implementationConfigurationName, sourceSet.implementationConfigurationName, forced = false)
|
||||||
addExtendsFromRelation(compileOnlyConfigurationName, sourceSet.compileOnlyConfigurationName, forced = false)
|
addExtendsFromRelation(compileOnlyConfigurationName, sourceSet.compileOnlyConfigurationName, forced = false)
|
||||||
|
|
||||||
if (this is KotlinCompilationToRunnableFiles<*>) {
|
if (this@AbstractKotlinCompilation is KotlinCompilationToRunnableFiles<*>) {
|
||||||
addExtendsFromRelation(runtimeOnlyConfigurationName, sourceSet.runtimeOnlyConfigurationName, forced = false)
|
addExtendsFromRelation(runtimeOnlyConfigurationName, sourceSet.runtimeOnlyConfigurationName, forced = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sourceSet.name != defaultSourceSetName) {
|
if (sourceSet.name != defaultSourceSetName) {
|
||||||
kotlinExtension.sourceSets.findByName(defaultSourceSetName)?.let { defaultSourceSet ->
|
kotlinExtension.sourceSets.findByName(defaultSourceSetName)?.let { defaultSourceSet ->
|
||||||
// Temporary solution for checking consistency across source sets participating in a compilation that may
|
// Temporary solution for checking consistency across source sets participating in a compilation that may
|
||||||
// not be interconnected with the dependsOn relation: check the settings as if the default source set of
|
// not be interconnected with the dependsOn relation: check the settings as if the default source set of
|
||||||
// the compilation depends on the one added to the compilation:
|
// the compilation depends on the one added to the compilation:
|
||||||
defaultSourceSetLanguageSettingsChecker.runAllChecks(
|
defaultSourceSetLanguageSettingsChecker.runAllChecks(
|
||||||
defaultSourceSet,
|
defaultSourceSet,
|
||||||
sourceSet
|
sourceSet
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user