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.

Variablebranch=Xmerge_requesttag=Xenv=X
CI_COMMIT_BRANCHX(not set)(not set)(from git)
CI_COMMIT_TAG(not set)(not set)X(from git)
CI_COMMIT_REF_NAMEXsource branchX(from git)
CI_DEFAULT_BRANCHdetected(from git)(from git)(from git)
CI_PIPELINE_SOURCEpushmerge_request_eventpushpush
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"
Esc