Target Platforms

  • Linux
  • Java Script
  • JVM
  • Common

The Library

Version Management

There are several ways to manage versions. But the best is to place it under buildSrc.

Note You cannot use buildSrc versions in settings.gradle.kts. This file is compiled before buildSrc

buildSrc/build.gradle.kts

plugins {
    `kotlin-dsl`
}
repositories {
    gradlePluginPortal()
    mavenCentral()
    jcenter()
}
kotlinDslPluginOptions {
    experimentalWarning.set(false)
}

buildSrc/src/main/kotlin/design/animus/kotlin/frm/Versions.kt

package design.animus.kotlin.frm

object Versions {
    object Plugins {
        const val kotlin = Dependencies.kotlin
        const val gradlePluginPublish = "0.10.1"
    }

    object Dependencies {
        const val kotlin = "1.3.61"
        const val serialization = "0.14.0"
        const val coroutine = "1.3.3"
        const val vertx = "3.8.5"
        const val postgreSQL = "42.2.5"
        const val junit = "4.12"
        const val kotlinPoet = "1.4.0"
        const val jasync = "1.0.12"
        const val kotlinLogging = "1.7.9-SNAPSHOT"
        const val logback = "1.2.3"
        const val MPDataTypes = "0.1.0-SNAPSHOT"
        const val mariaDBDriver = "2.5.2"
    }
}
Settings

gradle.properties

kotlin.js.experimental.generateKotlinExternals=true
org.gradle.internal.publish.checksums.insecure=true
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configureondemand=true
org.gradle.workers.max=6
// https://github.com/gradle/gradle/issues/1630
org.gradle.configureondemand=false

settings.gradle.kts

enableFeaturePreview("GRADLE_METADATA")
rootProject.name = "kotlin-frm"

pluginManagement {
    resolutionStrategy {
        eachPlugin {
            if (requested.id.id.contains("org.flywaydb.flyway")) {
                useVersion("6.0.7")
            }
            if (requested.id.id.startsWith("org.jetbrains.dokka")) {
                // Update Version Build Source if being changed.
                useVersion("0.10.0")
            }
            if (requested.id.id.startsWith("org.jetbrains.kotlin.") || requested.id.id.startsWith("org.jetbrains.kotlin.plugin.serialization") ) {
                // Update Version Build Source if being changed.
                useVersion("1.3.61")
            }
        }
    }
    repositories {
        maven { url = java.net.URI("https://dl.bintray.com/kotlin/kotlinx") }
        mavenCentral()
        mavenLocal()
        jcenter()
        gradlePluginPortal()
    }
}

include("projectName")

Here we are intercepting any plugin calls later in the project. Ensuring a common version. As noted we cannot utilize buildSrc. So there is a comment to change the version in the buildSrc file.

build.gradle.kts

Here we find all projects under the sql name space, or project hierarchy.

  • Apply the legacy version.gradle.kts, this is being phased out for buildSrc
  • Apply publishing, noted below.
  • Apply plugin maven-publish
  • Set common repositories
  • Set a common group and version
import java.net.URI

allprojects {
    buildscript {
        repositories {
            mavenCentral()
            mavenLocal()
            jcenter()
            google()
            maven { url = URI("https://kotlin.bintray.com/kotlinx") }
            maven { url = URI("https://dl.bintray.com/kotlin/kotlin-js-wrappers") }
            maven { url = URI("https://kotlin.bintray.com/kotlinx") }
            maven { url = URI("https://maven.google.com") }
            maven { url = URI("https://plugins.gradle.org/m2/") }
            maven { url = URI("http://dl.bintray.com/kotlin/kotlin-dev") }
            maven { url = URI("https://dl.bintray.com/kotlin/kotlin-eap") }
            maven { url = URI("https://maven.fabric.io/public") }
            maven { url = URI("https://nexus.animus.design/repository/AnimusDesignSnapshot/") }
            maven { url = URI("https://nexus.animus.design/repository/AnimusDesign/") }
        }
    }


    allprojects.filter { it.name.contains("sql") }.forEach { project ->
        project.subprojects {
            apply("$rootDir/versions.gradle.kts")
            apply("$rootDir/gradle/common/publishing-repos.gradle.kts")
            apply(plugin = "maven-publish")
            repositories {
                mavenCentral()
                mavenLocal()
                jcenter()
                google()
                maven { url = URI("https://kotlin.bintray.com/kotlinx") }
                maven { url = URI("https://dl.bintray.com/kotlin/kotlin-js-wrappers") }
                maven { url = URI("https://kotlin.bintray.com/kotlinx") }
                maven { url = URI("https://maven.google.com") }
                maven { url = URI("https://plugins.gradle.org/m2/") }
                maven { url = URI("http://dl.bintray.com/kotlin/kotlin-dev") }
                maven { url = URI("https://dl.bintray.com/kotlin/kotlin-eap") }
                maven { url = URI("https://maven.fabric.io/public") }
                maven { url = URI("https://nexus.animus.design/repository/AnimusDesignSnapshot/") }
                maven { url = URI("https://nexus.animus.design/repository/AnimusDesign/") }
            }
            group = "${extra["baseGroup"]}.sql"
            version = "${extra["projectVersion"]}"
        }
    }
}

