Starlark, the configuration language for Bazel, is actually a restricted subset of Python designed for safe, deterministic execution within a larger system, not a full-blown programming language.
Let’s see how Drone CI leverages Starlark to define complex pipelines with code.
Imagine you have a project that needs to build a Docker image, run tests, and then deploy to Kubernetes. Without Starlark, this would be a series of static YAML blocks. With Starlark, you can make this dynamic.
Here’s a simplified drone.star file:
# drone.star
load("github.com/drone/drone-go/drone", "matrix")
def build_matrix(arch, os):
return {
"name": "build-" + arch + "-" + os,
"arch": arch,
"os": os,
"steps": [
{
"name": "build-" + arch + "-" + os + "-binary",
"image": "golang:1.19",
"commands": [
"go build -o app -v",
"echo 'Built for ' + arch + ' on ' + os",
],
}
],
}
def deploy_stage(env):
return {
"name": "deploy-" + env,
"steps": [
{
"name": "deploy-to-" + env,
"image": "plugins/kubernetes",
"settings": {
"namespace": env,
"kubeconfig": "#!/bin/bash\necho $KUBECONFIG_" + env.upper(),
},
}
],
}
# Define different build targets
builds = [
build_matrix("amd64", "linux"),
build_matrix("arm64", "linux"),
]
# Define deployment environments
deploys = [
deploy_stage("staging"),
deploy_stage("production"),
]
# Combine them into a pipeline
matrix(
builds + deploys,
name="pipeline",
)
In this example:
- We
loadthematrixfunction from the Drone Go library, which is how Drone injects its core pipeline building blocks. build_matrixanddeploy_stageare Python-like functions that generate pipeline stage configurations. They take arguments like architecture, OS, or environment.buildsanddeploysare lists that use these functions to create multiple build and deploy stages. Notice howbuild_matrixdynamically generates names and commands based on its inputs.- Finally,
matrix(builds + deploys, name="pipeline")concatenates these generated stages into a single, dynamic pipeline definition. Drone executes this Starlark script and interprets the resulting data structure as its pipeline.
This isn’t just about generating repetitive YAML. It’s about defining a process that can adapt. If you needed to add a new architecture, you’d just add another entry to the builds list, not duplicate blocks of YAML.
The most surprising thing about Starlark in Drone is how it enforces immutability and determinism. Even though it looks like Python, you can’t, for example, open files, access the network, or call arbitrary external processes. This restriction is crucial because Drone needs to execute your pipeline definition reliably and reproducibly on any agent, without side effects that could compromise build security or consistency. The language is designed to produce a data structure, not to perform arbitrary computation.
The next concept you’ll run into is how to manage secrets and sensitive information within these Starlark-defined pipelines, as directly embedding them would violate the security principles Starlark enforces.