cue.dev/x/gitlab@v0.10.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}