vars, src, resources, and Loading

Scenario: Fifty repositories copy the same deployment helper and patch a security defect at different speeds.

Stop copy-pasting the same twenty lines into every Jenkinsfile

Once you have more than a couple of application repositories, you'll notice the same chunk of Pipeline logic - say, "deploy to our internal platform correctly" - getting copy-pasted into every single Jenkinsfile, with tiny variations creeping in each time someone tweaks their own copy. A shared library is Jenkins' answer: write that logic once, in one place, and let every Jenkinsfile call it like a single, reusable command.

Analogy: Think of a shared library like a company-wide style guide and template library for writing memos, instead of every employee individually reinventing their own memo format, header, and footer from scratch each time. When the company decides to update its standard disclaimer text, it changes the one central template, and every future memo written using that template picks up the change automatically - instead of someone having to hunt down and manually edit every memo ever written. The tradeoff, which this whole module explores, is that now everyone's memos genuinely depend on that one central template staying correct and trustworthy.

Everything in this module - vars, src, resources, trust levels, versioning - is really about answering one question well: how do you get the benefits of "write once, reuse everywhere" without creating a single fragile point where one bad change breaks every single consumer at once?

Pipeline example

@Library('delivery-lib@3.4.1') _
pipeline { agent any; stages { stage('Verify') { steps { companyVerify() } } } }

Libraries expose three distinct surfaces

Files placed in a library's vars/ directory expose global steps, callable by their filename (a file named vars/companyVerify.groovy becomes callable as companyVerify() in any Jenkinsfile that loads the library), with an optional matching .txt file providing built-in documentation shown in Jenkins' own snippet generator. src/ follows normal Java/Groovy package structure for actual Groovy classes that get placed on the Pipeline's classpath - useful for genuinely reusable logic that benefits from real object-oriented structure. resources/ contains static template files, read at runtime with libraryResource. Runtime code inside a library should orchestrate existing Jenkins steps - it should not grow into its own miniature application framework, and it should not reach directly into Jenkins' internal controller objects just because Groovy technically allows it.

The @Library annotation loads a configured library before the rest of the script is even compiled, which is what enables normal-looking imports and makes global variables from vars/ available throughout the file. The dynamic library(...) step, by contrast, loads a library later, during execution - and because compilation already happened, it cannot retroactively add normal Groovy imports the way @Library can. Whichever mechanism you use, Jenkins resolves an SCM source and a requested version for that library - record the actual resolved revision somewhere visible in the build, since a mutable "always get the latest" default can silently change what an otherwise-unchanged application Jenkinsfile actually executes.

[Pipeline] Loading library delivery-lib@3.4.1
Resolved to commit 7a3f9c2 (tag 3.4.1)
[Pipeline] { (Verify)
[Pipeline] companyVerify
Running standard verification checks...
All checks passed
[Pipeline] }

Notice the resolved commit is logged explicitly, right alongside the requested version tag - this is exactly the kind of provenance that lets someone investigating a problem months later confirm precisely which library code actually ran for this specific build.

Design small, restart-safe APIs

A step like companyVerify should accept clearly named arguments, validate them itself, call visible, ordinary Pipeline primitives underneath, and return simple, serializable data (strings, numbers, maps) - remembering the CPS/serialization constraints covered in the Scripted Pipeline module, since shared library code runs under the exact same durability rules. Avoid stateful global objects inside a library, and avoid values that can't safely cross a CPS suspension point. Unit-test the library's own validation logic and step-calling code in isolation, then separately integration-test it against real agents, real credentials, deliberately injected failures, and an actual controller restart mid-execution.

A pitfall: fifty repositories, fifty different patch speeds

Keep genuinely application-specific settings (like a particular service's own deployment target names) inside the consuming repository's own Jenkinsfile, not baked into the shared library itself. Centralize only stable, organization-wide policy and safely-repeatable orchestration logic that many teams should share identically. The real incident this module's scenario describes - fifty repositories all independently copy-pasting the same deployment helper, then patching a discovered security defect in that copied code at fifty different speeds, some fast, some very slow or never - is precisely the problem a shared library is meant to solve: a library earns its cost specifically when it makes a security correction or an operational contract consistently applied across every consumer at once, not merely when it happens to remove a few lines of repetitive, readable Jenkinsfile text.

Goal: Practice the concrete behavior in jenkins-declarative-rescue. Learn sections have no Jenkins terminal; the Jenkins lab opens the real shared service in a new full-screen tab inside your private folder.