Context Simulation
glci simulates different CI pipeline contexts so you can test how rules: evaluate without pushing to GitLab. The default context is merge_request.
Usage#
glci run --context branch=main
glci run --context merge_request --mr-source feature --mr-target main
glci run --context tag=v1.2.3
glci run --context env=production
glci run --context tag=v1.0 --env RELEASE=true
glci show --context merge_request
Context types#
Each context type sets specific CI variables that drive rules: evaluation:
branch#
glci run --context branch=main
Sets CI_COMMIT_BRANCH, CI_COMMIT_REF_NAME, CI_DEFAULT_BRANCH, and CI_PIPELINE_SOURCE=push.
merge_request (default)#
glci run --context merge_request --mr-source feature/login --mr-target main
Source defaults to the current git branch, target defaults to the detected default branch. Sets CI_PIPELINE_SOURCE=merge_request_event, CI_MERGE_REQUEST_SOURCE_BRANCH_NAME, CI_MERGE_REQUEST_TARGET_BRANCH_NAME, CI_MERGE_REQUEST_IID=1, and CI_MERGE_REQUEST_TITLE=local.
tag#
glci run --context tag=v1.0.0
Sets CI_COMMIT_TAG, CI_COMMIT_REF_NAME, and CI_PIPELINE_SOURCE=push. Does not set CI_COMMIT_BRANCH.
env#
glci run --context env=production
Sets CI_ENVIRONMENT_NAME and CI_PIPELINE_SOURCE=push, while preserving the current branch/tag from git.
CI variables by context type#
Variables not listed here (CI_COMMIT_SHA, CI_PROJECT_NAME, etc.) are derived from git and remain the same across all contexts.
| Variable | branch=X | merge_request | tag=X | env=X |
|---|---|---|---|---|
CI_COMMIT_BRANCH | X | (not set) | (not set) | (from git) |
CI_COMMIT_TAG | (not set) | (not set) | X | (from git) |
CI_COMMIT_REF_NAME | X | source branch | X | (from git) |
CI_DEFAULT_BRANCH | detected | (from git) | (from git) | (from git) |
CI_PIPELINE_SOURCE | push | merge_request_event | push | push |
CI_MERGE_REQUEST_SOURCE_BRANCH_NAME | (not set) | source branch | (not set) | (not set) |
CI_MERGE_REQUEST_TARGET_BRANCH_NAME | (not set) | target branch | (not set) | (not set) |
CI_MERGE_REQUEST_IID | (not set) | 1 | (not set) | (not set) |
CI_MERGE_REQUEST_TITLE | (not set) | local | (not set) | (not set) |
CI_ENVIRONMENT_NAME | (not set) | (not set) | (not set) | X |
CI_DEFAULT_BRANCH#
CI_DEFAULT_BRANCH is the project’s default branch, not the branch you happen to have checked out. glci reads it from refs/remotes/origin/HEAD and falls back to main when the clone has none — so rules: if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH matches locally only where it would match on GitLab.
For a repository whose clone has no origin/HEAD and whose default branch is not main, the fix is git remote set-head origin -a: that teaches git the project’s default branch, and glci follows it. --env CI_DEFAULT_BRANCH=<branch> overrides the variable for a single run, but it does not change the branch the served repository advertises (below) or CI_DEFAULT_BRANCH_SLUG.
The repository glci serves to the runner advertises the same branch as its HEAD, the way a GitLab-hosted repository does. With git 2.47 or newer in the job image, git records that as refs/remotes/origin/HEAD during the checkout, so a job reading it agrees with $CI_DEFAULT_BRANCH; on older git the ref is simply absent, exactly as in real CI.
Careful with diffs against the default branch. The repository glci serves is a single synthetic commit, and it carries the default branch as a second name for that same commit. So origin/<default-branch> resolves in a job, but it points at the commit under test rather than at the project’s real default branch: git diff origin/main...HEAD comes back empty instead of failing with unknown revision. A job that lints or scans “only what changed against the default branch” therefore checks nothing locally, and passes. Don’t read a green result from such a job as meaningful — run it against real history.
Comparing contexts#
# Compare job sets across contexts
diff <(glci show --json --context branch=main) \
<(glci show --json --context tag=v2.0.0)
Combining context with –env#
--env adds or overrides variables on top of the context-derived set. Precedence: --env > context-derived > git-derived. See Variables & Secrets for the full table.
glci run --context branch=staging --env DEPLOY_ENV=staging
glci run --context tag=v1.0 --env-file release.env
--env/--env-file work the same way on glci show, glci jobs, and glci variables, so you can preview which jobs a variable-scoped rules: gate selects — without running anything:
# Which jobs run when DEPLOY_ENV=prod, under a tag pipeline?
glci show --context tag=v1.0 --env DEPLOY_ENV=prod
glci jobs --env DEPLOY_ENV=prod
Context presets#
Save frequently-used contexts in .glciconfig.toml or ~/.glci/config.toml:
[contexts.staging]
context = "branch=staging"
env = { DEPLOY_ENV = "staging" }
[contexts.mr-to-main]
context = "merge_request"
mr_source = "feature/current"
mr_target = "main"
Use by name:
glci run --context staging
glci show --context mr-to-main
Context presets can also be embedded in pipeline presets:
[pipelines.quick]
stages = ["lint", "test"]
context = "merge_request"