1package buildkite
2
3import (
4 "strings"
5 "list"
6 "struct"
7 "regexp"
8)
9
10// JSON schema for Buildkite pipeline configuration files
11#Pipeline: {
12 @jsonschema(schema="http://json-schema.org/draft-07/schema#")
13 "env"?: #env
14 "agents"?: #agents
15 "notify"?: #buildNotify
16 "image"?: #image
17 "secrets"?: #secrets
18 "priority"?: #priority
19
20 // Configure git checkout behavior. Pipeline-level values are inherited by each
21 // step unless that step overrides the same key. ssh_secret is step-level only
22 // and is not valid here
23 "checkout"?: #checkout &
24 (null | bool | number | string | [...] | {
25 "ssh_secret"?: error("disallowed")
26 ...
27 })
28 "steps"!: #pipelineSteps
29 ...
30
31 #agents: matchN(1, [#agentsObject, #agentsList])
32
33 // Query rules to target specific agents in k=v format
34 #agentsList: [...string]
35
36 // Query rules to target specific agents
37 #agentsObject: {...}
38
39 // Whether to proceed with this step and further steps if a step named in the
40 // depends_on attribute fails
41 #allowDependencyFailure: true | false | "true" | "false"
42
43 // A list of teams that are permitted to unblock this step, whose values are a
44 // list of one or more team slugs or IDs
45 #allowedTeams: matchN(>=1, [string, [...string]])
46
47 #automaticRetry: close({
48 // The exit status number that will cause this job to retry
49 "exit_status"?: matchN(>=1, ["*", int, [...int]])
50
51 // The number of times this job can be retried
52 "limit"?: int & >=0 & <=10
53
54 // The exit signal, if any, that may be retried
55 "signal"?: string
56
57 // The exit signal reason, if any, that may be retried
58 "signal_reason"?: "*" |
59 "none" |
60 "agent_incompatible" |
61 "agent_refused" |
62 "agent_stop" |
63 "cancel" |
64 "process_run_error" |
65 "signature_rejected" |
66 "stack_error"
67 })
68
69 #automaticRetryList: [...#automaticRetry]
70
71 #blockStep: close({
72 "allow_dependency_failure"?: #allowDependencyFailure
73
74 // The label of the block step
75 "block"?: _#defs."/definitions/blockStep/properties/block"
76
77 // The state that the build is set to when the build is blocked by this block step
78 "blocked_state"?: "passed" | "failed" | "running"
79 "branches"?: #branches
80 "depends_on"?: #dependsOn
81 "fields"?: #fields
82 "if"?: #if
83 "key"?: _#defs."/definitions/blockStep/properties/key"
84 "identifier"?: _#defs."/definitions/blockStep/properties/key"
85 "id"?: _#defs."/definitions/blockStep/properties/key"
86 "label"?: _#defs."/definitions/blockStep/properties/block"
87 "name"?: _#defs."/definitions/blockStep/properties/block"
88 "prompt"?: #prompt
89 "allowed_teams"?: #allowedTeams
90 "type"?: "block"
91 })
92
93 // Which branches will include this step in their builds
94 #branches: matchN(>=1, [string, [...string]])
95
96 // Array of notification options for this step
97 #buildNotify: [
98 ...matchN(1, [
99 #notifySimple,
100 #notifyEmail,
101 #notifyBasecamp,
102 #notifySlack,
103 #notifyWebhook,
104 #notifyPagerduty,
105 #notifyGithubCommitStatus,
106 #notifyGithubCheck,
107 ])
108 ]
109
110 // The paths for the caches to be used in the step
111 #cache: matchN(>=1, [
112 string,
113 [...string], {
114 "paths"!: [...string]
115 "size"?: =~"^\\d+g$"
116 "name"?: string
117 ...
118 }
119 ])
120
121 // Whether to cancel the job as soon as the build is marked as failing
122 #cancelOnBuildFailing: true | false | "true" | "false"
123
124 // Configure git checkout behavior. Pipeline-level values are inherited by each
125 // step unless that step overrides the same key
126 #checkout: close({
127 // Number of commits to fetch when performing a shallow clone; omit for full history
128 "depth"?: int & >=1 | =~"^[1-9][0-9]*$"
129
130 // Skip the git checkout phase. An explicit null is treated as unset
131 "skip"?: true | false | "true" | "false" | null
132
133 // Initialize, sync, update, and clean submodules recursively as part of
134 // checkout. An explicit null is treated as unset
135 "submodules"?: true | false | "true" | "false" | null
136
137 // Verify the checked-out commit is on the expected branch; strict fails the job
138 // on a definitive mismatch, warn only logs
139 "commit_verification"?: "strict" | "warn"
140
141 // Custom flags passed to git commands during checkout. Flag strings are passed
142 // to git verbatim and are not sanitized; do not interpolate untrusted input.
143 // See the agent documentation for precedence and defaults:
144 // https://buildkite.com/docs/agent/v3/configuration
145 "flags"?: close({
146 // Flags for the git clone command
147 "clone"?: string
148
149 // Flags for the git fetch command
150 "fetch"?: string
151
152 // Flags for the git checkout command
153 "checkout"?: string
154
155 // Flags for the git clean command
156 "clean"?: string
157 })
158
159 // Name of an SSH private key secret from Buildkite Secrets to use for git
160 // clone/fetch operations. The name must start with a letter, contain only
161 // letters, numbers, and underscores, and must not start with `buildkite` or
162 // `bk` (case-insensitive).
163 "ssh_secret"?: matchN(0, [
164 null | bool | number | =~"^([Bb][Uu][Ii][Ll][Dd][Kk][Ii][Tt][Ee]|[Bb][Kk])" | [...] | {...}
165 ]) &
166 strings.MinRunes(1) &
167 strings.MaxRunes(255) &
168 =~"^[A-Za-z][A-Za-z0-9_]*$"
169
170 // Whether to install Git LFS and fetch LFS objects after checkout. An explicit
171 // null is treated as unset
172 "lfs"?: true | false | "true" | "false" | null
173
174 // Check out only the specified paths in git cone mode; requires git 2.27+ on the agent
175 "sparse"?: close({
176 // Repository-relative directory paths within the worktree, as one path or a
177 // list of paths; cone mode includes each directory recursively, not file globs
178 "paths"!: matchN(>=1, [#checkoutSparsePath, list.UniqueItems() & [_, ...] & [...#checkoutSparsePath]])
179 })
180 })
181
182 #checkoutSparsePath: matchN(0, [
183 null |
184 bool |
185 number |
186 =~"^[-\\t\\n\\v\\f\\r \u0085\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]|[\\t\\n\\v\\f\\r \u0085\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]$" |
187 [...] |
188 {...}
189 ]) &
190 =~"^[^,\\t\\n\\v\\f\\r]+$"
191
192 #commandStep: close({
193 "agents"?: #agents
194 "allow_dependency_failure"?: #allowDependencyFailure
195
196 // The glob path/s of artifacts to upload once this step has finished running
197 "artifact_paths"?: matchN(>=1, [string, [...string]])
198 "branches"?: #branches
199 "cache"?: #cache
200 "cancel_on_build_failing"?: #cancelOnBuildFailing
201 "checkout"?: #checkout
202 "command"?: #commandStepCommand
203 "commands"?: #commandStepCommand
204
205 // The maximum number of jobs created from this step that are allowed to run at
206 // the same time. If you use this attribute, you must also define
207 // concurrency_group.
208 "concurrency"?: int
209
210 // A unique name for the concurrency group that you are creating with the concurrency attribute
211 "concurrency_group"?: string
212
213 // Control command order, allowed values are 'ordered' (default) and 'eager'. If
214 // you use this attribute, you must also define concurrency_group and
215 // concurrency.
216 "concurrency_method"?: "ordered" | "eager"
217 "depends_on"?: #dependsOn
218 "env"?: #env
219 "if"?: #if
220 "if_changed"?: #ifChanged
221 "key"?: _#defs."/definitions/commandStep/properties/key"
222 "identifier"?: _#defs."/definitions/commandStep/properties/key"
223 "id"?: _#defs."/definitions/commandStep/properties/key"
224 "image"?: #image
225 "label"?: _#defs."/definitions/commandStep/properties/label"
226
227 // The signature of the command step, generally injected by agents at pipeline upload
228 "signature"?: {
229 // The algorithm used to generate the signature
230 "algorithm"?: string
231
232 // The signature value, a JWS compact signature with a detached body
233 "value"?: string
234
235 // The fields that were signed to form the signature value
236 "signed_fields"?: [...string]
237 ...
238 }
239 "matrix"?: #matrix
240 "name"?: _#defs."/definitions/commandStep/properties/label"
241 "notify"?: #commandStepNotify
242
243 // The number of parallel jobs that will be created based on this step
244 "parallelism"?: int
245 "plugins"?: #plugins
246 "soft_fail"?: #softFail
247
248 // The conditions for retrying this step.
249 "retry"?: close({
250 "automatic"?: #commandStepAutomaticRetry
251 "manual"?: #commandStepManualRetry
252 })
253 "skip"?: #skip
254
255 // The number of minutes to time out a job
256 "timeout_in_minutes"?: int & >=1
257 "type"?: "script" | "command" | "commands"
258 "priority"?: #priority
259 "secrets"?: #secrets
260 })
261
262 // Whether to allow a job to retry automatically. If set to true, the retry
263 // conditions are set to the default value.
264 #commandStepAutomaticRetry: matchN(>=1, [true | false | "true" | "false", #automaticRetry, #automaticRetryList])
265
266 // The commands to run on the agent
267 #commandStepCommand: matchN(>=1, [[...string], string])
268
269 // Whether to allow a job to be retried manually
270 #commandStepManualRetry: matchN(>=1, [true | false | "true" | "false", #commandStepManualRetryObject])
271
272 #commandStepManualRetryObject: close({
273 // Whether or not this job can be retried manually
274 "allowed"?: true | false | "true" | "false"
275
276 // Whether or not this job can be retried after it has passed
277 "permit_on_passed"?: true | false | "true" | "false"
278
279 // A string that will be displayed in a tooltip on the Retry button in
280 // Buildkite. This will only be displayed if the allowed attribute is set to
281 // false.
282 "reason"?: string
283 })
284
285 // Array of notification options for this step
286 #commandStepNotify: [
287 ...matchN(1, [#notifySimple, #notifyBasecamp, #notifySlack, #notifyGithubCommitStatus, #notifyGithubCheck])
288 ]
289
290 // The step keys for a step to depend on
291 #dependsOn: matchN(>=1, [null, string, #dependsOnList])
292
293 #dependsOnList: [...matchN(>=1, [
294 string,
295 close({
296 "step"?: string
297 "allow_failure"?: true | false | "true" | "false"
298 })
299 ])]
300
301 // Environment variables for this step
302 #env: {...}
303
304 // A list of input fields required to be filled out before unblocking the step
305 #fields: [...matchN(1, [#textField, #selectField])]
306
307 #groupStep: close({
308 "depends_on"?: #dependsOn
309
310 // The name to give to this group of steps
311 "group"!: _#defs."/definitions/groupStep/properties/group"
312 "if"?: #if
313 "if_changed"?: #ifChanged
314 "key"?: _#defs."/definitions/groupStep/properties/key"
315 "identifier"?: _#defs."/definitions/groupStep/properties/key"
316 "id"?: _#defs."/definitions/groupStep/properties/key"
317 "label"?: _#defs."/definitions/groupStep/properties/group"
318 "name"?: _#defs."/definitions/groupStep/properties/group"
319 "allow_dependency_failure"?: #allowDependencyFailure
320 "notify"?: #buildNotify
321 "skip"?: #skip
322 "steps"!: #groupSteps
323 })
324
325 // A list of steps
326 #groupSteps: [_, ...] & [
327 ...matchN(>=1, [
328 #blockStep,
329 #nestedBlockStep,
330 #stringBlockStep,
331 #inputStep,
332 #nestedInputStep,
333 #stringInputStep,
334 #commandStep,
335 #nestedCommandStep,
336 #waitStep,
337 #nestedWaitStep,
338 #stringWaitStep,
339 #triggerStep,
340 #nestedTriggerStep,
341 ])
342 ]
343
344 // A boolean expression that omits the step when false
345 #if: string
346
347 // Agent-applied attribute: A glob pattern that omits the step from a build if
348 // it does not match any files changed in the build. Can be a single pattern,
349 // list of patterns, or an object with include/exclude attributes.
350 #ifChanged: matchN(1, [
351 string,
352 [...string], close({
353 // Pattern or list of patterns to include
354 "include"!: matchN(1, [string, [...string]])
355
356 // Pattern or list of patterns to exclude
357 "exclude"?: matchN(1, [string, [...string]])
358 })
359 ])
360
361 // (Kubernetes stack only) The container image to use for this pipeline or step
362 #image: string
363
364 #inputStep: close({
365 "allow_dependency_failure"?: #allowDependencyFailure
366
367 // The label of the input step
368 "input"?: _#defs."/definitions/inputStep/properties/input"
369 "branches"?: #branches
370 "depends_on"?: #dependsOn
371 "fields"?: #fields
372
373 // The state that the build is set to when the build is blocked by this input step
374 "blocked_state"?: "passed" | "failed" | "running"
375 "if"?: #if
376 "key"?: _#defs."/definitions/inputStep/properties/key"
377 "identifier"?: _#defs."/definitions/inputStep/properties/key"
378 "id"?: _#defs."/definitions/inputStep/properties/key"
379 "label"?: _#defs."/definitions/inputStep/properties/input"
380 "name"?: _#defs."/definitions/inputStep/properties/input"
381 "prompt"?: #prompt
382 "allowed_teams"?: #allowedTeams
383 "type"?: "input"
384 })
385
386 // A unique identifier for a step, must not resemble a UUID
387 #key: matchN(0, [
388 null |
389 bool |
390 number |
391 =~"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" |
392 [...] |
393 {...}
394 ]) &
395 strings.MaxRunes(100) &
396 =~"^[a-zA-Z0-9_\\-:${}.,]+$"
397
398 // The label that will be displayed in the pipeline visualisation in Buildkite. Supports emoji.
399 #label: string
400
401 #matrix: matchN(1, [#matrixElementList, #matrixObject])
402
403 // An adjustment to a Build Matrix
404 #matrixAdjustments: {
405 "with"!: matchN(1, [#matrixElementList, #matrixAdjustmentsWithObject])
406 "skip"?: #skip
407 "soft_fail"?: #softFail
408 ...
409 }
410
411 // Specification of a new or existing Build Matrix combination
412 #matrixAdjustmentsWithObject: {[string]: _} & {[string]: string}
413
414 #matrixElement: matchN(1, [string, int, bool])
415
416 // List of elements for single-dimension Build Matrix
417 #matrixElementList: [...#matrixElement]
418
419 // Configuration for multi-dimension Build Matrix
420 #matrixObject: {
421 "setup"!: #matrixSetup
422
423 // List of Build Matrix adjustments
424 "adjustments"?: [...#matrixAdjustments]
425 ...
426 }
427
428 #matrixSetup: matchN(1, [#matrixElementList, {[=~"^[a-zA-Z0-9_]+$"]: _} & {[string]: [...#matrixElement]}])
429
430 #nestedBlockStep: close({"block"?: #blockStep})
431
432 #nestedCommandStep: close({
433 "command"?: #commandStep
434 "commands"?: #commandStep
435 "script"?: #commandStep
436 })
437
438 #nestedInputStep: close({"input"?: #inputStep})
439
440 #nestedTriggerStep: close({"trigger"?: #triggerStep})
441
442 #nestedWaitStep: close({
443 "wait"?: #waitStep
444 "waiter"?: #waitStep
445 })
446
447 #notifyBasecamp: close({
448 "basecamp_campfire"?: string
449 "if"?: #if
450 })
451
452 #notifyEmail: close({
453 "email"?: string
454 "if"?: #if
455 })
456
457 #notifyGithubCheck: close({
458 "github_check"?: close({
459 // The name of the GitHub check
460 "name"?: string
461 "output"?: close({
462 // The title of the GitHub check's output
463 "title"?: string
464
465 // The summary of the GitHub check's output
466 "summary"?: string
467
468 // The details of the GitHub check's output. Supports Markdown
469 "text"?: string
470 "annotations"?: [...close({
471 // The path of the file to add an annotation to, relative to the repository root
472 "path"!: string
473
474 // The start line of the annotation
475 "start_line"!: int
476
477 // The end line of the annotation
478 "end_line"!: int
479
480 // The start column of the annotation. Only valid when start_line and end_line are equal
481 "start_column"?: int
482
483 // The end column of the annotation. Only valid when start_line and end_line are equal
484 "end_column"?: int
485
486 // The level of the annotation
487 "annotation_level"!: "notice" | "warning" | "failure"
488
489 // The message for the annotation
490 "message"!: string
491
492 // The title for the annotation
493 "title"?: string
494
495 // Additional details for the annotation, displayed alongside the message
496 "raw_details"?: string
497 })]
498 })
499 })
500 "if"?: #if
501 })
502
503 #notifyGithubCommitStatus: close({
504 "github_commit_status"?: close({
505 // GitHub commit status name
506 "context"?: string
507 })
508 "if"?: #if
509 })
510
511 #notifyPagerduty: close({
512 "pagerduty_change_event"?: string
513 "if"?: #if
514 })
515
516 #notifySimple: "github_check" | "github_commit_status"
517
518 #notifySlack: close({
519 "slack"?: matchN(1, [=~"^[^ \\t\\n\\v\\f\\r]+$", #notifySlackObject])
520 "if"?: #if
521 })
522
523 #notifySlackObject: {
524 "channels"!: [_, ...] & [...=~"^[^ \\t\\n\\v\\f\\r]+$"]
525 "message"?: string
526 ...
527 }
528
529 #notifyWebhook: close({
530 "webhook"?: string
531 "if"?: #if
532 })
533
534 // A list of steps
535 #pipelineSteps: [
536 ...matchN(>=1, [
537 #blockStep,
538 #nestedBlockStep,
539 #stringBlockStep,
540 #inputStep,
541 #nestedInputStep,
542 #stringInputStep,
543 #commandStep,
544 #nestedCommandStep,
545 #waitStep,
546 #nestedWaitStep,
547 #stringWaitStep,
548 #triggerStep,
549 #nestedTriggerStep,
550 #groupStep,
551 ])
552 ]
553
554 #plugins: matchN(>=1, [#pluginsList, #pluginsObject])
555
556 // Array of plugins for this step
557 #pluginsList: [...matchN(1, [string, struct.MaxFields(1)])]
558
559 // A map of plugins for this step. Deprecated: please use the array syntax.
560 #pluginsObject: {...}
561
562 // Priority of all jobs in the pipeline, higher priorities are assigned to
563 // agents. When set pipeline-wide, it applies to all steps that do not have
564 // their own priority key set.
565 #priority: int
566
567 // The instructional message displayed in the dialog box when the unblock step is activated
568 #prompt: string
569
570 // A list of secret names or a mapping of environment variable names to secret
571 // names to be made available to the build or step
572 #secrets: matchN(>=1, [[...string], {[string]: string}])
573
574 #selectField: close({
575 // The text input name
576 "select"?: string
577
578 // The meta-data key that stores the field's input
579 "key"!: =~"^[a-zA-Z0-9-_]+$"
580
581 // The value of the option(s) that will be pre-selected in the dropdown
582 "default"?: matchN(1, [string, [...string]])
583
584 // The explanatory text that is shown after the label
585 "hint"?: string
586
587 // Whether more than one option may be selected
588 "multiple"?: true | false | "true" | "false"
589 "options"!: [_, ...] & [...#selectFieldOption]
590
591 // Whether the field is required for form submission
592 "required"?: true | false | "true" | "false"
593 })
594
595 #selectFieldOption: close({
596 // The text displayed on the select list item
597 "label"!: string
598
599 // The value to be stored as meta-data
600 "value"!: string
601
602 // The text displayed directly under the select field’s label
603 "hint"?: string
604
605 // Whether the field is required for form submission
606 "required"?: true | false | "true" | "false"
607 })
608
609 // Whether this step should be skipped. Passing a string provides a reason for skipping this command
610 #skip: matchN(>=1, [bool, strings.MaxRunes(70)])
611
612 // The conditions for marking the step as a soft-fail.
613 #softFail: matchN(>=1, [true | false | "true" | "false", #softFailList])
614
615 #softFailList: [...#softFailObject]
616
617 #softFailObject: {
618 // The exit status number that will cause this job to soft-fail
619 "exit_status"?: matchN(>=1, ["*", int])
620 ...
621 }
622
623 // Pauses the execution of a build and waits on a user to unblock it
624 #stringBlockStep: "block"
625
626 // Pauses the execution of a build and waits on a user to unblock it
627 #stringInputStep: "input"
628
629 // Waits for previous steps to pass before continuing
630 #stringWaitStep: "wait" | "waiter"
631
632 #textField: close({
633 // The text input name
634 "text"?: string
635
636 // The meta-data key that stores the field's input
637 "key"!: =~"^[a-zA-Z0-9-_]+$"
638
639 // The explanatory text that is shown after the label
640 "hint"?: string
641
642 // The format must be a regular expression implicitly anchored to the beginning
643 // and end of the input and is functionally equivalent to the HTML5 pattern
644 // attribute.
645 "format"?: regexp.Valid
646
647 // Whether the field is required for form submission
648 "required"?: true | false | "true" | "false"
649
650 // The value that is pre-filled in the text field
651 "default"?: string
652 })
653
654 #triggerStep: close({
655 "allow_dependency_failure"?: #allowDependencyFailure
656
657 // Whether to continue the build without waiting for the triggered step to complete
658 "async"?: true | false | "true" | "false"
659 "branches"?: #branches
660
661 // Properties of the build that will be created when the step is triggered
662 "build"?: close({
663 // The branch for the build
664 "branch"?: string
665
666 // The commit hash for the build
667 "commit"?: string
668 "env"?: #env
669
670 // The message for the build (supports emoji)
671 "message"?: string
672
673 // Meta-data for the build
674 "meta_data"?: {...}
675 })
676 "depends_on"?: #dependsOn
677 "if"?: #if
678 "if_changed"?: #ifChanged
679 "key"?: _#defs."/definitions/triggerStep/properties/key"
680 "identifier"?: _#defs."/definitions/triggerStep/properties/key"
681 "id"?: _#defs."/definitions/triggerStep/properties/key"
682 "label"?: _#defs."/definitions/triggerStep/properties/label"
683 "name"?: _#defs."/definitions/triggerStep/properties/label"
684 "type"?: "trigger"
685
686 // The slug of the pipeline to create a build
687 "trigger"!: string
688 "skip"?: #skip
689 "soft_fail"?: #softFail
690 })
691
692 #waitStep: close({
693 "allow_dependency_failure"?: #allowDependencyFailure
694 "branches"?: #branches
695
696 // Continue to the next steps, even if the previous group of steps fail
697 "continue_on_failure"?: true | false | "true" | "false"
698 "depends_on"?: #dependsOn
699 "if"?: #if
700 "key"?: _#defs."/definitions/waitStep/properties/key"
701 "label"?: _#defs."/definitions/waitStep/properties/wait"
702 "name"?: _#defs."/definitions/waitStep/properties/wait"
703 "identifier"?: _#defs."/definitions/waitStep/properties/key"
704 "id"?: _#defs."/definitions/waitStep/properties/key"
705 "type"?: "wait" | "waiter"
706
707 // Waits for previous steps to pass before continuing
708 "wait"?: _#defs."/definitions/waitStep/properties/wait"
709 })
710
711 // The label of the block step
712 _#defs: "/definitions/blockStep/properties/block": string
713
714 _#defs: "/definitions/blockStep/properties/key": #key
715
716 _#defs: "/definitions/commandStep/properties/key": #key
717
718 _#defs: "/definitions/commandStep/properties/label": #label
719
720 // The name to give to this group of steps
721 _#defs: "/definitions/groupStep/properties/group": null | string
722
723 _#defs: "/definitions/groupStep/properties/key": #key
724
725 // The label of the input step
726 _#defs: "/definitions/inputStep/properties/input": string
727
728 _#defs: "/definitions/inputStep/properties/key": #key
729
730 _#defs: "/definitions/triggerStep/properties/key": #key
731
732 _#defs: "/definitions/triggerStep/properties/label": #label
733
734 _#defs: "/definitions/waitStep/properties/key": #key
735
736 // Waits for previous steps to pass before continuing
737 _#defs: "/definitions/waitStep/properties/wait": null | string
738}