diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index d3a915d..e4c3a7c 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -23,7 +23,7 @@ jobs: fail-fast: false matrix: os: - - runner: macos-11 + - runner: macos-latest shell: bash - runner: ubuntu-latest shell: bash diff --git a/.sdkmanrc b/.sdkmanrc index 50cabbe..b5ac733 100644 --- a/.sdkmanrc +++ b/.sdkmanrc @@ -1,3 +1,3 @@ # Enable auto-env through the sdkman_auto_env config # Add key=value pairs of SDKs to use below -java=11.0.2-open +java=11.0.19-tem diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cc263a..3cdc47a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,44 +1,56 @@ +# 2.0.0 + +## Changes + +- Migrated to gradle version catalogs +- New kotlin target layout following support tiers and using `targetHierarchy` +- `local.properties` is now also respected at the module level and overrides root project + level `local.properties` +- New `wasm` target support +- Streamlined build host control + # 1.1.4 ## Changes -* Back to spotless + ktlint -* Fixed GH actions issues with runners -* `local.properties` support -* Custom refreshVersions rules setup -* `.sdkmanrc` for easier local env setup -* Version bumps (kotlin@1.6.10, gradle@7.3.3) +- Back to spotless + ktlint +- Fixed GH actions issues with runners +- `local.properties` support +- Custom refreshVersions rules setup +- `.sdkmanrc` for easier local env setup +- Version bumps (kotlin@1.6.10, gradle@7.3.3) # 1.1.3 ## Changes -* Swapped out ktlint for spotless + ktfmt -* Disabling git hooks on CI -* Added android support +- Swapped out ktlint for spotless + ktfmt +- Disabling git hooks on CI +- Added android support # 1.1.2 ## Changes -* Removed incorrect hashed imports from gradle scripts -* Bumped versions -* Introduced nativeMain and nativeTest sourceSets -* Added BlockingTest utility interface -* Removed snapshot repository support -* macosArm64() target added -* iosSimulatorArm64() target added -* watchosSimulatorArm64() target added -* tvosSimulatorArm64() target added +- Removed incorrect hashed imports from gradle scripts +- Bumped versions +- Introduced nativeMain and nativeTest sourceSets +- Added BlockingTest utility interface +- Removed snapshot repository support +- macosArm64() target added +- iosSimulatorArm64() target added +- watchosSimulatorArm64() target added +- tvosSimulatorArm64() target added # 1.1.1 ## Changes -* Stricter publication and test control to avoid duplicate builds on matrix jobs -* Reworked gradle precompiled script plugins to better separate different functionalities -* Sandbox GH action to quickly check gradle scripts on different hosts -* Added baseline flow for setting up required native libraries on different CI hosts via [scripts/] directory -* Native library caching for check and release actions -* Upgraded versions -* Fixed detekt issues +- Stricter publication and test control to avoid duplicate builds on matrix jobs +- Reworked gradle precompiled script plugins to better separate different functionalities +- Sandbox GH action to quickly check gradle scripts on different hosts +- Added baseline flow for setting up required native libraries on different CI hosts via [scripts/] + directory +- Native library caching for check and release actions +- Upgraded versions +- Fixed detekt issues diff --git a/README.md b/README.md index 8856c7d..78e6bbb 100644 --- a/README.md +++ b/README.md @@ -12,21 +12,25 @@ except deprecated wasm32. ## Features * Native target grouping and shared sourceSets -* Wrapper library module that declares dependencies on all lib modules -* Uniform configuration via conventional plugins `plugin.common`, `plugin.library-mpp` & `plugin.publishing-mpp` -* Local `test` module for shared test utilities (a helper function to run coroutine tests in common sourceSet included) +* Wrapper library module that declares dependencies on all library modules +* Uniform configuration via convention + plugins `convention.base`, `convention.library-mpp`, `convention.library-android` & `convention.publishing-mpp` +* Incremental kotlin target sets following support tiers +* Separation of source and tests to allow for lower support tier sources, being tested by higher and + more supported tier test module * Local `sandbox` module for easy library consumer side checks * Publication control to avoid multiple publications for targets that can be built on multiple hosts -* `ktlint` plugin with automatic `git-hooks` -* `refreshVersions` plugin for better library version control +* `detekt` plugin with automatic `git-hooks` * Main host for publications can be changed via `gradle.properties#project.mainOS` property * Gradle Build Scan setup +* Gradle version catalog with easy updates `./gradlew versionCatalogUpdate` * GH dependabot setup * GH release action for platform dependant publications * GH check action for platform dependant tests on PRs * Maven Central publishing setup * GH Packages publishing setup -* `SDKMAN` support for local env (`sdk man env install` to get the required JDM and `sdkman env` to switch to it) +* `SDKMAN` support for local env (`sdk man env install` to get the required JDM and `sdkman env` to + switch to it) ## Setup @@ -34,11 +38,13 @@ Here are some pointers to help you get up and running with this template ### Badges -This README contains some useful badges for your project. To tailor them to your artefacts the following changes needs +This README contains some useful badges for your project. To tailor them to your artefacts the +following changes needs to be made: * `Dokka docs` - change the link as `(http://$GH_USERNAME.github.io/$GH_PROJECT_NAME)` -* `Version maven-central` - change all occurrences of `dev.petuska` to your own group and `template-kmp-library` to your +* `Version maven-central` - change all occurrences of `dev.petuska` to your own group + and `template-kmp-library` to your root library name ### gradle.properties @@ -48,28 +54,45 @@ Have a look at `gradle.properties` file and change these properties as needed * `gh.owner.id` - main library developer's username * `gh.owner.name` - main library developer's name * `gh.owner.email` - main library developer's email -* `project.mainOS` - main host to publish cross-platform artefacts from (to avoid duplicate publications) +* `project.mainOS` - main host to publish cross-platform artefacts from (to avoid duplicate + publications). Supported values are `linux`, `windows`, `macosX64` & `macosArm64`. Note that some + mac targets can be compiled on all architectures and are set to require `macosX64` by default. + This can be changed in [./build-conventions/src/main/kotlin/util/buildHost.kt]. * `group` - artefacts' group * `description` - library description * `version` - library version (overridden in CI, so doesn't really matter here) ### Modules -All the library modules should go to [./lib] directory and be included in [./settings.gradle.kts]. There are already two -sample modules to illustrate how simple the setup is ([./lib/template-kmp-library-core] & [./lib/template-kmp-library-dsl]). -They both contain some sample code and tests that make use of local [./test] module with testing utilities. +All the library modules should go to [./modules] directory and be included +in [./settings.gradle.kts]. +There are already two sample modules to illustrate how simple the setup +is - [./modules/template-kmp-library-core] & [./modules/template-kmp-library-dsl]. +They both contain some sample code and tests +in [./tests/template-kmp-library-core-tests] & [./tests/template-kmp-library-dsl-tests] ### Kotlin Targets -The template comes packed with all kotlin targets preconfigured, however if you want to remove some of them or tweak the -config, you only need to make changes as needed in [./buildSrc/src/main/kotlin/plugin.library-mpp.gradle.kts]. Removing -targets from this file will not break any publications as they're configured on top of pre-registered targets. +The template comes packed with all kotlin targets preconfigured and grouped by support tiers +controlled by a set of plugins. Lower tier plugins apply all of the higher tier plugins so you +should only ever need to pick one. + +- `convention.kotlin-mpp-tier0` +- `convention.kotlin-mpp-tier1` +- `convention.kotlin-mpp-tier2` +- `convention.kotlin-mpp-tier3` + +Changing tiers will not break any publications as they're configured on top of pre-registered +targets. ### GitHub Actions -The template also comes with GH actions to check builds on PRs and publish artefacts when creating a GH release. By -default, it'll publish to GH packages and Maven Central. However, to fully unlock Maven Central publishing, you'll need -to add these secrets to your GH repository. If you want to quickly disable Maven Central publishing, you can toggle it +The template also comes with GH actions to check builds on PRs and publish artefacts when creating a +GH release. By +default, it'll publish to GH packages and Maven Central. However, to fully unlock Maven Central +publishing, you'll need +to add these secrets to your GH repository. If you want to quickly disable Maven Central publishing, +you can toggle it at [./.github/workflows/release.yml#L80]` * `SIGNING_KEY` - GPG signing key diff --git a/build-conventions/build.gradle.kts b/build-conventions/build.gradle.kts new file mode 100644 index 0000000..26bf4e1 --- /dev/null +++ b/build-conventions/build.gradle.kts @@ -0,0 +1,30 @@ +plugins { + `kotlin-dsl` +} + +repositories { + gradlePluginPortal() + google() + mavenCentral() +} + +dependencies { + implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) + + implementation(libs.plugin.kotlin) + implementation(libs.plugin.kotlin.serialization) + implementation(libs.plugin.android) + implementation(libs.plugin.git.hooks) + implementation(libs.plugin.detekt) + implementation(libs.plugin.dokka) + implementation(libs.plugin.versions) + implementation(libs.plugin.versions.update) + implementation(libs.plugin.container.tasks) +} + +gradleEnterprise { + buildScan { + termsOfServiceUrl = "https://gradle.com/terms-of-service" + termsOfServiceAgree = "yes" + } +} diff --git a/build-conventions/gradle b/build-conventions/gradle new file mode 120000 index 0000000..3337596 --- /dev/null +++ b/build-conventions/gradle @@ -0,0 +1 @@ +../gradle \ No newline at end of file diff --git a/build-conventions/settings.gradle.kts b/build-conventions/settings.gradle.kts new file mode 100644 index 0000000..07339d8 --- /dev/null +++ b/build-conventions/settings.gradle.kts @@ -0,0 +1,23 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} + +plugins { + id("com.gradle.enterprise") version "3.13" +} + +@Suppress("UnstableApiUsage") +dependencyResolutionManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + mavenLocal() + } +} + +enableFeaturePreview("STABLE_CONFIGURATION_CACHE") diff --git a/build-conventions/src/main/kotlin/convention.base.gradle.kts b/build-conventions/src/main/kotlin/convention.base.gradle.kts new file mode 100644 index 0000000..1cb07d0 --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.base.gradle.kts @@ -0,0 +1,17 @@ +plugins { + idea + id("convention.local-properties") +} + +idea { + module { + isDownloadJavadoc = true + isDownloadSources = true + } +} + +repositories { + mavenCentral() + google() + mavenLocal() +} diff --git a/build-conventions/src/main/kotlin/convention.detekt.gradle.kts b/build-conventions/src/main/kotlin/convention.detekt.gradle.kts new file mode 100644 index 0000000..306ffb4 --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.detekt.gradle.kts @@ -0,0 +1,28 @@ +import io.gitlab.arturbosch.detekt.Detekt + +plugins { + id("convention.base") + id("io.gitlab.arturbosch.detekt") +} + +dependencies { + detektPlugins(libs.detekt.formatting) +} + +detekt { + config.from(rootDir.resolve("gradle/detekt.yml")) + buildUponDefaultConfig = true +} + +tasks.withType { + reports { + // observe findings in your browser with structure and code snippets + html.required.set(true) + // checkstyle like format mainly for integrations like Jenkins + xml.required.set(true) + // similar to the console output, contains issue signature to manually edit baseline files + txt.required.set(true) + // standardized SARIF format (https://sarifweb.azurewebsites.net/) to support integrations with Github Code Scanning + sarif.required.set(true) + } +} diff --git a/build-conventions/src/main/kotlin/convention.git-hooks.gradle.kts b/build-conventions/src/main/kotlin/convention.git-hooks.gradle.kts new file mode 100644 index 0000000..d0a191c --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.git-hooks.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("convention.base") + id("com.github.jakemarsden.git-hooks") apply (System.getenv("CI") !in arrayOf(null, "0", "false", "n", "N")) +} + +gitHooks { + setHooks( + mapOf( + "pre-commit" to "detekt --auto-correct", + "pre-push" to "detekt" + ) + ) +} diff --git a/build-conventions/src/main/kotlin/convention.jvm.gradle.kts b/build-conventions/src/main/kotlin/convention.jvm.gradle.kts new file mode 100644 index 0000000..35e8baf --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.jvm.gradle.kts @@ -0,0 +1,27 @@ +import com.android.build.gradle.LibraryExtension + +plugins { + id("convention.base") + `java-base` +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(libs.versions.java.get().toInt())) + } +} + +plugins.withId("com.android.library") { + configure { + compileOptions { + sourceCompatibility = JavaVersion.toVersion(libs.versions.java.get()) + targetCompatibility = sourceCompatibility + } + } +} + +tasks { + withType { + useJUnitPlatform() + } +} \ No newline at end of file diff --git a/build-conventions/src/main/kotlin/convention.kotlin-mpp-tier0.gradle.kts b/build-conventions/src/main/kotlin/convention.kotlin-mpp-tier0.gradle.kts new file mode 100644 index 0000000..8f1560e --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.kotlin-mpp-tier0.gradle.kts @@ -0,0 +1,27 @@ +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension + +plugins { + id("convention.jvm") + id("convention.kotlin-mpp") +} + +plugins.withId("com.android.library") { + configure { + android() + } +} + +kotlin { + js { + useCommonJs() + browser { + commonWebpackConfig { + cssSupport { enabled.set(true) } + scssSupport { enabled.set(true) } + } + testTask { useKarma() } + } + } + + jvm() +} diff --git a/build-conventions/src/main/kotlin/convention.kotlin-mpp-tier1.gradle.kts b/build-conventions/src/main/kotlin/convention.kotlin-mpp-tier1.gradle.kts new file mode 100644 index 0000000..8bf6929 --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.kotlin-mpp-tier1.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id("convention.kotlin-mpp-tier0") +} + +// https://kotlinlang.org/docs/native-target-support.html#tier-1 +kotlin { + linuxX64() + + macosX64() + macosArm64() + + iosX64() + iosSimulatorArm64() +} diff --git a/build-conventions/src/main/kotlin/convention.kotlin-mpp-tier2.gradle.kts b/build-conventions/src/main/kotlin/convention.kotlin-mpp-tier2.gradle.kts new file mode 100644 index 0000000..eec7e3b --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.kotlin-mpp-tier2.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("convention.kotlin-mpp-tier1") +} + +// https://kotlinlang.org/docs/native-target-support.html#tier-2 +kotlin { + linuxArm64() + + watchosSimulatorArm64() + watchosX64() + watchosArm32() + watchosArm64() + + tvosSimulatorArm64() + tvosX64() + tvosArm64() + + iosArm64() +} diff --git a/build-conventions/src/main/kotlin/convention.kotlin-mpp-tier3.gradle.kts b/build-conventions/src/main/kotlin/convention.kotlin-mpp-tier3.gradle.kts new file mode 100644 index 0000000..f308ffd --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.kotlin-mpp-tier3.gradle.kts @@ -0,0 +1,25 @@ +import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl + +plugins { + id("convention.kotlin-mpp-tier2") +} + +// https://kotlinlang.org/docs/native-target-support.html#tier-3 +kotlin { + @OptIn(ExperimentalWasmDsl::class) + wasm { + browser { + commonWebpackConfig { + cssSupport { enabled.set(true) } + scssSupport { enabled.set(true) } + } + testTask { useKarma() } + } + } + androidNativeArm32() + androidNativeArm64() + androidNativeX86() + androidNativeX64() + mingwX64() + watchosDeviceArm64() +} diff --git a/build-conventions/src/main/kotlin/convention.kotlin-mpp.gradle.kts b/build-conventions/src/main/kotlin/convention.kotlin-mpp.gradle.kts new file mode 100644 index 0000000..a6afb78 --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.kotlin-mpp.gradle.kts @@ -0,0 +1,19 @@ +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi + +plugins { + id("convention.base") + kotlin("multiplatform") +} + +kotlin { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + targetHierarchy.default() + + sourceSets { + commonTest { + dependencies { + implementation(kotlin("test")) + } + } + } +} diff --git a/build-conventions/src/main/kotlin/convention.library-android.gradle.kts b/build-conventions/src/main/kotlin/convention.library-android.gradle.kts new file mode 100644 index 0000000..b6ba2dc --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.library-android.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("convention.library") + id("com.android.library") +} + +android { + namespace = "$group.${name.replace(Regex("[_-]"), ".")}" + compileSdk = 31 + defaultConfig { + minSdk = 1 + aarMetadata { + minCompileSdk = minSdk + } + } +} diff --git a/build-conventions/src/main/kotlin/convention.library-mpp.gradle.kts b/build-conventions/src/main/kotlin/convention.library-mpp.gradle.kts new file mode 100644 index 0000000..afad5df --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.library-mpp.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("convention.kotlin-mpp") + id("convention.library") + id("convention.library-android") +} + +kotlin { + explicitApi() +} diff --git a/build-conventions/src/main/kotlin/convention.library.gradle.kts b/build-conventions/src/main/kotlin/convention.library.gradle.kts new file mode 100644 index 0000000..b08d40d --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.library.gradle.kts @@ -0,0 +1,5 @@ +plugins { + id("convention.base") + id("convention.jvm") + id("convention.detekt") +} diff --git a/build-conventions/src/main/kotlin/convention.local-properties.gradle.kts b/build-conventions/src/main/kotlin/convention.local-properties.gradle.kts new file mode 100644 index 0000000..9ef701a --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.local-properties.gradle.kts @@ -0,0 +1,12 @@ +import java.util.* + +fun File.localProperties() = resolve("local.properties").takeIf(File::exists)?.let { + Properties().apply { + it.inputStream().use(::load) + }.mapKeys { (k, _) -> k.toString() } +}?.toList()?.forEach { (k, v) -> + project.extra[k] = v +} + +rootDir.localProperties() +projectDir.localProperties() \ No newline at end of file diff --git a/build-conventions/src/main/kotlin/convention.pom.gradle.kts b/build-conventions/src/main/kotlin/convention.pom.gradle.kts new file mode 100644 index 0000000..d2b4b56 --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.pom.gradle.kts @@ -0,0 +1,41 @@ +plugins { + id("convention.base") + `maven-publish` +} + +publishing { + publications { + val ghOwnerId: String = project.properties["gh.owner.id"]!!.toString() + val ghOwnerName: String = project.properties["gh.owner.name"]!!.toString() + val ghOwnerEmail: String = project.properties["gh.owner.email"]!!.toString() + withType { + pom { + name by project.name + url by "https://github.com/$ghOwnerId/${rootProject.name}" + description by provider { project.description } + + licenses { + license { + name by "The Apache License, Version 2.0" + url by "https://www.apache.org/licenses/LICENSE-2.0.txt" + } + } + + developers { + developer { + id by ghOwnerId + name by ghOwnerName + email by ghOwnerEmail + } + } + + scm { + connection by "scm:git:git://github.com:$ghOwnerId/${rootProject.name}.git" + developerConnection.set("scm:git:git@github.com:$ghOwnerId/${rootProject.name}.git") + url by "https://github.com/$ghOwnerId/${rootProject.name}.git" + tag by Git.headCommitHash + } + } + } + } +} diff --git a/build-conventions/src/main/kotlin/convention.publishing-dokka.gradle.kts b/build-conventions/src/main/kotlin/convention.publishing-dokka.gradle.kts new file mode 100644 index 0000000..5f88f01 --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.publishing-dokka.gradle.kts @@ -0,0 +1,20 @@ +plugins { + id("convention.publishing") + id("org.jetbrains.dokka") +} + +tasks { + register("javadocJar") { + dependsOn(dokkaHtml) + archiveClassifier by "javadoc" + from(dokkaHtml) + } +} + +publishing { + publications { + withType { + artifact(tasks["javadocJar"]) + } + } +} diff --git a/build-conventions/src/main/kotlin/convention.publishing-mpp.gradle.kts b/build-conventions/src/main/kotlin/convention.publishing-mpp.gradle.kts new file mode 100644 index 0000000..eed2ef7 --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.publishing-mpp.gradle.kts @@ -0,0 +1,55 @@ +import Env.CI +import Env.SANDBOX +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation +import org.jetbrains.kotlin.konan.target.HostManager +import util.buildHost +import util.enabled +import util.mainHost + +plugins { + id("convention.kotlin-mpp") + id("convention.publishing") + id("convention.publishing-dokka") +} + +kotlin { + fun configurePublishTasks(name: String, action: Action) { + publishing { + publications.matching { it.name == name }.all { + val targetPublication = this@all + tasks.withType() + .matching { it.publication == targetPublication } + .all(action) + tasks.withType() + .matching { it.publication.orNull == targetPublication } + .all(action) + } + } + } + + targets.all target@{ + val control = Action { + onlyIf { + !CI || this@target.enabled || (SANDBOX && this@target.buildHost == mainHost) + } + } + compilations.all compilation@{ + compileTaskProvider.configure(control) + + if (this@compilation is KotlinNativeCompilation) { + this@compilation.cinterops.all { + tasks.named(interopProcessingTaskName, control) + } + } + configurePublishTasks(this@target.name, control) + } + + if (this@target is KotlinAndroidTarget && (!CI || this@target.enabled || SANDBOX)) + this@target.publishLibraryVariants("release", "debug") + } + + configurePublishTasks("kotlinMultiplatform") { + !CI || SANDBOX || HostManager.host == mainHost + } +} diff --git a/build-conventions/src/main/kotlin/convention.publishing.gradle.kts b/build-conventions/src/main/kotlin/convention.publishing.gradle.kts new file mode 100644 index 0000000..b318496 --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.publishing.gradle.kts @@ -0,0 +1,60 @@ +plugins { + id("convention.pom") + `maven-publish` + signing +} + +tasks { + withType { + manifest { + attributes += sortedMapOf( + "Built-By" to System.getProperty("user.name"), + "Build-Jdk" to System.getProperty("java.version"), + "Implementation-Version" to project.version, + "Created-By" to "${GradleVersion.current()}", + "Created-From" to Git.headCommitHash + ) + } + } + val cleanMavenLocal by registering { + group = "build" + doLast { + val groupRepo = + file( + "${System.getProperty("user.home")}/.m2/repository/${ + project.group.toString().replace(".", "/") + }" + ) + publishing.publications.filterIsInstance().forEach { + groupRepo.resolve(it.artifactId).deleteRecursively() + } + } + } + named("clean") { + dependsOn(cleanMavenLocal) + } +} + +signing { + val signingKey: String? by project + val signingPassword: String? by project + if (signingKey != null) { + useInMemoryPgpKeys(signingKey, signingPassword) + sign(publishing.publications) + } +} + +publishing { + publications { + val ghOwnerId: String = project.properties["gh.owner.id"]!!.toString() + repositories { + maven("https://maven.pkg.github.com/$ghOwnerId/${rootProject.name}") { + name = "GitHub" + credentials { + username = System.getenv("GH_USERNAME") + password = System.getenv("GH_PASSWORD") + } + } + } + } +} diff --git a/build-conventions/src/main/kotlin/convention.versions.gradle.kts b/build-conventions/src/main/kotlin/convention.versions.gradle.kts new file mode 100644 index 0000000..a0732e2 --- /dev/null +++ b/build-conventions/src/main/kotlin/convention.versions.gradle.kts @@ -0,0 +1,31 @@ +import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask +import java.util.* + +plugins { + id("convention.base") + id("com.github.ben-manes.versions") + id("nl.littlerobots.version-catalog-update") +} + +versionCatalogUpdate { + keep { + keepUnusedVersions by true + keepUnusedLibraries by true + keepUnusedPlugins by true + } +} + +val isNonStable: (String) -> Boolean = { version -> + val stableKeyword = setOf("RELEASE", "FINAL", "GA").any { version.uppercase(Locale.ROOT).contains(it) } + val regex = Regex("^[0-9,.v-]+(-r)?$") + !stableKeyword && !(version matches regex) +} + +tasks { + withType { + gradleReleaseChannel = "current" + rejectVersionIf { + isNonStable(candidate.version) && !isNonStable(currentVersion) + } + } +} diff --git a/build-conventions/src/main/kotlin/util/PrefixedLogger.kt b/build-conventions/src/main/kotlin/util/PrefixedLogger.kt new file mode 100644 index 0000000..5acec02 --- /dev/null +++ b/build-conventions/src/main/kotlin/util/PrefixedLogger.kt @@ -0,0 +1,64 @@ +package util + +import org.gradle.api.tasks.Internal +import org.slf4j.Logger +import org.slf4j.Marker +import org.slf4j.MarkerFactory + +/** + * Standardised logging utilities with the plugin name prefix + */ +interface PrefixedLogger { + @get:Internal + val prefix: String + + @get:Internal + val marker: Marker get() = MarkerFactory.getMarker(prefix) + + @Internal + /** + * Logger provider + * @return logger to use for all logging events + */ + fun getLogger(): Logger + + /** + * Logs at error level + * @param message provider + */ + fun error(message: () -> String) { + if (getLogger().isErrorEnabled) { + getLogger().error(marker, "[$prefix] ${message()}") + } + } + + /** + * Logs at warn level + * @param message provider + */ + fun warn(message: () -> String) { + if (getLogger().isWarnEnabled) { + getLogger().warn(marker, "[$prefix] ${message()}") + } + } + + /** + * Logs at info level + * @param message provider + */ + fun info(message: () -> String) { + if (getLogger().isInfoEnabled) { + getLogger().info(marker, "[$prefix] ${message()}") + } + } + + /** + * Logs at debug level + * @param message provider + */ + fun debug(message: () -> String) { + if (getLogger().isDebugEnabled) { + getLogger().debug(marker, "[$prefix] ${message()}") + } + } +} diff --git a/build-conventions/src/main/kotlin/util/buildHost.kt b/build-conventions/src/main/kotlin/util/buildHost.kt new file mode 100644 index 0000000..92f64cd --- /dev/null +++ b/build-conventions/src/main/kotlin/util/buildHost.kt @@ -0,0 +1,66 @@ +package util + +import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.plugin.KotlinTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.jetbrains.kotlin.konan.target.HostManager +import org.jetbrains.kotlin.konan.target.KonanTarget + +val KotlinTarget.buildHost + get() = if (this is KotlinNativeTarget) konanTarget.buildHost else project.mainHost + +val KonanTarget.buildHost: KonanTarget + get() = when (this) { + // LINUX_X64 targets + KonanTarget.ANDROID_ARM32, + KonanTarget.ANDROID_ARM64, + KonanTarget.ANDROID_X64, + KonanTarget.ANDROID_X86, + KonanTarget.LINUX_ARM32_HFP, + KonanTarget.LINUX_ARM64, + KonanTarget.LINUX_MIPS32, + KonanTarget.LINUX_MIPSEL32, + KonanTarget.WASM32, + is KonanTarget.ZEPHYR, + KonanTarget.LINUX_X64 -> KonanTarget.LINUX_X64 + + // MACOS_ARM64 only targets + KonanTarget.IOS_SIMULATOR_ARM64, + KonanTarget.TVOS_SIMULATOR_ARM64, + KonanTarget.WATCHOS_DEVICE_ARM64, + KonanTarget.WATCHOS_SIMULATOR_ARM64, + KonanTarget.MACOS_ARM64 -> KonanTarget.MACOS_ARM64 + + // MACOS_X64 only targets + KonanTarget.WATCHOS_X64, + KonanTarget.WATCHOS_X86, + KonanTarget.TVOS_X64, + KonanTarget.IOS_X64, + KonanTarget.MACOS_X64 -> KonanTarget.MACOS_X64 + + // MACOS_X64 and MACOS_ARM64 targets - change host as preferred + KonanTarget.TVOS_ARM64, + KonanTarget.WATCHOS_ARM32, + KonanTarget.WATCHOS_ARM64, + KonanTarget.IOS_ARM32, + KonanTarget.IOS_ARM64, + -> KonanTarget.MACOS_X64 + + // MINGW_X64 targets + KonanTarget.MINGW_X64, + KonanTarget.MINGW_X86 -> KonanTarget.MINGW_X64 + } + +val Project.mainHost: KonanTarget + get() = when (val os = "${properties["project.mainOS"]}") { + "linux" -> KonanTarget.LINUX_X64 + "windows" -> KonanTarget.MINGW_X64 + "macosX64" -> KonanTarget.MACOS_X64 + "macosArm64" -> KonanTarget.MACOS_ARM64 + else -> error( + "mainOS key $os unknown. " + + "Supported keys are [linux, windows, macosX64, macosArm64]" + ) + } + +val KotlinTarget.enabled get() = buildHost == HostManager.host \ No newline at end of file diff --git a/build-conventions/src/main/kotlin/util/global.kt b/build-conventions/src/main/kotlin/util/global.kt new file mode 100644 index 0000000..edcf5d9 --- /dev/null +++ b/build-conventions/src/main/kotlin/util/global.kt @@ -0,0 +1,26 @@ +@file:Suppress("PackageDirectoryMismatch") + +import org.gradle.accessors.dm.LibrariesForLibs +import org.gradle.api.Project +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.kotlin.dsl.the +import java.nio.charset.Charset + +internal inline val Project.libs get() = the() + +infix fun Property.by(value: T) = set(value) +infix fun Property.by(value: Provider) = set(value) + +object Git { + val headCommitHash by lazy { + val child = Runtime.getRuntime().exec("git rev-parse --verify HEAD") + child.waitFor() + child.inputStream.readAllBytes().toString(Charset.defaultCharset()).trim() + } +} + +object Env { + val CI = System.getenv("CI") !in arrayOf(null, "0", "false", "n", "N") + val SANDBOX by lazy { !"false".equals(System.getenv("SANDBOX") ?: "false", true) } +} diff --git a/build-conventions/src/main/kotlin/util/targetGroup.kt b/build-conventions/src/main/kotlin/util/targetGroup.kt new file mode 100644 index 0000000..c2efd60 --- /dev/null +++ b/build-conventions/src/main/kotlin/util/targetGroup.kt @@ -0,0 +1,64 @@ +package util + +import org.gradle.api.Action +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.kotlin.dsl.get +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.KotlinTarget + +fun KotlinMultiplatformExtension.targetGroup( + name: String, + mainSourceSetTarget: KotlinSourceSet, + testSourceSetTarget: KotlinSourceSet, + vararg targets: T +): Pair { + val mainName = "${name}Main" + val testName = "${name}Test" + val main = sourceSets.maybeCreate(mainName).apply { dependsOn(mainSourceSetTarget) } + val test = sourceSets.maybeCreate(testName).apply { dependsOn(testSourceSetTarget) } + targets.forEach { target -> + target.compilations["main"].defaultSourceSet { dependsOn(main) } + target.compilations["test"].defaultSourceSet { dependsOn(test) } + } + return main to test +} + +fun KotlinMultiplatformExtension.targetGroup( + name: String, + mainSourceSetTarget: String, + testSourceSetTarget: String, + vararg targets: T +): Pair = targetGroup( + name = name, + mainSourceSetTarget = sourceSets.getByName(mainSourceSetTarget), + testSourceSetTarget = sourceSets.getByName(testSourceSetTarget), + targets = targets, +) + +fun NamedDomainObjectContainer.withName(name: String, action: Action) { + matching { it.name == name }.all(action) +} + +private fun NamedDomainObjectContainer.sharedSourceSets( + vararg sourceSets: String, + action: Action, +) { + sourceSets.forEach { withName(it, action) } +} + +fun NamedDomainObjectContainer.jvmCommonMain(action: Action) { + sharedSourceSets("jvmCommonMain", "androidMain", action = action) +} + +fun NamedDomainObjectContainer.jvmCommonTest(action: Action) { + sharedSourceSets("jvmCommonTest", "androidUnitTest", action = action) +} + +fun NamedDomainObjectContainer.blockingMain(action: Action) { + sharedSourceSets("blockingMain", "androidMain", action = action) +} + +fun NamedDomainObjectContainer.blockingTest(action: Action) { + sharedSourceSets("blockingTest", "androidUnitTest", action = action) +} diff --git a/build.gradle.kts b/build.gradle.kts index 8c4ddc9..cb6c39a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,10 +1,19 @@ plugins { - if (System.getenv("CI") == null) { - id("plugin.git-hooks") + alias(libs.plugins.nexus.publish) + id("convention.versions") + id("convention.git-hooks") + + id("convention.kotlin-mpp-tier3") + id("convention.library-android") + id("convention.library-mpp") + id("convention.publishing-mpp") +} + +nexusPublishing.repositories { + sonatype { + nexusUrl by uri("https://s01.oss.sonatype.org/service/local/") + snapshotRepositoryUrl by uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") } - id("plugin.library-mpp") - id("plugin.publishing-nexus") - id("plugin.publishing-mpp") } gradleEnterprise { @@ -17,7 +26,7 @@ gradleEnterprise { kotlin { sourceSets { commonMain { - dependencies { subprojects.filter { it.path.startsWith(":lib:") }.forEach { api(it) } } + dependencies { subprojects.filter { it.path.startsWith(":modules:") }.forEach { api(it) } } } } } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts deleted file mode 100644 index 04b6625..0000000 --- a/buildSrc/build.gradle.kts +++ /dev/null @@ -1,18 +0,0 @@ -plugins { `kotlin-dsl` } - -repositories { - gradlePluginPortal() - mavenCentral() - google() -} - -dependencies { - implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:_") - implementation("com.android.library:com.android.library.gradle.plugin:_") - implementation("org.jetbrains.dokka:dokka-gradle-plugin:_") - implementation("org.jetbrains.kotlin:kotlin-serialization:_") - implementation("com.github.jakemarsden:git-hooks-gradle-plugin:_") - implementation("com.diffplug.spotless:spotless-plugin-gradle:_") - implementation("io.github.gradle-nexus:publish-plugin:_") - implementation("dev.petuska:klip-gradle-plugin:_") -} diff --git a/buildSrc/gradle.properties b/buildSrc/gradle.properties deleted file mode 100644 index 6a6eb44..0000000 --- a/buildSrc/gradle.properties +++ /dev/null @@ -1,12 +0,0 @@ -org.gradle.project.sourceCompatibility=11 -org.gradle.project.targetCompatibility=11 -org.gradle.vfs.watch=true -kotlin.style=official -kotlin.js.generate.externals=false -kotlin.js.compiler=ir -kotlin.incremental.js=true -kotlin.stdlib.default.dependency=true -kotlin.mpp.stability.nowarn=true -kotlin.mpp.enableGranularSourceSetsMetadata=true -kotlin.native.enableDependencyPropagation=false -kotlin.native.ignoreDisabledTargets=true diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts deleted file mode 100644 index b9c0a8f..0000000 --- a/buildSrc/settings.gradle.kts +++ /dev/null @@ -1,9 +0,0 @@ -pluginManagement { - plugins { - id("de.fayard.refreshVersions") version "0.51.0" - } -} - -plugins { - id("de.fayard.refreshVersions") -} diff --git a/buildSrc/src/main/kotlin/plugin.common.gradle.kts b/buildSrc/src/main/kotlin/plugin.common.gradle.kts deleted file mode 100644 index 4c020b6..0000000 --- a/buildSrc/src/main/kotlin/plugin.common.gradle.kts +++ /dev/null @@ -1,64 +0,0 @@ -import de.fayard.refreshVersions.core.versionFor -import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile -import org.jetbrains.kotlin.gradle.tasks.KotlinTest -import java.util.Properties - -plugins { - id("com.diffplug.spotless") - idea -} - -rootDir.resolve("local.properties").takeIf(File::exists)?.let { - Properties().apply { - it.inputStream().use(::load) - }.mapKeys { (k, _) -> k.toString() } -}?.toList()?.forEach { (k, v) -> - project.extra[k] = v -} - -repositories { - mavenCentral() - google() -} - -idea { - module { - isDownloadSources = true - isDownloadJavadoc = true - } -} - -spotless { - val ktlintSettings = mapOf( - "indent_size" to "2", - "continuation_indent_size" to "4", - "disabled_rules" to "no-wildcard-imports" - ) - kotlin { - target("src/**/*.kt") - ktlint(versionFor("version.ktlint")).userData(ktlintSettings) - } - kotlinGradle { - target("*.kts") - ktlint(versionFor("version.ktlint")).userData(ktlintSettings) - } -} - -tasks { - withType { useJUnitPlatform() } - - afterEvaluate { - if (tasks.findByName("compile") == null) { - register("compile") { - dependsOn(withType(AbstractKotlinCompile::class)) - group = "build" - } - } - if (tasks.findByName("allTests") == null) { - register("allTests") { - dependsOn(withType(KotlinTest::class)) - group = "verification" - } - } - } -} diff --git a/buildSrc/src/main/kotlin/plugin.git-hooks.gradle.kts b/buildSrc/src/main/kotlin/plugin.git-hooks.gradle.kts deleted file mode 100644 index e392ce8..0000000 --- a/buildSrc/src/main/kotlin/plugin.git-hooks.gradle.kts +++ /dev/null @@ -1,3 +0,0 @@ -plugins { id("com.github.jakemarsden.git-hooks") } - -gitHooks { setHooks(mapOf("pre-commit" to "spotlessApply", "pre-push" to "spotlessCheck")) } diff --git a/buildSrc/src/main/kotlin/plugin.library-mpp.gradle.kts b/buildSrc/src/main/kotlin/plugin.library-mpp.gradle.kts deleted file mode 100644 index ab1c1d6..0000000 --- a/buildSrc/src/main/kotlin/plugin.library-mpp.gradle.kts +++ /dev/null @@ -1,127 +0,0 @@ -import org.gradle.kotlin.dsl.invoke -import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile -import org.jetbrains.kotlin.gradle.tasks.CInteropProcess -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import org.jetbrains.kotlin.konan.target.HostManager -import util.KotlinTargetDetails -import util.buildHost -import util.nativeTargetGroup - -plugins { - kotlin("multiplatform") - kotlin("plugin.serialization") - id("plugin.common") - id("dev.petuska.klip") - id("com.android.library") -} - -android { - compileSdkVersion(31) - defaultConfig { - minSdkVersion(1) - targetSdkVersion(31) - } -} - -kotlin { - sourceSets { - val commonMain by getting - val commonTest by getting { dependencies { implementation(project(":test")) } } - create("nativeMain") { dependsOn(commonMain) } - create("nativeTest") { dependsOn(commonTest) } - } - - explicitApi() - android() - jvm() - js { - binaries.library() - useCommonJs() - nodejs() - // browser { - // commonWebpackConfig { - // cssSupport.enabled = true - // } - // testTask { - // useKarma { - // useFirefox() - // useChrome() - // useSafari() - // } - // } - // } - } - - nativeTargetGroup( - "androidNdk", - androidNativeArm32(), - androidNativeArm64(), - ) - - nativeTargetGroup( - "linux", - linuxX64(), - linuxMips32(), - linuxMipsel32(), - linuxArm64(), - linuxArm32Hfp(), - ) - - nativeTargetGroup( - "ios", - iosArm32(), - iosArm64(), - iosX64(), - iosSimulatorArm64(), - ) - - nativeTargetGroup( - "watchos", - watchosArm32(), - watchosArm64(), - watchosX86(), - watchosX64(), - watchosSimulatorArm64(), - ) - - nativeTargetGroup( - "tvos", - tvosArm64(), - tvosX64(), - tvosSimulatorArm64(), - ) - - nativeTargetGroup( - "macos", - macosX64(), - macosArm64(), - ) - - nativeTargetGroup( - "mingw", - mingwX86(), - mingwX64(), - ) - - val targetsWithCoroutines = - KotlinTargetDetails.values() - .filter(KotlinTargetDetails::hasCoroutines) - .map(KotlinTargetDetails::presetName) - - targets.filter { it.preset?.name in targetsWithCoroutines }.forEach { - (it.compilations.findByName("main")?.defaultSourceSet - ?: sourceSets.findByName("${it.name}Main"))?.apply { - dependencies { api("org.jetbrains.kotlinx:kotlinx-coroutines-core:_") } - } - } -} - -tasks { - project.properties["org.gradle.project.targetCompatibility"]?.toString()?.let { - withType { kotlinOptions { jvmTarget = it } } - } - withType { onlyIf { konanTarget.buildHost == HostManager.host.family } } - withType> { - onlyIf { compilation.konanTarget.buildHost == HostManager.host.family } - } -} diff --git a/buildSrc/src/main/kotlin/plugin.publishing-jvm.gradle.kts b/buildSrc/src/main/kotlin/plugin.publishing-jvm.gradle.kts deleted file mode 100644 index 79efc5d..0000000 --- a/buildSrc/src/main/kotlin/plugin.publishing-jvm.gradle.kts +++ /dev/null @@ -1,37 +0,0 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import util.CI -import util.isMainHost - -plugins { - kotlin("jvm") - id("plugin.publishing") -} - -val mainHostSpec: Spec = Spec { !CI || isMainHost } - -tasks { - withType { - onlyIf(mainHostSpec) - inputs.property("project.mainOS", project.property("project.mainOS")) - } -} - -afterEvaluate { - publishing { - publications { - all { - val targetPublication = this@all - tasks.withType() - .matching { it.publication == targetPublication } - .configureEach { - onlyIf(mainHostSpec) - } - tasks.withType() - .matching { it.publication.get() == targetPublication } - .configureEach { - onlyIf(mainHostSpec) - } - } - } - } -} diff --git a/buildSrc/src/main/kotlin/plugin.publishing-mpp.gradle.kts b/buildSrc/src/main/kotlin/plugin.publishing-mpp.gradle.kts deleted file mode 100644 index 2dbdc4b..0000000 --- a/buildSrc/src/main/kotlin/plugin.publishing-mpp.gradle.kts +++ /dev/null @@ -1,81 +0,0 @@ -import org.jetbrains.kotlin.gradle.plugin.KotlinTarget -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget -import org.jetbrains.kotlin.konan.target.Family -import org.jetbrains.kotlin.konan.target.HostManager -import util.CI -import util.SANDBOX -import util.buildHost -import util.isMainHost - -plugins { - kotlin("multiplatform") - id("plugin.publishing") -} - -kotlin { - fun Collection.onlyBuildIf(enabled: Spec) { - forEach { - it.compilations.all { - compileKotlinTask.onlyIf(enabled) - } - } - } - - fun Collection.onlyPublishIf(enabled: Spec) { - val publications: Collection = map { it.name } - afterEvaluate { - publishing { - publications { - matching { it.name in publications }.all { - val targetPublication = this@all - tasks.withType() - .matching { it.publication == targetPublication } - .configureEach { - onlyIf(enabled) - } - tasks.withType() - .matching { it.publication.get() == targetPublication } - .configureEach { - onlyIf(enabled) - } - } - } - } - } - } - - val nativeTargets = targets.withType() - val windowsHostTargets = nativeTargets.filter { it.konanTarget.buildHost == Family.MINGW } - val linuxHostTargets = nativeTargets.filter { it.konanTarget.buildHost == Family.LINUX } - val osxHostTargets = nativeTargets.filter { it.konanTarget.buildHost == Family.OSX } - val androidTargets = targets.withType() - val mainHostTargets = targets.filter { it !in nativeTargets } - logger.info("Linux host targets: $linuxHostTargets") - logger.info("OSX host targets: $osxHostTargets") - logger.info("Windows host targets: $windowsHostTargets") - logger.info("Android targets: $androidTargets") - logger.info("Main host targets: $mainHostTargets") - - linuxHostTargets.onlyBuildIf { !CI || HostManager.hostIsLinux } - linuxHostTargets.onlyPublishIf { !CI || HostManager.hostIsLinux } - - osxHostTargets.onlyBuildIf { !CI || HostManager.hostIsMac } - osxHostTargets.onlyPublishIf { !CI || HostManager.hostIsMac } - - windowsHostTargets.onlyBuildIf { !CI || HostManager.hostIsMingw } - windowsHostTargets.onlyPublishIf { !CI || HostManager.hostIsMingw } - - androidTargets.forEach { - if (!CI || SANDBOX || isMainHost) { - it.publishLibraryVariants("release", "debug") - } - } - - mainHostTargets.onlyBuildIf { - !CI || SANDBOX || isMainHost - } - (mainHostTargets + Named { "kotlinMultiplatform" }).onlyPublishIf { - !CI || SANDBOX || isMainHost - } -} diff --git a/buildSrc/src/main/kotlin/plugin.publishing-nexus.gradle.kts b/buildSrc/src/main/kotlin/plugin.publishing-nexus.gradle.kts deleted file mode 100644 index ae8b341..0000000 --- a/buildSrc/src/main/kotlin/plugin.publishing-nexus.gradle.kts +++ /dev/null @@ -1,15 +0,0 @@ -import util.by - -plugins { - id("plugin.common") - id("io.github.gradle-nexus.publish-plugin") -} - -nexusPublishing { - repositories { - sonatype { - nexusUrl by uri("https://s01.oss.sonatype.org/service/local/") - snapshotRepositoryUrl by uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") - } - } -} diff --git a/buildSrc/src/main/kotlin/plugin.publishing.gradle.kts b/buildSrc/src/main/kotlin/plugin.publishing.gradle.kts deleted file mode 100644 index 92c0d5d..0000000 --- a/buildSrc/src/main/kotlin/plugin.publishing.gradle.kts +++ /dev/null @@ -1,105 +0,0 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import org.jetbrains.kotlin.konan.target.HostManager -import util.Git -import util.by - -plugins { - id("plugin.common") - id("org.jetbrains.dokka") - `maven-publish` - signing -} - -tasks { - register("javadocJar") { - dependsOn(dokkaHtml) - archiveClassifier.set("javadoc") - from(dokkaHtml.get().outputDirectory) - } - withType { - manifest { - attributes += sortedMapOf( - "Built-By" to System.getProperty("user.name"), - "Build-Jdk" to System.getProperty("java.version"), - "Implementation-Version" to project.version, - "Created-By" to "${GradleVersion.current()}", - "Created-From" to "${Git.headCommitHash}" - ) - } - } - val cleanMavenLocal by registering { - group = "build" - doLast { - val groupRepo = - file("${System.getProperty("user.home")}/.m2/repository/${project.group.toString().replace(".", "/")}") - publishing.publications.filterIsInstance().forEach { - groupRepo.resolve(it.artifactId).deleteRecursively() - } - } - } - named("clean") { - dependsOn(cleanMavenLocal) - } -} - -signing { - val signingKey: String? by project - val signingPassword: String? by project - if (signingKey != null) { - useInMemoryPgpKeys(signingKey, signingPassword) - sign(publishing.publications) - } -} - -val isMainHost = HostManager.simpleOsName().equals("${project.properties["project.mainOS"]}", true) -tasks { - withType { - onlyIf - } -} - -publishing { - publications { - val ghOwnerId: String = project.properties["gh.owner.id"]!!.toString() - val ghOwnerName: String = project.properties["gh.owner.name"]!!.toString() - val ghOwnerEmail: String = project.properties["gh.owner.email"]!!.toString() - repositories { - maven("https://maven.pkg.github.com/$ghOwnerId/${rootProject.name}") { - name = "GitHub" - credentials { - username = System.getenv("GH_USERNAME") - password = System.getenv("GH_PASSWORD") - } - } - } - withType { - artifact(tasks["javadocJar"]) - pom { - name by project.name - url by "https://github.com/$ghOwnerId/${rootProject.name}" - description by project.description - - licenses { - license { - name by "The Apache License, Version 2.0" - url by "https://www.apache.org/licenses/LICENSE-2.0.txt" - } - } - - developers { - developer { - id by ghOwnerId - name by ghOwnerName - email by ghOwnerEmail - } - } - - scm { - connection by "scm:git:git@github.com:$ghOwnerId/${rootProject.name}.git" - url by "https://github.com/$ghOwnerId/${rootProject.name}" - tag by Git.headCommitHash - } - } - } - } -} diff --git a/buildSrc/src/main/kotlin/util/KotlinTargetDetails.kt b/buildSrc/src/main/kotlin/util/KotlinTargetDetails.kt deleted file mode 100644 index 29255c9..0000000 --- a/buildSrc/src/main/kotlin/util/KotlinTargetDetails.kt +++ /dev/null @@ -1,67 +0,0 @@ -package util - -import org.jetbrains.kotlin.konan.target.Family -import org.jetbrains.kotlin.konan.target.KonanTarget - -enum class KotlinTargetDetails( - val presetName: String, - val hasCoroutines: Boolean, -) { - JVM("jvm", true), - ANDROID("android", true), - JS("jsIr", true), - ANDROID_NDK_ARM32("androidNativeArm32", false), - ANDROID_NDK_ARM64("androidNativeArm64", false), - IOS_ARM32("iosArm32", true), - IOS_ARM64("iosArm64", true), - IOS_X64("iosX64", true), - IOS_SIMULATOR_ARM64("iosSimulatorArm64", true), - WATCHOS_X86("watchosX86", true), - WATCHOS_X64("watchosX64", true), - WATCHOS_ARM64("watchosArm64", true), - WATCHOS_ARM32("watchosArm32", true), - WATCHOS_SIMULATOR_ARM64("watchosSimulatorArm64", true), - TVOS_ARM64("tvosArm64", true), - TVOS_X64("tvosX64", true), - TVOS_SIMULATOR_ARM64("tvosSimulatorArm64", true), - MACOS_X64("macosX64", true), - MACOS_ARM64("macosArm64", true), - LINUX_ARM32_HFP("linuxArm32Hfp", false), - LINUX_MIPS32("linuxMips32", false), - LINUX_MIPSEL32("linuxMipsel32", false), - LINUX_X64("linuxX64", true), - LINUX_ARM64("linuxArm64", false), - MINGW_X64("mingwX64", true), - MINGW_X32("mingwX86", false), -} - -val KonanTarget.buildHost: Family - get() = - when (this) { - KonanTarget.ANDROID_X64, - KonanTarget.ANDROID_X86, - KonanTarget.ANDROID_ARM32, - KonanTarget.ANDROID_ARM64, - KonanTarget.LINUX_ARM64, - KonanTarget.LINUX_ARM32_HFP, - KonanTarget.LINUX_MIPS32, - KonanTarget.LINUX_MIPSEL32, - KonanTarget.LINUX_X64 -> Family.LINUX - KonanTarget.MINGW_X86, KonanTarget.MINGW_X64 -> Family.MINGW - KonanTarget.IOS_ARM32, - KonanTarget.IOS_ARM64, - KonanTarget.IOS_X64, - KonanTarget.IOS_SIMULATOR_ARM64, - KonanTarget.WATCHOS_ARM32, - KonanTarget.WATCHOS_ARM64, - KonanTarget.WATCHOS_X86, - KonanTarget.WATCHOS_X64, - KonanTarget.WATCHOS_SIMULATOR_ARM64, - KonanTarget.TVOS_ARM64, - KonanTarget.TVOS_X64, - KonanTarget.TVOS_SIMULATOR_ARM64, - KonanTarget.MACOS_X64, - KonanTarget.MACOS_ARM64 -> Family.OSX - KonanTarget.WASM32 -> throw IllegalStateException("Target $this not supported") - is KonanTarget.ZEPHYR -> throw IllegalStateException("Target $this not supported") - } diff --git a/buildSrc/src/main/kotlin/util/gradle.kt b/buildSrc/src/main/kotlin/util/gradle.kt deleted file mode 100644 index 1519d17..0000000 --- a/buildSrc/src/main/kotlin/util/gradle.kt +++ /dev/null @@ -1,42 +0,0 @@ -package util - -import groovy.lang.Closure -import org.gradle.api.Project -import org.gradle.api.provider.Property -import org.jetbrains.kotlin.konan.target.HostManager -import java.nio.charset.Charset - -typealias Lambda = R.() -> V - -val CI by lazy { !"false".equals(System.getenv("CI") ?: "false", true) } -val SANDBOX by lazy { !"false".equals(System.getenv("SANDBOX") ?: "false", true) } - -fun Lambda.toClosure(owner: Any? = null, thisObj: Any? = null) = - object : Closure(owner, thisObj) { - @Suppress("UNCHECKED_CAST") - fun doCall() { - with(delegate as R) { this@toClosure() } - } - } - -fun closureOf(owner: Any? = null, thisObj: Any? = null, func: R.() -> V) = - func.toClosure(owner, thisObj) - -infix fun Property.by(value: T) { - set(value) -} - -object Git { - val headCommitHash by lazy { execAndCapture("git rev-parse --verify HEAD") } -} - -fun execAndCapture(cmd: String): String? { - val child = Runtime.getRuntime().exec(cmd) - child.waitFor() - return if (child.exitValue() == 0) { - child.inputStream.readAllBytes().toString(Charset.defaultCharset()).trim() - } else null -} - -val Project.isMainHost: Boolean - get() = HostManager.simpleOsName().equals("${properties["project.mainOS"]}", true) diff --git a/buildSrc/src/main/kotlin/util/nativeTargetGroup.kt b/buildSrc/src/main/kotlin/util/nativeTargetGroup.kt deleted file mode 100644 index 9d366c7..0000000 --- a/buildSrc/src/main/kotlin/util/nativeTargetGroup.kt +++ /dev/null @@ -1,39 +0,0 @@ -package util - -import org.gradle.kotlin.dsl.get -import org.gradle.kotlin.dsl.invoke -import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget - -fun KotlinMultiplatformExtension.nativeTargetGroup( - name: String, - vararg targets: KotlinNativeTarget -): Array { - sourceSets { - val (main, test) = if (targets.size > 1) { - val nativeMain = getByName("nativeMain") - val nativeTest = getByName("nativeTest") - val main = create("${name}Main") { - dependsOn(nativeMain) - } - val test = create("${name}Test") { - dependsOn(nativeTest) - } - main to test - } else (null to null) - - targets.forEach { target -> - main?.let { - target.compilations["main"].defaultSourceSet { - dependsOn(main) - } - } - test?.let { - target.compilations["test"].defaultSourceSet { - dependsOn(test) - } - } - } - } - return targets -} diff --git a/gradle.properties b/gradle.properties index ed580e4..d50e5d5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,12 +10,16 @@ kotlin.style=official kotlin.stdlib.default.dependency=true kotlin.js.generate.externals=false kotlin.js.compiler=ir +kotlin.js.browser.karma.browsers=chromium-headless kotlin.incremental.js=true kotlin.mpp.stability.nowarn=true -kotlin.mpp.enableGranularSourceSetsMetadata=true -kotlin.native.enableDependencyPropagation=false kotlin.native.ignoreDisabledTargets=true -kapt.includeCompileClasspath=false +kotlin.mpp.androidSourceSetLayoutVersion=2 +# https://youtrack.jetbrains.com/issue/KT-51293/Unresolved-references-with-hierarchical-project-structure-when-building-KotlinMetadata-from-native-common-source-set#focus=Comments-27-6220848.0-0 +kotlin.mpp.import.enableKgpDependencyResolution=true +#======================================== Android ======================================= +android.useAndroidX=true +android.enableJetifier=true #======================================== GitHub ======================================== gh.owner.id=mpetuska gh.owner.name=Martynas Petuska @@ -25,5 +29,5 @@ group=dev.petuska description=Template for kotlin multiplatform library version=0.0.0 #======================================== Build ========================================= -# linux | macos | windows +# linux | windows | macosX64 | macosArm64 project.mainOS=linux diff --git a/gradle/detekt.yml b/gradle/detekt.yml new file mode 100644 index 0000000..4152704 --- /dev/null +++ b/gradle/detekt.yml @@ -0,0 +1,42 @@ +config: + warningsAsErrors: true + +comments: + active: true + CommentOverPrivateFunction: + active: false + CommentOverPrivateProperty: + active: false + DeprecatedBlockTag: + active: true + OutdatedDocumentation: + active: true + allowParamOnConstructorProperties: false + UndocumentedPublicClass: + active: true + UndocumentedPublicFunction: + active: true + UndocumentedPublicProperty: + active: true + +naming: + MatchingDeclarationName: + active: false + InvalidPackageDeclaration: + active: false + +style: + WildcardImport: + active: false + UnnecessaryAbstractClass: + active: false + MaxLineLength: + active: false + +formatting: + Filename: + active: false + NoWildcardImports: + active: false + Indentation: + indentSize: 2 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..de07c11 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,39 @@ +# Sharing dependency versions between projects +# https://docs.gradle.org/current/userguide/platforms.html +[versions] +detekt = "1.22.0" +dokka = "1.8.10" +java = "11" +junit-jupiter = "5.9.3" +kotest = "5.6.1" +kotlin = "1.8.21" +kotlinx-coroutines = "1.6.4" + +[libraries] +detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } +junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit-jupiter" } +junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit-jupiter" } +kotest-assertions-core = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" } +kotest-assertions-json = { module = "io.kotest:kotest-assertions-json", version.ref = "kotest" } +kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } +plugin-android = "com.android.tools.build:gradle:8.0.0" +plugin-container-tasks = "dev.petuska:container-tasks-gradle-plugin:0.0.4" +plugin-detekt = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" } +plugin-git-hooks = "com.github.jakemarsden:git-hooks-gradle-plugin:0.0.2" +plugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } +plugin-kotlin-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin" } +plugin-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" } +plugin-nebula-node = "com.netflix.nebula:nebula-node-plugin:3.0.0" +plugin-versions = "com.github.ben-manes:gradle-versions-plugin:0.46.0" +plugin-versions-update = "nl.littlerobots.vcu:plugin:0.8.0" + +[bundles] +kotest-assertions = [ + "kotest-assertions-core", + "kotest-assertions-json", +] + +[plugins] +nexus-publish = "io.github.gradle-nexus.publish-plugin:1.3.0" +plugin-publish = "com.gradle.plugin-publish:1.2.0" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180..943f0cb 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 070cb70..8707e8b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c787..65dcd68 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,10 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' @@ -143,12 +143,16 @@ fi if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -205,6 +209,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index ac1b06f..6689b85 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/lib/template-kmp-library-core/build.gradle.kts b/lib/template-kmp-library-core/build.gradle.kts deleted file mode 100644 index b921376..0000000 --- a/lib/template-kmp-library-core/build.gradle.kts +++ /dev/null @@ -1,4 +0,0 @@ -plugins { - id("plugin.library-mpp") - id("plugin.publishing-mpp") -} diff --git a/lib/template-kmp-library-core/src/androidMain/kotlin/platform.kt b/lib/template-kmp-library-core/src/androidMain/kotlin/platform.kt deleted file mode 100644 index b1bf5bb..0000000 --- a/lib/template-kmp-library-core/src/androidMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.core - -internal actual val platform: String = "Android" diff --git a/lib/template-kmp-library-core/src/androidNdkMain/kotlin/platform.kt b/lib/template-kmp-library-core/src/androidNdkMain/kotlin/platform.kt deleted file mode 100644 index ebc72df..0000000 --- a/lib/template-kmp-library-core/src/androidNdkMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.core - -internal actual val platform: String = "Android NDK" diff --git a/lib/template-kmp-library-core/src/commonTest/kotlin/CoreLibTest.kt b/lib/template-kmp-library-core/src/commonTest/kotlin/CoreLibTest.kt deleted file mode 100644 index 464f323..0000000 --- a/lib/template-kmp-library-core/src/commonTest/kotlin/CoreLibTest.kt +++ /dev/null @@ -1,29 +0,0 @@ -package dev.petuska.template.kmp.library.core - -import dev.petuska.klip.api.assertKlip -import local.test.BlockingTest -import kotlin.test.Test -import kotlin.test.assertEquals - -class CoreLibTest : BlockingTest { - @Test - fun test() = blockingTest { - val result = CoreLib().sampleApi() - println(result) - assertEquals(result, platform) - } - - @Test - fun testSuspend() = blockingTest { - val result = CoreLib().sampleSuspendApi() - println(result) - assertEquals(result, platform) - } - - @Test - fun testValue() = blockingTest { - val result = CoreLib().sampleValue - println(result) - result.assertKlip() - } -} diff --git a/lib/template-kmp-library-core/src/commonTest/kotlin/__klips__/CoreLibTest.kt.klip b/lib/template-kmp-library-core/src/commonTest/kotlin/__klips__/CoreLibTest.kt.klip deleted file mode 100644 index 659c8fd..0000000 --- a/lib/template-kmp-library-core/src/commonTest/kotlin/__klips__/CoreLibTest.kt.klip +++ /dev/null @@ -1,4 +0,0 @@ -:::::>> KLIPS :::::>> -:::::>>dev.petuska.template.kmp.library.core.CoreLibTest.testValue#0:::::>> -28980 -:::::>>:::::>>:::::>> diff --git a/lib/template-kmp-library-core/src/macosMain/kotlin/platform.kt b/lib/template-kmp-library-core/src/macosMain/kotlin/platform.kt deleted file mode 100644 index 5bd1f80..0000000 --- a/lib/template-kmp-library-core/src/macosMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.core - -internal actual val platform: String = "macOS" diff --git a/lib/template-kmp-library-core/src/mingwMain/kotlin/platform.kt b/lib/template-kmp-library-core/src/mingwMain/kotlin/platform.kt deleted file mode 100644 index b1ca32c..0000000 --- a/lib/template-kmp-library-core/src/mingwMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.core - -internal actual val platform: String = "Windows" diff --git a/lib/template-kmp-library-core/src/watchosMain/kotlin/platform.kt b/lib/template-kmp-library-core/src/watchosMain/kotlin/platform.kt deleted file mode 100644 index 7d48aac..0000000 --- a/lib/template-kmp-library-core/src/watchosMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.core - -internal actual val platform: String = "watchOS" diff --git a/lib/template-kmp-library-dsl/build.gradle.kts b/lib/template-kmp-library-dsl/build.gradle.kts deleted file mode 100644 index 48c0f28..0000000 --- a/lib/template-kmp-library-dsl/build.gradle.kts +++ /dev/null @@ -1,8 +0,0 @@ -plugins { - id("plugin.library-mpp") - id("plugin.publishing-mpp") -} - -kotlin { - sourceSets { commonMain { dependencies { api(project(":lib:template-kmp-library-core")) } } } -} diff --git a/lib/template-kmp-library-dsl/src/androidMain/kotlin/platform.kt b/lib/template-kmp-library-dsl/src/androidMain/kotlin/platform.kt deleted file mode 100644 index 754be8a..0000000 --- a/lib/template-kmp-library-dsl/src/androidMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.dsl - -internal actual val platform: String = "Android" diff --git a/lib/template-kmp-library-dsl/src/androidNdkMain/kotlin/platform.kt b/lib/template-kmp-library-dsl/src/androidNdkMain/kotlin/platform.kt deleted file mode 100644 index bd5c228..0000000 --- a/lib/template-kmp-library-dsl/src/androidNdkMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.dsl - -internal actual val platform: String = "Android NDK" diff --git a/lib/template-kmp-library-dsl/src/commonMain/kotlin/DslLib.kt b/lib/template-kmp-library-dsl/src/commonMain/kotlin/DslLib.kt deleted file mode 100644 index 74f0e1f..0000000 --- a/lib/template-kmp-library-dsl/src/commonMain/kotlin/DslLib.kt +++ /dev/null @@ -1,6 +0,0 @@ -package dev.petuska.template.kmp.library.dsl - -internal expect val platform: String - -public fun String.withPlatform(): String = "[$platform] $this" -public suspend fun String.withPlatformSuspend(): String = withPlatform() diff --git a/lib/template-kmp-library-dsl/src/commonTest/kotlin/DslLibTest.kt b/lib/template-kmp-library-dsl/src/commonTest/kotlin/DslLibTest.kt deleted file mode 100644 index 8af59da..0000000 --- a/lib/template-kmp-library-dsl/src/commonTest/kotlin/DslLibTest.kt +++ /dev/null @@ -1,29 +0,0 @@ -package dev.petuska.template.kmp.library.dsl - -import local.test.BlockingTest -import kotlin.test.Test -import kotlin.test.assertTrue - -class DslLibTest : BlockingTest { - override suspend fun beforeEach() { - println("Starting") - } - - override suspend fun afterEach() { - println("Completed") - } - - @Test - fun test() = blockingTest { - val result = "sync".withPlatform() - println(result) - assertTrue(result.contains(platform)) - } - - @Test - fun testSuspend() = blockingTest { - val result = "async".withPlatformSuspend() - println(result) - assertTrue(result.contains(platform)) - } -} diff --git a/lib/template-kmp-library-dsl/src/iosMain/kotlin/platform.kt b/lib/template-kmp-library-dsl/src/iosMain/kotlin/platform.kt deleted file mode 100644 index be958a6..0000000 --- a/lib/template-kmp-library-dsl/src/iosMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.dsl - -internal actual val platform: String = "iOS" diff --git a/lib/template-kmp-library-dsl/src/jsMain/kotlin/platform.kt b/lib/template-kmp-library-dsl/src/jsMain/kotlin/platform.kt deleted file mode 100644 index 5a59099..0000000 --- a/lib/template-kmp-library-dsl/src/jsMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.dsl - -internal actual val platform: String = "JS" diff --git a/lib/template-kmp-library-dsl/src/jvmMain/kotlin/platform.kt b/lib/template-kmp-library-dsl/src/jvmMain/kotlin/platform.kt deleted file mode 100644 index 68f492e..0000000 --- a/lib/template-kmp-library-dsl/src/jvmMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.dsl - -internal actual val platform: String = "JVM" diff --git a/lib/template-kmp-library-dsl/src/linuxMain/kotlin/platform.kt b/lib/template-kmp-library-dsl/src/linuxMain/kotlin/platform.kt deleted file mode 100644 index 9825c86..0000000 --- a/lib/template-kmp-library-dsl/src/linuxMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.dsl - -internal actual val platform: String = "Linux" diff --git a/lib/template-kmp-library-dsl/src/macosMain/kotlin/platform.kt b/lib/template-kmp-library-dsl/src/macosMain/kotlin/platform.kt deleted file mode 100644 index 152aef0..0000000 --- a/lib/template-kmp-library-dsl/src/macosMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.dsl - -internal actual val platform: String = "macOS" diff --git a/lib/template-kmp-library-dsl/src/main/AndroidManifest.xml b/lib/template-kmp-library-dsl/src/main/AndroidManifest.xml deleted file mode 100644 index 504086e..0000000 --- a/lib/template-kmp-library-dsl/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/template-kmp-library-dsl/src/mingwMain/kotlin/platform.kt b/lib/template-kmp-library-dsl/src/mingwMain/kotlin/platform.kt deleted file mode 100644 index 309c455..0000000 --- a/lib/template-kmp-library-dsl/src/mingwMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.dsl - -internal actual val platform: String = "Windows" diff --git a/lib/template-kmp-library-dsl/src/tvosMain/kotlin/platform.kt b/lib/template-kmp-library-dsl/src/tvosMain/kotlin/platform.kt deleted file mode 100644 index 01badda..0000000 --- a/lib/template-kmp-library-dsl/src/tvosMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.dsl - -internal actual val platform: String = "tvOS" diff --git a/lib/template-kmp-library-dsl/src/watchosMain/kotlin/platform.kt b/lib/template-kmp-library-dsl/src/watchosMain/kotlin/platform.kt deleted file mode 100644 index 8f4e552..0000000 --- a/lib/template-kmp-library-dsl/src/watchosMain/kotlin/platform.kt +++ /dev/null @@ -1,3 +0,0 @@ -package dev.petuska.template.kmp.library.dsl - -internal actual val platform: String = "watchOS" diff --git a/modules/template-kmp-library-core/build.gradle.kts b/modules/template-kmp-library-core/build.gradle.kts new file mode 100644 index 0000000..7e383e4 --- /dev/null +++ b/modules/template-kmp-library-core/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("convention.kotlin-mpp-tier3") + id("convention.library-android") + id("convention.library-mpp") + id("convention.publishing-mpp") +} + +kotlin { + sourceSets { + commonTest { + dependencies { + } + } + } +} diff --git a/lib/template-kmp-library-core/src/linuxMain/kotlin/platform.kt b/modules/template-kmp-library-core/src/androidMain/kotlin/platform.kt similarity index 50% rename from lib/template-kmp-library-core/src/linuxMain/kotlin/platform.kt rename to modules/template-kmp-library-core/src/androidMain/kotlin/platform.kt index 8b79054..151e0ed 100644 --- a/lib/template-kmp-library-core/src/linuxMain/kotlin/platform.kt +++ b/modules/template-kmp-library-core/src/androidMain/kotlin/platform.kt @@ -1,3 +1,3 @@ package dev.petuska.template.kmp.library.core -internal actual val platform: String = "Linux" +public actual val platform: String = "Android" diff --git a/modules/template-kmp-library-core/src/androidNativeMain/kotlin/platform.kt b/modules/template-kmp-library-core/src/androidNativeMain/kotlin/platform.kt new file mode 100644 index 0000000..cdf3cd6 --- /dev/null +++ b/modules/template-kmp-library-core/src/androidNativeMain/kotlin/platform.kt @@ -0,0 +1,3 @@ +package dev.petuska.template.kmp.library.core + +public actual val platform: String = "Android NDK" diff --git a/lib/template-kmp-library-core/src/commonMain/kotlin/CoreLib.kt b/modules/template-kmp-library-core/src/commonMain/kotlin/CoreLib.kt similarity index 85% rename from lib/template-kmp-library-core/src/commonMain/kotlin/CoreLib.kt rename to modules/template-kmp-library-core/src/commonMain/kotlin/CoreLib.kt index 022c5d6..70231d2 100644 --- a/lib/template-kmp-library-core/src/commonMain/kotlin/CoreLib.kt +++ b/modules/template-kmp-library-core/src/commonMain/kotlin/CoreLib.kt @@ -1,6 +1,6 @@ package dev.petuska.template.kmp.library.core -internal expect val platform: String +public expect val platform: String public class CoreLib { public fun sampleApi(): String = platform diff --git a/lib/template-kmp-library-core/src/jsMain/kotlin/platform.kt b/modules/template-kmp-library-core/src/iosMain/kotlin/platform.kt similarity index 51% rename from lib/template-kmp-library-core/src/jsMain/kotlin/platform.kt rename to modules/template-kmp-library-core/src/iosMain/kotlin/platform.kt index 69f5368..a4404cc 100644 --- a/lib/template-kmp-library-core/src/jsMain/kotlin/platform.kt +++ b/modules/template-kmp-library-core/src/iosMain/kotlin/platform.kt @@ -1,3 +1,3 @@ package dev.petuska.template.kmp.library.core -internal actual val platform: String = "JS" +public actual val platform: String = "iOS" diff --git a/lib/template-kmp-library-core/src/iosMain/kotlin/platform.kt b/modules/template-kmp-library-core/src/jsMain/kotlin/platform.kt similarity index 51% rename from lib/template-kmp-library-core/src/iosMain/kotlin/platform.kt rename to modules/template-kmp-library-core/src/jsMain/kotlin/platform.kt index 1356e6a..c0dc8be 100644 --- a/lib/template-kmp-library-core/src/iosMain/kotlin/platform.kt +++ b/modules/template-kmp-library-core/src/jsMain/kotlin/platform.kt @@ -1,3 +1,3 @@ package dev.petuska.template.kmp.library.core -internal actual val platform: String = "iOS" +public actual val platform: String = "JS" diff --git a/lib/template-kmp-library-core/src/jvmMain/kotlin/platform.kt b/modules/template-kmp-library-core/src/jvmMain/kotlin/platform.kt similarity index 51% rename from lib/template-kmp-library-core/src/jvmMain/kotlin/platform.kt rename to modules/template-kmp-library-core/src/jvmMain/kotlin/platform.kt index f3d26b8..2cff21f 100644 --- a/lib/template-kmp-library-core/src/jvmMain/kotlin/platform.kt +++ b/modules/template-kmp-library-core/src/jvmMain/kotlin/platform.kt @@ -1,3 +1,3 @@ package dev.petuska.template.kmp.library.core -internal actual val platform: String = "JVM" +public actual val platform: String = "JVM" diff --git a/lib/template-kmp-library-core/src/tvosMain/kotlin/platform.kt b/modules/template-kmp-library-core/src/linuxMain/kotlin/platform.kt similarity index 50% rename from lib/template-kmp-library-core/src/tvosMain/kotlin/platform.kt rename to modules/template-kmp-library-core/src/linuxMain/kotlin/platform.kt index 9c5dd21..033220b 100644 --- a/lib/template-kmp-library-core/src/tvosMain/kotlin/platform.kt +++ b/modules/template-kmp-library-core/src/linuxMain/kotlin/platform.kt @@ -1,3 +1,3 @@ package dev.petuska.template.kmp.library.core -internal actual val platform: String = "tvOS" +public actual val platform: String = "Linux" diff --git a/modules/template-kmp-library-core/src/macosMain/kotlin/platform.kt b/modules/template-kmp-library-core/src/macosMain/kotlin/platform.kt new file mode 100644 index 0000000..2b93401 --- /dev/null +++ b/modules/template-kmp-library-core/src/macosMain/kotlin/platform.kt @@ -0,0 +1,3 @@ +package dev.petuska.template.kmp.library.core + +public actual val platform: String = "macOS" diff --git a/lib/template-kmp-library-core/src/main/AndroidManifest.xml b/modules/template-kmp-library-core/src/main/AndroidManifest.xml similarity index 100% rename from lib/template-kmp-library-core/src/main/AndroidManifest.xml rename to modules/template-kmp-library-core/src/main/AndroidManifest.xml diff --git a/modules/template-kmp-library-core/src/mingwMain/kotlin/platform.kt b/modules/template-kmp-library-core/src/mingwMain/kotlin/platform.kt new file mode 100644 index 0000000..f0700f1 --- /dev/null +++ b/modules/template-kmp-library-core/src/mingwMain/kotlin/platform.kt @@ -0,0 +1,3 @@ +package dev.petuska.template.kmp.library.core + +public actual val platform: String = "Windows" diff --git a/modules/template-kmp-library-core/src/tvosMain/kotlin/platform.kt b/modules/template-kmp-library-core/src/tvosMain/kotlin/platform.kt new file mode 100644 index 0000000..9430d1c --- /dev/null +++ b/modules/template-kmp-library-core/src/tvosMain/kotlin/platform.kt @@ -0,0 +1,3 @@ +package dev.petuska.template.kmp.library.core + +public actual val platform: String = "tvOS" diff --git a/modules/template-kmp-library-core/src/wasmMain/kotlin/platform.kt b/modules/template-kmp-library-core/src/wasmMain/kotlin/platform.kt new file mode 100644 index 0000000..7f961d0 --- /dev/null +++ b/modules/template-kmp-library-core/src/wasmMain/kotlin/platform.kt @@ -0,0 +1,3 @@ +package dev.petuska.template.kmp.library.core + +public actual val platform: String = "WASM" diff --git a/modules/template-kmp-library-core/src/watchosMain/kotlin/platform.kt b/modules/template-kmp-library-core/src/watchosMain/kotlin/platform.kt new file mode 100644 index 0000000..fae5e8a --- /dev/null +++ b/modules/template-kmp-library-core/src/watchosMain/kotlin/platform.kt @@ -0,0 +1,3 @@ +package dev.petuska.template.kmp.library.core + +public actual val platform: String = "watchOS" diff --git a/modules/template-kmp-library-dsl/build.gradle.kts b/modules/template-kmp-library-dsl/build.gradle.kts new file mode 100644 index 0000000..8117e10 --- /dev/null +++ b/modules/template-kmp-library-dsl/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + id("convention.kotlin-mpp-tier3") + id("convention.library-android") + id("convention.library-mpp") + id("convention.publishing-mpp") +} + +kotlin { + sourceSets { + commonMain { + dependencies { + api(project(":modules:template-kmp-library-core")) + } + } + } +} diff --git a/modules/template-kmp-library-dsl/src/commonMain/kotlin/DslLib.kt b/modules/template-kmp-library-dsl/src/commonMain/kotlin/DslLib.kt new file mode 100644 index 0000000..3b6af3b --- /dev/null +++ b/modules/template-kmp-library-dsl/src/commonMain/kotlin/DslLib.kt @@ -0,0 +1,7 @@ +package dev.petuska.template.kmp.library.dsl + +import dev.petuska.template.kmp.library.core.CoreLib +import dev.petuska.template.kmp.library.core.platform + +public fun CoreLib.withPlatform(message: String): String = "[$platform] $message" +public suspend fun CoreLib.withPlatformSuspend(message: String): String = withPlatform(message) diff --git a/settings.gradle.kts b/settings.gradle.kts index 7e16c76..6aa8b99 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,17 +1,27 @@ -plugins { - id("de.fayard.refreshVersions") version "0.51.0" - id("com.gradle.enterprise") version "3.12.3" +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } } -refreshVersions { - extraArtifactVersionKeyRules(rootDir.resolve("versions.rules")) +plugins { + id("com.gradle.enterprise") version "3.13" } +enableFeaturePreview("STABLE_CONFIGURATION_CACHE") + rootProject.name = "template-kmp-library" +includeBuild("./build-conventions/") +include(":tests:test-utils") -include(":test") +include( + ":modules:template-kmp-library-core", + ":tests:template-kmp-library-core-tests" +) include( - ":lib:template-kmp-library-core", - ":lib:template-kmp-library-dsl" + ":modules:template-kmp-library-dsl", + ":tests:template-kmp-library-dsl-tests" ) diff --git a/test/build.gradle.kts b/test/build.gradle.kts deleted file mode 100644 index 4b6c229..0000000 --- a/test/build.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -plugins { id("plugin.library-mpp") } - -description = "Local test utilities" - -kotlin { - explicitApi = null - sourceSets { - commonMain { - dependencies { - api(kotlin("test")) - api(kotlin("test-annotations-common")) - api("dev.petuska:klip:_") - } - } - named("androidMain") { dependencies { api(kotlin("test-junit5")) } } - named("jvmMain") { dependencies { api(kotlin("test-junit5")) } } - named("jsMain") { dependencies { api(kotlin("test-js")) } } - } -} diff --git a/test/src/androidMain/kotlin/Environment.kt b/test/src/androidMain/kotlin/Environment.kt deleted file mode 100644 index 4cabfb9..0000000 --- a/test/src/androidMain/kotlin/Environment.kt +++ /dev/null @@ -1,5 +0,0 @@ -package local.test - -actual object Environment { - actual operator fun get(key: String): String? = System.getenv(key) -} diff --git a/test/src/androidMain/kotlin/runBlockingTest.kt b/test/src/androidMain/kotlin/runBlockingTest.kt deleted file mode 100644 index cdabb6d..0000000 --- a/test/src/androidMain/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,8 +0,0 @@ -package local.test - -import kotlinx.coroutines.runBlocking - -actual typealias CoroutineScope = kotlinx.coroutines.CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - runBlocking(block = test) diff --git a/test/src/androidNdkMain/kotlin/runBlockingTest.kt b/test/src/androidNdkMain/kotlin/runBlockingTest.kt deleted file mode 100644 index 05615c6..0000000 --- a/test/src/androidNdkMain/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,6 +0,0 @@ -package local.test - -actual interface CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - println("Coroutines not supported on androidNdk") diff --git a/test/src/commonMain/kotlin/BlockingTest.kt b/test/src/commonMain/kotlin/BlockingTest.kt deleted file mode 100644 index b552998..0000000 --- a/test/src/commonMain/kotlin/BlockingTest.kt +++ /dev/null @@ -1,21 +0,0 @@ -package local.test - -expect interface CoroutineScope - -internal expect fun runBlockingTest(test: suspend CoroutineScope.() -> Unit) - -interface BlockingTest { - suspend fun beforeEach() {} - suspend fun afterEach() {} - - fun blockingTest(action: suspend CoroutineScope.() -> Unit) = runBlockingTest { - try { - beforeEach() - action() - } catch (e: Throwable) { - afterEach() - throw e - } - afterEach() - } -} diff --git a/test/src/commonMain/kotlin/Environment.kt b/test/src/commonMain/kotlin/Environment.kt deleted file mode 100644 index c4564a3..0000000 --- a/test/src/commonMain/kotlin/Environment.kt +++ /dev/null @@ -1,13 +0,0 @@ -package local.test - -import kotlin.properties.ReadOnlyProperty -import kotlin.reflect.KProperty - -expect object Environment { - operator fun get(key: String): String? -} - -operator fun Environment.getValue(thisRef: Nothing?, property: KProperty<*>): String? = get(property.name) - -infix fun Environment.or(default: String): ReadOnlyProperty = - ReadOnlyProperty { _, property -> Environment[property.name] ?: default } diff --git a/test/src/iosMain/kotlin/runBlockingTest.kt b/test/src/iosMain/kotlin/runBlockingTest.kt deleted file mode 100644 index cdabb6d..0000000 --- a/test/src/iosMain/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,8 +0,0 @@ -package local.test - -import kotlinx.coroutines.runBlocking - -actual typealias CoroutineScope = kotlinx.coroutines.CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - runBlocking(block = test) diff --git a/test/src/jsMain/kotlin/Environment.kt b/test/src/jsMain/kotlin/Environment.kt deleted file mode 100644 index bbab661..0000000 --- a/test/src/jsMain/kotlin/Environment.kt +++ /dev/null @@ -1,10 +0,0 @@ -package local.test - -import kotlin.js.Json - -private external val process: Json - -actual object Environment { - private val env: Json = process["env"].unsafeCast() - actual operator fun get(key: String): String? = env[key]?.toString() -} diff --git a/test/src/jsMain/kotlin/runBlockingTest.kt b/test/src/jsMain/kotlin/runBlockingTest.kt deleted file mode 100644 index 18612cd..0000000 --- a/test/src/jsMain/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,10 +0,0 @@ -package local.test - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.promise -import kotlin.coroutines.EmptyCoroutineContext - -actual typealias CoroutineScope = CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): dynamic = - CoroutineScope(EmptyCoroutineContext).promise(block = test) diff --git a/test/src/jvmMain/kotlin/Environment.kt b/test/src/jvmMain/kotlin/Environment.kt deleted file mode 100644 index 4cabfb9..0000000 --- a/test/src/jvmMain/kotlin/Environment.kt +++ /dev/null @@ -1,5 +0,0 @@ -package local.test - -actual object Environment { - actual operator fun get(key: String): String? = System.getenv(key) -} diff --git a/test/src/jvmMain/kotlin/runBlockingTest.kt b/test/src/jvmMain/kotlin/runBlockingTest.kt deleted file mode 100644 index cdabb6d..0000000 --- a/test/src/jvmMain/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,8 +0,0 @@ -package local.test - -import kotlinx.coroutines.runBlocking - -actual typealias CoroutineScope = kotlinx.coroutines.CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - runBlocking(block = test) diff --git a/test/src/linuxArm32HfpMain/kotlin/runBlockingTest.kt b/test/src/linuxArm32HfpMain/kotlin/runBlockingTest.kt deleted file mode 100644 index 2a77059..0000000 --- a/test/src/linuxArm32HfpMain/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,6 +0,0 @@ -package local.test - -actual interface CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - println("Coroutines not supported on linuxArm32Hfp") diff --git a/test/src/linuxArm64Main/kotlin/runBlockingTest.kt b/test/src/linuxArm64Main/kotlin/runBlockingTest.kt deleted file mode 100644 index f23f0e8..0000000 --- a/test/src/linuxArm64Main/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,6 +0,0 @@ -package local.test - -actual interface CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - println("Coroutines not supported on linuxArm64") diff --git a/test/src/linuxMips32Main/kotlin/runBlockingTest.kt b/test/src/linuxMips32Main/kotlin/runBlockingTest.kt deleted file mode 100644 index a147e9d..0000000 --- a/test/src/linuxMips32Main/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,6 +0,0 @@ -package local.test - -actual interface CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - println("Coroutines not supported on linuxMips32") diff --git a/test/src/linuxMipsel32Main/kotlin/runBlockingTest.kt b/test/src/linuxMipsel32Main/kotlin/runBlockingTest.kt deleted file mode 100644 index f5111c4..0000000 --- a/test/src/linuxMipsel32Main/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,6 +0,0 @@ -package local.test - -actual interface CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - println("Coroutines not supported on linuxMipsel32") diff --git a/test/src/linuxX64Main/kotlin/runBlockingTest.kt b/test/src/linuxX64Main/kotlin/runBlockingTest.kt deleted file mode 100644 index cdabb6d..0000000 --- a/test/src/linuxX64Main/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,8 +0,0 @@ -package local.test - -import kotlinx.coroutines.runBlocking - -actual typealias CoroutineScope = kotlinx.coroutines.CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - runBlocking(block = test) diff --git a/test/src/macosMain/kotlin/runBlockingTest.kt b/test/src/macosMain/kotlin/runBlockingTest.kt deleted file mode 100644 index cdabb6d..0000000 --- a/test/src/macosMain/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,8 +0,0 @@ -package local.test - -import kotlinx.coroutines.runBlocking - -actual typealias CoroutineScope = kotlinx.coroutines.CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - runBlocking(block = test) diff --git a/test/src/main/AndroidManifest.xml b/test/src/main/AndroidManifest.xml deleted file mode 100644 index 71a91c7..0000000 --- a/test/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/test/src/mingwX64Main/kotlin/runBlockingTest.kt b/test/src/mingwX64Main/kotlin/runBlockingTest.kt deleted file mode 100644 index cdabb6d..0000000 --- a/test/src/mingwX64Main/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,8 +0,0 @@ -package local.test - -import kotlinx.coroutines.runBlocking - -actual typealias CoroutineScope = kotlinx.coroutines.CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - runBlocking(block = test) diff --git a/test/src/mingwX86Main/kotlin/runBlockingTest.kt b/test/src/mingwX86Main/kotlin/runBlockingTest.kt deleted file mode 100644 index 1b1d625..0000000 --- a/test/src/mingwX86Main/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,6 +0,0 @@ -package local.test - -actual interface CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - println("Coroutines not supported on mingwX86") diff --git a/test/src/tvosMain/kotlin/runBlockingTest.kt b/test/src/tvosMain/kotlin/runBlockingTest.kt deleted file mode 100644 index cdabb6d..0000000 --- a/test/src/tvosMain/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,8 +0,0 @@ -package local.test - -import kotlinx.coroutines.runBlocking - -actual typealias CoroutineScope = kotlinx.coroutines.CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - runBlocking(block = test) diff --git a/test/src/watchosMain/kotlin/runBlockingTest.kt b/test/src/watchosMain/kotlin/runBlockingTest.kt deleted file mode 100644 index cdabb6d..0000000 --- a/test/src/watchosMain/kotlin/runBlockingTest.kt +++ /dev/null @@ -1,8 +0,0 @@ -package local.test - -import kotlinx.coroutines.runBlocking - -actual typealias CoroutineScope = kotlinx.coroutines.CoroutineScope - -actual fun runBlockingTest(test: suspend CoroutineScope.() -> Unit): Unit = - runBlocking(block = test) diff --git a/tests/template-kmp-library-core-tests/build.gradle.kts b/tests/template-kmp-library-core-tests/build.gradle.kts new file mode 100644 index 0000000..8036027 --- /dev/null +++ b/tests/template-kmp-library-core-tests/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("convention.kotlin-mpp-tier1") + id("convention.library-android") +} + +kotlin { + sourceSets { + commonTest { + dependencies { + implementation(project(":tests:test-utils")) + implementation(project(":modules:template-kmp-library-core")) + } + } + } +} \ No newline at end of file diff --git a/tests/template-kmp-library-core-tests/src/commonTest/kotlin/CoreLibTest.kt b/tests/template-kmp-library-core-tests/src/commonTest/kotlin/CoreLibTest.kt new file mode 100644 index 0000000..d37c046 --- /dev/null +++ b/tests/template-kmp-library-core-tests/src/commonTest/kotlin/CoreLibTest.kt @@ -0,0 +1,34 @@ +package dev.petuska.template.kmp.library.core + +import io.kotest.matchers.shouldBe +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import kotlin.test.BeforeTest +import kotlin.test.Test + +@OptIn(ExperimentalCoroutinesApi::class) +class CoreLibTest { + + @BeforeTest + fun setUp() { + println("Running on $platform") + } + + @Test + fun test() = runTest { + val result = CoreLib().sampleApi() + result shouldBe platform + } + + @Test + fun testSuspend() = runTest { + val result = CoreLib().sampleSuspendApi() + result shouldBe platform + } + + @Test + fun testValue() = runTest { + val result = CoreLib().sampleValue + result shouldBe 28980 + } +} diff --git a/tests/template-kmp-library-dsl-tests/build.gradle.kts b/tests/template-kmp-library-dsl-tests/build.gradle.kts new file mode 100644 index 0000000..c209f47 --- /dev/null +++ b/tests/template-kmp-library-dsl-tests/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("convention.kotlin-mpp-tier1") + id("convention.library-android") +} + +kotlin { + sourceSets { + commonTest { + dependencies { + implementation(project(":tests:test-utils")) + implementation(project(":modules:template-kmp-library-dsl")) + } + } + } +} \ No newline at end of file diff --git a/tests/template-kmp-library-dsl-tests/src/commonTest/kotlin/DslLibTest.kt b/tests/template-kmp-library-dsl-tests/src/commonTest/kotlin/DslLibTest.kt new file mode 100644 index 0000000..01042b2 --- /dev/null +++ b/tests/template-kmp-library-dsl-tests/src/commonTest/kotlin/DslLibTest.kt @@ -0,0 +1,21 @@ +package dev.petuska.template.kmp.library.dsl + +import dev.petuska.template.kmp.library.core.CoreLib +import dev.petuska.template.kmp.library.core.platform +import io.kotest.matchers.string.shouldContain +import kotlinx.coroutines.test.runTest +import kotlin.test.Test + +class DslLibTest { + @Test + fun test() = runTest { + val result = CoreLib().withPlatform("sync") + result shouldContain platform + } + + @Test + fun testSuspend() = runTest { + val result = CoreLib().withPlatformSuspend("async") + result shouldContain platform + } +} diff --git a/tests/test-utils/build.gradle.kts b/tests/test-utils/build.gradle.kts new file mode 100644 index 0000000..fb1d00d --- /dev/null +++ b/tests/test-utils/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("convention.kotlin-mpp-tier1") + id("convention.library-android") +} + +kotlin { + sourceSets { + commonMain { + dependencies { + api(libs.kotlinx.coroutines.test) + api(libs.bundles.kotest.assertions) + } + } + } +} \ No newline at end of file diff --git a/tests/test-utils/src/androidMain/kotlin/Env.kt b/tests/test-utils/src/androidMain/kotlin/Env.kt new file mode 100644 index 0000000..c16a540 --- /dev/null +++ b/tests/test-utils/src/androidMain/kotlin/Env.kt @@ -0,0 +1,5 @@ +package test + +actual object Env { + actual operator fun get(key: String): String? = System.getenv(key) +} \ No newline at end of file diff --git a/tests/test-utils/src/commonMain/kotlin/Env.kt b/tests/test-utils/src/commonMain/kotlin/Env.kt new file mode 100644 index 0000000..f1f0021 --- /dev/null +++ b/tests/test-utils/src/commonMain/kotlin/Env.kt @@ -0,0 +1,5 @@ +package test + +expect object Env { + operator fun get(key: String): String? +} \ No newline at end of file diff --git a/tests/test-utils/src/jsMain/kotlin/Env.kt b/tests/test-utils/src/jsMain/kotlin/Env.kt new file mode 100644 index 0000000..3bc1f74 --- /dev/null +++ b/tests/test-utils/src/jsMain/kotlin/Env.kt @@ -0,0 +1,5 @@ +package test + +actual object Env { + actual operator fun get(key: String): String? = null +} \ No newline at end of file diff --git a/tests/test-utils/src/jvmMain/kotlin/Env.kt b/tests/test-utils/src/jvmMain/kotlin/Env.kt new file mode 100644 index 0000000..c16a540 --- /dev/null +++ b/tests/test-utils/src/jvmMain/kotlin/Env.kt @@ -0,0 +1,5 @@ +package test + +actual object Env { + actual operator fun get(key: String): String? = System.getenv(key) +} \ No newline at end of file diff --git a/test/src/nativeMain/kotlin/Environment.kt b/tests/test-utils/src/nativeMain/kotlin/Env.kt similarity index 76% rename from test/src/nativeMain/kotlin/Environment.kt rename to tests/test-utils/src/nativeMain/kotlin/Env.kt index 943be50..a6172b9 100644 --- a/test/src/nativeMain/kotlin/Environment.kt +++ b/tests/test-utils/src/nativeMain/kotlin/Env.kt @@ -1,8 +1,8 @@ -package local.test +package test import kotlinx.cinterop.toKStringFromUtf8 import platform.posix.getenv -actual object Environment { +actual object Env { actual operator fun get(key: String): String? = getenv(key)?.toKStringFromUtf8() -} +} \ No newline at end of file diff --git a/versions.properties b/versions.properties index df367cc..b20f716 100644 --- a/versions.properties +++ b/versions.properties @@ -1,19 +1,28 @@ #### Dependencies and Plugin versions with their available updates. -#### Generated by `./gradlew refreshVersions` version 0.40.1 +#### Generated by `./gradlew refreshVersions` version 0.51.0 #### #### Don't manually edit or split the comments that start with four hashtags (####), #### they will be overwritten by refreshVersions. #### #### suppress inspection "SpellCheckingInspection" for whole file #### suppress inspection "UnusedProperty" for whole file + #======================================= Plugins ======================================== plugin.android=4.2.2 -version.klip=0.3.0 + + version.klip=0.3.0 + version.ktlint=0.43.2 + version.com.diffplug.spotless..spotless-plugin-gradle=6.3.0 + version.com.github.jakemarsden..git-hooks-gradle-plugin=0.0.2 + version.io.github.gradle-nexus..publish-plugin=1.1.0 + version.org.jetbrains.dokka..dokka-gradle-plugin=1.6.10 + #====================================== Libraries ======================================= version.kotlin=1.6.10 + version.kotlinx.coroutines=1.6.0