cue.dev/x/gitlab@v0.5.0

gitlabci/schema.cue raw

   1package gitlabci
   2
   3import (
   4	"net"
   5	"list"
   6	"strings"
   7	"struct"
   8	"time"
   9	"regexp"
  10)
  11
  12#Pipeline: {
  13	@jsonschema(schema="http://json-schema.org/draft-07/schema#")
  14	@jsonschema(id="https://gitlab.com/.gitlab-ci.yml")
  15	"$schema"?: net.AbsURL
  16	"spec"?: close({
  17		"inputs"?: #configInputs
  18	})
  19	"image"?:         #image
  20	"services"?:      #services
  21	"before_script"?: #before_script
  22	"after_script"?:  #after_script
  23	"variables"?:     #globalVariables
  24	"cache"?:         #cache
  25	"!reference"?:    #."!reference"
  26	"default"?: close({
  27		"after_script"?:  #after_script
  28		"artifacts"?:     #artifacts
  29		"before_script"?: #before_script
  30		"hooks"?:         #hooks
  31		"cache"?:         #cache
  32		"image"?:         #image
  33		"interruptible"?: #interruptible
  34		"id_tokens"?:     #id_tokens
  35		"identity"?:      #identity
  36		"retry"?:         #retry
  37		"services"?:      #services
  38		"tags"?:          #tags
  39		"timeout"?:       #timeout
  40		"!reference"?:    #."!reference"
  41	})
  42	"stages"?: list.UniqueItems() & [...matchN(>=1, [string, [...string]])] & [_, ...]
  43	"include"?: matchN(1, [#include_item, [...#include_item]])
  44	"pages"?: #job
  45	"workflow"?: {
  46		"name"?:        #workflowName
  47		"auto_cancel"?: #workflowAutoCancel
  48		"rules"?: [...matchN(>=1, [{
  49			...
  50		}, [_, ...] & [...string]]) & ([...] | close({
  51			"if"?:          #if
  52			"changes"?:     #changes
  53			"exists"?:      #exists
  54			"variables"?:   #rulesVariables
  55			"when"?:        "always" | "never"
  56			"auto_cancel"?: #workflowAutoCancel
  57		}))]
  58		...
  59	}
  60
  61	{[=~"^[.]" & !~"^(\\$schema|spec|image|services|before_script|after_script|variables|cache|!reference|default|stages|include|pages|workflow)$"]: matchN(>=1, [#job_template, _])}
  62	{[!~"^[.]" & !~"^(\\$schema|spec|image|services|before_script|after_script|variables|cache|!reference|default|stages|include|pages|workflow)$"]: #job}
  63
  64	#: "!reference": [...strings.MinRunes(1)]
  65
  66	#after_script: #optional_script
  67
  68	#allow_failure: matchN(1, [bool, close({
  69		"exit_codes"!: int
  70	}), close({
  71		"exit_codes"!: list.UniqueItems() & [_, ...] & [...int]
  72	})])
  73
  74	#artifacts: null | close({
  75		"paths"?: [...string] & [_, ...]
  76		"exclude"?: [...string] & [_, ...]
  77		"expose_as"?: string
  78		"name"?:      string
  79		"untracked"?: bool
  80		"when"?:      "on_success" | "on_failure" | "always"
  81		"access"?:    "none" | "developer" | "maintainer" | "all"
  82		"expire_in"?: string
  83		"reports"?: close({
  84			// Path to JSON file with accessibility report.
  85			"accessibility"?: string
  86
  87			// Path to JSON file with annotations report.
  88			"annotations"?: string
  89
  90			// Path for file(s) that should be parsed as JUnit XML result
  91			"junit"?: matchN(1, [string, [...string] & [_, ...]])
  92
  93			// Path to a single file with browser performance metric
  94			// report(s).
  95			"browser_performance"?: string
  96
  97			// Used to collect coverage reports from the job.
  98			"coverage_report"?: null | {
  99				// Code coverage format used by the test framework.
 100				"coverage_format"?: "cobertura" | "jacoco"
 101
 102				// Path to the coverage report file that should be parsed.
 103				"path"?: strings.MinRunes(1)
 104				...
 105			}
 106			"codequality"?:         #string_file_list
 107			"dotenv"?:              #string_file_list
 108			"lsif"?:                #string_file_list
 109			"sast"?:                #string_file_list
 110			"dependency_scanning"?: #string_file_list
 111			"container_scanning"?:  #string_file_list
 112			"dast"?:                #string_file_list
 113			"license_management"?:  #string_file_list
 114			"license_scanning"?:    #string_file_list
 115			"requirements"?:        #string_file_list
 116			"secret_detection"?:    #string_file_list
 117			"metrics"?:             #string_file_list
 118			"terraform"?:           #string_file_list
 119			"cyclonedx"?:           #string_file_list
 120			"sarif"?:               #string_file_list
 121			"load_performance"?:    #string_file_list
 122			"repository_xray"?:     #string_file_list
 123		})
 124	})
 125
 126	#baseInput: {
 127		"type"?:        "array" | "boolean" | "number" | "string"
 128		"description"?: strings.MaxRunes(1024)
 129		"options"?: [...bool | number | string]
 130		"regex"?:   string
 131		"default"?: _
 132		...
 133	}
 134
 135	#before_script: #optional_script
 136
 137	#cache: matchN(1, [#cache_item, [...#cache_item]])
 138
 139	#cache_item: {
 140		"key"?: matchN(1, [=~"^[^/]*[^./][^/]*$", {
 141			"files"?: list.MaxItems(2) & [...string] & [_, ...]
 142			"files_commits"?: list.MaxItems(2) & [...string] & [_, ...]
 143			"prefix"?: string
 144			...
 145		}])
 146		"paths"?: [...string]
 147		"policy"?:    =~"pull-push|pull|push|\\$\\w{1,255}"
 148		"unprotect"?: bool
 149		"untracked"?: bool
 150		"when"?:      "on_success" | "on_failure" | "always"
 151		"fallback_keys"?: list.MaxItems(5) & [...string]
 152		...
 153	}
 154
 155	#changes: matchN(>=1, [matchN(1, [{
 156		"paths"!: _
 157		...
 158	}, {
 159		"regexp"!: _
 160		...
 161	}]) & close({
 162		// List of file paths.
 163		"paths"?: [...string]
 164
 165		// Ref for comparing changes.
 166		"compare_to"?: string
 167
 168		// Regular expression to match against changed file paths.
 169		"regexp"?: strings.MaxRunes(255)
 170	}), [...string]])
 171
 172	#configInputs: {
 173		{[=~".*"]: matchN(1, [matchN(3, [#baseInput, null | bool | number | string | [...] | {
 174			"rules"?: [...{
 175				...
 176			}]
 177			...
 178		}, matchN(5, [matchIf(null | bool | number | string | [...] | {
 179			"type"!: "string"
 180			...
 181		}, null | bool | number | string | [...] | {
 182			"default"?: null | string
 183			...
 184		}, _), matchIf(null | bool | number | string | [...] | {
 185			"type"!: "number"
 186			...
 187		}, null | bool | number | string | [...] | {
 188			"default"?: null | number
 189			...
 190		}, _), matchIf(null | bool | number | string | [...] | {
 191			"type"!: "boolean"
 192			...
 193		}, null | bool | number | string | [...] | {
 194			"default"?: null | bool
 195			...
 196		}, _), matchIf(null | bool | number | string | [...] | {
 197			"type"!: "array"
 198			...
 199		}, null | bool | number | string | [...] | {
 200			"default"?: null | [...]
 201			...
 202		}, _), matchIf(matchN(0, [null | bool | number | string | [...] | {
 203			"type"!: _
 204			...
 205		}]), null | bool | number | string | [...] | {
 206			"default"?: null | string
 207			...
 208		}, _)])]), null])
 209		}
 210		...
 211	}
 212
 213	#exists: matchN(>=1, [[...string], matchN(1, [{
 214		"paths"!: _
 215		...
 216	}, {
 217		"regexp"!: _
 218		...
 219	}]) & close({
 220		// List of file paths.
 221		"paths"?: [...string]
 222
 223		// Path of the project to search in.
 224		"project"?: string
 225
 226		// Regular expression to match against file paths in the
 227		// repository.
 228		"regexp"?: strings.MaxRunes(255)
 229	}), matchN(1, [{
 230		"paths"!: _
 231		...
 232	}, {
 233		"regexp"!: _
 234		...
 235	}]) & close({
 236		// List of file paths.
 237		"paths"?: [...string]
 238
 239		// Path of the project to search in.
 240		"project"!: string
 241
 242		// Ref of the project to search in.
 243		"ref"?: string
 244
 245		// Regular expression to match against file paths in the
 246		// repository.
 247		"regexp"?: strings.MaxRunes(255)
 248	})])
 249
 250	#filter: matchN(1, [null, #filter_refs, close({
 251		"refs"?: #filter_refs
 252
 253		// Filter job based on if Kubernetes integration is active.
 254		"kubernetes"?: "active"
 255		"variables"?: [...string]
 256
 257		// Filter job creation based on files that were modified in a git
 258		// push.
 259		"changes"?: [...string]
 260	})])
 261
 262	// Filter job by different keywords that determine origin or
 263	// state, or by supplying string/regex to check against
 264	// branch/tag names.
 265	#filter_refs: [...matchN(>=1, [matchN(1, ["branches", "tags", "api", "external", "pipelines", "pushes", "schedules", "triggers", "web"]), string])]
 266
 267	#globalVariables: {
 268		{[=~".*"]: matchN(1, [bool | number | string, close({
 269			"value"?: string
 270			"options"?: list.UniqueItems() & [...string] & [_, ...]
 271			"description"?: string
 272			"expand"?:      bool
 273		})])
 274		}
 275		...
 276	}
 277
 278	#hooks: close({
 279		"pre_get_sources_script"?: #optional_script
 280	})
 281
 282	#id_tokens: {
 283		{[=~".*"]: close({
 284			"aud"!: matchN(1, [string, list.UniqueItems() & [...string] & [_, ...]])
 285		})
 286		}
 287		...
 288	}
 289
 290	#identity: "google_cloud"
 291
 292	#if: string
 293
 294	#image: matchN(1, [strings.MinRunes(1), close({
 295		// Full name of the image that should be used. It should contain
 296		// the Registry part if needed.
 297		"name"!: strings.MinRunes(1)
 298
 299		// Command or script that should be executed as the container's
 300		// entrypoint. It will be translated to Docker's --entrypoint
 301		// option while creating the container. The syntax is similar to
 302		// Dockerfile's ENTRYPOINT directive, where each shell token is a
 303		// separate string in the array.
 304		"entrypoint"?: [_, ...]
 305		"docker"?: close({
 306			// Image architecture to pull.
 307			"platform"?: strings.MinRunes(1)
 308
 309			// Username or UID to use for the container.
 310			"user"?: strings.MinRunes(1) & strings.MaxRunes(255)
 311		})
 312		"kubernetes"?: close({
 313			// Username or UID to use for the container. It also supports the
 314			// UID:GID format.
 315			"user"?: int | strings.MinRunes(1) & strings.MaxRunes(255)
 316		})
 317		"pull_policy"?: matchN(1, ["always" | "never" | "if-not-present", list.UniqueItems() & [..."always" | "never" | "if-not-present"] & [_, ...]])
 318	})])
 319
 320	#includeRules: null | [...matchN(>=1, [close({
 321		"if"?:      #if
 322		"changes"?: #changes
 323		"exists"?:  #exists
 324		"when"?: matchN(1, ["never" | "always", null])
 325	}), strings.MinRunes(1), [_, ...] & [...string]])]
 326
 327	#include_item: matchN(1, [matchN(>=1, [=~"^https?://", matchN(0, [null | bool | number | =~"^\\w+://" | [...] | {
 328		...
 329	}]) & string]) & (net.URL & =~"\\w\\.ya?ml$"), close({
 330		// Relative path from local repository root (`/`) to the
 331		// `yaml`/`yml` file template. The file must be on the same
 332		// branch, and does not work across git submodules.
 333		"local"!:  net.URL & =~"\\.ya?ml$"
 334		"rules"?:  #includeRules
 335		"inputs"?: #inputs
 336	}), close({
 337		// Path to the project, e.g. `group/project`, or
 338		// `group/sub-group/project` [Learn
 339		// more](https://docs.gitlab.com/ci/yaml/#includeproject).
 340		"project"!: =~"(?:\\S/\\S|\\$\\S+)"
 341
 342		// Branch/Tag/Commit-hash for the target project.
 343		"ref"?: string
 344		"file"!: matchN(1, [=~"\\.ya?ml$", [...=~"\\.ya?ml$"]])
 345		"rules"?:  #includeRules
 346		"inputs"?: #inputs
 347	}), close({
 348		// Use a `.gitlab-ci.yml` template as a base, e.g.
 349		// `Nodejs.gitlab-ci.yml`.
 350		"template"!: net.URL & =~"\\.ya?ml$"
 351		"rules"?:    #includeRules
 352		"inputs"?:   #inputs
 353	}), close({
 354		// Local path to component directory or full path to external
 355		// component directory.
 356		"component"!: net.URL
 357		"rules"?:     #includeRules
 358		"inputs"?:    #inputs
 359	}), close({
 360		// URL to a `yaml`/`yml` template file using HTTP/HTTPS.
 361		"remote"!: net.URL & =~"^https?://.+\\.ya?ml$"
 362
 363		// SHA256 integrity hash of the remote file content.
 364		"integrity"?: =~"^sha256-[A-Za-z0-9+/]{43}=$"
 365		"rules"?:     #includeRules
 366		"inputs"?:    #inputs
 367	})])
 368
 369	#inputs: close({
 370		{[=~"^[a-zA-Z0-9_-]+$"]: matchN(1, [strings.MaxRunes(1024), number, bool, [...matchN(1, [string, number, bool, {
 371			...
 372		}, [...null | bool | number | string | [...] | {
 373			...
 374		}]])], {
 375			...
 376		}, null])
 377		}
 378	})
 379
 380	#interruptible: bool
 381
 382	#job: #job_template
 383
 384	#jobInputs: struct.MaxFields(50) & {
 385		{[=~".*"]: matchN(3, [#baseInput, null | bool | number | string | [...] | {
 386			"default"!: _
 387			...
 388		}, matchN(5, [matchIf(null | bool | number | string | [...] | {
 389			"type"!: "string"
 390			...
 391		}, null | bool | number | string | [...] | {
 392			"default"?: string
 393			...
 394		}, _), matchIf(null | bool | number | string | [...] | {
 395			"type"!: "number"
 396			...
 397		}, null | bool | number | string | [...] | {
 398			"default"?: number
 399			...
 400		}, _), matchIf(null | bool | number | string | [...] | {
 401			"type"!: "boolean"
 402			...
 403		}, null | bool | number | string | [...] | {
 404			"default"?: bool
 405			...
 406		}, _), matchIf(null | bool | number | string | [...] | {
 407			"type"!: "array"
 408			...
 409		}, null | bool | number | string | [...] | {
 410			"default"?: [...]
 411			...
 412		}, _), matchIf(matchN(0, [null | bool | number | string | [...] | {
 413			"type"!: _
 414			...
 415		}]), null | bool | number | string | [...] | {
 416			"default"?: string
 417			...
 418		}, _)])])
 419		}
 420		...
 421	}
 422
 423	#jobVariables: {
 424		{[=~".*"]: matchN(1, [bool | number | string, close({
 425			"value"?:  string
 426			"expand"?: bool
 427		})])
 428		}
 429		...
 430	}
 431
 432	#job_template: matchN(1, [{
 433		"when"!:     "delayed"
 434		"start_in"!: _
 435		...
 436	}, {
 437		"when"?: matchN(0, ["delayed"])
 438		...
 439	}]) & close({
 440		"image"?:         #image
 441		"services"?:      #services
 442		"before_script"?: #before_script
 443		"after_script"?:  #after_script
 444		"hooks"?:         #hooks
 445		"rules"?:         #rules
 446		"variables"?:     #jobVariables
 447		"cache"?:         #cache
 448		"id_tokens"?:     #id_tokens
 449		"identity"?:      #identity
 450		"inputs"?:        #jobInputs
 451		"secrets"?:       #secrets
 452		"script"?:        #script
 453		"run"?:           #steps
 454
 455		// Define what stage the job will run in.
 456		"stage"?: matchN(>=1, [strings.MinRunes(1), [_, ...] & [...string]])
 457		"only"?: #filter
 458
 459		// The name of one or more jobs to inherit configuration from.
 460		"extends"?: matchN(1, [string, [...string] & [_, ...]])
 461
 462		// The list of jobs in previous stages whose sole completion is
 463		// needed to start the current job.
 464		"needs"?: [...matchN(1, [string, close({
 465			"job"!:       string
 466			"artifacts"?: bool
 467			"optional"?:  bool
 468			"parallel"?:  #parallel_matrix
 469		}), close({
 470			"pipeline"!:  string
 471			"job"!:       string
 472			"artifacts"?: bool
 473			"parallel"?:  #parallel_matrix
 474		}), close({
 475			"job"!:       string
 476			"project"!:   string
 477			"ref"!:       string
 478			"artifacts"?: bool
 479			"parallel"?:  #parallel_matrix
 480		}), #."!reference"])]
 481		"except"?:              #filter
 482		"tags"?:                #tags
 483		"allow_failure"?:       #allow_failure
 484		"timeout"?:             #timeout
 485		"when"?:                #when
 486		"start_in"?:            #start_in
 487		"manual_confirmation"?: string
 488
 489		// Specify a list of job names from earlier stages from which
 490		// artifacts should be loaded. By default, all previous artifacts
 491		// are passed. Use an empty array to skip downloading artifacts.
 492		"dependencies"?: [...string]
 493		"artifacts"?: #artifacts
 494
 495		// Used to associate environment metadata with a deploy.
 496		// Environment can have a name and URL attached to it, and will
 497		// be displayed under /environments under the project.
 498		"environment"?: matchN(1, [string, close({
 499			// The name of the environment, e.g. 'qa', 'staging',
 500			// 'production'.
 501			"name"!: strings.MinRunes(1)
 502
 503			// When set, this will expose buttons in various places for the
 504			// current environment in GitLab, that will take you to the
 505			// defined URL.
 506			"url"?: net.AbsURL & =~"^(https?://.+|\\$[A-Za-z]+)"
 507
 508			// The name of a job to execute when the environment is about to
 509			// be stopped.
 510			"on_stop"?: string
 511
 512			// Specifies what this job will do. 'start' (default) indicates
 513			// the job will start the deployment. 'prepare'/'verify'/'access'
 514			// indicates this will not affect the deployment. 'stop'
 515			// indicates this will stop the deployment.
 516			"action"?: "start" | "prepare" | "stop" | "verify" | "access"
 517
 518			// The amount of time it should take before GitLab will
 519			// automatically stop the environment. Supports a wide variety of
 520			// formats, e.g. '1 week', '3 mins 4 sec', '2 hrs 20 min',
 521			// '2h20min', '6 mos 1 day', '47 yrs 6 mos and 4d', '3 weeks and
 522			// 2 days'.
 523			"auto_stop_in"?: string
 524
 525			// Used to configure the kubernetes deployment for this
 526			// environment. This is currently not supported for kubernetes
 527			// clusters that are managed by GitLab.
 528			"kubernetes"?: {
 529				// Specifies the GitLab Agent for Kubernetes. The format is
 530				// `path/to/agent/project:agent-name`.
 531				"agent"?: string
 532
 533				// Deprecated. Use `dashboard.namespace` instead. The kubernetes
 534				// namespace where this environment's dashboard should be
 535				// deployed to.
 536				"namespace"?: strings.MinRunes(1)
 537
 538				// Deprecated. Use `dashboard.flux_resource_path` instead. The
 539				// Flux resource path to associate with this environment. This
 540				// must be the full resource path. For example,
 541				// 'helm.toolkit.fluxcd.io/v2/namespaces/gitlab-agent/helmreleases/gitlab-agent'.
 542				"flux_resource_path"?: string
 543
 544				// Used to configure the managed resources for this environment.
 545				"managed_resources"?: {
 546					// Indicates whether the managed resources are enabled for this
 547					// environment.
 548					"enabled"?: bool
 549					...
 550				}
 551
 552				// Used to configure the dashboard for this environment.
 553				"dashboard"?: {
 554					// The kubernetes namespace where the dashboard for this
 555					// environment should be deployed to.
 556					"namespace"?: strings.MinRunes(1)
 557
 558					// The Flux resource path to associate with this environment. This
 559					// must be the full resource path. For example,
 560					// 'helm.toolkit.fluxcd.io/v2/namespaces/gitlab-agent/helmreleases/gitlab-agent'.
 561					"flux_resource_path"?: string
 562					...
 563				}
 564				...
 565			}
 566
 567			// Explicitly specifies the tier of the deployment environment if
 568			// non-standard environment name is used.
 569			"deployment_tier"?: string
 570		})])
 571
 572		// Indicates that the job creates a Release.
 573		"release"?: close({
 574			// The tag_name must be specified. It can refer to an existing Git
 575			// tag or can be specified by the user.
 576			"tag_name"!: strings.MinRunes(1)
 577
 578			// Message to use if creating a new annotated tag.
 579			"tag_message"?: string
 580
 581			// Specifies the longer description of the Release.
 582			"description"!: strings.MinRunes(1)
 583
 584			// The Release name. If omitted, it is populated with the value of
 585			// release: tag_name.
 586			"name"?: string
 587
 588			// If the release: tag_name doesn’t exist yet, the release is
 589			// created from ref. ref can be a commit SHA, another tag name,
 590			// or a branch name.
 591			"ref"?: string
 592
 593			// The title of each milestone the release is associated with.
 594			"milestones"?: [...string]
 595
 596			// The date and time when the release is ready. Defaults to the
 597			// current date and time if not defined. Should be enclosed in
 598			// quotes and expressed in ISO 8601 format.
 599			"released_at"?: time.Time & =~"^(?:[1-9]\\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:Z|[+-][01]\\d:[0-5]\\d)$"
 600			"assets"?: close({
 601				// Include asset links in the release.
 602				"links"!: [...close({
 603					// The name of the link.
 604					"name"!: strings.MinRunes(1)
 605
 606					// The URL to download a file.
 607					"url"!: strings.MinRunes(1)
 608
 609					// The redirect link to the url.
 610					"filepath"?: string
 611
 612					// The content kind of what users can download via url.
 613					"link_type"?: "runbook" | "package" | "image" | "other"
 614				})] & [_, ...]
 615			})
 616		})
 617
 618		// Must be a regular expression, optionally but recommended to be
 619		// quoted, and must be surrounded with '/'. Example: '/Code
 620		// coverage: \d+\.\d+/'
 621		"coverage"?:      regexp.Valid & =~"^/.+/$"
 622		"retry"?:         #retry
 623		"parallel"?:      #parallel
 624		"interruptible"?: #interruptible
 625
 626		// Limit job concurrency. Can be used to ensure that the Runner
 627		// will not run certain jobs simultaneously.
 628		"resource_group"?: string
 629		"trigger"?: matchN(1, [close({
 630			// Path to the project, e.g. `group/project`, or
 631			// `group/sub-group/project`.
 632			"project"!: =~"(?:\\S/\\S|\\$\\S+)"
 633
 634			// The branch name that a downstream pipeline will use
 635			"branch"?: string
 636
 637			// You can mirror or depend on the pipeline status from the
 638			// triggered pipeline to the source bridge job by using strategy:
 639			// `depend` or `mirror`
 640			"strategy"?: "depend" | "mirror"
 641			"inputs"?:   #inputs
 642
 643			// Specify what to forward to the downstream pipeline.
 644			"forward"?: close({
 645				// Variables defined in the trigger job are passed to downstream
 646				// pipelines.
 647				"yaml_variables"?: bool
 648
 649				// Variables added for manual pipeline runs and scheduled
 650				// pipelines are passed to downstream pipelines.
 651				"pipeline_variables"?: bool
 652			})
 653			branch?: _
 654			if branch != _|_ {
 655				"project"!: _
 656			}
 657			{}
 658		}), close({
 659			"include"?: matchN(1, [net.URL & =~"\\.ya?ml$", list.MaxItems(3) & [...matchN(1, [close({
 660				// Relative path from local repository root (`/`) to the local
 661				// YAML file to define the pipeline configuration.
 662				"local"!:  net.URL & =~"\\.ya?ml$"
 663				"inputs"?: #inputs
 664			}), close({
 665				// Name of the template YAML file to use in the pipeline
 666				// configuration.
 667				"template"!: net.URL & =~"\\.ya?ml$"
 668				"inputs"?:   #inputs
 669			}), close({
 670				// Relative path to the generated YAML file which is extracted
 671				// from the artifacts and used as the configuration for
 672				// triggering the child pipeline.
 673				"artifact"!: net.URL & =~"\\.ya?ml$"
 674
 675				// Job name which generates the artifact
 676				"job"!:    string
 677				"inputs"?: #inputs
 678			}), close({
 679				// Path to another private project under the same GitLab instance,
 680				// like `group/project` or `group/sub-group/project`.
 681				"project"!: =~"(?:\\S/\\S|\\$\\S+)"
 682
 683				// Branch/Tag/Commit hash for the target project.
 684				"ref"?: strings.MinRunes(1)
 685
 686				// Relative path from repository root (`/`) to the pipeline
 687				// configuration YAML file.
 688				"file"!:   net.URL & =~"\\.ya?ml$"
 689				"inputs"?: #inputs
 690			}), close({
 691				// Local path to component directory or full path to external
 692				// component directory.
 693				"component"!: net.URL
 694				"inputs"?:    #inputs
 695			}), close({
 696				// URL to a `yaml`/`yml` template file using HTTP/HTTPS.
 697				"remote"!: net.URL & =~"^https?://.+\\.ya?ml$"
 698				"inputs"?: #inputs
 699			})])]])
 700
 701			// You can mirror or depend on the pipeline status from the
 702			// triggered pipeline to the source bridge job by using strategy:
 703			// `depend` or `mirror`
 704			"strategy"?: "depend" | "mirror"
 705
 706			// Specify what to forward to the downstream pipeline.
 707			"forward"?: close({
 708				// Variables defined in the trigger job are passed to downstream
 709				// pipelines.
 710				"yaml_variables"?: bool
 711
 712				// Variables added for manual pipeline runs and scheduled
 713				// pipelines are passed to downstream pipelines.
 714				"pipeline_variables"?: bool
 715			})
 716		}), =~"(?:\\S/\\S|\\$\\S+)"])
 717		"inherit"?: close({
 718			"default"?: matchN(1, [bool, [..."after_script" | "artifacts" | "before_script" | "cache" | "image" | "interruptible" | "retry" | "services" | "tags" | "timeout"]])
 719			"variables"?: matchN(1, [bool, [...string]])
 720		})
 721
 722		// Deprecated. Use `pages.publish` instead. A path to a directory
 723		// that contains the files to be published with Pages.
 724		"publish"?: string
 725		"pages"?: matchN(1, [close({
 726			"path_prefix"?: string
 727			"expire_in"?:   string
 728			"publish"?:     string
 729		}), bool])
 730	})
 731
 732	#optional_script: matchN(1, [string, [...matchN(>=1, [string, [...string]])]])
 733
 734	// Splits up a single job into multiple that run in parallel.
 735	// Provides `CI_NODE_INDEX` and `CI_NODE_TOTAL` environment
 736	// variables to the jobs.
 737	#parallel: matchN(1, [int & >=1 & <=200, close({
 738		// Defines different variables for jobs that are running in
 739		// parallel.
 740		"matrix"!: list.MaxItems(200) & [...{
 741			[string]: number | string | [...]
 742		}]
 743	})])
 744
 745	// Use the `needs:parallel:matrix` keyword to specify parallelized
 746	// jobs needed to be completed for the job to run. [Learn
 747	// More](https://docs.gitlab.com/ci/yaml/#needsparallelmatrix)
 748	#parallel_matrix: close({
 749		// Defines different variables for jobs that are running in
 750		// parallel.
 751		"matrix"!: list.MaxItems(200) & [...{
 752			[string]: number | string | [...]
 753		}]
 754	})
 755
 756	#retry: matchN(1, [#retry_max, close({
 757		"max"?: #retry_max
 758		"when"?: matchN(1, [#retry_errors, [...#retry_errors]])
 759		"exit_codes"?: matchN(1, [list.UniqueItems() & [_, ...] & [...int], int])
 760	})])
 761
 762	#retry_errors: matchN(1, ["always", "unknown_failure", "script_failure", "api_failure", "stuck_or_timeout_failure", "stuck_pending_with_matching_runners", "stuck_pending_no_matching_runners", "no_updates_running", "no_updates_canceling", "runner_system_failure", "runner_configuration_error", "runner_external_dependency_failure", "runner_interrupted", "runner_unsupported", "stale_schedule", "job_execution_timeout", "server_timeout_running", "server_timeout_canceling", "archived_failure", "unmet_prerequisites", "scheduler_failure", "data_integrity_failure"])
 763
 764	// The number of times the job will be retried if it fails.
 765	// Defaults to 0 and can max be retried 2 times (3 times total).
 766	#retry_max: int & >=0 & <=2
 767
 768	#rules: null | [...matchN(>=1, [close({
 769		"if"?:            #if
 770		"changes"?:       #changes
 771		"exists"?:        #exists
 772		"variables"?:     #rulesVariables
 773		"when"?:          #when
 774		"start_in"?:      #start_in
 775		"allow_failure"?: #allow_failure
 776		"needs"?:         #rulesNeeds
 777		"interruptible"?: #interruptible
 778	}), strings.MinRunes(1), [_, ...] & [...string]])]
 779
 780	#rulesNeeds: [...matchN(1, [string, close({
 781		// Name of a job that is defined in the pipeline.
 782		"job"!: strings.MinRunes(1)
 783
 784		// Download artifacts of the job in needs.
 785		"artifacts"?: bool
 786
 787		// Whether the job needs to be present in the pipeline to run
 788		// ahead of the current job.
 789		"optional"?: bool
 790	})])]
 791
 792	#rulesVariables: {
 793		{[=~".*"]: bool | number | string}
 794		...
 795	}
 796
 797	#script: matchN(1, [strings.MinRunes(1), [...matchN(>=1, [string, [...string]])] & [_, ...]])
 798
 799	#secrets: {
 800		{[=~".*"]: matchN(>=1, [{
 801			"vault"!: _
 802			...
 803		}, {
 804			"azure_key_vault"!: _
 805			...
 806		}, {
 807			"gcp_secret_manager"!: _
 808			...
 809		}, {
 810			"aws_secrets_manager"!: _
 811			...
 812		}, {
 813			"gitlab_secrets_manager"!: _
 814			...
 815		}]) & close({
 816			"vault"?: matchN(1, [string, close({
 817				"engine"!: {
 818					"name"!: string
 819					"path"!: string
 820					...
 821				}
 822				"path"!:  string
 823				"field"!: string
 824			})])
 825			"gcp_secret_manager"?: close({
 826				"name"!: string
 827				"version"?: matchN(1, [string, int])
 828			})
 829			"azure_key_vault"?: close({
 830				"name"!:    string
 831				"version"?: string
 832			})
 833			"aws_secrets_manager"?: matchN(1, [string, close({
 834				// The ARN or name of the secret to retrieve. To retrieve a secret
 835				// from another account, you must use an ARN.
 836				"secret_id"!: string
 837
 838				// The unique identifier of the version of the secret to retrieve.
 839				// If you include both this parameter and VersionStage, the two
 840				// parameters must refer to the same secret version. If you don't
 841				// specify either a VersionStage or VersionId, Secrets Manager
 842				// returns the AWSCURRENT version.
 843				"version_id"?: string
 844
 845				// The staging label of the version of the secret to retrieve. If
 846				// you include both this parameter and VersionStage, the two
 847				// parameters must refer to the same secret version. If you don't
 848				// specify either a VersionStage or VersionId, Secrets Manager
 849				// returns the AWSCURRENT version.
 850				"version_stage"?: string
 851
 852				// The AWS region where the secret is stored. Use this to override
 853				// the region for a specific secret. Defaults to AWS_REGION
 854				// variable.
 855				"region"?: string
 856
 857				// The ARN of the IAM role to assume before retrieving the secret.
 858				// Use this to override the ARN. Defaults to AWS_ROLE_ARN
 859				// variable.
 860				"role_arn"?: string
 861
 862				// The name of the session to use when assuming the role. Use this
 863				// to override the session name. Defaults to
 864				// AWS_ROLE_SESSION_NAME variable.
 865				"role_session_name"?: string
 866
 867				// The name of the field to retrieve from the secret. If not
 868				// specified, the entire secret is retrieved.
 869				"field"?: string
 870			})])
 871			"gitlab_secrets_manager"?: close({
 872				// Name of the secret. Only letters, digits, and underscores are
 873				// allowed.
 874				"name"!: =~"^[a-zA-Z0-9_]+$"
 875
 876				// Source of the secret. Defaults to the current project if not
 877				// given. For fetching a secret from a group, provide
 878				// group/<full_path_of_the_group>
 879				"source"?: string
 880			})
 881			"file"?: bool
 882
 883			// Specifies the JWT variable that should be used to authenticate
 884			// with the secret provider.
 885			"token"?:            string
 886			gcp_secret_manager?: _
 887			if gcp_secret_manager != _|_ {
 888				"token"!: _
 889			}
 890			{}
 891		})
 892		}
 893		...
 894	}
 895
 896	#services: [...matchN(1, [strings.MinRunes(1), close({
 897		// Full name of the image that should be used. It should contain
 898		// the Registry part if needed.
 899		"name"!: strings.MinRunes(1)
 900		"entrypoint"?: [_, ...] & [...string]
 901		"docker"?: close({
 902			// Image architecture to pull.
 903			"platform"?: strings.MinRunes(1)
 904
 905			// Username or UID to use for the container.
 906			"user"?: strings.MinRunes(1) & strings.MaxRunes(255)
 907		})
 908		"kubernetes"?: close({
 909			// Username or UID to use for the container. It also supports the
 910			// UID:GID format.
 911			"user"?: int | strings.MinRunes(1) & strings.MaxRunes(255)
 912		})
 913		"pull_policy"?: matchN(1, ["always" | "never" | "if-not-present", list.UniqueItems() & [..."always" | "never" | "if-not-present"] & [_, ...]])
 914		"command"?:   #script
 915		"alias"?:     strings.MinRunes(1)
 916		"variables"?: #jobVariables
 917	})])]
 918
 919	#start_in: strings.MinRunes(1)
 920
 921	// Any of these function use cases are valid.
 922	#step: matchN(1, [matchN(1, [matchN(0, [null | bool | number | string | [...] | {
 923		"func"!: _
 924		...
 925	}]) & {
 926		"step"!: _
 927		...
 928	}, matchN(0, [null | bool | number | string | [...] | {
 929		"step"!: _
 930		...
 931	}]) & {
 932		"func"!: _
 933		...
 934	}]) & close({
 935		"name"!:   #stepName
 936		"env"?:    #stepNamedStrings
 937		"inputs"?: #stepNamedValues
 938		"step"?:   #stepFuncReference
 939		"func"?:   #stepFuncReference
 940	}), close({
 941		"name"!:   #stepName
 942		"env"?:    #stepNamedStrings
 943		"script"!: strings.MinRunes(1)
 944	})])
 945
 946	#stepFuncReference: matchN(1, [string, #stepGitReference, #stepOciReference])
 947
 948	// GitReference is a reference to a function in a Git repository.
 949	#stepGitReference: close({
 950		"git"!: close({
 951			"url"!:  string
 952			"dir"?:  string
 953			"rev"!:  string
 954			"file"?: string
 955		})
 956	})
 957
 958	#stepName: =~"^[a-zA-Z_][a-zA-Z0-9_]*$"
 959
 960	#stepNamedStrings: close({
 961		{[=~"^[a-zA-Z_][a-zA-Z0-9_]*$"]: string}
 962	})
 963
 964	#stepNamedValues: close({
 965		{[=~"^[a-zA-Z_][a-zA-Z0-9_]*$"]: _}
 966	})
 967
 968	// OCIReference is a reference to a function hosted in an OCI
 969	// repository.
 970	#stepOciReference: close({
 971		"oci"!: close({
 972			// The <host>[:<port>] of the container registry server.
 973			"registry"!: string
 974
 975			// A path within the registry containing related OCI images.
 976			// Typically the namespace, project, and image name.
 977			"repository"!: string
 978
 979			// A pointer to the image manifest hosted in the OCI repository.
 980			"tag"!: string
 981
 982			// A directory inside the OCI image where the function can be
 983			// found.
 984			"dir"?: string
 985
 986			// The name of the file that defines the function, defaults to
 987			// func.yml.
 988			"file"?: string
 989		})
 990	})
 991
 992	#steps: [...#step]
 993
 994	#string_file_list: matchN(1, [string, [...string]])
 995
 996	#tags: [_, ...] & [...matchN(>=1, [strings.MinRunes(1), [_, ...] & [...string]])]
 997
 998	#timeout: strings.MinRunes(1)
 999
1000	#when: "on_success" | "on_failure" | "always" | "never" | "manual" | "delayed"
1001
1002	// Define the rules for when pipeline should be automatically
1003	// cancelled.
1004	#workflowAutoCancel: close({
1005		"on_job_failure"?: "none" | "all"
1006		"on_new_commit"?:  "conservative" | "interruptible" | "none"
1007	})
1008
1009	#workflowName: strings.MinRunes(1) & strings.MaxRunes(255)
1010}