migrated cocoapods test with xcodebuild to new test dsl (junit 5 and gradle test kit)
#KT-51553 In Progress
This commit is contained in:
committed by
Space Team
parent
b8785fbd90
commit
65aa5fc02e
-183
@@ -13,8 +13,6 @@ import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Compan
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.POD_INSTALL_TASK_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.POD_SETUP_BUILD_TASK_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.POD_SPEC_TASK_NAME
|
||||
import org.jetbrains.kotlin.gradle.testbase.TestVersions
|
||||
import org.jetbrains.kotlin.gradle.testbase.normalizeCocoapadsFrameworkName
|
||||
import org.jetbrains.kotlin.gradle.util.createTempDir
|
||||
import org.jetbrains.kotlin.gradle.util.modify
|
||||
import org.jetbrains.kotlin.gradle.util.runProcess
|
||||
@@ -109,58 +107,6 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testXcodeUseFrameworksSingle() = doTestXcode(
|
||||
cocoapodsSingleKtPod,
|
||||
ImportMode.FRAMEWORKS,
|
||||
"ios-app", mapOf("kotlin-library" to null)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseFrameworksWithCustomFrameworkNameSingle() = doTestXcode(
|
||||
cocoapodsSingleKtPod,
|
||||
ImportMode.FRAMEWORKS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to "MultiplatformLibrary")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseModularHeadersSingle() = doTestXcode(
|
||||
cocoapodsSingleKtPod,
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to null)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseModularHeadersWithCustomFrameworkNameSingle() = doTestXcode(
|
||||
cocoapodsSingleKtPod,
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to "MultiplatformLibrary")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeBuildsWithKotlinLibraryFromRootProject() {
|
||||
|
||||
val project = transformProjectWithPluginsDsl(templateProjectName, GradleVersionRequired.AtLeast(TestVersions.Gradle.G_7_6))
|
||||
|
||||
project.gradleBuildScript().appendToCocoapodsBlock("""
|
||||
framework {
|
||||
baseName = "kotlin-library"
|
||||
}
|
||||
name = "kotlin-library"
|
||||
podfile = project.file("ios-app/Podfile")
|
||||
""".trimIndent())
|
||||
|
||||
doTestXcode(
|
||||
project,
|
||||
ImportMode.FRAMEWORKS,
|
||||
"ios-app",
|
||||
mapOf("" to null),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPodImportSingle() {
|
||||
val project = getProjectByName(cocoapodsSingleKtPod)
|
||||
@@ -194,38 +140,6 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
project.testSynthetic(":second-library:podImport")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testXcodeUseFrameworksMultiple() = doTestXcode(
|
||||
cocoapodsMultipleKtPods,
|
||||
ImportMode.FRAMEWORKS,
|
||||
null,
|
||||
mapOf("kotlin-library" to null, "second-library" to null)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseFrameworksWithCustomFrameworkNameMultiple() = doTestXcode(
|
||||
cocoapodsMultipleKtPods,
|
||||
ImportMode.FRAMEWORKS,
|
||||
null,
|
||||
mapOf("kotlin-library" to "FirstMultiplatformLibrary", "second-library" to "SecondMultiplatformLibrary")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseModularHeadersMultiple() = doTestXcode(
|
||||
cocoapodsMultipleKtPods,
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
null,
|
||||
mapOf("kotlin-library" to null, "second-library" to null)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testXcodeUseModularHeadersWithCustomFrameworkNameMultiple() = doTestXcode(
|
||||
cocoapodsMultipleKtPods,
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
null,
|
||||
mapOf("kotlin-library" to "FirstMultiplatformLibrary", "second-library" to "SecondMultiplatformLibrary")
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testSpecReposImport() {
|
||||
val podName = "example"
|
||||
@@ -1512,19 +1426,6 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.useCustomFrameworkName(subproject: String, frameworkName: String, iosAppLocation: String? = null) {
|
||||
// Change the name at the Gradle side.
|
||||
gradleBuildScript(subproject).appendToFrameworkBlock("baseName = \"$frameworkName\"")
|
||||
|
||||
// Change swift sources import if needed.
|
||||
if (iosAppLocation != null) {
|
||||
val iosAppDir = projectDir.resolve(iosAppLocation)
|
||||
iosAppDir.resolve("ios-app/ViewController.swift").modify {
|
||||
it.replace("import ${subproject.normalizeCocoapadsFrameworkName}", "import $frameworkName")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum class ImportMode(val directive: String) {
|
||||
FRAMEWORKS("use_frameworks!"),
|
||||
MODULAR_HEADERS("use_modular_headers!")
|
||||
@@ -1565,90 +1466,6 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
CommandResult(process.exitValue(), stdOut, stdErr).block()
|
||||
}
|
||||
|
||||
private fun doTestXcode(
|
||||
projectName: String,
|
||||
mode: ImportMode,
|
||||
iosAppLocation: String?,
|
||||
subprojectsToFrameworkNamesMap: Map<String, String?>,
|
||||
) {
|
||||
val gradleProject = transformProjectWithPluginsDsl(projectName, gradleVersion)
|
||||
|
||||
doTestXcode(
|
||||
gradleProject = gradleProject,
|
||||
mode = mode,
|
||||
iosAppLocation = iosAppLocation,
|
||||
subprojectsToFrameworkNamesMap = subprojectsToFrameworkNamesMap,
|
||||
)
|
||||
}
|
||||
|
||||
private fun doTestXcode(
|
||||
gradleProject: Project,
|
||||
mode: ImportMode,
|
||||
iosAppLocation: String?,
|
||||
subprojectsToFrameworkNamesMap: Map<String, String?>,
|
||||
arch: String = "x86_64",
|
||||
) {
|
||||
|
||||
gradleProject.projectDir.resolve("gradle.properties")
|
||||
.takeIf(File::exists)
|
||||
?.let {
|
||||
it.appendLine("kotlin_version=${defaultBuildOptions().kotlinVersion}")
|
||||
it.appendLine("test_fixes_version=${defaultBuildOptions().kotlinVersion}")
|
||||
}
|
||||
|
||||
with(gradleProject) {
|
||||
setupWorkingDir()
|
||||
|
||||
for ((subproject, frameworkName) in subprojectsToFrameworkNamesMap) {
|
||||
|
||||
val taskPrefix = if (subproject.isNotEmpty()) ":$subproject" else ""
|
||||
|
||||
// Add property with custom framework name
|
||||
frameworkName?.let {
|
||||
useCustomFrameworkName(subproject, it, iosAppLocation)
|
||||
}
|
||||
|
||||
// Generate podspec.
|
||||
build("$taskPrefix:podspec", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
|
||||
assertSuccessful()
|
||||
}
|
||||
iosAppLocation?.also {
|
||||
// Set import mode for Podfile.
|
||||
preparePodfile(it, mode)
|
||||
// Install pods.
|
||||
build("$taskPrefix:podInstall", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
|
||||
assertSuccessful()
|
||||
}
|
||||
|
||||
projectDir.resolve(it).apply {
|
||||
// Run Xcode build.
|
||||
runCommand(
|
||||
this, "xcodebuild",
|
||||
"-sdk", "iphonesimulator",
|
||||
"-configuration", "Release",
|
||||
"-workspace", "$name.xcworkspace",
|
||||
"-scheme", name,
|
||||
"-arch", arch,
|
||||
inheritIO = true // Xcode doesn't finish the process if the PIPE redirect is used.
|
||||
) {
|
||||
assertEquals(
|
||||
0, exitCode, """
|
||||
|Exit code mismatch for `xcodebuild`.
|
||||
|stdout:
|
||||
|$stdOut
|
||||
|
|
||||
|stderr:
|
||||
|$stdErr
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.preparePodfile(iosAppLocation: String, mode: ImportMode) {
|
||||
val iosAppDir = projectDir.resolve(iosAppLocation)
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ import kotlin.io.path.readText
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@OsCondition(supportedOn = [OS.MAC], enabledOnCI = [OS.MAC])
|
||||
@DisplayName("K/N tests cocoapods")
|
||||
@DisplayName("K/N tests with cocoapods' podspec")
|
||||
@NativeGradlePluginTests
|
||||
class CocoaPodsPodspecIT : KGPBaseTest() {
|
||||
|
||||
|
||||
+235
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.native
|
||||
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.gradle.testbase.*
|
||||
import org.jetbrains.kotlin.gradle.util.assertProcessRunResult
|
||||
import org.jetbrains.kotlin.gradle.util.replaceText
|
||||
import org.jetbrains.kotlin.gradle.util.runProcess
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.condition.OS
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.name
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@OsCondition(supportedOn = [OS.MAC], enabledOnCI = [OS.MAC])
|
||||
@DisplayName("K/N tests cocoapods with xcodebuild")
|
||||
@NativeGradlePluginTests
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_0)
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
class CocoaPodsXcodeIT : KGPBaseTest() {
|
||||
|
||||
private val podfileImportDirectivePlaceholder = "<import_mode_directive>"
|
||||
|
||||
private val cocoapodsSingleKtPod = "native-cocoapods-single"
|
||||
private val cocoapodsMultipleKtPods = "native-cocoapods-multiple"
|
||||
private val templateProjectName = "native-cocoapods-template"
|
||||
|
||||
private val environmentVariables = EnvironmentalVariables(
|
||||
mapOf(
|
||||
// CocoaPods 1.11 requires UTF-8 locale being set, more details: https://github.com/CocoaPods/CocoaPods/issues/10939
|
||||
"LC_ALL" to "en_US.UTF-8"
|
||||
)
|
||||
)
|
||||
|
||||
@DisplayName("Checks xcodebuild for ios-app with a single framework")
|
||||
@GradleTest
|
||||
fun testXcodeUseFrameworksSingle(gradleVersion: GradleVersion) = doTestXcode(
|
||||
cocoapodsSingleKtPod,
|
||||
gradleVersion,
|
||||
ImportMode.FRAMEWORKS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to null)
|
||||
)
|
||||
|
||||
@DisplayName("Checks xcodebuild for ios-app with a single framework with custom name")
|
||||
@GradleTest
|
||||
fun testXcodeUseFrameworksWithCustomFrameworkNameSingle(gradleVersion: GradleVersion) = doTestXcode(
|
||||
cocoapodsSingleKtPod,
|
||||
gradleVersion,
|
||||
ImportMode.FRAMEWORKS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to "MultiplatformLibrary")
|
||||
)
|
||||
|
||||
@DisplayName("Checks xcodebuild for ios-app using modular headers with a single framework")
|
||||
@GradleTest
|
||||
fun testXcodeUseModularHeadersSingle(gradleVersion: GradleVersion) = doTestXcode(
|
||||
cocoapodsSingleKtPod,
|
||||
gradleVersion,
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to null)
|
||||
)
|
||||
|
||||
|
||||
@DisplayName("Checks xcodebuild for ios-app using modular headers with a single framework with custom name")
|
||||
@GradleTest
|
||||
fun testXcodeUseModularHeadersWithCustomFrameworkNameSingle(gradleVersion: GradleVersion) = doTestXcode(
|
||||
cocoapodsSingleKtPod,
|
||||
gradleVersion,
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
"ios-app",
|
||||
mapOf("kotlin-library" to "MultiplatformLibrary")
|
||||
)
|
||||
|
||||
@DisplayName("Checks xcodebuild for ios-app with kotlin library from root project")
|
||||
@GradleTest
|
||||
fun testXcodeBuildsWithKotlinLibraryFromRootProject(gradleVersion: GradleVersion) {
|
||||
|
||||
nativeProject(templateProjectName, gradleVersion, environmentVariables = environmentVariables) {
|
||||
|
||||
buildGradleKts.addCocoapodsBlock(
|
||||
"""
|
||||
framework {
|
||||
baseName = "kotlin-library"
|
||||
}
|
||||
name = "kotlin-library"
|
||||
podfile = project.file("ios-app/Podfile")
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
doTestXcode(
|
||||
ImportMode.FRAMEWORKS,
|
||||
"ios-app",
|
||||
mapOf("" to null),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("Checks xcodebuild for two libraries with framework")
|
||||
@GradleTest
|
||||
fun testXcodeUseFrameworksMultiple(gradleVersion: GradleVersion) = doTestXcode(
|
||||
cocoapodsMultipleKtPods,
|
||||
gradleVersion,
|
||||
ImportMode.FRAMEWORKS,
|
||||
null,
|
||||
mapOf("kotlin-library" to null, "second-library" to null)
|
||||
)
|
||||
|
||||
@DisplayName("Checks xcodebuild for two libraries with framework and custom names")
|
||||
@GradleTest
|
||||
fun testXcodeUseFrameworksWithCustomFrameworkNameMultiple(gradleVersion: GradleVersion) = doTestXcode(
|
||||
cocoapodsMultipleKtPods,
|
||||
gradleVersion,
|
||||
ImportMode.FRAMEWORKS,
|
||||
null,
|
||||
mapOf("kotlin-library" to "FirstMultiplatformLibrary", "second-library" to "SecondMultiplatformLibrary")
|
||||
)
|
||||
|
||||
@DisplayName("Checks xcodebuild for two libraries with modular headers")
|
||||
@GradleTest
|
||||
fun testXcodeUseModularHeadersMultiple(gradleVersion: GradleVersion) = doTestXcode(
|
||||
cocoapodsMultipleKtPods,
|
||||
gradleVersion,
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
null,
|
||||
mapOf("kotlin-library" to null, "second-library" to null)
|
||||
)
|
||||
|
||||
@DisplayName("Checks xcodebuild for two libraries with modular headers and custom names")
|
||||
@GradleTest
|
||||
fun testXcodeUseModularHeadersWithCustomFrameworkNameMultiple(gradleVersion: GradleVersion) = doTestXcode(
|
||||
cocoapodsMultipleKtPods,
|
||||
gradleVersion,
|
||||
ImportMode.MODULAR_HEADERS,
|
||||
null,
|
||||
mapOf("kotlin-library" to "FirstMultiplatformLibrary", "second-library" to "SecondMultiplatformLibrary")
|
||||
)
|
||||
|
||||
private enum class ImportMode(val directive: String) {
|
||||
FRAMEWORKS("use_frameworks!"),
|
||||
MODULAR_HEADERS("use_modular_headers!")
|
||||
}
|
||||
|
||||
private fun TestProject.preparePodfile(iosAppLocation: String, mode: ImportMode) {
|
||||
val iosAppDir = projectPath.resolve(iosAppLocation)
|
||||
|
||||
// Set import mode for Podfile.
|
||||
iosAppDir.resolve("Podfile")
|
||||
.takeIf { it.exists() }
|
||||
?.replaceText(podfileImportDirectivePlaceholder, mode.directive)
|
||||
}
|
||||
|
||||
private fun doTestXcode(
|
||||
projectName: String,
|
||||
gradleVersion: GradleVersion,
|
||||
mode: ImportMode,
|
||||
iosAppLocation: String?,
|
||||
subprojectsToFrameworkNamesMap: Map<String, String?>,
|
||||
) {
|
||||
|
||||
nativeProject(projectName, gradleVersion, environmentVariables = environmentVariables) {
|
||||
doTestXcode(
|
||||
mode = mode,
|
||||
iosAppLocation = iosAppLocation,
|
||||
subprojectsToFrameworkNamesMap = subprojectsToFrameworkNamesMap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun TestProject.doTestXcode(
|
||||
mode: ImportMode,
|
||||
iosAppLocation: String?,
|
||||
subprojectsToFrameworkNamesMap: Map<String, String?>,
|
||||
arch: String = "x86_64",
|
||||
) {
|
||||
|
||||
gradleProperties
|
||||
.takeIf(Path::exists)
|
||||
?.let {
|
||||
it.append("kotlin_version=${defaultBuildOptions.kotlinVersion}")
|
||||
it.append("test_fixes_version=${defaultBuildOptions.kotlinVersion}")
|
||||
}
|
||||
|
||||
for ((subproject, frameworkName) in subprojectsToFrameworkNamesMap) {
|
||||
|
||||
val taskPrefix = if (subproject.isNotEmpty()) ":$subproject" else ""
|
||||
|
||||
// Add property with custom framework name
|
||||
frameworkName?.let {
|
||||
useCustomCocoapodsFrameworkName(subproject, it, iosAppLocation)
|
||||
}
|
||||
|
||||
val buildOptions = defaultBuildOptions.copy(
|
||||
nativeOptions = defaultBuildOptions.nativeOptions.copy(
|
||||
cocoapodsGenerateWrapper = true
|
||||
)
|
||||
)
|
||||
|
||||
// Generate podspec.
|
||||
build("$taskPrefix:podspec", buildOptions = buildOptions)
|
||||
iosAppLocation?.also {
|
||||
// Set import mode for Podfile.
|
||||
preparePodfile(it, mode)
|
||||
// Install pods.
|
||||
build("$taskPrefix:podInstall", buildOptions = buildOptions)
|
||||
|
||||
projectPath.resolve(it).apply {
|
||||
// Run Xcode build.
|
||||
val xcodebuildResult = runProcess(
|
||||
cmd = listOf(
|
||||
"xcodebuild",
|
||||
"-sdk", "iphonesimulator",
|
||||
"-configuration", "Release",
|
||||
"-workspace", "$name.xcworkspace",
|
||||
"-scheme", name,
|
||||
"-arch", arch
|
||||
),
|
||||
environmentVariables = environmentVariables.environmentalVariables,
|
||||
workingDir = this.toFile(),
|
||||
)
|
||||
assertProcessRunResult(xcodebuildResult) {
|
||||
assertEquals(0, exitCode, "Exit code mismatch for `xcodebuild`.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -34,9 +34,9 @@ fun TestProject.useCustomCocoapodsFrameworkName(
|
||||
}
|
||||
}
|
||||
|
||||
private fun Path.addKotlinBlock(str: String) = appendLine(str.wrapIntoBlock("kotlin"))
|
||||
fun Path.addCocoapodsBlock(str: String) = addKotlinBlock(str.wrapIntoBlock("cocoapods"))
|
||||
|
||||
private fun Path.addCocoapodsBlock(str: String) = addKotlinBlock(str.wrapIntoBlock("cocoapods"))
|
||||
private fun Path.addKotlinBlock(str: String) = appendLine(str.wrapIntoBlock("kotlin"))
|
||||
|
||||
private fun Path.addFrameworkBlock(str: String) = addCocoapodsBlock(str.wrapIntoBlock("framework"))
|
||||
|
||||
|
||||
-1
@@ -131,7 +131,6 @@ fun KGPBaseTest.nativeProject(
|
||||
/**
|
||||
* Trigger test project build with given [buildArguments] and assert build is successful.
|
||||
*/
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
fun TestProject.build(
|
||||
vararg buildArguments: String,
|
||||
forceOutput: Boolean = this.forceOutput,
|
||||
|
||||
+9
-2
@@ -13,7 +13,8 @@ class ProcessRunResult(
|
||||
private val cmd: List<String>,
|
||||
private val workingDir: File,
|
||||
val exitCode: Int,
|
||||
val output: String
|
||||
val output: String,
|
||||
val stdErr: String,
|
||||
) {
|
||||
val isSuccessful: Boolean
|
||||
get() = exitCode == 0
|
||||
@@ -47,9 +48,10 @@ fun runProcess(
|
||||
}
|
||||
sb.append(it).append(SYSTEM_LINE_SEPARATOR)
|
||||
}
|
||||
val stdErr = process.errorStream.bufferedReader().use { it.readText() }
|
||||
val exitCode = process.waitFor()
|
||||
|
||||
return ProcessRunResult(cmd, workingDir, exitCode, sb.toString())
|
||||
return ProcessRunResult(cmd, workingDir, exitCode, sb.toString(), stdErr)
|
||||
}
|
||||
|
||||
fun createGradleCommand(wrapperDir: File, tailParameters: List<String>): List<String> {
|
||||
@@ -86,6 +88,11 @@ fun assertProcessRunResult(result: ProcessRunResult, assertions: ProcessRunResul
|
||||
|${result.output}
|
||||
|#######################
|
||||
|
|
||||
|Process error output:
|
||||
|#######################
|
||||
|${result.stdErr}
|
||||
|#######################
|
||||
|
|
||||
""".trimMargin()
|
||||
)
|
||||
throw e
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id("org.jetbrains.kotlin.multiplatform").version("<pluginMarkerVersion>")
|
||||
id("org.jetbrains.kotlin.native.cocoapods").version("<pluginMarkerVersion>")
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
id("org.jetbrains.kotlin.native.cocoapods")
|
||||
}
|
||||
|
||||
group = "com.example"
|
||||
|
||||
Reference in New Issue
Block a user