Skip to content

Instantly share code, notes, and snippets.

@dgengtek
Created May 24, 2026 15:27
Show Gist options
  • Select an option

  • Save dgengtek/c64b02d794aa7d5a3512d49d9d3b66b2 to your computer and use it in GitHub Desktop.

Select an option

Save dgengtek/c64b02d794aa7d5a3512d49d9d3b66b2 to your computer and use it in GitHub Desktop.
Concourse pipeline schema definition in Nickel
let DurationContract =
std.contract.from_predicate (fun value =>
if std.typeof value != 'String then
false
else
# Simple validation for duration strings like "1m", "1h", etc. In practice, more robust parsing could be added.
std.string.is_match "^[0-9]+[smhd]$" value
)
in
let UrlContract =
std.contract.from_predicate (fun value =>
if std.typeof value != 'String then
false
else
std.string.is_match "^(http|https)://.*" value || std.string.is_match "^/.*" value
)
in
let CssFilterContract =
std.contract.from_predicate (fun value =>
if std.typeof value != 'String then false else true # Placeholder; validate CSS filter syntax if needed
)
in
let PositiveNumber = std.contract.from_predicate (fun x => x > 0) in
let NonNegativeNumber = std.contract.from_predicate (fun x => x >= 0) in
let Version =
std.contract.any_of [
"latest" | String,
"every" | String,
Dyn # For specific version objects
]
in
let Inputs =
std.contract.any_of [
String,
Array String
]
in
let ContainerLimits = {
cpu | optional | NonNegativeNumber = 0,
memory | optional | NonNegativeNumber = 0,
}
in
let Input = {
name | String,
}
in
let Output = {
name | String,
}
in
let ImageResource = {
type | String,
source | Dyn,
}
in
let Run = {
path | String,
args | optional | Array String,
}
in
let TaskConfig = {
platform | optional | String,
image_resource | optional | ImageResource,
run | Run,
inputs | optional | Array Input,
outputs | optional | Array Output,
params | optional | Dyn,
container_limits | optional | ContainerLimits,
hermetic | optional | Bool,
}
in
let GetStep = {
get | String,
resource | String | optional,
passed | optional | Array String,
params | optional | Dyn,
trigger | optional | Bool,
version | optional | Version,
}
in
let SetPipelineStep = {
set_pipeline | String,
file | String,
var_files | optional | Array String,
vars | optional | Dyn,
instance_vars | optional | Dyn,
team | optional | String,
}
in
let PutStep = {
put | String,
resource | String | optional,
inputs | optional | Inputs,
params | optional | Dyn,
get_params | optional | Dyn,
no_get | optional | Bool,
}
in
let TaskStep = {
task | String,
config | optional | TaskConfig,
file | optional | String,
image | optional | String,
privileged | optional | Bool,
vars | optional | Dyn,
params | optional | Dyn,
container_limits | optional | ContainerLimits,
hermetic | optional | Bool,
input_mapping | optional | Dyn,
output_mapping | optional | Dyn,
tags | optional | Array String,
}
in
let rec Step =
std.contract.custom (fun label value =>
let HookStep = {
across
| Array {
var | String,
values | Array String,
max_in_flight | optional | PositiveNumber,
}
| optional,
timeout | String | DurationContract | optional,
attempts | PositiveNumber | optional,
tags | optional | Array String,
on_success | Step | optional,
on_failure | Step | optional,
on_abort | Step | optional,
on_error | Step | optional,
ensure | Step | optional,
}
in
let InParallel = {
limit | optional | PositiveNumber,
fail_fast | optional | Bool,
steps | Array Step,
}
in
let identifier_exists = fun id => std.record.has_field id value in
let check_contract = fun contract => std.contract.check contract label value in
check_contract (
if identifier_exists "get" then
GetStep & HookStep
else if identifier_exists "put" then
PutStep & HookStep
else if identifier_exists "task" then
TaskStep & HookStep
else if identifier_exists "set_pipeline" then
SetPipelineStep & HookStep
else if identifier_exists "in_parallel" then
{ in_parallel | InParallel }
else if identifier_exists "do" then
{ do | Array Step }
else if identifier_exists "try" then
{ try | Step }
else if identifier_exists "retry" then
{ retry | { times | PositiveNumber, step | Step } }
else
std.contract.blame_with_message "Unable to match any step" label
)
)
in
let BuildLogRetention = {
days | optional | NonNegativeNumber,
builds | optional | PositiveNumber,
minimum_succeeded_builds | optional | NonNegativeNumber = 0,
}
in
let Job = {
name | String,
plan | Array Step,
old_name | optional | String,
serial | optional | Bool,
serial_groups | optional | Array String,
max_in_flight | optional | PositiveNumber,
build_log_retention | optional | BuildLogRetention,
build_logs_to_retain | optional | PositiveNumber, # Deprecated
public | optional | Bool = false,
disable_manual_trigger | optional | Bool,
interruptible | optional | Bool,
on_success | optional | Step,
on_failure | optional | Step,
on_error | optional | Step,
on_abort | optional | Step,
ensure | optional | Step,
}
in
let Resource = {
name | String,
type | String,
source | Dyn,
old_name | optional | String,
icon | optional | String,
version | optional | Dyn,
check_every | optional | String | DurationContract,
check_timeout | optional | String | DurationContract,
expose_build_created_by | optional | Bool,
tags | optional | Array String,
public | optional | Bool,
webhook_token | optional | String,
}
in
let ResourceType = {
name | String,
type | String,
source | Dyn,
privileged | optional | Bool,
params | optional | Dyn,
check_every | optional | String | DurationContract,
tags | optional | Array String = [],
defaults | optional | Dyn,
}
in
let VarSourceConfig = Dyn in # Type-specific, can be expanded with unions
let VarSource = {
name | String,
type | std.contract.Enum ["vault", "ssm", "dummy", "idtoken"],
config | VarSourceConfig,
}
in
let Group = {
name | String,
jobs | Array String,
}
in
let Display = {
background_image | String | UrlContract,
background_filter | optional | String | CssFilterContract,
}
in
let Pipeline = {
jobs | Array Job | std.contract.from_predicate (fun arr => std.array.length arr > 0),
resources | optional | Array Resource,
resource_types | optional | Array ResourceType,
var_sources | optional | Array VarSource,
groups | optional | Array Group,
display | optional | Display,
}
in
Pipeline
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment