Skip to content

Commit 43a127e

Browse files
timofey-soloninSpace Team
authored andcommitted
Add compatibility rules for Android to resolve UKlib fallback variant
This variant should resolve in pre-UKlib dependencies when no other targets match. ^KT-79876 ^KT-81412
1 parent c166672 commit 43a127e

File tree

4 files changed

+365
-0
lines changed

4 files changed

+365
-0
lines changed

libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/uklibs/UklibConsumptionIT.kt

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,131 @@ class UklibConsumptionIT : KGPBaseTest() {
13241324
}
13251325
}
13261326

1327+
@GradleAndroidTest
1328+
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_88)
1329+
fun `uklib consumption - KMP androidLibrary resolves to fallback variant with pre-UKlib dependencies`(
1330+
version: GradleVersion,
1331+
androidVersion: String,
1332+
) {
1333+
val configureAndroidLibrary: KotlinMultiplatformExtension.() -> Unit = {
1334+
val target = targets.getByName("android")
1335+
val klass = target::class.java.classLoader.loadClass("com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryExtension")
1336+
val compileSdk = klass.getMethod("setCompileSdk", Int::class.javaObjectType)
1337+
compileSdk.invoke(target, 31)
1338+
val namespace = klass.getMethod("setNamespace", String::class.java)
1339+
namespace.invoke(target, "foo")
1340+
}
1341+
val producer = project(
1342+
"empty",
1343+
version,
1344+
) {
1345+
addKgpToBuildScriptCompilationClasspath()
1346+
addAgpToBuildScriptCompilationClasspath(androidVersion)
1347+
buildScriptInjection {
1348+
project.applyMultiplatform {
1349+
iosArm64()
1350+
iosX64()
1351+
js()
1352+
sourceSets.commonMain.get().compileSource("class Common")
1353+
}
1354+
}
1355+
}.publish(publisherConfiguration = PublisherConfiguration(group = "producer"))
1356+
1357+
val consumer = project("empty", version) {
1358+
addKgpToBuildScriptCompilationClasspath()
1359+
addAgpToBuildScriptCompilationClasspath(androidVersion)
1360+
addPublishedProjectToRepositories(producer)
1361+
buildScriptInjection {
1362+
project.setUklibResolutionStrategy()
1363+
project.setUklibPublicationStrategy()
1364+
project.plugins.apply("com.android.kotlin.multiplatform.library")
1365+
project.applyMultiplatform {
1366+
configureAndroidLibrary()
1367+
sourceSets.commonMain.dependencies {
1368+
implementation(producer.rootCoordinate)
1369+
}
1370+
}
1371+
}
1372+
}
1373+
1374+
assertEquals<PrettyPrint<Map<String, ResolvedComponentWithArtifacts>>>(
1375+
mutableMapOf<String, ResolvedComponentWithArtifacts>(
1376+
"org.jetbrains.kotlin:kotlin-stdlib:${defaultBuildOptions.kotlinVersion}" to ResolvedComponentWithArtifacts(
1377+
artifacts = mutableListOf(
1378+
mutableMapOf(
1379+
"artifactType" to "jar",
1380+
"org.gradle.category" to "library",
1381+
"org.gradle.jvm.environment" to "standard-jvm",
1382+
"org.gradle.libraryelements" to "jar",
1383+
"org.gradle.usage" to "java-api",
1384+
"org.jetbrains.kotlin.platform.type" to "jvm",
1385+
),
1386+
),
1387+
configuration = "jvmApiElements",
1388+
),
1389+
"org.jetbrains:annotations:13.0" to ResolvedComponentWithArtifacts(
1390+
artifacts = mutableListOf(
1391+
mutableMapOf(
1392+
"artifactType" to "jar",
1393+
"org.gradle.category" to "library",
1394+
"org.gradle.libraryelements" to "jar",
1395+
"org.gradle.usage" to "java-api",
1396+
),
1397+
),
1398+
configuration = "compile",
1399+
),
1400+
"producer:empty:1.0" to ResolvedComponentWithArtifacts(
1401+
artifacts = mutableListOf(
1402+
),
1403+
configuration = "fallbackVariant_KT-81412",
1404+
),
1405+
).prettyPrinted,
1406+
consumer.buildScriptReturn {
1407+
project.ignoreAccessViolations {
1408+
project.configurations.getByName("androidCompileClasspath").resolveProjectDependencyComponentsWithArtifacts()
1409+
}
1410+
}.buildAndReturn("assemble").prettyPrinted
1411+
)
1412+
assertEquals<PrettyPrint<Map<String, ResolvedComponentWithArtifacts>>>(
1413+
mutableMapOf<String, ResolvedComponentWithArtifacts>(
1414+
"org.jetbrains.kotlin:kotlin-stdlib:${defaultBuildOptions.kotlinVersion}" to ResolvedComponentWithArtifacts(
1415+
artifacts = mutableListOf(
1416+
mutableMapOf(
1417+
"artifactType" to "jar",
1418+
"org.gradle.category" to "library",
1419+
"org.gradle.jvm.environment" to "standard-jvm",
1420+
"org.gradle.libraryelements" to "jar",
1421+
"org.gradle.usage" to "java-runtime",
1422+
"org.jetbrains.kotlin.platform.type" to "jvm",
1423+
),
1424+
),
1425+
configuration = "jvmRuntimeElements",
1426+
),
1427+
"org.jetbrains:annotations:13.0" to ResolvedComponentWithArtifacts(
1428+
artifacts = mutableListOf(
1429+
mutableMapOf(
1430+
"artifactType" to "jar",
1431+
"org.gradle.category" to "library",
1432+
"org.gradle.libraryelements" to "jar",
1433+
"org.gradle.usage" to "java-runtime",
1434+
),
1435+
),
1436+
configuration = "runtime",
1437+
),
1438+
"producer:empty:1.0" to ResolvedComponentWithArtifacts(
1439+
artifacts = mutableListOf(
1440+
),
1441+
configuration = "fallbackVariant_KT-81412",
1442+
),
1443+
).prettyPrinted,
1444+
consumer.buildScriptReturn {
1445+
project.ignoreAccessViolations {
1446+
project.configurations.getByName("androidRuntimeClasspath").resolveProjectDependencyComponentsWithArtifacts()
1447+
}
1448+
}.buildAndReturn("assemble").prettyPrinted
1449+
)
1450+
}
1451+
13271452
@GradleAndroidTest
13281453
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_88)
13291454
fun `uklib consumption - KMP androidLibrary with stub JVM variant - KT-81434`(

libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/uklibs/consumption/UklibConsumptionSetupAction.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,16 @@ internal class AllowPlatformConfigurationsToFallBackToMetadataForLenientKmpResol
451451
)
452452
if (
453453
mapOf(
454+
/**
455+
* Fallback variant for Android resolution
456+
* Android compile/runtime classpath request the JAVA_* usages. Since Android is not published in the UKlib and we don't
457+
* support lenient resolution in Android variants we register a fallback without dependencies for Android. The only use case
458+
* should be pre-UKlib KMP publication.
459+
*
460+
* We should remove this compatibility in the future when all KMP libraries will have a proper or stub JVM variant
461+
*/
462+
JAVA_API to setOf(KOTLIN_UKLIB_FALLBACK_VARIANT),
463+
JAVA_RUNTIME to setOf(KOTLIN_UKLIB_FALLBACK_VARIANT),
454464
/**
455465
* KOTLIN_UKLIB_API is requested in platform compile dependency configurations
456466
*/

libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/ResolutionTestingAttributes.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,22 @@ val jvmRuntimeClassifiedAttributes = mapOf(
6161
"org.gradle.usage" to "java-runtime",
6262
)
6363

64+
val kmpAndroidLibraryApiAttributes = mapOf(
65+
"org.gradle.category" to "library",
66+
"org.gradle.jvm.environment" to "android",
67+
"org.gradle.libraryelements" to "aar",
68+
"org.gradle.usage" to "java-api",
69+
"org.jetbrains.kotlin.platform.type" to "jvm",
70+
)
71+
val kmpAndroidLibraryRuntimeAttributes = mapOf(
72+
"org.gradle.category" to "library",
73+
"org.gradle.jvm.environment" to "android",
74+
"org.gradle.libraryelements" to "aar",
75+
"org.gradle.usage" to "java-runtime",
76+
"org.jetbrains.kotlin.platform.type" to "jvm",
77+
)
78+
79+
6480
val kmpJvmRuntimeVariantAttributes = mapOf(
6581
"org.gradle.category" to "library",
6682
"org.gradle.jvm.environment" to "standard-jvm",

libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/uklibs/UklibResolutionWithMockComponents.kt

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,207 @@ class UklibResolutionTestsWithMockComponents {
14071407
}
14081408
}
14091409

1410+
@Test
1411+
fun `uklib resolution - legacy android library resolves fallback variant - in KMP publication without JVM + androidLibrary target`() {
1412+
val repo = generateMockRepository(
1413+
tmpDir,
1414+
listOf(
1415+
GradleComponent(
1416+
GradleMetadataComponent(
1417+
component = directGradleComponent,
1418+
variants = listOf(
1419+
kmpMetadataJarVariant,
1420+
kmpIosArm64MetadataJarVariant,
1421+
kmpIosArm64KlibVariant,
1422+
),
1423+
),
1424+
directMavenComponent(),
1425+
),
1426+
)
1427+
)
1428+
1429+
val consumer = uklibConsumer {
1430+
androidLibrary {
1431+
compileSdk = 31
1432+
namespace = "foo"
1433+
}
1434+
kotlin {
1435+
androidTarget()
1436+
sourceSets.commonMain.dependencies { implementation("foo:direct:1.0") }
1437+
}
1438+
repositories.maven(repo)
1439+
}
1440+
1441+
assertEquals(
1442+
mapOf<String, ResolvedComponentWithArtifacts>(
1443+
"foo:direct:1.0" to ResolvedComponentWithArtifacts(
1444+
configuration = "fallbackVariant_KT-81412",
1445+
artifacts = mutableListOf()
1446+
),
1447+
).prettyPrinted,
1448+
consumer.configurations.getByName("androidDebugCompileClasspath")
1449+
.resolveProjectDependencyComponentsWithArtifacts().prettyPrinted
1450+
)
1451+
assertEquals(
1452+
mapOf<String, ResolvedComponentWithArtifacts>(
1453+
"foo:direct:1.0" to ResolvedComponentWithArtifacts(
1454+
configuration = "fallbackVariant_KT-81412",
1455+
artifacts = mutableListOf()
1456+
),
1457+
).prettyPrinted,
1458+
consumer.configurations.getByName("androidDebugRuntimeClasspath")
1459+
.resolveProjectDependencyComponentsWithArtifacts().prettyPrinted
1460+
)
1461+
}
1462+
1463+
@Test
1464+
fun `uklib resolution - legacy android library resolves fallback variant - in KMP publication with JVM`() {
1465+
val repo = generateMockRepository(
1466+
tmpDir,
1467+
listOf(
1468+
GradleComponent(
1469+
GradleMetadataComponent(
1470+
component = directGradleComponent,
1471+
variants = listOf(
1472+
kmpMetadataJarVariant,
1473+
kmpIosArm64MetadataJarVariant,
1474+
kmpIosArm64KlibVariant,
1475+
kmpJvmApiVariant,
1476+
kmpJvmRuntimeVariant,
1477+
),
1478+
),
1479+
directMavenComponent(),
1480+
),
1481+
)
1482+
)
1483+
1484+
val consumer = uklibConsumer {
1485+
androidLibrary {
1486+
compileSdk = 31
1487+
namespace = "foo"
1488+
}
1489+
kotlin {
1490+
androidTarget()
1491+
sourceSets.commonMain.dependencies { implementation("foo:direct:1.0") }
1492+
}
1493+
repositories.maven(repo)
1494+
}
1495+
1496+
assertEquals(
1497+
mapOf<String, ResolvedComponentWithArtifacts>(
1498+
"foo:direct:1.0" to ResolvedComponentWithArtifacts(
1499+
artifacts = mutableListOf(
1500+
mapOf(
1501+
"artifactType" to "jar",
1502+
"org.gradle.category" to "library",
1503+
"org.gradle.jvm.environment" to "standard-jvm",
1504+
"org.gradle.libraryelements" to "jar",
1505+
"org.gradle.usage" to "java-api",
1506+
"org.jetbrains.kotlin.platform.type" to "jvm",
1507+
),
1508+
),
1509+
configuration = "jvmApiElements-published",
1510+
),
1511+
).prettyPrinted,
1512+
consumer.configurations.getByName("androidDebugCompileClasspath")
1513+
.resolveProjectDependencyComponentsWithArtifacts().prettyPrinted
1514+
)
1515+
assertEquals(
1516+
mapOf<String, ResolvedComponentWithArtifacts>(
1517+
"foo:direct:1.0" to ResolvedComponentWithArtifacts(
1518+
artifacts = mutableListOf(
1519+
mapOf(
1520+
"artifactType" to "jar",
1521+
"org.gradle.category" to "library",
1522+
"org.gradle.jvm.environment" to "standard-jvm",
1523+
"org.gradle.libraryelements" to "jar",
1524+
"org.gradle.usage" to "java-runtime",
1525+
"org.jetbrains.kotlin.platform.type" to "jvm",
1526+
),
1527+
),
1528+
configuration = "jvmRuntimeElements-published",
1529+
),
1530+
).prettyPrinted,
1531+
consumer.configurations.getByName("androidDebugRuntimeClasspath")
1532+
.resolveProjectDependencyComponentsWithArtifacts().prettyPrinted
1533+
)
1534+
}
1535+
1536+
@Test
1537+
fun `uklib resolution - legacy android library resolves fallback variant - in KMP publication with JVM and new android`() {
1538+
val repo = generateMockRepository(
1539+
tmpDir,
1540+
listOf(
1541+
GradleComponent(
1542+
GradleMetadataComponent(
1543+
component = directGradleComponent,
1544+
variants = listOf(
1545+
kmpMetadataJarVariant,
1546+
kmpIosArm64MetadataJarVariant,
1547+
kmpIosArm64KlibVariant,
1548+
kmpJvmApiVariant,
1549+
kmpJvmRuntimeVariant,
1550+
kmpAndroidApiVariant,
1551+
kmpAndroidRuntimeVariant
1552+
),
1553+
),
1554+
directMavenComponent(),
1555+
),
1556+
)
1557+
)
1558+
1559+
val consumer = uklibConsumer {
1560+
androidLibrary {
1561+
compileSdk = 31
1562+
namespace = "foo"
1563+
}
1564+
kotlin {
1565+
androidTarget()
1566+
sourceSets.commonMain.dependencies { implementation("foo:direct:1.0") }
1567+
}
1568+
repositories.maven(repo)
1569+
}
1570+
1571+
assertEquals(
1572+
mapOf<String, ResolvedComponentWithArtifacts>(
1573+
"foo:direct:1.0" to ResolvedComponentWithArtifacts(
1574+
artifacts = mutableListOf(
1575+
mapOf(
1576+
"artifactType" to "jar",
1577+
"org.gradle.category" to "library",
1578+
"org.gradle.jvm.environment" to "android",
1579+
"org.gradle.libraryelements" to "aar",
1580+
"org.gradle.usage" to "java-api",
1581+
"org.jetbrains.kotlin.platform.type" to "jvm",
1582+
),
1583+
),
1584+
configuration = "androidApiElements-published",
1585+
),
1586+
).prettyPrinted,
1587+
consumer.configurations.getByName("androidDebugCompileClasspath")
1588+
.resolveProjectDependencyComponentsWithArtifacts().prettyPrinted
1589+
)
1590+
assertEquals(
1591+
mapOf<String, ResolvedComponentWithArtifacts>(
1592+
"foo:direct:1.0" to ResolvedComponentWithArtifacts(
1593+
artifacts = mutableListOf(
1594+
mapOf(
1595+
"artifactType" to "jar",
1596+
"org.gradle.category" to "library",
1597+
"org.gradle.jvm.environment" to "android",
1598+
"org.gradle.libraryelements" to "aar",
1599+
"org.gradle.usage" to "java-runtime",
1600+
"org.jetbrains.kotlin.platform.type" to "jvm",
1601+
),
1602+
),
1603+
configuration = "androidRuntimeElements-published",
1604+
),
1605+
).prettyPrinted,
1606+
consumer.configurations.getByName("androidDebugRuntimeClasspath")
1607+
.resolveProjectDependencyComponentsWithArtifacts().prettyPrinted
1608+
)
1609+
}
1610+
14101611
@Test
14111612
fun `uklib resolution - resolvable configuration without attributes prefers JVM variants over fallback - KT-81488`() {
14121613
val repo = generateMockRepository(
@@ -2294,6 +2495,19 @@ class UklibResolutionTestsWithMockComponents {
22942495
dependencies = listOf()
22952496
)
22962497

2498+
private val kmpAndroidApiVariant = Variant(
2499+
name = "androidApiElements-published",
2500+
attributes = kmpAndroidLibraryApiAttributes,
2501+
files = listOf(kmpJvmMock),
2502+
dependencies = listOf()
2503+
)
2504+
private val kmpAndroidRuntimeVariant = Variant(
2505+
name = "androidRuntimeElements-published",
2506+
attributes = kmpAndroidLibraryRuntimeAttributes,
2507+
files = listOf(kmpJvmMock),
2508+
dependencies = listOf()
2509+
)
2510+
22972511
private val kmpPreHmppAndWithoutCategoryJvmApiVariant = Variant(
22982512
name = "jvmApiElements-published",
22992513
attributes = kmpPreHmppAndWithoutCategoryJvmApiVariantAttributes,

0 commit comments

Comments
 (0)