Pipeline Flow

How a Jenkins build threads through the shared library — from first-run parameter setup to rendered artifacts on an agent. This page is intentionally mechanical; the operational view lives in Usage and the state view in Lifecycle.

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 / setupParameters()

Jenkins master (during "Build Now")

Yes — full vars/, src/, resources/.

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 (node { …​ } blocks)

Master or runner depending on the node(label) selector

Yes on master; yes on runners only for @NonCPS safe calls — agent filesystem is not reachable from master helpers like utils.exists.

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.

A Create → Deploy sequence

create-deploy

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():

  1. The primary source parameters (CascadeChoiceParameter for DATABASE_TYPE, checkbox-based SELECTED_SERVICES) drive state via standard Active Choices reference mechanics.

  2. Every reactive panel writes an aggregate JSON snapshot into _UI_STATE on each change.

  3. Derived parameters (SERVICE_VARIABLES, RESOURCE_ESTIMATE, DEP_GRAPH, FINAL_PREVIEW) read _UI_STATE to 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 → deployEnvStep aborts before compose up; utils.findPortOwners reports which env squatted on the port.

  • Missing mandatory dependency → utils.findMissingMandatoryDeps populates the "missing deps" banner; the operator may still opt in via ALLOW_MISSING_DEPS (see Dependency Management).

  • .qa-build.log is archived via utils.archiveLogOnFailure() — download it from the build’s Artifacts panel for the verbose trace, regardless of QA_LOG_VERBOSE.

  • On CPS serialisation errors (e.g. a YAML LazyMap leaking into state), convert via utils.toBasic(…​) before writeJSON — see CPS Limitations.