diff --git a/.github/actions/checkout-head/action.yml b/.github/actions/checkout-head/action.yml index f3632d4..1eec81a 100644 --- a/.github/actions/checkout-head/action.yml +++ b/.github/actions/checkout-head/action.yml @@ -23,6 +23,11 @@ inputs: commands. The post-job step removes the PAT. default: ${{ github.token }} required: false + submodules: + description: > + Whether to checkout submodules. `true` to checkout submodules or `recursive` to recursively checkout submodules + default: 'false' + required: 'false' runs: using: composite @@ -44,7 +49,9 @@ runs: echo "ref=$ref" >> "$GITHUB_OUTPUT" else baseref="main" - if [ -n "$GITHUB_BASE_REF" ]; then + if [[ "$ref" == kn-* ]] && git ls-remote --exit-code --heads "https://github.com/$REPOSITORY.git" "kn-main"; then + baseref="kn-main" + elif [ -n "$GITHUB_BASE_REF" ]; then echo "attempting GH base ref: $GITHUB_BASE_REF" if git ls-remote --exit-code --heads "https://github.com/$REPOSITORY.git" "$GITHUB_BASE_REF"; then baseref="$GITHUB_BASE_REF" @@ -60,4 +67,5 @@ runs: path: ${{ inputs.path }} repository: ${{ inputs.repository }} ref: ${{ steps.repo.outputs.ref }} - token: ${{ inputs.token }} \ No newline at end of file + token: ${{ inputs.token }} + submodules: ${{ inputs.submodules }} diff --git a/build-plugins/kmp-conventions/src/main/kotlin/aws/sdk/kotlin/gradle/kmp/ConfigureIosSimulator.kt b/build-plugins/kmp-conventions/src/main/kotlin/aws/sdk/kotlin/gradle/kmp/ConfigureIosSimulator.kt new file mode 100644 index 0000000..d8f444a --- /dev/null +++ b/build-plugins/kmp-conventions/src/main/kotlin/aws/sdk/kotlin/gradle/kmp/ConfigureIosSimulator.kt @@ -0,0 +1,59 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package aws.sdk.kotlin.gradle.kmp + +import org.gradle.api.Project +import org.gradle.api.tasks.Exec +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest +import org.jetbrains.kotlin.konan.target.HostManager + +/** + * Disables standalone mode in simulator tests since it causes issues with TLS. + * This means we need to manage the simulator state ourselves (booting, shutting down). + * https://youtrack.jetbrains.com/issue/KT-38317 + */ +public fun Project.configureIosSimulatorTasks() { + if (!HostManager.hostIsMac) return + + val simulatorDeviceName = project.findProperty("iosSimulatorDevice") as? String ?: "iPhone 15" + val xcrun = "/usr/bin/xcrun" + + val bootTask = rootProject.tasks.maybeCreate("bootIosSimulatorDevice", Exec::class.java).apply { + isIgnoreExitValue = true + commandLine(xcrun, "simctl", "boot", simulatorDeviceName) + + doLast { + val result = executionResult.get() + val code = result.exitValue + if (code != 148 && code != 149) { // ignore "simulator already running" errors + result.assertNormalExitValue() + } + } + } + + val shutdownTask = rootProject.tasks.maybeCreate("shutdownIosSimulatorDevice", Exec::class.java).apply { + isIgnoreExitValue = true + commandLine(xcrun, "simctl", "shutdown", simulatorDeviceName) + + doLast { + val result = executionResult.get() + val code = result.exitValue + if (code != 148 && code != 149) { // ignore "simulator already shutdown" errors + result.assertNormalExitValue() + } + } + } + + allprojects { + val simulatorTasks = tasks.withType() + simulatorTasks.configureEach { + dependsOn(bootTask) + standalone.set(false) + device.set(simulatorDeviceName) + } + shutdownTask.mustRunAfter(simulatorTasks) + } +} diff --git a/build-plugins/kmp-conventions/src/main/kotlin/aws/sdk/kotlin/gradle/kmp/ConfigureTargets.kt b/build-plugins/kmp-conventions/src/main/kotlin/aws/sdk/kotlin/gradle/kmp/ConfigureTargets.kt index e450c4c..2ed42ed 100644 --- a/build-plugins/kmp-conventions/src/main/kotlin/aws/sdk/kotlin/gradle/kmp/ConfigureTargets.kt +++ b/build-plugins/kmp-conventions/src/main/kotlin/aws/sdk/kotlin/gradle/kmp/ConfigureTargets.kt @@ -4,12 +4,18 @@ */ package aws.sdk.kotlin.gradle.kmp +import aws.sdk.kotlin.gradle.util.prop import org.gradle.api.Project +import org.gradle.api.publish.maven.tasks.AbstractPublishToMaven +import org.gradle.api.publish.tasks.GenerateModuleMetadata import org.gradle.api.tasks.testing.Test import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.kotlin.dsl.* import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.jetbrains.kotlin.konan.target.Family +import org.jetbrains.kotlin.konan.target.HostManager import java.io.File internal fun Project.tryGetClass(className: String): Class? { @@ -45,7 +51,7 @@ val Project.hasWindows: Boolean get() = hasNative || files.any { it.name == "win * Test if a project follows the convention and needs configured for KMP (used in handful of spots where we have a * subproject that is just a container for other projects but isn't a KMP project itself). */ -public val Project.needsKmpConfigured: Boolean get() = hasCommon || hasJvm || hasNative || hasJs +public val Project.needsKmpConfigured: Boolean get() = hasCommon || hasJvm || hasNative || hasJs || hasJvmAndNative || hasDesktop || hasLinux || hasApple || hasWindows @OptIn(ExperimentalKotlinGradlePluginApi::class) fun Project.configureKmpTargets() { @@ -64,7 +70,8 @@ fun Project.configureKmpTargets() { return@withPlugin } - // configure the target hierarchy, this does not actually enable the targets, just their relationships + // extend the default KMP target hierarchy + // this does not actually enable the targets, just their relationships // see https://kotlinlang.org/docs/multiplatform-hierarchy.html#see-the-full-hierarchy-template kmpExt.applyDefaultHierarchyTemplate { if (hasJvmAndNative) { @@ -95,7 +102,7 @@ fun Project.configureKmpTargets() { } } - // enable targets + // enable the targets configureCommon() if (hasJvm && JVM_ENABLED) { @@ -103,16 +110,24 @@ fun Project.configureKmpTargets() { } // FIXME Configure JS - // FIXME Configure Apple - // FIXME Configure Windows - withIf(hasLinux && NATIVE_ENABLED, kmpExt) { - configureLinux() - } - - withIf(hasDesktop && NATIVE_ENABLED, kmpExt) { - configureLinux() - // FIXME Configure desktop + if (NATIVE_ENABLED) { + if (hasApple) { + kmpExt.apply { configureApple() } + } + if (hasWindows) { + kmpExt.apply { configureWindows() } + } + if (hasLinux) { + kmpExt.apply { configureLinux() } + } + if (hasDesktop) { + kmpExt.apply { + configureLinux() + configureMacos() + configureWindows() + } + } } kmpExt.configureSourceSetsConvention() @@ -155,14 +170,31 @@ fun Project.configureJvm() { fun Project.configureLinux() { kotlin { - linuxX64 { - // FIXME enable tests once the target is fully implemented - tasks.named("linuxX64Test") { - enabled = false - } - } - // FIXME - Okio missing arm64 target support - // linuxArm64() + linuxX64() + linuxArm64() // FIXME - Okio missing arm64 target support + } +} + +fun Project.configureApple() { + kotlin { + configureMacos() + iosSimulatorArm64() + iosArm64() + iosX64() + } +} + +fun Project.configureMacos() { + kotlin { + macosX64() + macosArm64() + } +} + +fun Project.configureWindows() { + kotlin { + // FIXME Set up Docker files and CMake tasks for Windows +// mingwX64() } } @@ -179,8 +211,62 @@ fun KotlinMultiplatformExtension.configureSourceSetsConvention() { } } -internal inline fun withIf(condition: Boolean, receiver: T, block: T.() -> Unit) { - if (condition) { - receiver.block() +val Project.JVM_ENABLED get() = prop("aws.kotlin.jvm")?.let { it == "true" } ?: true +val Project.NATIVE_ENABLED get() = prop("aws.kotlin.native")?.let { it == "true" } ?: true + +/** + * Kotlin/Native Linux and Windows targets are generally enabled on all hosts since + * the Kotlin toolchain and backend compilers support cross compilation. We + * are using cinterop and have to compile CRT for those platforms which sometimes + * requires using docker which isn't always available in CI or setup in users environment. + * + * See [KT-30498](https://youtrack.jetbrains.com/issue/KT-30498) + */ +fun Project.disableCrossCompileTargets() { + plugins.withId("org.jetbrains.kotlin.multiplatform") { + configure { + targets.withType { + val knTarget = this + when { + HostManager.hostIsMac && (knTarget.isLinux || knTarget.isWindows) -> disable(knTarget) + HostManager.hostIsLinux && knTarget.isApple -> disable(knTarget) + HostManager.hostIsMingw && (knTarget.isLinux || knTarget.isApple) -> disable(knTarget) + } + } + } + } +} + +private val KotlinNativeTarget.isLinux: Boolean + get() = konanTarget.family == Family.LINUX + +private val KotlinNativeTarget.isApple: Boolean + get() = konanTarget.family.isAppleFamily + +private val KotlinNativeTarget.isWindows: Boolean + get() = konanTarget.family == Family.MINGW + +internal fun Project.disable(knTarget: KotlinNativeTarget) { + logger.warn("disabling Kotlin/Native target: ${knTarget.name}") + knTarget.apply { + compilations.all { + cinterops.all { + tasks.named(interopProcessingTaskName).configure { enabled = false } + } + compileTaskProvider.configure { enabled = false } + } + + binaries.all { + linkTaskProvider.configure { enabled = false } + } + + mavenPublication { + tasks.withType().configureEach { + onlyIf { publication != this@mavenPublication } + } + tasks.withType().configureEach { + onlyIf { publication != this@mavenPublication } + } + } } } diff --git a/build-plugins/kmp-conventions/src/main/kotlin/aws/sdk/kotlin/gradle/kmp/IdeUtils.kt b/build-plugins/kmp-conventions/src/main/kotlin/aws/sdk/kotlin/gradle/kmp/IdeUtils.kt deleted file mode 100644 index 8ab7cf8..0000000 --- a/build-plugins/kmp-conventions/src/main/kotlin/aws/sdk/kotlin/gradle/kmp/IdeUtils.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ -package aws.sdk.kotlin.gradle.kmp - -import aws.sdk.kotlin.gradle.util.prop -import org.gradle.api.Project -import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget -import org.jetbrains.kotlin.konan.target.HostManager -import org.jetbrains.kotlin.konan.target.KonanTarget -import java.util.* - -/** - * Whether Intellij is active or not - */ -val IDEA_ACTIVE = System.getProperty("idea.active") == "true" - -val OS_NAME = System.getProperty("os.name").lowercase() - -val HOST_NAME = when { - OS_NAME.startsWith("linux") -> "linux" - OS_NAME.startsWith("windows") -> "windows" - OS_NAME.startsWith("mac") -> "macos" - else -> error("Unknown os name `$OS_NAME`") -} - -val Project.JVM_ENABLED get() = prop("aws.kotlin.jvm")?.let { it == "true" } ?: true -val Project.NATIVE_ENABLED get() = prop("aws.kotlin.native")?.let { it == "true" } ?: true - -/** - * Scope down the native target enabled when working in intellij - */ -val KotlinMultiplatformExtension.ideaTarget: KotlinNativeTarget - get() = when (HostManager.host) { - is KonanTarget.LINUX_X64 -> linuxX64() - is KonanTarget.LINUX_ARM64 -> linuxArm64() - is KonanTarget.MACOS_X64 -> macosX64() - is KonanTarget.MACOS_ARM64 -> macosArm64() - is KonanTarget.MINGW_X64 -> mingwX64() - else -> error("Unsupported target ${HostManager.host}") - }