Tag: gradle

Publish Kotlin Library on Bintray using Gradle Kotlin DSL and Travis CI

Publish Kotlin Library on Bintray using Gradle Kotlin DSL and Travis CI

Distribute a Library on Bintray using Gradle Kotlin DSL

In my latest blog post, published a few weeks back, I informed about the usage of the Gradle Kotlin DSL and how it helps with describing build scripts. In another earlier post, I introduced a small library that can be utilized for simplifying the creation of TLS/SSL sockets using a custom Kotlin DSL: SeKurity.

In this post, we’ll investigate how such a library can be made available to others that actually want to make use of it inside other projects. Ultimately, it should be possible to list the SeKurity library as a simple dependency in a build script like Maven or Gradle. Since the library itself is already backed by Gradle, I’ll show a way of publishing the resulting artifacts at the end of that build.

Where to publish?

In order to make a library available to anybody else, it needs to be published to a publicly accessible e.g. Maven repository like the famous Maven Central. Unless you’re absolutely certain about the quality of your library, it’s recommended to share it on custom repositories rather than THE central one directly as you’ll kinda lose control of it once it’s out there. One alternative is called Bintray and it will also be used in the present article. After creating an account or simply signing in with your GitHub, Google or Twitter account, you can create your own repositories there.

Automating the Build

Before enabling our build to publish the built artifacts, the process should be automated in a CI tool like Travis CI, which interacts nicely with GitHub. To make it work, it must be enabled in the GitHub repo settings by adding it as a service (see Settings -> Integrations & services). Travis expects the repository to incorporate a .travis.yml configuration that tells it what to do. For a simple Java/Kotlin project using Gradle, the following will be sufficient:

language: java

before_install:
- chmod +x gradlew

script: ./gradlew clean bintrayUpload -PbintrayUser=$BINTRAY_USER -PbintrayApiKey=$BINTRAY_KEY

It’s normally not necessary to specify the script command explicitly as long as you’re using the default instructions. In the shown case, Gradle runs the bintrayUpload task, which we will learn about later. The used properties $BINTRAY_USER and $BINTRAY_KEY contain private data and are therefore securely stored in Travis directly. When the build is run, Travis takes care of replacing them.
You can finally enable the repository in Travis and it will start a build on every push immediately. For further information on Travis, the documentation is highly recommended.

The Gradle Build

As shown earlier, the bintrayUpload Gradle task gets invoked in the build. Where does it come from? Let’s have a look at the relevant parts of the gradle.build.kts file.

The Plugins

plugins {
    kotlin("jvm") version "1.2.30"
    id("com.github.johnrengelman.shadow") version "2.0.2"
    `maven-publish`
    id("com.jfrog.bintray") version "1.8.0"
}
  • The shadow plugin is used because we need the library to be bundled with all its dependencies in order to avoid classpath conflicts.
  • The maven-publish plugin helps with creating the relevant artifact and a relevant pom.xml file that will also be published.
  • The bintray plugin does all the heavy work at the end of the build. It refers to the maven-publish result and pushes the artifacts to Bintray.

Plugin Configuration

The build file also adds custom configurations for all previously shown plugins as shown next:

I Shadow

val artifactID = "sekurity"

val shadowJar: ShadowJar by tasks
shadowJar.apply {
     baseName = artifactID
     classifier = null
}

The shadow plugin uses the project’s name as the artifact’s baseName and the “all” qualifier by default, which is overridden here.

II Maven-Publish

fun MavenPom.addDependencies() = withXml {
    asNode().appendNode("dependencies").let { depNode ->
        configurations.compile.allDependencies.forEach {
            depNode.appendNode("dependency").apply {
                appendNode("groupId", it.group)
                appendNode("artifactId", it.name)
                appendNode("version", it.version)
            }
        }
    }
}

val publicationName = "tlslib"
publishing {
    publications.invoke {
        publicationName(MavenPublication::class) {
            artifactId = artifactID
            artifact(shadowJar)
            pom.addDependencies()
        }
    }
}

This one is a bit tricky. We reuse the result of shadow and add it to the publication which will be published under the artifactId that corresponds to the JAR’s baseName. By default, the generated POM does not list the library dependencies, which is done by mapping each compile dependency to a valid dependency XML node.

III Bintray

