Created
May 24, 2026 15:27
-
-
Save dgengtek/c64b02d794aa7d5a3512d49d9d3b66b2 to your computer and use it in GitHub Desktop.
Concourse pipeline schema definition in Nickel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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