The Delivery Pipeline plugin visualizes delivery pipelines in Jenkins: chains of jobs with upstream/downstream dependencies, and Pipeline (Jenkinsfile) jobs. It is made for information radiators (there is a full screen page) and for everyday use next to the jobs. Version 1117 gained full support for both Declarative and Scripted Pipeline syntax.
Plugin documentation: plugins.jenkins.io/delivery-pipeline-plugin. Bugs and feature requests go to the GitHub issue tracker.
This plugin was contributed to the community by Diabol AB.
🤖 Version 1117+ generated with Claude Code Fable 5.1 September 2026
The same board follows the Jenkins dark theme:
A Pipeline job on the same kind of view: the newest run was restarted from its Deploy stage, so the stages before it were not built, and the run before it waited at an input step in its Approve stage.
A wall board: the full-screen page of a board with twenty chains of eight jobs and four Pipelines, as a screen in a team room shows it during a deployment.
The same board as a page, at half scale, with the aggregated row above every chain:
Pipeline shapes side by side, from the test suite's corpus: runs that started other runs laid out on rows with arrows across, a chain of freestyle jobs behind a Pipeline, nested and parallel stages:
A chain that fans out and in again:
One Pipeline run that started two jobs from one stage, each on a row of its own, and the Pipeline one of them started in turn:
The same boards in the dark theme: large, shapes, diamond, chain of runs.
1117+ is a rewrite of the plugin on the Jenkins 2.555 LTS baseline and Java 21. Existing views, jobs and Job DSL scripts keep working; what changed is underneath and around them.
What stays the same
- The view type,
Delivery Pipeline View, with the same persisted configuration. Views created by 1.x and by Job DSL'sdeliveryPipelineView { ... }load unchanged. - The
Delivery Pipeline configurationjob property (stage name, task name, description template) and thedeliveryPipelineConfigurationJob DSL call. - The
Create Delivery Pipeline versionbuild wrapper with itsPIPELINE_VERSIONvariable and token. - The URLs: the view page,
?fullscreen=truefor the wall board page,?component=N&page=Pfor paging.
What is new
- One view type for both kinds of pipelines. A component of a view points at the first job of a chain, or at a Pipeline job. The "Delivery Pipeline View for Jenkins Pipelines" of 1.x is gone as a type; a saved one is turned into a Delivery Pipeline View with the same components when Jenkins loads it.
- Pipeline jobs are read from the run's flow graph. Every top-level stage is a stage; the innermost stages nested in it, or else its parallel branches, are its tasks, so that sequential stages inside a parallel branch each get a task, named "Linux: Unit" after the branch and the stage. Declarative
parallelandmatrixblocks render one task per branch; matrix cells are named by their axes and stay one task each. A stage inside a scripted parallel branch is shown as "branch: stage", so that two branches with the same stages stay apart, and aparallelnested inside a branch shows its inner branches as tasks, named the same way. A run without any stage, as a scripted Pipeline of plain steps is, is shown as its parallel branches, or else as one task named after its job, the way a chained job without a stage name is. Notaskstep is needed; the step of 1.x is deprecated but still works, shows its block as a task as before, and prints a reminder to use a nestedstage. - The view model is a set of immutable records with one documented JSON contract, served by
<view>/api/json(seese.diabol.jenkins.pipeline.model). The page script renders that JSON; it uses no third-party libraries and no page globals, works under a Content-Security-Policy and follows the Jenkins theme, dark themes included. - Computed models are cached for a short while and dropped whenever a build starts, ends or is deleted, the queue changes or a job is reconfigured, so many wall boards polling the same view cost little more than one.
- Actions the page posts (start, manual trigger, rebuild, abort, proceed input) are checked on the server against the view's settings and the user's permissions; buttons only appear for users who may use them.
- Task descriptions are rendered through the markup formatter configured for Jenkins, exactly like job descriptions. To use HTML in description templates, configure a formatter that allows it (for example the OWASP Markup Formatter plugin with "Safe HTML").
- Stages are laid out by the longest path from the first stage, so arrows always point to the right.
- Pipeline runs can be run again with the same parameters from the button next to the run's heading. Declarative runs can also be restarted from any of their stages, from the button of the stage's task, through the "Restart from Stage" feature of the Pipeline: Declarative plugin when it is installed.
- Test results recorded by a
junitstep inside a stage or a parallel branch show on that task. Warnings Next Generation results of a Pipeline run belong to the run as a whole and show under the run's heading. - Only the stages a Jenkinsfile declares are shown; the stages Declarative Pipeline generates around them ("Declarative: Checkout SCM", "Post Actions", "Tool Install") are left out, and test results recorded there, or anywhere outside the tasks shown, are listed under the run's heading. A run waiting in the queue is shown before it starts, laid out like the previous run. A task waiting at an input step with parameters links to the input page, since only that page can collect them; one without parameters is proceeded from the view.
- When the Pipeline Graph View plugin is installed (it is one of the plugins a fresh Jenkins suggests), every stage, nested stage and parallel branch links to its own log in that plugin's console page. Without it, a running stage links to the run's console and a finished one to the run.
- A Pipeline that starts other jobs with the
buildstep shows the runs it started as part of the same pipeline: their stages follow the stage that started them, named "job: stage", on the first row with room, with an arrow from that stage, and the runs they start in turn follow them. A started job that is not a Pipeline brings the chain of jobs downstream of it, laid out as a component of that job would show it. A chained job that triggers a Pipeline job, through the core build trigger, the Parameterized Trigger plugin or the Pipeline job's own "build after other projects" trigger, is followed into that run the same way, in components of chained jobs too, so chains of jobs and Pipeline runs mix freely. A run still waiting in the queue is a queued task; one cancelled before it started is left out. Thebuildstep part needs the Pipeline: Build Step plugin, part of the suggested set, at version 539 (December 2023) or newer, which records the started runs; with an older one the runs stay separate. As with chains of jobs, everyone who can see the view sees every job the chain reaches; acting on one still needs the permission on that job. - The aggregated row, in which every stage shows the latest version that reached it, is drawn for Pipeline components too. It is laid out like the newest run that completed its stages, since a failed scripted run stops at the failing stage, and each stage shows the newest run in which it ran, with that run's display name as the version.
- Every stage and every run carries its own status too. When a stage's own steps fail or go unstable outside its tasks, as a
junitstep after the branches or a stage'spostsection does, the stage header shows it; when a run fails outside its stages, its heading says so. A board no longer shows all green for an unstable run. - A Delivery Pipeline manual step post-build action of its own, so manual steps no longer need the Build Pipeline plugin.
- The required dependencies are plugins a fresh Jenkins installs with its suggested set (Pipeline: Job, Pipeline: API, Pipeline: Input Step, JUnit, Token Macro, Structs) plus Pipeline Graph Analysis, the small library that reads stage status and timing from a run's flow graph; the plugin manager installs it alongside. Everything else is optional and activates when the plugin is present: Build Pipeline (manual triggers), Promoted Builds (promotions, promotion-triggered jobs), Warnings Next Generation (static analysis results), Parameterized Trigger (blocking sub-projects, Pipeline jobs it triggers), Pipeline: Declarative (restart from stage), Pipeline Graph View (a log per stage), Pipeline: Build Step (the runs a
buildstep started, as a chain).
A component can also name a multibranch project, or any folder: it becomes one pipeline per job inside, named "component / branch", the primary branch first. A regular expression such as app/(.*) still picks branches by name.
What was removed (settings of 1.x that 1117+ ignores when loading an old view)
- Custom CSS URLs (
embeddedCss,fullScreenCss) and themes: the view follows the Jenkins theme instead. showAvatars,linkRelativeandlinkToConsoleLog: links are always relative to the Jenkins root and running tasks always link to their console.- The aggregated change log (
showAggregatedChanges,aggregatedChangesGroupingPattern). - The Dashboard View portlet.
Delivery Pipeline plugin 1117+ requires Jenkins 2.555.3 or later and Java 21.
Delivery Pipeline plugin 1.5 and 1.6 require Java 17 and Jenkins 2.541.2 or later; 1.4.0 and later require Java 8 and Jenkins 2.164 or later.
Create a view of type Delivery Pipeline View. Under Pipelines, add a component per pipeline: a name and the initial job. For a chain of jobs the view follows the downstream dependencies of the initial job (build triggers, parameterized triggers, promotions); an optional final job stops the chain there. Alternatively a regular expression over job names creates one component per match, named by the expression's capture group. Job names are typed, with suggestions as you type and a check of what you typed, rather than picked from a list of every job, so that the form opens at once on a controller with thousands of jobs too.
Jobs are grouped into stages by the Delivery Pipeline configuration property of each job: jobs with the same stage name share a stage, and the task name is what the job's box says. Without the property, the job's display name is used for both.
The Display and Actions sections control what the view shows (aggregated pipeline, change log, descriptions, test results, static analysis results, promotions, total build time, paging, columns, sorting) and what the page lets users do (start a pipeline, trigger manual steps, rebuild a task, abort a build).
The same options are available from Job DSL:
deliveryPipelineView('Ancestry') {
pipelineInstances(4)
showAggregatedPipeline()
enablePaging()
showChangeLog()
showDescription()
showTotalBuildTime()
allowPipelineStart()
allowRebuild()
enableManualTriggers()
updateInterval(45)
pipelines {
component('Ancestry', 'Ancestry_Automated/build')
}
}
Job names may be full names, as above, or relative to the view's folder; the configuration form keeps them as they are stored.
Add the Delivery Pipeline manual step post-build action to a job and list the jobs a person starts by hand. They show up downstream of the job in the view, nothing starts them automatically, and with Allow manual triggers enabled each one gets a play button once the upstream build has finished, for users who may build it. The build that is started gets the upstream build's parameters where the job defines them, the job's defaults for the rest, and belongs to the same pipeline instance. From Job DSL:
job('build') {
publishers {
deliveryPipelineManualStep {
downstreamProjectNames('deploy_staging, deploy_production')
}
}
}
Jobs listed in the Build Pipeline plugin's Build other projects (manual step) action are recognised in the same way when that plugin is installed. Pipeline runs waiting at an input step show a button that lets them proceed.
A view with many pipelines can get one parent above them, the consolidated pipeline, which runs them all, a few at a time. Switch on Show the consolidated pipeline in the view's configuration and set:
- Number of concurrent pipelines (default 3): how many pipelines a batch holds, and so the most that ever run side by side.
- Sleep time between concurrent pipelines (default 10 seconds): the pause after a batch has finished, before the next one starts.
The view then shows a component named Consolidated pipeline first, across the whole width: a stage per batch, each leading to the next, and a task per pipeline with the status of that pipeline as a whole. With Allow starting a pipeline on, users who may build the first job of every pipeline get a button that runs them all and, while a run is going, one that stops it.
A run takes the pipelines in the order the view is configured in, whatever the sorting and however many components the view shows, and cuts them into batches. It builds the first job of every pipeline of a batch (a job with parameters gets their defaults), waits until all of them have come to an end, sleeps, and goes on with the next batch, whatever the outcome of the last one. A pipeline has come to an end when none of its tasks is running or waiting in the queue any more, blocked queue items included, and that has been so for three seconds: the whole chain downstream of the first build counts, or for a Pipeline job the run with the runs it started. A Pipeline run waiting at an input step holds its batch until someone answers; a manual step that nobody triggers does not.
That is the point of batches over simply starting everything. Take image builds that share an agent, where the clean-up job of each image is blocked while any build is running: started all at once, the builds keep the clean-ups in the queue until the last build is over, and the agent's disk fills up first. Run three at a time, the clean-ups of each batch get their turn before the next three builds start.
The run is planned when it starts: reconfiguring the view, or a seed job replacing it, does not change a run that is going. Runs are kept in $JENKINS_HOME/se.diabol.jenkins.pipeline.consolidated.ConsolidatedRuns.xml, so a run goes on after a restart, and no new batch starts while Jenkins is preparing to shut down. Stopping a run starts no further batch; the pipelines that are running go on, and the run ends when they have. Stopping it a second time ends it at once, which is the way out when a pipeline can never end, such as one whose job waits in the queue for an agent that is gone. Between runs the component shows what a run started now would do, each pipeline with the outcome it had in the last run. The builds a run starts name it as their cause, and so do the pipelines in the view.
While a run is going the component says when it is expected to end, and between runs how long a run takes. It goes by how long each pipeline took in the last run, from the start of its first build until nothing of it was running or queued any more, which includes the waiting that comes with the company it had on the agents. Before a pipeline has been through a run, the newest instance of it that ran to a good end counts instead, and a pipeline nothing is known of counts as the average of the others. The expected end is what is left of the current batch, going by its slowest pipeline, and for every batch to come its slowest pipeline and the sleep before it; the first run of a view tends to be expected too early, because pipelines that ran alone were not held up by others.
Job DSL has no methods for these options yet; a configure block sets the view's fields:
deliveryPipelineView('Ancestry_Automated/all pipelines') {
pipelineInstances(1)
allowPipelineStart()
pipelines {
component('hivealpine', 'Ancestry_Automated/0/build_hivealpine_master')
component('hivegolang', 'Ancestry_Automated/0/build_hivegolang_master')
}
configure { view ->
view / 'showConsolidatedPipeline'(true)
view / 'noOfConcurrentPipelines'(3)
view / 'sleepBetweenConcurrentPipelines'(10)
}
}
Scripts can start and stop a run with a POST to <view>/startConsolidated and <view>/stopConsolidated, which answer 403 to a user who may not build every pipeline and 409 when a run is going already, or none is.
<view>/api/json returns the components with their pipelines, stages and tasks, plus the view's settings. The contract is documented in the se.diabol.jenkins.pipeline.model package. Timestamps are epoch milliseconds, durations are milliseconds and URLs are relative to the Jenkins root. The page polls this endpoint every update interval seconds.
Computing a view means walking the build history of every job in its pipelines, or the flow graph of every run of a Pipeline job. The plugin does that once per view and page, keeps the result in memory, and serves it to every browser that polls the view; only the per-user facts (whether the buttons may be shown) are added when the JSON is written. Each cached model remembers the jobs it shows: when a build of one of them starts, ends or is deleted, or one of them enters or leaves the queue, only the models showing that job are dropped, so a busy controller does not recompute every board on every event. A job being created, reconfigured, renamed or deleted empties the cache, because that can change which jobs belong to which pipeline. Between events an entry is served for a limited time:
| System property | Default | Applies to |
|---|---|---|
se.diabol.jenkins.pipeline.cache.ModelCache.idleSeconds |
30 | a view in which nothing is running or queued |
se.diabol.jenkins.pipeline.cache.ModelCache.activeSeconds |
2 | a view with a running or queued build |
The active limit bounds how stale a progress bar or the stages of a running Pipeline can be, because stages come and go without any of the events above. The idle limit only matters for a controller where builds are rare and the views are large. Zero turns the cache off, which is useful when measuring.
Set the properties at startup with the Java options of the controller, for example -Dse.diabol.jenkins.pipeline.cache.ModelCache.activeSeconds=5, or change them at runtime from the script console with System.setProperty(...): they are read on every request. Raise activeSeconds when many wall boards show Pipeline jobs that run for a long time; raise idleSeconds when large chains of jobs are shown on many screens and builds are rare. The update interval of each view is the other knob: polls that arrive within the cached time cost almost nothing, so a short interval is fine as long as the limits above fit the controller.
The JSON itself is exported once per model and viewer and kept with the cached model, and every response carries an ETag made of the model's version and the viewer. The page sends it back on the next poll, and a poll that finds the model unchanged is answered with 304 Not Modified and no body, so a quiet board costs a header exchange per poll and a busy one costs one export per model and viewer however many screens watch it. Only serverTime is written afresh into every response. Requests with Stapler's tree, depth, pretty or xpath parameters are exported on the spot.
To see what a view costs, time <view>/api/json twice: the first answer after an event is the computation, the second one is the cache. On a controller with views of several hundred tasks the first takes a few seconds and the second a fraction of one.
Finished Pipeline runs are analysed once and remembered separately until they are deleted, so a Pipeline job with a long history costs the flow graph walk only for the runs that are still going on.
Only Docker is needed. Maven and the JDK run in a container, with the Maven repository cached in docker/.m2:
docker/run.sh build # target/delivery-pipeline-plugin.hpi, ready to upload to a controller
docker/run.sh test # the test suite and SpotBugs (mvn verify) in the container
docker/run.sh mvn hpi:run # any other Maven command, here a local Jenkins with the plugin
The test suite renders the view in HtmlUnit with JavaScript enabled and takes a few minutes. With Java 21 and Maven 3.9 installed, mvn clean verify works as usual, and LOCAL_MAVEN=1 docker/run.sh ... uses that Maven.
The suite also carries a Jenkinsfile zoo in docker/jenkinsfiles/: one Pipeline script per shape (nested and parallel stages, a matrix, skipped and failed stages, retries, an input with parameters, a Pipeline starting another), each with the stages, tasks and statuses the view must show. Add a script and its expectations to cover a new shape.
docker/run.sh all
builds the plugin and a Jenkins 2.568.3 image with it, seeds a folder of chains and Pipeline jobs that exercise every feature (fan-out, fan-in, manual steps of both kinds, failures, a disabled job, a matrix job, an eight-stage chain, parallel and nested stages, an input gate, unstable and skipped stages), runs docker/validate.py against it, which checks every view's JSON and page and performs every action the page can post, and captures light, dark, full screen and phone screenshots into docker/out/. docker/upgrade.sh upgrades a controller from 1.4.2 to this checkout on one Jenkins home and checks what loaded. See docker/README.md.








