Pipeline Inputs
For pipelines using spec: inputs:, pass values via CLI flags or a YAML file.
Usage#
glci run --input force_build=true --input runner_version=17.6.0
glci run --inputs-file inputs.yml
glci run --inputs-file defaults.yml --input force_build=true # CLI overrides file
glci show --input force_build=true # works with show too
glci merged --input force_build=true # and with merged
Input types#
| Type | Accepted values | Normalization |
|---|---|---|
string | Any value | None |
boolean | true, false, yes, no, 1, 0 | Normalized to true/false |
number | Any valid number | None |
array | Any value | Formatted as YAML flow sequence |
Inputs file format#
# inputs.yml
force_build: true
runner_version: "17.6.0"
environment: staging
Conditional defaults with rules:#
An input can take its options and default from a rules: list instead of declaring them directly. Rules are evaluated in order and the first match wins; an entry with no if: is the fallback.
spec:
inputs:
environment:
options: ['development', 'production']
default: 'development'
instance_type:
rules:
- if: $[[ inputs.environment ]] == 'development'
options: ['small', 'medium']
default: 'small'
- if: $[[ inputs.environment ]] == 'production'
options: ['large', 'xlarge']
default: 'large'
A rule’s if: can only reference other inputs. CI/CD variables are not in scope, so a $CI_COMMIT_TAG written in an input rule is undefined whatever triggered the pipeline. Comparing an undefined value against "" is false, so a rule written that way never matches — and $CI_COMMIT_TAG == null is always true, so a rule written that way always matches. This is GitLab’s behaviour, which evaluates these rules with the inputs alone.
Inputs resolve in declaration order. A rule may reference another input, but only one declared before it will have a value — a reference to an input declared later sees nothing, not that input’s default, unless the caller supplied a value for it explicitly. That is how GitLab resolves them, and it is worth knowing because it looks like a bug:
spec:
inputs:
image: # declared first
rules:
- if: $[[ inputs.flavor ]] == 'slim'
default: 'alpine'
- default: 'debian' # always taken: flavor has no value yet
flavor:
default: 'slim'
Swap the two entries and image resolves to alpine.
A rule may also name an input that does not exist, or two inputs may read each other. Neither is an error — GitLab accepts both, and so does glci: an unknown name is simply undefined, and a cycle cannot loop because each input resolves exactly once. The practical consequence is that a typo in an input reference is silent: the rule never matches and the fallback wins, with nothing reported. Check the resolved value with glci merged if a rule is not behaving.
Further rules, all matching GitLab:
rules:cannot be combined with a top-leveldefault:oroptions:.- Every rule must carry a
default:key.default:with no value is allowed on a rule that declares nooptions:, and leaves the input without one. The same is true of a top-leveldefault:: the key’s presence is what makes the input optional, sodefault:alone means “optional, no value” rather than a default of any kind. - A rule declaring
options:must have itsdefault:among them. A valuelessdefault:counts only if the list itself has anullentry (options: [null, 'a']), which is how GitLab compares it; otherwise the two cannot be combined. - Any rule carrying a
default:key makes the input optional, whether or not that rule ends up matching. - If no rule matches and none is unconditional, the input resolves to no value rather than erroring, and is not checked against any options. Add a trailing entry with no
if:if that is not what you want. - Supplying an empty value for a rules-bearing input does not override the rule: the empty string is discarded and the matching rule’s default applies. A plain input with a
default:behaves the opposite way, where--input key=does override it. - A resolved input keeps its declared type in a rule, which is not only about text:
- A
booleaninput set tofalseis falsy. Astringinput whose value happens to be"false"is not. - A
numberorarrayinput is never equal to a quoted string, however alike the two print.$[[ inputs.count ]] == "3"is false forcount: {type: number, default: 3}, because GitLab compares anIntegeragainst aString. Compare against another input of the same type, or declare the input as astring. - An empty
arrayinput is falsy, soif: $[[ inputs.list ]]takes the fallback whenlistresolved to[]. A non-empty array is truthy. - Only an input already resolved carries its type. A value supplied for an input declared later is still plain text in an earlier input’s rule.
- A
- A rule’s resolved
default:is checked against its input’s type even when you supply a value that overrides it, as GitLab does:count: {type: number, rules: [{default: abc}]}fails whatever--input count=says. A rule’soptions:are not type-checked, so this is the only place such a default is reported.
Validation#
glci validates inputs before starting the pipeline:
- Required inputs: Inputs without a
defaultmust be provided. Error messages include the input’sdescriptionif available. - Type checking: Boolean inputs reject non-boolean values; number inputs reject non-numeric values.
- Options: When
options:is declared, the provided value must match one of the listed options. When the input usesrules:, the matching rule’s options apply. Abooleaninput is the exception: GitLab never checks one against options at all, not even a rule’s, so neither does glci.
An included file or component whose inputs do not resolve fails the parse, naming the include it came from:
CI configuration is invalid: parsing CI config: resolving includes: include local "/ci/comp.yml": resolving inputs: required input "env" not provided
An include’s inputs come only from that include entry’s own inputs: map. --input and --inputs-file reach the root file’s spec: and nothing else, which is also how GitLab behaves.
Interactive TUI#
The TUI (glci with no subcommand) shows an input form with descriptions and defaults pre-filled. Required inputs are highlighted and validated before submission.
An input whose default/options come from rules: is shown blank and unmarked: the form does not evaluate the rules, so nothing is pre-filled and the matching rule’s options: are not enforced there. They are still enforced when the pipeline is resolved, so a value the rule forbids fails the run rather than the form.