DSL Reference
The Automation DSL is a domain specific language whose goal is to help you write Space automation scripts. The DSL is based on Kotlin programming language. This means that you can use Kotlin data types and language constructs inside your scripts.
job
is a defined task consisting of steps.
job(name: String, init: Task.() -> Unit)
| |
|
For example:
job("Hello World!") {
container(image = "hello-world")
}
requirements
specifies requirements to the job run environment.
requirements(init: ScriptJobRequirementsBuilder.() -> Unit)
|
For example:
job("Example") {
host("Run it on macOS") {
shellScript {
location = "./myscript.sh"
}
requirements {
os { type = OSType.Mac }
}
}
}
container
runs a container and executes the specified command or script inside this container.
container(image: String, init: Container.() -> Unit = {})
container(displayName: String?, image: String, init: Container.() -> Unit = {})
| |||||||||||||||||||||
| |||||||||||||||||||||
|
warning
kotlinScript
,shellScript
, andargs
|entrypoint
items are mutually exclusive. You should specify only one of them inside acontainer
. If you specify more than one, the job will fail.
For example:
job("Example") {
// in the container with 'gradle' image
container(image = "gradle") {
// run 'gradle build'
shellScript {
content = "gradle build"
}
}
}
If entrypoint
is specified, args
provides arguments for the entrypoint
command. Otherwise, args
provides arguments for the default image command (for example, set by ENTRYPOINT
). Each argument must be a separate string in the args
array. If you specify more than one args
, only the last one will take effect.
note
The max total size of container arguments, environment variables, secrets, and parameters cannot be larger than 30KB. Otherwise, a step will fail.
args(vararg args: String)
For example:
job("Example args") {
container(image = "alpine") {
args("echo", "Hello World!")
}
}
cache
speeds up builds by caching project dependencies in a file repository. Learn more
cache(init: FileCache.() -> Unit)
|
For example:
job("File caches") {
container(displayName = "Use cache", image = "node") {
cache {
storeKey = "npm-{{ hashFiles('package.json') }}"
restoreKeys {
+"npm-master"
}
localPath = "node_modules/*"
}
// here goes the rest of the script
}
}
dockerRegistryConnections
defines Docker registries to log into before running the container
step. The step can use an image from these Docker registries. This makes possible using images from registries that require authentication. Note that the corresponding registry connections should first be declared in your project settings. Learn more
warning
It is not possible to use login credentials with the Docker CLI from inside the
container
, because the Docker configuration and the corresponding credential stores are located on the host machine. If you want to communicate with private registries via the Docker CLI from inside the container, declare project secrets with the registry credentials, and manually rundocker login
in the container.
dockerRegistryConnections(init: DockerRegistryConnections.() -> Unit)
Inside dockerRegistryConnections
, use the unary +
operator to add connections.
For example:
job("Example") {
container(displayName = "Get image from private registry", image = "some.registry.com/image:1.2.3") {
dockerRegistryConnections {
// some-registry is the connection key
// the connection contains registry URL and access credentials
+"some-registry"
}
// here goes the rest of the script
}
}
entrypoint
runs the specified command overriding the default image command. This is equivalent to Docker's ENTRYPOINT
. Command arguments must be provided as separate strings in the args
array . If you specify more than one entrypoint
, only the last one will take effect.
entrypoint(entryPoint: String)
For example:
job("Example entrypoint") {
// override the default command set in 'myImage'
container(image = "myImage") {
entrypoint("/bin/sh")
args("echo", "Hello World!")
}
}
env
lets you set environment variables in a container. Note that you can get various information about the current run context with the help of Automation environment variables.
env = Environment()
The
|
For example:
job("Example") {
container(image = "alpine") {
env.set("SITE_URL", "staging.mysite.com")
}
}
fileArtifacts
uploads file artifacts generated by the step to a file repository. Learn more
fileArtifacts(init: FileArtifact.() -> Unit)
|
For example:
job("Generate zip file") {
container(image = "ubuntu") {
// Here goes some code...
fileArtifacts {
localPath = "build/build.zip"
remotePath = "{{ run:number }}/build.zip"
}
}
}
fileInput
populates a file from one of the specified sources. Learn more
fileInput(init: FileInput.() -> Unit)
|
For example:
job("File artifacts") {
container(displayName = "Create file", image = "ubuntu") {
fileInput {
source = FileSource.FileArtifact("repo-name", "artifacts/remote-file.txt")
localPath = "local-file.txt"
}
// here goes the rest of the script
}
}
kotlinScript
runs arbitrary Kotlin code. If you specify more than one kotlinScript
, only the last one will be run. Note that in order to run a Kotlin script, the container image you use must include JRE/JDK 11 or later.
kotlinScript(init: ProcessKotlinScript.(ScriptAPI) -> Unit)
For example:
job("Example kotlin script") {
container(image = "amazoncorretto:17-alpine") {
kotlinScript { api ->
if (api.gitBranch() == "refs/heads/main") {
println("Running in main branch")
} else {
println("Running in custom branch")
}
}
}
}
job("Example script") {
container(image = "amazoncorretto:17-alpine") {
kotlinScript { api ->
val totalMembers = api.space().teamDirectory.stats.getAllStats().totalMembers
val user = ChannelIdentifier.Profile(ProfileIdentifier.Username("Anna"))
val msg = ChatMessage.Text("Hi! Employees total is $totalMembers")
api.space().chats.messages.sendMessage(channel = user, content = msg)
}
}
}
kotlinScript
provides access to various APIs. The APIs let you work with particular Space modules or with build tools like Gradle. Currently, the following APIs are available:
Function | Returns | Description |
---|---|---|
|
| Runs Gradle commands using the Gradle wrapper from the project sources. For example: |
|
| Returns the URL of your Space instance. |
|
| Returns the name of the current Git branch. For example, |
|
| Returns the current Git revision number. For example, |
|
| Returns the number of the current Automation script execution. You can use this number, for example, to generate the application version number. |
|
| Returns the ID and the key of the current project. |
|
| Returns the current client ID and secret. These are temporary OAuth 2.0 credentials issued to the current script. The script uses them to authenticate in various Space modules. For example, you might need it to authenticate in a Packages repository in order to publish script artifacts. |
|
| Lets you use parameters in Kolin scripts. Learn more |
|
| Lets you use project secrets in Kolin scripts. Learn more |
| Lets you share files between job steps. Learn more | |
| Lets you work with various Space modules. For example:
The Space modules API works through the Space HTTP API. In other words, |
resources
limits the resources for a container. The default resources constraints are:
2 virtual CPUs
7800 MB memory
resources(init: ExplicitResources.() -> Unit)
|
For example:
job("Example") {
container(image = "alpine") {
resources {
cpu = 1.cpu
memory = 2000.mb
}
}
}
requirements
specifies requirements to the host machine that should be used to run the step. Specify requirements
in case you want to run a job with a container
step not in the Space cloud but on a specific worker. Learn more
requirements(init: ContainerRequirementsBuilder.() -> Unit)
|
For example:
job("Example") {
container(displayName = "Run in a worker", image = "amazoncorretto:17-alpine") {
shellScript {
location = "./myscript.sh"
}
requirements {
workerTags("Pool1")
}
}
}
runIf
lets you run a step on a specific condition. If runIf
is an empty string, false
, or code block that returns 0
, the step is skipped. Learn more
runIf(condition: String)
For example:
job("Example") {
container(displayName = "Check branch", image = "ubuntu") {
kotlinScript { api ->
api["isMainBranch"] = (api.gitBranch() == "refs/heads/main").toString()
}
}
container(displayName = "Check branch", image = "ubuntu") {
// This step will run only if the branch is "main"
runIf("{{ isMainBranch }}")
// ...
}
}
service
runs a container with a network-accessible service. Learn more
service(image: String, init: Service.() -> Unit = {})
| |||||||||||||||
|
For example:
job("ping") {
container(image = "alpine") {
// ping service 5 times
shellScript {
content = "ping -c 5 db"
}
service("mysql:5.7") {
alias("db")
env["MYSQL_ROOT_PASSWORD"] = "pwd1234"
}
}
}
shellScript
runs the provided shell script.
shellScript(init: ContainerShellScript.() -> Unit)
|
For example:
job("Example shell scripts") {
container(image = "ubuntu") {
shellScript {
interpreter = "/bin/bash"
content = """
echo 'echo Username: $1 Password: $2' >> /mnt/space/share/myscript.sh
chmod +x /mnt/space/share/myscript.sh
"""
}
}
container(image = "ubuntu") {
shellScript {
location = "/mnt/space/share/myscript.sh"
args("anna", "1234")
}
}
// In job logs, we'll see 'Username: anna Password: 1234'
}
Note that marking the script file as executable with chmod +x
is not necessary: Automation automatically sets the 'executable' flag for the script file specified in location
.
host
executes the specified script directly on a host machine. This could be a hosted or a cloud worker.
host(displayName: String? = null, init: Host.() -> Unit = {})
| |||||||||
|
warning
kotlinScript
andshellScript
elements are mutually exclusive. You should specify only one of them inside ahost
. If you specify more than one, the job will fail.
For example:
job("Example") {
host("Run build") {
// run msbuild
shellScript {
content = """
C:\"Program Files (x86)"\MSBuild\14.0\Bin\MsBuild.exe MySolution.sln
"""
}
// on any worker with Windows
requirements {
type = OSType.Windows
}
}
}
cache
speeds up builds by caching project dependencies in a file repository. Learn more
cache(init: FileCache.() -> Unit)
|
For example:
job("File caches") {
host {
cache {
storeKey = "npm-{{ hashFiles('package.json') }}"
restoreKeys {
+"npm-master"
}
localPath = "node_modules/*"
}
// here goes the rest of the script
}
}
dockerBuildPush
is a special helper block used to build and publish Docker images in self-hosted or Space Cloud workers. Learn more
dockerBuildPush(displayName: String? = null, init: DockerBuildPushAction.() -> Unit)
| |||||||||||||||||||||
|
For example:
job("Build and push Docker") {
host("Build and push a Docker image") {
dockerBuildPush {
push = true
context = "docker"
// ./docker/Dockerfile
file = "docker/Dockerfile"
tags {
+"mycompany.registry.jetbrains.space/p/prjkey/mydocker/myimage:1.0.${"$"}JB_SPACE_EXECUTION_NUMBER"
}
}
}
}
dockerRegistryConnections
defines Docker registries to log into before running the host
step. This makes possible using registries that require authentication inside the host
step. For example, you can publish images to such repositories. Note that the corresponding registry connections should first be declared in your project settings. Learn more
dockerRegistryConnections(init: DockerRegistryConnections.() -> Unit)
Inside dockerRegistryConnections
, use the unary +
operator to add connections.
For example:
job("Example") {
host {
dockerRegistryConnections {
// some-registry-1 and -2 are the connection keys
// the connection contains registry URL and access credentials
+"some-registry-1"
+"some-registry-2"
}
dockerBuildPush {
tags {
+"myimages/myimage:1.0.1"
}
}
}
}
env
lets you set environment variables on the host machine. Note that you can get various information about the current run context with the help of Automation environment variables.
env = Environment()
The
|
For example:
job("Example") {
container(image = "alpine") {
// one way to set env var
env.set("SITE_URL", "staging.mysite.com")
// another way to set env var
env["USERNAME"] = "anna"
}
}
fileArtifacts
uploads file artifacts generated by the step to a file repository. Learn more
fileArtifacts(init: FileArtifact.() -> Unit)
|
For example:
job("Generate zip file") {
host {
// Here goes some code...
fileArtifacts {
localPath = "build/build.zip"
remotePath = "{{ run:number }}/build.zip"
}
}
}
fileInput
populates a file from one of the specified sources. Learn more
fileInput(init: FileInput.() -> Unit)
|
For example:
job("File artifacts") {
host {
fileInput {
source = FileSource.FileArtifact("repo-name", "artifacts/remote-file.txt")
localPath = "local-file.txt"
}
// here goes the rest of the script
}
}
kotlinScript
runs arbitrary Kotlin code.
kotlinScript(init: ProcessKotlinScript.(ScriptAPI) -> Unit)
For example:
job("Example Kotlin script") {
host {
kotlinScript { api ->
if (api.gitBranch() == "refs/heads/main") {
println("Running in main branch")
} else {
println("Running in custom branch")
}
}
}
}
job("Example Kotlin script") {
host {
kotlinScript { api ->
val totalMembers = api.space().teamDirectory.stats.getAllStats().totalMembers
val user = ChannelIdentifier.Profile(ProfileIdentifier.Username("Anna"))
val msg = ChatMessage.Text("Hi! Employees total is $totalMembers")
api.space().chats.messages.sendMessage(channel = user, content = msg)
}
}
}
kotlinScript
provides access to various APIs. The APIs let you work with particular Space modules or with build tools like Gradle. For the full list of available APIs, refer to job.container.kotlinScript
requirements
specifies requirements to the host machine that should be used to run the step. Learn more
requirements(init: HostRequirementsBuilder.() -> Unit)
|
For example:
job("Example") {
host("Run it on macOS") {
shellScript {
location = "./myscript.sh"
}
requirements {
os { type = OSType.Mac }
}
}
}
os
specifies the required operating system. Automation will route the job only to the worker with the specified operating system. Learn more
os(configure: OSRequirementsBuilder.() -> Unit)
|
For example:
job("Example") {
host("Run it on Ubuntu") {
shellScript {
location = "./myscript.sh"
}
requirements {
os {
type = OSType.Linux
version = "ubuntu-20.02"
arch = "x86_64"
}
// run on Linux Mint
// os {
// name = "Linux Mint"
// arch = "x86"
// }
}
}
}
resources
specifies requirements to the available system resources (CPU cores and RAM) on the host machine. Automation will route the job only to the worker with the sufficient resources. Learn more
resources(configure: ResourceRequirementsBuidler.() -> Unit)
|
For example:
job("Example") {
host("Run it on Ubuntu") {
shellScript {
location = "./myscript.sh"
}
requirements {
resources {
minCpu = 4000
minMemory = 10.gb
}
}
}
}
workerTags
specifies the required tag(s). Automation will route the job only to the worker that is marked with the specified tag(s). Learn more
workerTags(vararg tags: String)
For example:
job("Example") {
host("Run it on machines from pool-1 and pool-2") {
shellScript {
location = "./myscript.sh"
}
requirements {
workerTags("pool-1", "pool-2")
}
}
}
runIf
lets you run a step on a specific condition. If runIf
is an empty string, false
, or code block that returns 0
, the step is skipped. Learn more
runIf(condition: String)
For example:
job("Example") {
host {
kotlinScript { api ->
api["isMainBranch"] = (api.gitBranch() == "refs/heads/main").toString()
}
}
host {
// This step will run only if the branch is "main"
runIf("{{ isMainBranch }}")
// ...
}
}
shellScript
runs the specified shell script.
shellScript(displayName: String? = null, init: HostShellScript.() -> Unit)
| |||||||||
|
For example:
job("Job with host and container") {
host("Prepare myscript.sh") {
shellScript {
interpreter = "/bin/bash"
content = """
echo Username: $1' >> ../../share/myscript.sh
echo Password: $2' >> ../../share/myscript.sh
chmod +x ../../share/myscript.sh
"""
}
}
// it's fine to use both 'host' and 'container' in one job
container(image = "ubuntu") {
shellScript {
location = "/mnt/space/share/myscript.sh"
args("anna", "1234")
}
}
// In job logs, we'll see 'Username: anna Password: 1234'
}
Note that marking the script file as executable with chmod +x
is not necessary: Automation automatically sets the 'executable' flag for the script file specified in location
.
git
lets you specify Git repository checkout options. There are two main use-cases of the git
item:
Fetching additional branches and revisions: By default, Automation checks out only the current revision (the one that contains the currently running
.space.kts
script).Checking out additional repositories in projects with multiple repositories: When the build script requires the source code from several repositories at once.
git(init: DefaultGitRepository.() -> Unit = {})
git(repositoryName: String, init: ExternalGitRepository.() -> Unit = {})
| |||||||||||
|
For example:
job("git checkout") {
git {
// get all commits for the main repo
depth = UNLIMITED_DEPTH
}
// checkout repo-2 as well
git("repo-2") {
// put it inside /mnt/space/work/secondRepo
cloneDir = "secondRepo"
// fetch the new-feature branch (not check out!)
refSpec = "new-feature"
}
container(image = "alpine") {
shellScript {
content = """
echo Checked-out repos:
ls /mnt/space/work
echo Working dir:
pwd
"""
// Checked-out repos:
// /mnt/space/work/main-project-repo
// /mnt/space/work/secondRepo
// Working dir:
// /mnt/space/work/main-project-repo
}
}
}
By default, all container
steps are executed sequentially inside a job
. To execute them in parallel, put them inside a parallel
block.
parallel(init: StepFork.() -> Unit)
|
For example:
job("Example") {
// I run before others
container(displayName = "Step 1", image = "alpine") {
args("echo", "1")
}
parallel {
// I run after 'Step 1'
container(displayName = "Step 2", image = "alpine") {
args("echo", "2")
}
// I run along with 'Step 2'
container(displayName = "Step 3", image = "alpine") {
args("echo", "3")
}
}
}
sequential
executes container
steps inside the parallel
block sequentially.
sequential(init: StepSequence.() -> Unit)
|
For example:
job("Example") {
// I run before others
container(displayName = "Step 1", image = "alpine") {
args("echo", "1")
}
parallel {
// I run after 'Step 1'
container(displayName = "Step 2", image = "alpine") {
args("echo", "2")
}
sequential {
// I run along with 'Step 2'
container(displayName = "Step 3", image = "alpine") {
args("echo", "3")
}
// I run after 'Step 3' and along with 'Step 2'
container(displayName = "Step 4", image = "alpine") {
args("echo", "4")
}
}
}
}
The parameters
block let you define job parameters as well as reference project secrets and parameters. Learn more
parameters(init: Parameters.() -> Unit)
|
For example:
job("Create configured param") {
parameters {
text("my-param", value = "here goes value")
}
container("ubuntu") {
shellScript {
content = "echo {{ my-param }}"
}
}
// Output:
// here goes value
}
The startOn
block contains events that trigger the job
.
startOn(init: Triggers.() -> Unit)
|
For example:
job("example") {
startOn {
codeReviewOpened{}
}
}
gitPush
runs the job after a commit is pushed to the project repository. By default, the gitPush
trigger is enabled for a project. Important: Once you add any other trigger to the job, the gitPush
trigger will be disabled.
gitPush(init: GitPushTrigger.() -> Unit)
|
For example:
job("example") {
startOn {
// Trigger job on changes in all 'release-*' branches
// excluding 'release-main' and release branches
// with numbers like 'release-42'
// The changes must be only in 'src/mainModule/' and
// its subdirectories, but not in the 'myfile.kt' files
gitPush {
anyBranchMatching {
+"release-*"
-"release-main"
}
pathFilter {
+"src/mainModule/**"
-"**/myfile.kt"
}
}
}
}
warning
The
schedule
trigger works only in the project's default branch (main
).
Runs the job on schedule
. For example, once a day at a certain time (UTC timezone).
schedule(init: ScheduleTrigger.() -> Unit)
|
For example:
job("example") {
startOn {
// every day at 08 AM UTC
schedule { cron("0 8 * * *") }
}
}
gitBranchDeleted
runs the job when a git branch is deleted from the project repository. Works only in the project's default branch (main
).
gitBranchDeleted(init: GitBranchDeletedTrigger.() -> Unit = {})
|
For example:
job("example") {
startOn {
gitBranchDeleted {
anyRefMatching
+"refs/heads/*new-feature*"
-"refs/heads/my-new-feature"
}
}
}
}
codeReviewOpened
runs the job when a code review is opened in the project.
codeReviewOpened(init: CodeReviewOpenedTrigger.() -> Unit = {})
|
For example:
job("example") {
startOn {
codeReviewOpened{
branchToCheckout = CodeReviewBranch.MERGE_REQUEST_SOURCE
}
}
}
codeReviewClosed
runs the job when a code review is closed in the project.
codeReviewClosed(init: CodeReviewClosedTrigger.() -> Unit = {})
|
For example:
job("example") {
startOn {
codeReviewClosed{
branchToCheckout = CodeReviewBranch.MERGE_REQUEST_SOURCE
}
}
}
The failOn
block contains conditions under which a job
will be considered failed. By default, failed tests and non-zero exit code are failure conditions.
failOn(init: FailureConditions.() -> Unit)
|
job("example") {
failOn {
testFailed { enabled = false }
}
}
With nonZeroExitCode
, the job is considered failed when it returns nonzero status code. It is a default failure condition.
nonZeroExitCode(init: NonZeroExitCodeCondition.() -> Unit)
|
job("example") {
failOn {
// disable nonzero code condition
nonZeroExitCode { enabled = false }
}
}
With testFailed
, the job is considered failed if at least one test fails during the job run. It is a default failure condition. Automation detects failed tests by parsing the job output. Currently, only Gradle test output is supported.
testFailed(init: TestFailedCondition.() -> Unit)
|
For example:
job("example") {
failOn {
// disable testFailed condition
testFailed { enabled = false }
}
}
With outOfMemory
, the job is considered failed if any of job containers runs out of memory (based on the OOMKilled
event). It is a default failure condition.
outOfMemory(init: OutOfMemoryCondition.() -> Unit)
|
For example:
job("example") {
failOn {
// disable outOfMemory condition
outOfMemory { enabled = false }
}
}
With timeOut
, the job is considered failed if it cannot start within the specified time period or runs longer than the specified time period. To specify the timeouts period, you should use the timeOutInMinutes
keyword inside timeOut
. The default and maximum allowed timeout is 120 minutes.
timeOut(init: TimeOutFailedCondition.() -> Unit)
|
For example:
job("example") {
failOn {
// fail after 15 minutes
timeOut {
runningTimeOutInMinutes = 15
}
}
}
volumeSize
sets the size of the disk mounted to a container. The disk contains project repository. By default, 5 GiBs. Supports the mb
and gb
units for MB and GB. For example, 10000.mb
or 10.gb
.
volumeSize: Any?
For example:
job("example") {
// mount 10GB volume
volumeSize = 10.gb
}
kaniko
is a special step used to build and publish Docker images. The step runs in a container based on a custom image with the Kaniko tool. Learn more
kaniko(init: KanikoStep.() -> Unit)
|
For example:
job("Build and push Docker") {
container(displayName = "Build sources", image = "amazoncorretto:17-alpine") {
shellScript {
content = """
./gradlew build
cp output mnt/space/share
"""
}
}
kaniko {
beforeBuildScript {
content = "cp mnt/space/share docker"
}
build {
context = "docker"
// ./docker/config/Dockerfile
dockerfile = "config/Dockerfile"
labels["vendor"] = "mycompany"
args["HTTP_PROXY"] = "http://10.20.30.2:1234"
}
push("mycompany.registry.jetbrains.space/mydocker/myimage") {
tags{
+"version1.0"
+"stable"
}
}
}
}
gradlew
is a special helper item that runs Gradle commands using Gradle wrapper from the project directory. Use gradlew
to simplify your build scripts. Learn more
gradlew(image: String? = null, vararg args: String, init: Project.Container.() -> Unit = {})
| |
| |
|
For example:
job("Example") {
// run 'gradlew build'
gradlew(null, "build")
}
warning
(Deprecated). Use a dev environment devfile to configure the warm-up.
warmup
lets you prepare warm-up data for dev environments.
warmup(ide: Ide, profileId: String? = null, init: Warmup.() -> Unit = {})
| |||||||||
| |||||||||
|
For example:
job("Prepare data and build indexes for IDEA") {
warmup(ide = Ide.Idea) {
scriptLocation = "./dev-env-warmup.sh"
devfile = "./devfile.yaml"
}
}
warning
(Deprecated). Use a dev environment devfile to configure the warm-up.
env
lets you set environment variables in a dev environment container. Note that you can get various information about the current run context with the help of Automation environment variables.
env = Environment()
The
|
For example:
job("My project warmup data") {
warmup(ide = Ide.Fleet, profileId = "fleet") {
// some env var that might be needed for the script
env["USERNAME"] = "SpaceUser"
requirements {
workerTags("fleet")
}
scriptLocation = "./dev-env-warmup.sh"
}
}
Thanks for your feedback!