Add variable inspection: `glci variables` and `run --show-variables`

Closes #87 (closed).

Surfaces the CI/CD variables each job resolves to — with the source of every value and the rule-evaluation trace — for debugging variable precedence and rules: matching.

glci variables [job...] (alias vars)

Resolves variables locally without running the pipeline, so jobs excluded by their rules: are still shown (status excluded) — the main way to debug why a rule did or did not match. It focuses on the variables you control: predefined CI_* variables are hidden by default (--all to show them), except any a rule's if: references. The rule trace is shown by default; variables are grouped by source precedence.

deploy_prod  (stage: deploy)  [included, when: on_success]

  Rules:
    #0  $CI_COMMIT_BRANCH (main) == $CI_DEFAULT_BRANCH (main)  → true

  Variables:
    KEY               VALUE       SOURCE
    CI_COMMIT_BRANCH  main        predefined
    DEPLOY_ENV        production  rules
    GREETING          hello       global

Flags: --all/-a, --rules trace (default on), --stage, --json, --unmask, --expand, --env, --env-file, plus shared context/preset/watch flags.

glci run --show-variables

Emits each running job's fully resolved set (including API secrets, dotenv, runtime CI_*) plus its rule trace, just before the job log. Same rendering, predefined-filtering (--all-variables), masking, and truncation as the static command.

Implementation

  • pkg/variables.Resolve — layered merge with per-value source attribution and an Overridden chain, sorted by source precedence then key.
  • pkg/rules.EvaluateWithTrace — per-rule outcomes incl. a Refs map (referenced var → evaluated value); Evaluate delegates to a shared withTrace-gated core so the planner hot path stays allocation-free.
  • MergeVariables gained an explicit preset layer; --env/--env-file are now sent as separate request fields so each attributes to its own source (precedence unchanged).
  • Daemon emits a transient job_variables event (vars + rule trace).

Output details

  • Sources: predefined, global, api:group, api:project, flag (--env), env-file, glci-env, preset, dotenv, job, rules, registry, predefined:job.
  • Rule trace: each condition rendered with inline values ($VAR (value)) and → true/→ false; failing changes:/exists: rules append a reason.
  • Truncation: long/multi-line values capped at 512 chars on a single line; --expand for full. JSON always carries full values.
  • JSON: each job carries rule_trace (with matched booleans + refs) and the full variables array for programmatic use.

Security

Secrets (masked vars + api:group/api:project sources) are masked by default everywhere they surface — variable table, Overridden chain, and inline rule-condition values — in both the table and --json (--unmask reveals). The job_variables event carries raw values but is transient: delivered only to the live client that requested --show-variables, never retained in the event bus, replayed to other watchers, or written to the on-disk event log.

Docs

user-guide/variables.md (Inspecting resolved variables), debugging.md, cli-reference/commands.md, SKILL.md, ARCHITECTURE.md — all with rendered sample output.

Testing

go build, go vet, gofmt, make test (1800+ unit tests) all green; pre-push glci check (fmt/vet/build) green. New unit tests cover resolution + source ordering, masking (incl. shadowed + rule-trace refs), the rule trace + Refs, condition annotation, predefined filtering, the transient event, and the daemon display helper. Reviewed via two rounds of /review-all (code, perf, security, docs, tests) with all findings fixed.

Edited by Georgi N. Georgiev | GitLab

Merge request reports

Loading
Loading