Pipeline Flow
Build-time vs run-time
A Jenkins pipeline has two distinct phases. The shared library is loaded in one but not the other:
| Phase | Who runs it | Shared library available? |
|---|---|---|
Pipeline definition / |
Jenkins master (during "Build Now") |
Yes — full |
Active Choices parameter render |
Active Choices sandbox on master (on every form refresh) |
No — only the String returned at build time is executed. |
Pipeline step bodies ( |
Master or runner depending on the |
Yes on master; yes on runners only for |
The Active Choices sandbox limitation is why qaUiScripts.* methods return pre-baked Strings and why the slashy-regex escaping inside those Strings looks doubled (see qaUiScripts — Build-time Active Choices Factory).
First-run handler
All user-facing jobs (Create, Update, Deploy, Manage, List) share the same first-run pattern:
def call(Map config = [:]) {
ansiColor('xterm') {
utils.logInit()
if (!params.containsKey('ENV_NAME')) {
setupParameters()
echo "Parameters configured. Refresh and run 'Build with Parameters'."
currentBuild.result = 'SUCCESS'
return
}
try {
doWork()
} catch (err) {
utils.archiveLogOnFailure()
utils.failureHints(err.message, [...], [...])
throw err
}
}
}
The first invocation has no parameters bound, so the step writes the Active Choices parameter definitions via properties([parameters([…])]) and exits. Users then reload the build page and click "Build with Parameters" for every subsequent run.
Active Choices ↔ hidden state parameter
Several parameters cascade off each other (database → services → versions → final preview). They communicate through a hidden _UI_STATE parameter injected by qaUiScripts.sharedCssJs():
-
The primary source parameters (
CascadeChoiceParameterforDATABASE_TYPE, checkbox-basedSELECTED_SERVICES) drive state via standard Active Choices reference mechanics. -
Every reactive panel writes an aggregate JSON snapshot into
_UI_STATEon each change. -
Derived parameters (
SERVICE_VARIABLES,RESOURCE_ESTIMATE,DEP_GRAPH,FINAL_PREVIEW) read_UI_STATEto render without triggering direct cascade chains.
DynamicReferenceParameter is used for display-only panels; it cannot serve as a cascade source for another parameter (see Active Choices — Patterns and Pitfalls).
Rendered artifacts per env
/var/jenkins_home/qa-data/envs/<env>/
├── docker-compose.yml # compose-<db>.yml filtered to SELECTED_SERVICES, profiles stripped
├── .env.<db> # global .env with user overrides
├── mysql/.env.mysql # per-service env files (one dir per selected service)
├── ftacs/.env
├── ...
├── meta.json # written via utils.atomicWriteMeta
└── .qa-build.log # only on failure, archived as an artifact
On the runner, under AGENT_ENVS_DIR (default /opt/qa-envs/<env>/), the same bundle is unstashed, plus any Docker bind-mount volumes created by the services themselves.
Failure paths
-
Port conflict on the runner →
deployEnvStepaborts beforecompose up;utils.findPortOwnersreports which env squatted on the port. -
Missing mandatory dependency →
utils.findMissingMandatoryDepspopulates the "missing deps" banner; the operator may still opt in viaALLOW_MISSING_DEPS(see Dependency Management). -
.qa-build.logis archived viautils.archiveLogOnFailure()— download it from the build’s Artifacts panel for the verbose trace, regardless ofQA_LOG_VERBOSE. -
On CPS serialisation errors (e.g. a YAML
LazyMapleaking into state), convert viautils.toBasic(…)beforewriteJSON— see CPS Limitations.