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