versions.gradle.kts

As noted this is being deprecated in favor of buildSrc. The parts being used here are largely the artifactUrl.

Note: We are stubbing default values to allow building in IntelliJ. Since Env File and gradle is buggy.

extra["KotlinVersion"] = "1.3.61"
extra["SerializationVersion"] = "0.14.0"
extra["CoroutineVersion"] = "1.3.3"
extra["VertXVersion"] = "3.8.4"
extra["PostgreSQLVersion"] = "42.2.5"
extra["JUNITVersion"] = "4.12"
extra["ArrowVersion"] = "0.10.3"
extra["KotlinLoggingVersion"] = "1.7.9-SNAPSHOT"
extra["Slf4jLog4jVersion"] = "1.7.25"
extra["LogBackVersion"] = "1.2.3"
extra["ShadowJarVersion"] = "4.0.2"
extra["FlyWayDBVersion"] = "6.0.7"
extra["DokkaVersion"] = "0.10.0"
extra["RetroFitVersion"] = "1.9.0"
extra["MicroMeterVersion"] = "1.2.0"
extra["JaSyncVersion"] = "1.0.12"
extra["KotlinPoetVersion"] = "1.4.0"
extra["HikariCPVersion"] = "3.4.1"
extra["LogBackVersion"] = "1.2.3"
extra["MariaDBDriver"] = "2.5.2"
extra["FlyWayDBVersion"] = "6.1.3"
extra["baseGroup"] = "design.animus.kotlin.frm"
extra["buildNumber"] = System.getenv("CI_COMMIT_SHA") ?: ""
extra["artifactUser"] = System.getenv("ArtifactUser") ?: "user"
extra["artifactPassword"] = System.getenv("ArtifactPassword") ?: "password"
extra["baseVersion"] = "0.1.5-SNAPSHOT"
extra["MPDataTypes"] = "0.1.0-SNAPSHOT"
val baseVersion = extra["baseVersion"] as String
extra["projectVersion"] = if (baseVersion.endsWith("SNAPSHOT")) {
    if (extra["buildNumber"].toString().isNotEmpty()) {
        baseVersion.replace("-SNAPSHOT", "-${extra["buildNumber"]}-SNAPSHOT")
    } else {
        baseVersion
    }
} else {
    baseVersion
}
extra["artifactUrl"] = if (extra["baseVersion"].toString().contains("SNAPSHOT")) {
    System.getenv("ArtifactSnapShotURL") ?: "https://127.0.0.1"
} else {
    System.getenv("ArtifactURL") ?: "https://127.0.0.1"
}

sql/query/query-common/build.gradle.kts

This is a sample of a multi platform gradle file. Note it only works on Linux right now. So remove host manager if not on Linux, or add your appropiate host.

import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.konan.target.HostManager

plugins {
    kotlin("multiplatform")
    id("org.jetbrains.dokka")
    `maven-publish`
    id("jacoco")
}