fun findProperty(s: String) = project.findProperty(s) as String?

bintray {
    user = findProperty("bintrayUser")
    key = findProperty("bintrayApiKey")
    publish = true
    setPublications(publicationName)
    pkg(delegateClosureOf {
        repo = "SeKurity"
        name = "SeKurity"
        userOrg = "simon-wirtz"
        vcsUrl = "https://github.com/s1monw1/TlsLibrary"
        setLabels("kotlin")
        setLicenses("MIT")
    })
}

The bintray plugin is most important since it takes care of actually uploading the generated artifacts to Bintray itself. The user and key are obtained from the Gradle project properties, which are passed by Travis later on as already shown earlier. By referring to the publication created in maven-publish, all artifacts will be uploaded as specified. The pkg block describes the library’s attributes and where, i.e. to what repository, the publishing happens.

The Result

All these blocks merged result in a pretty nice Gradle build script, which can be observed in this Gist and also the SeKurity repository itself. The resulting artifact is made available here: https://bintray.com/simon-wirtz/SeKurity

Referring to the published Library

Now that the library is being uploaded to Bintray, it can be listed as a dependency in arbitrary build files. If we have another Gradle-backed project, we first need to add the relevant repository to the list of repositories:

repositories {
    mavenCentral()
    jcenter()

    maven {
        setUrl("https://simon-wirtz.bintray.com/SeKurity")
    }
}

After that, the library can be added as a simple compile dependency like this:

dependencies {
    compile(kotlin("stdlib-jre8", kotlinVersion))
//...others...

    compile("de.swirtz:sekurity:0.0.1")

}

Recap

As shown, Gradle plugins can be used for setting up a proper build that publishes a custom library to Bintray easily. In order to automate the whole process, CI tools like Travis can be used for executing the build whenever a new change has been made.

I hope the little tutorial helps with your build as well! If you like, have a look at my Twitter account and follow if you’re interested in more Kotlin stuff 🙂 Thanks a lot.

Please follow and like this Blog 🙂
The Power of Gradle Kotlin DSL

The Power of Gradle Kotlin DSL

-The following is based on Gradle 4.3.1-

A few weeks ago I started migrating most of my Groovy-based gradle.build scripts to Kotlin-backed gradle.build.kts scripts using the Kotlin DSL. Why would I do that? Kotlin is my language of choice and I love the idea of using a single language to do all my work. I never learned programming with Groovy and only know the bloody basics, which always makes me think: “This can’t be the best way to do things…”. Kotlin, on the other hand, is a language I use on a daily basis and therefore I know how to use the language appropriately. Additionally, Kotlin is a statically-typed language, whereas Groovy isn’t. IDEs are having hard times offering code completion and error detection at compile time when a Groovy build script is being edited. As for the Kotlin DSL, this isn’t true. Especially IntelliJ knows how to help us with Kotlin development, even in gradle.build.kts files. All these reasons made me take a deeper look at the new style Gradle offers.

Minor Impediments

It can sometimes be a bit tedious to rewrite your gradle.build into gradle.build.kts files, especially in the IDE with all its caches malfunctioning during that process. I often had to reopen my project or even reimport it before IntelliJ understood what was going on. It also often helps to use “Refresh all Gradle projects” button in the Gradle view.

Let’s take a look

The following snippet shows the first part of a working example. It was taken from one of my projects, which is a Kotlin web application based on the Vert.x toolkit. Learn more about the technology in this post I wrote earlier.

The script first defines a few global variables, mostly containing version numbers, which are used throughout the build file. Next, we can observe the plugins block that simply defines a few plugins used for the build. Most importantly, the Kotlin Gradle plugin for JVM applications is included, which we can do with the DSL-specific function kotlin(module: String), that takes its module argument and appends it to "org.jetbrains.kotlin.", which then is put into the id(plugin: String) method, the default api for applying plugins. Last but not least, we can see the listing of dependencies, which again provides a kotlin convenience method we can use to reduce redundant declarations. A similar approach can be seen with the definition of the io.vertx dependencies. In order to only once write the "io.vertx.vertx" String, which is part of every single Vert.x dependency, it’s used as a receiver of let. A first example of real idiomatic code within the build script.

//imports

