From 6d03a75b3d83330af6b6d97be3c2a9d1eb165eb3 Mon Sep 17 00:00:00 2001 From: Kevin Galligan Date: Sat, 7 Dec 2024 20:19:00 -0500 Subject: [PATCH 1/4] Read parameter to set default native build type --- gradle.properties | 2 +- .../src/main/kotlin/co/touchlab/kmmbridge/KMMBridge.kt | 9 ++++++++- .../kotlin/co/touchlab/kmmbridge/KmmBridgeExtension.kt | 1 - 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 649c0053..59b9fcda 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,7 +18,7 @@ SONATYPE_HOST=DEFAULT RELEASE_SIGNING_ENABLED=true GROUP=co.touchlab.kmmbridge -VERSION_NAME=1.1.0 +VERSION_NAME=1.1.1 VERSION_NAME_3x=0.3.7 POM_URL=https://github.com/touchlab/KMMBridge diff --git a/kmmbridge/src/main/kotlin/co/touchlab/kmmbridge/KMMBridge.kt b/kmmbridge/src/main/kotlin/co/touchlab/kmmbridge/KMMBridge.kt index 5c9b0f1c..371ec27a 100644 --- a/kmmbridge/src/main/kotlin/co/touchlab/kmmbridge/KMMBridge.kt +++ b/kmmbridge/src/main/kotlin/co/touchlab/kmmbridge/KMMBridge.kt @@ -52,7 +52,14 @@ abstract class BaseKMMBridgePlugin : Plugin { val extension = extensions.create(EXTENSION_NAME) extension.dependencyManagers.convention(emptyList()) - extension.buildType.convention(NativeBuildType.RELEASE) + + val defaultNativeBuildType = if (project.findStringProperty("NATIVE_BUILD_TYPE") == "DEBUG") { + NativeBuildType.DEBUG + } else { + NativeBuildType.RELEASE + } + + extension.buildType.convention(defaultNativeBuildType) afterEvaluate { val kmmBridgeExtension = extensions.getByType() diff --git a/kmmbridge/src/main/kotlin/co/touchlab/kmmbridge/KmmBridgeExtension.kt b/kmmbridge/src/main/kotlin/co/touchlab/kmmbridge/KmmBridgeExtension.kt index 0e810474..80dbdd0e 100644 --- a/kmmbridge/src/main/kotlin/co/touchlab/kmmbridge/KmmBridgeExtension.kt +++ b/kmmbridge/src/main/kotlin/co/touchlab/kmmbridge/KmmBridgeExtension.kt @@ -42,7 +42,6 @@ interface KmmBridgeExtension { val buildType: Property - @Suppress("unused") fun Project.s3PublicArtifacts( region: String, From 7bd3322b538e897012a7cc490d433c9bdb674dba Mon Sep 17 00:00:00 2001 From: Kevin Galligan Date: Sun, 8 Dec 2024 10:37:37 -0500 Subject: [PATCH 2/4] Externally create release --- gradle.properties | 2 +- .../github/GithubReleaseArtifactManager.kt | 64 +++++++++++++------ .../kmmbridge/github/internal/GithubApi.kt | 6 ++ 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/gradle.properties b/gradle.properties index 59b9fcda..f24413c4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,7 +18,7 @@ SONATYPE_HOST=DEFAULT RELEASE_SIGNING_ENABLED=true GROUP=co.touchlab.kmmbridge -VERSION_NAME=1.1.1 +VERSION_NAME=1.1.2-a1 VERSION_NAME_3x=0.3.7 POM_URL=https://github.com/touchlab/KMMBridge diff --git a/kmmbridge-github/src/main/kotlin/co/touchlab/kmmbridge/github/GithubReleaseArtifactManager.kt b/kmmbridge-github/src/main/kotlin/co/touchlab/kmmbridge/github/GithubReleaseArtifactManager.kt index f879f2bb..2486deef 100644 --- a/kmmbridge-github/src/main/kotlin/co/touchlab/kmmbridge/github/GithubReleaseArtifactManager.kt +++ b/kmmbridge-github/src/main/kotlin/co/touchlab/kmmbridge/github/GithubReleaseArtifactManager.kt @@ -3,6 +3,8 @@ package co.touchlab.kmmbridge.github import co.touchlab.kmmbridge.KmmBridgeExtension import co.touchlab.kmmbridge.artifactmanager.ArtifactManager import co.touchlab.kmmbridge.github.internal.GithubCalls +import co.touchlab.kmmbridge.github.internal.githubArtifactIdentifierName +import co.touchlab.kmmbridge.github.internal.githubArtifactReleaseId import co.touchlab.kmmbridge.github.internal.githubPublishToken import co.touchlab.kmmbridge.github.internal.githubRepo import org.gradle.api.GradleException @@ -12,9 +14,14 @@ import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskProvider import org.gradle.kotlin.dsl.getByType import java.io.File - -internal class GithubReleaseArtifactManager( - private val repository: String?, private val releaseString: String?, private val useExistingRelease: Boolean +import kotlin.properties.Delegates + +open class GithubReleaseArtifactManager( + private val repository: String?, + private val releaseString: String?, + @Deprecated("Releases should be created externally. This parameter controls the flow for releases created " + + "by this class, which will eventually be unsupported.") + private val useExistingRelease: Boolean ) : ArtifactManager { @get:Input @@ -26,42 +33,53 @@ internal class GithubReleaseArtifactManager( @get:Input lateinit var frameworkName: String + @get:Input + lateinit var artifactIdentifierName: String + + @get:Input + var artifactReleaseId by Delegates.notNull() + // TODO: This value is stored in the config cache. It is encrypted, but this still feels insecure. Review alternatives. // https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:secrets lateinit var githubPublishToken: String override fun configure( - project: Project, - version: String, - uploadTask: TaskProvider, - kmmPublishTask: TaskProvider + project: Project, version: String, uploadTask: TaskProvider, kmmPublishTask: TaskProvider ) { this.releaseVersion = releaseString ?: project.version.toString() this.repoName = this.repository ?: project.githubRepo this.githubPublishToken = project.githubPublishToken this.frameworkName = project.kmmBridgeExtension.frameworkName.get() + artifactReleaseId = project.githubArtifactReleaseId?.toInt() ?: 0 + this.artifactIdentifierName = project.githubArtifactIdentifierName ?: "" } override fun deployArtifact(task: Task, zipFilePath: File, version: String): String { - val existingReleaseId = GithubCalls.findReleaseId( - githubPublishToken, repoName, releaseVersion - ) + val uploadReleaseId = if (artifactReleaseId == 0) { + val existingReleaseId = GithubCalls.findReleaseId( + githubPublishToken, repoName, releaseVersion + ) - task.logger.info("existingReleaseId: $existingReleaseId") + task.logger.info("existingReleaseId: $existingReleaseId") - if (existingReleaseId != null && !useExistingRelease) { - throw GradleException("Release for '$releaseVersion' exists. Set 'useExistingRelease = true' to update existing releases.") - } + if (existingReleaseId != null && !useExistingRelease) { + throw GradleException("Release for '$releaseVersion' exists. Set 'useExistingRelease = true' to update existing releases.") + } - val idReply: Int = existingReleaseId ?: GithubCalls.createRelease( - githubPublishToken, repoName, releaseVersion, null - ) + val idReply: Int = existingReleaseId ?: GithubCalls.createRelease( + githubPublishToken, repoName, releaseVersion, null + ) - task.logger.info("GitHub Release created with id: $idReply") + task.logger.info("GitHub Release created with id: $idReply") + + idReply + } else { + artifactReleaseId + } val fileName = artifactName(version, useExistingRelease) - val uploadUrl = GithubCalls.uploadZipFile(githubPublishToken, zipFilePath, repoName, idReply, fileName) + val uploadUrl = GithubCalls.uploadZipFile(githubPublishToken, zipFilePath, repoName, uploadReleaseId, fileName) return "${uploadUrl}.zip" } @@ -69,9 +87,15 @@ internal class GithubReleaseArtifactManager( return if (useExistingRelease) { "$frameworkName-${versionString}-${(System.currentTimeMillis() / 1000)}.xcframework.zip" } else { - "$frameworkName.xcframework.zip" + uploadZipFileName(versionString) } } + + open fun uploadZipFileName(versionString: String) = if (artifactIdentifierName.isNotEmpty()) { + "$frameworkName-${artifactIdentifierName}.xcframework.zip" + } else { + "$frameworkName.xcframework.zip" + } } internal val Project.kmmBridgeExtension get() = extensions.getByType() \ No newline at end of file diff --git a/kmmbridge-github/src/main/kotlin/co/touchlab/kmmbridge/github/internal/GithubApi.kt b/kmmbridge-github/src/main/kotlin/co/touchlab/kmmbridge/github/internal/GithubApi.kt index 537ce007..69582e5a 100644 --- a/kmmbridge-github/src/main/kotlin/co/touchlab/kmmbridge/github/internal/GithubApi.kt +++ b/kmmbridge-github/src/main/kotlin/co/touchlab/kmmbridge/github/internal/GithubApi.kt @@ -39,6 +39,12 @@ internal val Project.githubPublishToken get() = (project.property("GITHUB_PUBLISH_TOKEN") ?: throw IllegalArgumentException("KMMBridge Github operations need property GITHUB_PUBLISH_TOKEN")) as String +internal val Project.githubArtifactReleaseId + get() = project.findStringProperty("GITHUB_ARTIFACT_RELEASE_ID") + +internal val Project.githubArtifactIdentifierName + get() = project.findStringProperty("GITHUB_ARTIFACT_IDENTIFIER_NAME") + internal val Project.githubRepo: String get() = githubRepoOrNull ?: throw IllegalArgumentException("KMMBridge Github operations need a repo param or property GITHUB_REPO") From 241173121d0d2305c7ac548570eff89dadac06f0 Mon Sep 17 00:00:00 2001 From: Kevin Galligan Date: Wed, 11 Dec 2024 14:16:07 -0500 Subject: [PATCH 3/4] Add tests for the KMMBridgeExtension --- gradle/libs.versions.toml | 1 + kmmbridge/build.gradle.kts | 1 + .../kmmbridge/KmmBridgeExtensionTest.kt | 101 ++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 kmmbridge/src/test/kotlin/co/touchlab/kmmbridge/KmmBridgeExtensionTest.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 058eb425..78cc8273 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,6 +6,7 @@ mavenPublish = "0.30.0" aws = { module = "software.amazon.awssdk:s3", version = "2.23.8" } okhttp = { module = "com.squareup.okhttp3:okhttp", version = "4.12.0" } gson = { module = "com.google.code.gson:gson", version = "2.10.1" } +kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin-api", version.ref = "kotlin" } [plugins] kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } diff --git a/kmmbridge/build.gradle.kts b/kmmbridge/build.gradle.kts index 70c32e11..6a5a304b 100644 --- a/kmmbridge/build.gradle.kts +++ b/kmmbridge/build.gradle.kts @@ -57,6 +57,7 @@ dependencies { implementation(libs.gson) testImplementation(kotlin("test")) + testImplementation(libs.kotlin.gradle.plugin) testImplementation(gradleTestKit()) testImplementation("commons-io:commons-io:2.18.0") } diff --git a/kmmbridge/src/test/kotlin/co/touchlab/kmmbridge/KmmBridgeExtensionTest.kt b/kmmbridge/src/test/kotlin/co/touchlab/kmmbridge/KmmBridgeExtensionTest.kt new file mode 100644 index 00000000..803e7780 --- /dev/null +++ b/kmmbridge/src/test/kotlin/co/touchlab/kmmbridge/KmmBridgeExtensionTest.kt @@ -0,0 +1,101 @@ +package co.touchlab.kmmbridge + +import co.touchlab.kmmbridge.artifactmanager.ArtifactManager +import co.touchlab.kmmbridge.artifactmanager.AwsS3PublicArtifactManager +import co.touchlab.kmmbridge.artifactmanager.MavenPublishArtifactManager +import co.touchlab.kmmbridge.dependencymanager.CocoapodsDependencyManager +import co.touchlab.kmmbridge.dependencymanager.DependencyManager +import co.touchlab.kmmbridge.dependencymanager.SpmDependencyManager +import org.gradle.api.Project +import org.gradle.api.provider.Property +import org.gradle.testfixtures.ProjectBuilder +import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType +import kotlin.test.BeforeTest +import kotlin.test.Ignore +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class KmmBridgeExtensionTest { + private lateinit var project: Project + private lateinit var extension: TestKmmBridgeExtension + + @BeforeTest + fun setup() { + project = ProjectBuilder.builder().build() + extension = TestKmmBridgeExtension(project) + } + + @Test + fun `test s3 artifact configuration`() { + extension.apply { + project.s3PublicArtifacts( + region = "us-east-1", + bucket = "test-bucket", + accessKeyId = "test-key", + secretAccessKey = "test-secret" + ) + } + + val artifactManager = extension.artifactManager.get() + assertTrue(artifactManager is AwsS3PublicArtifactManager) + } + + @Test + fun `test maven publish configuration`() { + extension.apply { + project.mavenPublishArtifacts( + repository = "test-repo", + publication = "test-pub", + isMavenCentral = true + ) + } + + val artifactManager = extension.artifactManager.get() + assertTrue(artifactManager is MavenPublishArtifactManager) + } + + @Test + fun `test spm configuration`() { + extension.apply { + project.spm( + spmDirectory = "test-dir", + useCustomPackageFile = true + ) + } + + val dependencyManager = extension.dependencyManagers.get().first() + assertTrue(dependencyManager is SpmDependencyManager) + } + + @Test + @Ignore("CocoaPods plugin not loaded in test environment. Trunk specifically isn't important.") + fun `test cocoapods trunk configuration`() { + extension.apply { + project.cocoapodsTrunk( + allowWarnings = true, + verboseErrors = true + ) + } + + val dependencyManager = extension.dependencyManagers.get().first() + assertTrue(dependencyManager is CocoapodsDependencyManager) + } + + @Test + fun `test property finalization`() { + val testValue = "test-framework" + extension.frameworkName.set(testValue) + extension.frameworkName.finalizeValue() + + assertEquals(testValue, extension.frameworkName.get()) + assertTrue(extension.frameworkName.isPresent) + } +} + +private class TestKmmBridgeExtension(private val project: Project) : KmmBridgeExtension { + override val frameworkName: Property = project.objects.property(String::class.java) + override val dependencyManagers = project.objects.listProperty(DependencyManager::class.java) + override val artifactManager = project.objects.property(ArtifactManager::class.java) + override val buildType: Property = project.objects.property(NativeBuildType::class.java) +} From 0172357894d01f3115ff7044cb76084d096cb3c6 Mon Sep 17 00:00:00 2001 From: Kevin Galligan Date: Fri, 13 Dec 2024 01:23:17 -0500 Subject: [PATCH 4/4] Final debug builds support, v1.2.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f24413c4..0311854f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,7 +18,7 @@ SONATYPE_HOST=DEFAULT RELEASE_SIGNING_ENABLED=true GROUP=co.touchlab.kmmbridge -VERSION_NAME=1.1.2-a1 +VERSION_NAME=1.2.0 VERSION_NAME_3x=0.3.7 POM_URL=https://github.com/touchlab/KMMBridge