Jenkins pipeline shared library Gradle plugin
July 8, 2026 · View on GitHub
| Tested versions | |
|---|---|
A Gradle plugin for developing and testing Jenkins Pipeline Shared Libraries.
Features
- Groovy compilation of
src/andvars/against Jenkins APIs. - Unit testing via Jenkins Pipeline Unit.
- Integration testing via Jenkins Test Harness (
JenkinsRule). - Automatic Jenkins BOM injection and dependency alignment.
- Local library auto-registration for integration tests (no network needed).
- Configuration cache compliant.
Quick start
gradle/libs.versions.toml
[plugins]
jenkins-shared-library = { id = "com.mkobit.jenkins.pipelines.shared-library", version = "VERSION" }
build.gradle.kts
plugins {
alias(libs.plugins.jenkins.shared.library)
}
dependencies {
jenkinsPlugin("org.jenkinsci.plugins:pipeline-model-definition")
}
The plugin configures by convention:
src/andvars/compile as Groovy against Jenkins core and the default workflow pluginstest/unit/→testsuite with JenkinsPipelineUnit on the classpathtest/integration/→integrationTestsuite withjenkins-test-harness
No sharedLibrary {} block is required for the default configuration.
The default Jenkins line is 2.479.x LTS — see Changing the Jenkins LTS line to target a different version.
Source layout
Jenkins SCM loading imposes hard constraints on the main source directories.
When Jenkins loads a shared library, it places src/ directly on the Groovy classpath, so classes must be rooted there (src/com/example/Util.groovy → com.example.Util).
vars/ and resources/ must also sit at the repository root.
src/ ← Groovy shared library classes
vars/ ← pipeline step scripts (filename = step name)
resources/ ← files accessible via libraryResource()
test/
unit/groovy/ ← JenkinsPipelineUnit (fast, no Jenkins runtime)
unit/java/ ← Java unit tests (optional)
integration/groovy/ ← JenkinsRule integration tests (embedded Jenkins)
integration/java/ ← Java integration tests (optional)
Test sources may also be in test/unit/kotlin/ or test/integration/kotlin/ for Kotlin consumers.
sharedLibrary {} extension
All properties have sensible defaults and are optional.
sharedLibrary {
jenkins {
version = "2.528.3" // Jenkins core version (default: 2.479.1)
bomVersion = "6398.v1d26a_dd495e2" // BOM auto-injected into jenkinsPlugin
}
plugins {
plugin("org.jenkins-ci.plugins:git") // additional Jenkins plugins
}
dependencies {
sharedLibrary(project(":peer-lib")) // peer shared library (multi-project)
sharedLibrary("com.example:config-lib:1.0") // peer via composite build (includeBuild)
}
pipelineUnitVersion = "1.29" // JenkinsPipelineUnit version (test suite)
libraryName = "my-shared-lib" // Jenkins library name (default: project.name)
autoRegisterLibrary = true // generate SharedLibraryAutoRegistrar (default: true)
implicit = true // register library as implicit (default: true)
}
The Jenkins BOM for the configured LTS line is injected automatically into jenkinsPlugin — no explicit jenkinsPlugin(platform(...)) call is needed.
The BOM module coordinate is derived from jenkins.version (e.g., 2.479.1 → bom-2.479.x).
The plugins {} block is equivalent to dependencies { jenkinsPlugin("...") } — use whichever reads more naturally in your build.
Examples
The examples/ directory contains standalone Gradle composite builds demonstrating common usage patterns.
| Example | Demonstrates |
|---|---|
basic | Minimal plugin apply; JenkinsPipelineUnit unit tests and JenkinsRule integration tests |
additional-test-suites | Custom third test suite wired via sharedLibrary.withJenkins() |
explicit-library-name | libraryName override and implicit = false |
junit-groovy | Unit tests written in Groovy using JenkinsPipelineUnit |
kotest | Kotlin source with Kotest unit and integration test suites |
library-resource | Steps that read files via libraryResource() |
peer-libraries | Declaring another shared library as a peer dependency for cross-library step access |
peer-libraries-composite | Peer libraries across separate Gradle builds via includeBuild and GAV notation; transitive nested composite |
version-catalog | Version catalog wiring for plugin versions and Jenkins plugin coordinates |
Run all examples from the repo root:
./gradlew :examples:check
For a complete standalone example see the example repository.
IntelliJ IDEA import
The main project and all examples load together in a single IntelliJ IDEA import.
Open or import the root project directory in the IDE.
The composite build configuration automatically registers each example as an included build.
You can run and debug tasks (such as :examples:example-* or individual tests) directly from the IDE's Gradle tool window or from the code editor.
See examples/README.md for detailed instructions and troubleshooting notes on importing and running examples in the IDE.
Running tests
./gradlew test # JenkinsPipelineUnit unit tests
./gradlew integrationTest # JenkinsRule integration tests (downloads Jenkins WAR on first run)
./gradlew check # all suites
Jenkins downloads the WAR and plugins on first run; subsequent runs use the Gradle module cache.
Changing the Jenkins LTS line
Set version in sharedLibrary {} to target a different LTS line:
sharedLibrary {
jenkins {
version = "2.528.3"
}
}
The plugin derives the BOM module coordinate automatically from version (e.g., 2.528.3 → bom-2.528.x).
Renovate keeps the BOM version up to date within the configured LTS line.
To override the BOM version explicitly, set bomVersion as well.
Additional test suites
Register extra suites and opt them into full Jenkins wiring with withJenkins().
This applies the same wiring as the built-in integrationTest suite: jenkins-test-harness, HPI classpath, WAR path, system properties, JVM --add-opens flags, maxParallelForks = 1, and heap defaults.
See the additional-test-suites example.
Wire additional suites into check if they should run in CI:
tasks.check {
dependsOn(
tasks.named("smokeTest"),
)
}
Note
Spock 2.x brings Groovy 3.x onto the runtime classpath, which conflicts with the bundled groovy-all:2.4.21 on Jenkins 2.479.x LTS when sandbox=true.
Use sandbox=false in CpsFlowDefinition only for Spock-based suites on 2.479.x.
JUnit-based suites (the default test and integrationTest) are unaffected and should keep using sandbox=true.
The Spock restriction is expected to lift on Jenkins 2.492.x+ once its internal Groovy 3 migration completes.
Peer libraries
A shared library can declare other shared libraries as peer dependencies. Each declared peer is registered with the embedded Jenkins as a normal Jenkins Global Library — the same entries an admin would configure in Manage Jenkins → Global Pipeline Libraries — so pipelines call peer steps and reference peer classes exactly as they would in production.
sharedLibrary {
dependencies {
sharedLibrary(project(":peer-lib")) // subproject in the same build
sharedLibrary("com.example:config-lib:1.0.0") // composite build (includeBuild)
sharedLibrary(project(":config-lib")) {
libraryName = "config" // override the Jenkins library name
implicit = false // require @Library('config') _ in pipelines
}
}
}
Note
Binary GAV coordinates ("group:artifact:version") work when the peer is declared via includeBuild(...) in settings.gradle.kts and Gradle substitutes the coordinate with the local project.
Resolution from a remote Maven repository is not supported: the sharedLibrarySourceElements variant ships a directory artifact that Maven's publishing pipeline cannot upload.
See issue #165.
See the peer-libraries example.
JUnit 4
The built-in integrationTest suite defaults to JUnit Jupiter.
If you have an existing JUnit 4 test suite, configure it explicitly:
testing {
suites {
named<JvmTestSuite>("integrationTest") {
useJUnit()
dependencies {
implementation(libs.junit)
}
}
}
}
Migration from 0.10.x
See the 0.11.0 entry in CHANGELOG.md for the full API diff.
Troubleshooting
Jenkins WAR not found at runtime
Symptom: WarExploder or JenkinsRule fails with "WAR not found".
The plugin injects jth.jenkins-war.path automatically.
If you see this error, verify that integrationTest is configured by the plugin (not manually) and that jenkins-war is on the jenkinsPlugin configuration.
groovy-all conflict with sandbox=true and Spock 2.x on Jenkins 2.479.x
The plugin injects groovy-all:2.4.21 at integration test runtime to satisfy SandboxInterceptor.
Spock 2.x also brings groovy:3.x onto the classpath.
These conflict when sandbox=true.
Use sandbox=false on 2.479.x LTS, or move to a 2.492.x+ Jenkins line where the internal Groovy runtime is 3.x.
@Grab in shared library source
@Grab annotations resolve at Jenkins runtime via Grape/Ivy — not at Gradle build time.
Gradle's compileGroovy task runs in an isolated classloader that cannot resolve @Grab dependencies.
For tests that exercise @Grab-annotated code, use JenkinsRule (integrationTest) with network access, or set up a local Ivy repository pointed at the Gradle module cache.
ClassFilter errors with custom LocalLibraryRetriever
The generated META-INF/hudson.remoting.ClassFilter resource whitelists LocalLibraryRetriever for Jenkins remoting.
If you see ClassFilter rejections for the generated class, ensure generateLocalLibraryFiles has run (it is wired as a dependency of compileIntegrationTestJava automatically).