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