kotlin {
    val nativeMain by sourceSets.creating {
        dependencies {
            api("org.jetbrains.kotlin:kotlin-stdlib-common")
        }
    }
    jvm()
    js {
        compilations.named("main") {
            kotlinOptions {
                metaInfo = true
                sourceMap = true
                verbose = true
                moduleKind = "umd"
            }
        }
    }
    val linuxX64 by sourceSets.creating {
        dependsOn(nativeMain)
    }
    targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
        compilations["main"].defaultSourceSet.dependsOn(nativeMain)
        when {
            HostManager.hostIsLinux -> compilations["main"].defaultSourceSet.dependsOn(linuxX64)
            else -> error("Unsupported host platform")
        }
    }
    when {
        HostManager.hostIsLinux -> {
            targetFromPreset(presets["linuxX64"], "linuxX64")
        }
        else -> error("Unsupported host platform")
    } as KotlinNativeTarget
    sourceSets {
        commonMain {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${extra["CoroutineVersion"]}")
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:${extra["CoroutineVersion"]}")
                implementation("io.github.microutils:kotlin-logging:${extra["KotlinLoggingVersion"]}")
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:${extra["SerializationVersion"]}")
                implementation(kotlin("stdlib-common"))
                implementation("design.animus.kotlin.mp.functional.datatypes:multiplatform-functional-datatypes:${extra["MPDataTypes"]}")
            }
        }
        commonTest {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${extra["CoroutineVersion"]}")
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:${extra["CoroutineVersion"]}")
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
            }
        }
        named("jvmMain") {
            dependencies {
                implementation(kotlin("stdlib-jdk8"))
                implementation(kotlin("reflect"))
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${extra["CoroutineVersion"]}")
                implementation("io.github.microutils:kotlin-logging-jvm:${extra["KotlinLoggingVersion"]}")
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:${extra["SerializationVersion"]}")
                implementation("design.animus.kotlin.mp.functional.datatypes:multiplatform-functional-datatypes-jvm:${extra["MPDataTypes"]}")
            }
        }
        named("jvmTest") {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${extra["CoroutineVersion"]}")
                implementation(kotlin("test"))
                implementation(kotlin("test-junit"))
            }
        }
        named("jsMain") {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${extra["CoroutineVersion"]}")
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:${extra["CoroutineVersion"]}")
                implementation("io.github.microutils:kotlin-logging-js:${extra["KotlinLoggingVersion"]}")
                implementation(kotlin("stdlib-js"))
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:${extra["SerializationVersion"]}")
                implementation("design.animus.kotlin.mp.functional.datatypes:multiplatform-functional-datatypes-js:${extra["MPDataTypes"]}")
            }
        }
        named("jsTest") {
            dependencies {
                implementation(kotlin("test-js"))
            }
        }
        named("linuxX64Main") {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${extra["CoroutineVersion"]}")
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-native:${extra["CoroutineVersion"]}")
                implementation("design.animus.kotlin.mp.functional.datatypes:multiplatform-functional-datatypes-linuxx64:${extra["MPDataTypes"]}")
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:${extra["SerializationVersion"]}")
            }
        }
    }
}

tasks {
    val jvmTest by getting(org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest::class) {
        this.useJUnit()
        this.reports.junitXml.isEnabled = true
    }
}

It's important to note the artifacts it provides. Here is a tree sample.

.m2/repository/design/animus/kotlin/frm/sql/query-common
├── 0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT
│   ├── maven-metadata-local.xml
│   ├── query-common-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.module
│   └── query-common-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.pom
└── maven-metadata-local.xml
.m2/repository/design/animus/kotlin/frm/sql/query-common-js
├── 0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT
│   ├── maven-metadata-local.xml
│   ├── query-common-js-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.jar
│   ├── query-common-js-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.module
│   ├── query-common-js-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.pom
│   └── query-common-js-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT-sources.jar
└── maven-metadata-local.xml
.m2/repository/design/animus/kotlin/frm/sql/query-common-jvm
├── 0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT
│   ├── maven-metadata-local.xml
│   ├── query-common-jvm-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.jar
│   ├── query-common-jvm-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.module
│   ├── query-common-jvm-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.pom
│   └── query-common-jvm-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT-sources.jar
└── maven-metadata-local.xml
.m2/repository/design/animus/kotlin/frm/sql/query-common-linuxx64
├── 0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT
│   ├── maven-metadata-local.xml
│   ├── query-common-linuxx64-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.klib
│   ├── query-common-linuxx64-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.module
│   ├── query-common-linuxx64-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.pom
│   └── query-common-linuxx64-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT-sources.jar
└── maven-metadata-local.xml
.m2/repository/design/animus/kotlin/frm/sql/query-common-metadata
├── 0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT
│   ├── maven-metadata-local.xml
│   ├── query-common-metadata-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.jar
│   ├── query-common-metadata-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.module
│   ├── query-common-metadata-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.pom
│   └── query-common-metadata-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT-sources.jar
└── maven-metadata-local.xml
  • query-common Base depenedency for common main. It will direct the target platform to pick up it's appropiate dependency.
  • query-common-jvm The JDK/JVM Target
  • query-common-js The java script package
  • query-common-linuxX64 The kotlin native linux x64 versions.
  • query-common-metadata The over arching director for what packages are picked up.

