Add an IT for consumption of multiplatform resources

^KT-65540
This commit is contained in:
Timofey Solonin
2024-02-19 02:47:01 +01:00
committed by Space Team
parent 2fda16f526
commit 1435fcc50f
47 changed files with 397 additions and 12 deletions
@@ -43,8 +43,8 @@ class AndroidMultiplatformResourcesIT : KGPBaseTest() {
buildWithAGPVersion(
":consumer:zipApksForDebug",
androidVersion,
defaultBuildOptions,
androidVersion = androidVersion,
defaultBuildOptions = defaultBuildOptions,
)
val apkPath = projectPath.resolve("consumer/build/outputs/apk/debug/consumer-debug.apk")
assertAssetsMatchReference(apkPath)
@@ -100,8 +100,8 @@ class AndroidMultiplatformResourcesIT : KGPBaseTest() {
) {
buildWithAGPVersion(
":publishAllPublicationsToMavenRepository",
androidVersion,
defaultBuildOptions,
androidVersion = androidVersion,
defaultBuildOptions = defaultBuildOptions,
)
withRepositoryRoot(projectPath.resolve("build/repo"))
}
@@ -0,0 +1,227 @@
/*
* Copyright 2010-2024 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.mpp.resources
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resolve.KotlinTargetResourcesResolutionStrategy
import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.gradle.util.replaceText
import org.jetbrains.kotlin.incremental.testingUtils.assertEqualDirectoriesIgnoringDotFiles
import org.jetbrains.kotlin.konan.target.HostManager
import org.junit.jupiter.api.DisplayName
import java.nio.file.Path
import kotlin.io.path.name
import kotlin.io.path.pathString
@MppGradlePluginTests
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_73)
@DisplayName("Test resources consumption APIs")
class MultiplatformResourcesConsumptionIT : KGPBaseTest() {
@DisplayName("Resolve resources with consumption API using variant reselection")
// Before 7.6 Gradle fails to resolve project dependencies with variant reselection
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_74)
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_6)
@GradleAndroidTest
fun testWithVariantReselection(
gradleVersion: GradleVersion,
androidVersion: String,
providedJdk: JdkVersions.ProvidedJdk,
) {
test(gradleVersion, androidVersion, providedJdk, KotlinTargetResourcesResolutionStrategy.VariantReselection)
}
@DisplayName("Resolve resources with consumption API using resources configuration")
@GradleAndroidTest
fun testWithConfiguration(
gradleVersion: GradleVersion,
androidVersion: String,
providedJdk: JdkVersions.ProvidedJdk,
) {
test(gradleVersion, androidVersion, providedJdk, KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration)
}
private fun test(
gradleVersion: GradleVersion,
androidVersion: String,
providedJdk: JdkVersions.ProvidedJdk,
resolutionStrategy: KotlinTargetResourcesResolutionStrategy,
) {
project(
"multiplatformResources/consumption",
gradleVersion,
buildJdk = providedJdk.location,
) {
val sharedRepo = projectPath.resolve("build/repo")
prepareProjectDependencies(gradleVersion, providedJdk, sharedRepo).forEach {
settingsGradleKts.append(
"""
include(":${it.name}")
project(":${it.name}").projectDir = File("${it.pathString}")
""".trimIndent()
)
}
preparePublishedDependencies(gradleVersion, providedJdk, androidVersion, sharedRepo)
// Gradle 7.4.2 doesn't pick up sharedRepo from build.gradle.kts and Gradle 8.5 doesn't pick it up from settings.gradle.kts
buildGradleKts.setUpRepositoriesInBuildGradleKts(sharedRepo)
settingsGradleKts.setUpRepositoriesInSettingGradleKts(sharedRepo)
val resolvableTargets = listOf(
"linuxX64",
"wasmJs",
"wasmWasi",
) + if (HostManager.hostIsMac) listOf("iosArm64") else emptyList()
resolvableTargets.forEach { target ->
buildWithAGPVersion(
":${target}ResolveResources", "-Pkotlin.mpp.resourcesResolutionStrategy=${resolutionStrategy.propertyName}",
androidVersion = androidVersion,
defaultBuildOptions = defaultBuildOptions,
) {
assertEqualDirectoriesIgnoringDotFiles(
projectPath.resolve("reference/${target}").toFile(),
projectPath.resolve("build/${target}ResolvedResources").toFile(),
forgiveOtherExtraFiles = false,
)
}
}
// This platform is not provided in dependency variants
buildAndFailWithAGPVersion(
":linuxArm64",
androidVersion = androidVersion,
defaultBuildOptions = defaultBuildOptions,
)
}
}
private fun prepareProjectDependencies(
gradleVersion: GradleVersion,
providedJdk: JdkVersions.ProvidedJdk,
publicationRepository: Path,
): List<Path> {
val projectWithoutResources = project(
"multiplatformResources/consumption/dependency",
gradleVersion,
buildJdk = providedJdk.location,
projectPathAdditionalSuffix = "projectWithoutResources",
) {
buildGradleKts.replaceText("<dependencies>", "implementation(project(\":projectWithResources\"))")
buildGradleKts.replaceText("<enablePublication>", "false")
buildGradleKts.setUpRepositoriesInBuildGradleKts(publicationRepository)
}
val projectWithResources = project(
"multiplatformResources/consumption/dependency",
gradleVersion,
buildJdk = providedJdk.location,
projectPathAdditionalSuffix = "projectWithResources",
) {
buildGradleKts.replaceText("<dependencies>", "implementation(project(\":projectWithResourcesTransitive\"))")
buildGradleKts.replaceText("<enablePublication>", "true")
buildGradleKts.setUpRepositoriesInBuildGradleKts(publicationRepository)
}
val projectWithResourcesTransitive = project(
"multiplatformResources/consumption/dependency",
gradleVersion,
buildJdk = providedJdk.location,
projectPathAdditionalSuffix = "projectWithResourcesTransitive",
) {
buildGradleKts.replaceText("<dependencies>", "")
buildGradleKts.replaceText("<enablePublication>", "true")
buildGradleKts.setUpRepositoriesInBuildGradleKts(publicationRepository)
}
return listOf(projectWithoutResources, projectWithResources, projectWithResourcesTransitive).map { it.projectPath }
}
private fun preparePublishedDependencies(
gradleVersion: GradleVersion,
providedJdk: JdkVersions.ProvidedJdk,
androidVersion: String,
publicationRepository: Path,
) {
val publishedWithoutResources = project(
"multiplatformResources/consumption/dependency",
gradleVersion,
buildJdk = providedJdk.location,
projectPathAdditionalSuffix = "publishedWithoutResources",
localRepoDir = publicationRepository,
) {
buildGradleKts.replaceText("<dependencies>", "implementation(\"test:publishedWithResources:+\")")
buildGradleKts.replaceText("<enablePublication>", "false")
buildGradleKts.setUpPublishing(publicationRepository)
buildGradleKts.setUpRepositoriesInBuildGradleKts(publicationRepository)
}
val publishedWithResources = project(
"multiplatformResources/consumption/dependency",
gradleVersion,
buildJdk = providedJdk.location,
projectPathAdditionalSuffix = "publishedWithResources",
localRepoDir = publicationRepository,
) {
buildGradleKts.replaceText("<dependencies>", "implementation(\"test:publishedWithResourcesTransitive:+\")")
buildGradleKts.replaceText("<enablePublication>", "true")
buildGradleKts.setUpPublishing(publicationRepository)
buildGradleKts.setUpRepositoriesInBuildGradleKts(publicationRepository)
}
val publishedWithResourcesTransitive = project(
"multiplatformResources/consumption/dependency",
gradleVersion,
buildJdk = providedJdk.location,
projectPathAdditionalSuffix = "publishedWithResourcesTransitive",
localRepoDir = publicationRepository,
) {
buildGradleKts.replaceText("<dependencies>", "")
buildGradleKts.replaceText("<enablePublication>", "true")
buildGradleKts.setUpPublishing(publicationRepository)
buildGradleKts.setUpRepositoriesInBuildGradleKts(publicationRepository)
}
listOf(publishedWithResourcesTransitive, publishedWithResources, publishedWithoutResources).forEach {
it.buildWithAGPVersion(
":publishAllPublicationsToMavenRepository",
androidVersion = androidVersion,
defaultBuildOptions = defaultBuildOptions,
)
}
}
private fun Path.setUpRepositoriesInBuildGradleKts(publicationRepository: Path) = append(repositories(publicationRepository))
private fun Path.setUpRepositoriesInSettingGradleKts(publicationRepository: Path) = append(
"""
dependencyResolutionManagement {
${repositories(publicationRepository)}
}
""".trimIndent()
)
private fun repositories(publicationRepository: Path): String {
return """
repositories {
google()
mavenCentral()
mavenLocal()
maven {
url = uri("${publicationRepository.pathString}")
}
}
""".trimIndent()
}
private fun Path.setUpPublishing(publicationRepository: Path) {
append(
"""
publishing {
repositories {
maven {
url = uri("${publicationRepository.pathString}")
}
}
}
""".trimIndent()
)
}
}
@@ -80,8 +80,8 @@ class MultiplatformResourcesDependencyIT : KGPBaseTest() {
) {
buildWithAGPVersion(
":publishAllPublicationsToMavenRepository",
androidVersion,
defaultBuildOptions,
androidVersion = androidVersion,
defaultBuildOptions = defaultBuildOptions,
)
withRepositoryRoot(projectPath.resolve("build/repo"))
}
@@ -31,8 +31,8 @@ class MultiplatformResourcesPublicationIT : KGPBaseTest() {
) {
buildWithAGPVersion(
":publishAndroidReleasePublicationToMavenRepository",
androidVersion,
defaultBuildOptions,
androidVersion = androidVersion,
defaultBuildOptions = defaultBuildOptions,
)
val publishedAarPath = "build/repo/test/publication-android/1.0/publication-android-1.0.aar"
val classesInAar = projectPath.resolve("classesInAar")
@@ -189,8 +189,8 @@ class MultiplatformResourcesPublicationIT : KGPBaseTest() {
) {
buildWithAGPVersion(
publicationTask,
androidVersion,
defaultBuildOptions,
androidVersion = androidVersion,
defaultBuildOptions = defaultBuildOptions,
)
compareEmbeddedResources(
projectPath.resolve(publishedArchive),
@@ -9,6 +9,7 @@ import org.gradle.testkit.runner.BuildResult
import org.jetbrains.kotlin.gradle.testbase.BuildOptions
import org.jetbrains.kotlin.gradle.testbase.TestProject
import org.jetbrains.kotlin.gradle.testbase.build
import org.jetbrains.kotlin.gradle.testbase.buildAndFail
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
@@ -16,13 +17,26 @@ import java.nio.file.StandardCopyOption
import java.util.zip.ZipFile
fun TestProject.buildWithAGPVersion(
task: String,
vararg buildArguments: String,
androidVersion: String,
defaultBuildOptions: BuildOptions,
assertions: BuildResult.() -> Unit = {},
) {
build(
task,
*buildArguments,
buildOptions = defaultBuildOptions.copy(androidVersion = androidVersion),
assertions = assertions,
)
}
fun TestProject.buildAndFailWithAGPVersion(
vararg buildArguments: String,
androidVersion: String,
defaultBuildOptions: BuildOptions,
assertions: BuildResult.() -> Unit = {},
) {
buildAndFail(
*buildArguments,
buildOptions = defaultBuildOptions.copy(androidVersion = androidVersion),
assertions = assertions,
)
@@ -0,0 +1,39 @@
@file:OptIn(ComposeKotlinGradlePluginApi::class)
import org.jetbrains.kotlin.gradle.ComposeKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.KotlinTargetResourcesPublication
group = "test"
version = "1.0"
plugins {
kotlin("multiplatform")
id("com.android.library") apply false
}
kotlin {
val publication = project.ext.get(
KotlinTargetResourcesPublication.EXTENSION_NAME
) as KotlinTargetResourcesPublication
listOf(
linuxX64(),
iosArm64(),
iosSimulatorArm64(),
wasmJs(),
wasmWasi(),
).forEach { target ->
val assemblyTask = publication.resolveResources(target)
tasks.register<Copy>("${target.disambiguationClassifier}ResolveResources") {
from(assemblyTask)
into(layout.buildDirectory.dir("${target.disambiguationClassifier}ResolvedResources"))
}
}
sourceSets.commonMain {
dependencies {
implementation("test:publishedWithoutResources:+")
implementation(project(":projectWithoutResources"))
}
}
}
@@ -0,0 +1,66 @@
@file:OptIn(ComposeKotlinGradlePluginApi::class)
import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.ComposeKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.KotlinTargetResourcesPublication
import java.io.File
group = "test"
version = "1.0"
plugins {
kotlin("multiplatform")
id("com.android.library")
`maven-publish`
}
kotlin {
val publication = if (<enablePublication>) project.ext.get(
KotlinTargetResourcesPublication.EXTENSION_NAME
) as KotlinTargetResourcesPublication else null
listOf(
androidTarget {
publishAllLibraryVariants()
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
},
jvm(),
linuxX64(),
iosArm64(),
wasmJs(),
wasmWasi(),
).forEach { target ->
val relativeResourcePlacement = provider { File("embed/${project.name}") }
val sourceSetPathProvider: (KotlinSourceSet) -> (Provider<File>) = { sourceSet ->
project.provider { project.file("src/${sourceSet.name}/multiplatformResources") }
}
publication?.publishResourcesAsKotlinComponent(
target = target,
resourcePathForSourceSet = { sourceSet ->
KotlinTargetResourcesPublication.ResourceRoot(
resourcesBaseDirectory = sourceSetPathProvider(sourceSet),
includes = emptyList(),
excludes = emptyList(),
)
},
relativeResourcePlacement = relativeResourcePlacement,
)
}
sourceSets.commonMain {
dependencies {
<dependencies>
}
}
}
android {
namespace = "test.${project.name}"
compileSdk = 34
defaultConfig {
minSdk = 24
}
}