JetBrains Space Help

Run Kotlin Code

As the Automation DSL is based on Kotlin, you can run any Kotlin code inside job steps. In case of a container, you should put your code inside the kotlinScript block. For example:

job("Build and publish") { container(displayName = "Run publish script", image = "gradle:6.1.1-jre11") { kotlinScript { api -> api.gradle("build") try { api.gradle("publish") } catch (ex: Exception) { println("Publishing failed") } } } }

How it works under the hood (with some simplification): Space compiles the script into a .jar file and runs it with a command like java -jar script.jar. This means that the image you use to run the script must include JRE/JDK (version 9 or later).

Working with build tools, Automation features, and Space modules from Kotlin code

The kotlinScript block provides various helper APIs:

  • Working with build tools (currently, Gradle only).

  • Accessing build-related information and features: getting a Git branch, a script execution number, accessing the file share, and so on.

  • Accessing various Space modules (Chats, Documents, Issues, and so on) right from the Kotlin code. Learn more

Find the full list of APIs here.

In the example below we use api.gradlew() to run commands using the Gradle wrapper and api.gitBranch() to get the name of the current branch:

job("Example") { container(image = "gradle:7.1-jre11", displayName = "Use helper APIs") { kotlinScript { api -> api.gradlew("build") // run publish task for release branches if (api.gitBranch().contains("release")) { api.gradlew("publish") } } } }

Using Maven libraries

kotlinScript lets you use functions from external packages. To do this, you should reference the required package with the @file:DependsOn("$package_name") annotation. The $package_name is the name of the package available on Maven Central.

For example, the following script uses an OkHttp client to get the content of example.com and prints it to the job's log.

@file:DependsOn("com.squareup.okhttp:okhttp:2.7.4") import com.squareup.okhttp.* job("Get example.com") { container(image = "openjdk:11") { kotlinScript { val client = OkHttpClient() val request = Request.Builder().url("http://example.com").build() val response = client.newCall(request).execute() println(response) } } }

Using Kotlin to its full potential

One of the greatest things about Automation scripts is that they let you use full-featured Kotlin: in .space.kts you can create classes, extension methods, use coroutines, and much more.

For example, the following job uploads multiple files (say, build artifacts) to an external server over HTTP. As this may take a lot of time, the job uses Kotlin coroutines to upload the files asynchronously.

The example uses a Ktor HTTP client. Learn more about sending HTTP requests.

@file:DependsOn("io.ktor:ktor-client-core:1.6.0", "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0", "org.jetbrains.kotlinx:kotlinx-coroutines:0.19.2") import io.ktor.client.* import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.http.* import java.io.File import io.ktor.client.request.forms.* import io.ktor.client.statement.* import io.ktor.utils.io.core.* import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking job("Use Kotlin coroutines") { container(image = "openjdk:11", displayName = "Upload files to external server") { // get auth token from a project secret env["TOKEN"] = Secrets("auth-token") kotlinScript { val url = "https://external-service.url/upload" val token = System.getenv("TOKEN") // generate random text files // in real life, this could be build artifacts println("Generating files...") val files = FileGenerator.getTxtFiles(10, 100000, "log") // run a coroutine runBlocking { println("Starting upload...") files.forEach { // upload each file asynchronously val response = async { uploadFile(url, token, it) } // wait for response from server and print it to job log println("Response from server: ${response.await().receive<String>()}") } } } } } // upload a file to a remote server // uploading is a long operation that must not block other threads // that's why we made it a 'suspending function' that should be run from a coroutine suspend fun uploadFile(url: String, authToken: String, file: File): HttpResponse { val client = HttpClient() return client.post(url) { headers { append("Authorization", "Bearer $authToken") } body = MultiPartFormDataContent( formData { this.appendInput( key = file.name, headers = Headers.build { append(HttpHeaders.ContentDisposition,"filename=${file.name}") }, size = file.length() ) { buildPacket { writeFully(file.readBytes()) } } } ) } } // put all file generation activity in one place object FileGenerator { // create text files with random content // these files emulate output of a build script fun getTxtFiles(numberOfFiles: Int, length: Int, name: String): List<File> { return (0..numberOfFiles) .map { val file = File("$name$it.txt") file.writeText(getRandomString(length)) file } } private fun getRandomString(length: Int) : String { val chars = ('A'..'Z') + ('a'..'z') + ('0'..'9') return (1..length) .map { chars.random() } .joinToString("") } }
Last modified: 18 August 2021