When publishing we don't have to set artifact id. In fact don't adjust the artifact id. Just set the repository, and the target credentials, apply maven-publish. Then this will handle the rest.

Diving into Meta data

Below is the query-comon metadata. Under variants you can see

how it directs based on target, which library or package to pick up.

{
  "formatVersion": "1.1",
  "component": {
    "group": "design.animus.kotlin.frm.sql",
    "module": "query-common",
    "version": "0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT",
    "attributes": {
      "org.gradle.status": "integration"
    }
  },
  "createdBy": {
    "gradle": {
      "version": "6.1.1",
      "buildId": "g2lzmrvn3nepjld6st5z5n4i24"
    }
  },
  "variants": [
    {
      "name": "js-api",
      "attributes": {
        "org.gradle.usage": "kotlin-api",
        "org.jetbrains.kotlin.platform.type": "js"
      },
      "available-at": {
        "url": "../../query-common-js/0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT/query-common-js-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.module",
        "group": "design.animus.kotlin.frm.sql",
        "module": "query-common-js",
        "version": "0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT"
      }
    },
    {
      "name": "js-runtime",
      "attributes": {
        "org.gradle.usage": "kotlin-runtime",
        "org.jetbrains.kotlin.platform.type": "js"
      },
      "available-at": {
        "url": "../../query-common-js/0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT/query-common-js-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.module",
        "group": "design.animus.kotlin.frm.sql",
        "module": "query-common-js",
        "version": "0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT"
      }
    },
    {
      "name": "jvm-api",
      "attributes": {
        "org.gradle.libraryelements": "jar",
        "org.gradle.usage": "java-api",
        "org.jetbrains.kotlin.platform.type": "jvm"
      },
      "available-at": {
        "url": "../../query-common-jvm/0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT/query-common-jvm-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.module",
        "group": "design.animus.kotlin.frm.sql",
        "module": "query-common-jvm",
        "version": "0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT"
      }
    },
    {
      "name": "jvm-runtime",
      "attributes": {
        "org.gradle.libraryelements": "jar",
        "org.gradle.usage": "java-runtime",
        "org.jetbrains.kotlin.platform.type": "jvm"
      },
      "available-at": {
        "url": "../../query-common-jvm/0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT/query-common-jvm-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.module",
        "group": "design.animus.kotlin.frm.sql",
        "module": "query-common-jvm",
        "version": "0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT"
      }
    },
    {
      "name": "linuxX64-api",
      "attributes": {
        "org.gradle.usage": "kotlin-api",
        "org.jetbrains.kotlin.native.target": "linux_x64",
        "org.jetbrains.kotlin.platform.type": "native"
      },
      "available-at": {
        "url": "../../query-common-linuxx64/0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT/query-common-linuxx64-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.module",
        "group": "design.animus.kotlin.frm.sql",
        "module": "query-common-linuxx64",
        "version": "0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT"
      }
    },
    {
      "name": "metadata-api",
      "attributes": {
        "org.gradle.usage": "kotlin-api",
        "org.jetbrains.kotlin.platform.type": "common"
      },
      "available-at": {
        "url": "../../query-common-metadata/0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT/query-common-metadata-0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT.module",
        "group": "design.animus.kotlin.frm.sql",
        "module": "query-common-metadata",
        "version": "0.1.5-6114a7983210e4b41e2a838ea3d6672faf75ec39-SNAPSHOT"
      }
    }
  ]
}

Consuming Multi Platform Libs

One of the things I've seen commonlny is to rename

metadata -> comon on artifact id.

I.e. query-common-metadata -> query-common-common.

This wreaks all sort of havoc on dependency and the module system.

Below is the dependency on different source sets. This is pulled from an adjacent project but follows a similar hierarchy.

The call out is on commonMain we depend on the root project. Then only add the platform type for the other projects.

Common Main

implementation("design.animus.kotlin.mp.functional.datatypes:multiplatform-functional-datatypes:${extra["MPDataTypes"]}")

JVM Main

implementation("design.animus.kotlin.mp.functional.datatypes:multiplatform-functional-datatypes-jvm:${extra["MPDataTypes"]}")

JS Main

implementation("design.animus.kotlin.mp.functional.datatypes:multiplatform-functional-datatypes-js:${extra["MPDataTypes"]}")

Linux X64 Main

implementation("design.animus.kotlin.mp.functional.datatypes:multiplatform-functional-datatypes-linuxx64:${extra["MPDataTypes"]}")