//taken from the `plugins` defined later in the file
val kotlinVersion = plugins.getPlugin(KotlinPluginWrapper::class.java).kotlinPluginVersion
val kotlinCoroutinesVersion = "0.19.3"

val vertxVersion = "3.5.0" //
val nexusRepo = "http://x.x.x.x:8080/nexus/content/repositories/releases"

plugins {
    kotlin("jvm").version("1.2.0")
    application
    java
    `maven-publish`
}

dependencies {
    compile(kotlin("stdlib", kotlinVersion))
    compile(kotlin("reflect", kotlinVersion))
    compile("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion")

    "io.vertx:vertx".let { v ->
        compile("$v-lang-kotlin:$vertxVersion")
        compile("$v-lang-kotlin-coroutines:$vertxVersion")
        compile("$v-web:$vertxVersion")
        compile("$v-mongo-client:$vertxVersion")
        compile("$v-health-check:$vertxVersion")
        compile("$v-web-templ-thymeleaf:$vertxVersion")
    }

    compile("org.slf4j:slf4j-api:1.7.14")
    compile("ch.qos.logback:logback-classic:1.1.3")
    compile("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.0.pr3")

    testCompile(kotlin("test", kotlinVersion))
    testCompile(kotlin("test-junit", kotlinVersion))
    testCompile("io.vertx:vertx-unit:$vertxVersion")
    testCompile("org.mockito:mockito-core:2.6.2")
    testCompile("junit:junit:4.11")
}

// Part 2
}

The second part of the example project starts with defining repositories, which are used to find dependencies and plugins declared earlier. Again, we see an example of simplifying the code with the help of using the language: The custom Maven repositories are defined using the functional method forEach, and thus shortens the boilerplate. After that, the plugins are being configured, which for instance is necessary for enabling coroutine support or defining the application properties. Finally, we can observe a sequence of task configurations that control the behavior of single build steps, e.g. tests.

// ...Part 1

repositories {
    mavenCentral()
    jcenter()
    listOf("https://www.seasar.org/maven/maven2/",
            "https://plugins.gradle.org/m2/",
            nexusRepo).forEach {
        maven { url = uri(it) }
    }
}

kotlin {
    experimental.coroutines = Coroutines.ENABLE
}

application {
    group = "de.swirtz"
    version = "1.0.0"
    applicationName = "gradle-kotlindsl"
    mainClassName = "de.swirtz.ApplicationKt"
}

publishing {
    repositories {
        maven {
            url = uri(nexusRepo)
        }
    }
    if (!project.hasProperty("jenkins")) {
        println("Property 'jenkins' not set. Publishing only to MavenLocal")
    } else {
        (publications) {
            "maven"(MavenPublication::class) {
                from(components["java"])
            }
        }
    }
}

tasks {
    withType<KotlinCompile> {
        kotlinOptions.jvmTarget = "1.8"
    }

    withType<Test> {
        testLogging.showStandardStreams = true
    }

    withType<Jar> {
        manifest {
            attributes["Main-Class"] = application.mainClassName
        }
        from(configurations.runtime.map { if (it.isDirectory) it else zipTree(it) })
    }

    withType<GradleBuild> {
        finalizedBy("publishToMavenLocal")
    }
}

The Result

We’ve seen a rather simple build script written with the Gradle Kotlin DSL. I made use of a few idiomatic Kotlin functions in order to show the power of such .kts files. Especially for Kotlin developers, it can make much sense to completely switch to the shown approach. IntelliJ does support the creation of new build.gradle.kts files by default when you open the “New” option in “Project” view.

There will be situations, which make you want to ask somebody for help. I recommend reaching out directly in the corresponding Kotlin Slack channel: gradle.

I hope I could inspire you to give it a try! Good Luck 🙂

The whole script as a Gist

Please follow and like this Blog 🙂
Setup Vert.x Application written in Kotlin with Gradle

Setup Vert.x Application written in Kotlin with Gradle

I decided to write a Vert.x application in combination with Kotlin in a simple example because I’m really interested in Reactive Programming and love to use Kotlin. In this post, I will give some basic information on Vert.x as a tool set for writing reactive applications on the JVM and also introduce Kotlin a bit. In the end, I want to demonstrate how this application can be set up in Gradle.

Read More Read More

Please follow and like this Blog 🙂

Enjoy this blog? Please spread the word :)