Jenkins Shared Library Tutorial - Advanced Guide
Jenkins Shared Library - Advanced Guide
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#jenkins-shared-library---advanced-guide)
Prerequisites: Complete the main tutorial first to understand the basics.
This guide covers advanced topics for mastering Jenkins Shared Libraries.
Table of Contents
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#table-of-contents)
- Team-Based Architecture
- Testing Your Shared Library
- Job DSL and Seed Jobs
- Advanced Patterns
- Best Practices
- Enterprise Collaboration
Team-Based Architecture
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#team-based-architecture)
Modern Jenkins CI/CD has evolved from environment-based structures (development/production) to domain-specific team organization. This approach provides better scalability, team autonomy, and technology-specific optimizations.
Team Organization Model
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#team-organization-model)
jenkins-controllers/
├── common/ # Cross-team shared utilities
├── data-science/ # ML/AI workflows and experimentation
├── engineering/ # Software development and deployment
└── devops/ # Infrastructure and platform management
Seed Job Configuration
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#seed-job-configuration)
The seed job is configured to work with team-based controllers using JENKINS_TEAM_NAME instead of JENKINS_ENVIRONMENT_NAME.
File: jobs/jobSeed.groovy
// Team-based seed job pipeline
final String projectDir = 'demo-repository/jobs'
final String commonJobsDir = 'common'
// Team variables that must be set on the Jenkins controller
assert env.JENKINS_TEAM_NAME, 'JENKINS_TEAM_NAME must be set (data-science, engineering, devops)'
assert env.JENKINS_TEAM_NAME != commonJobsDir, 'JENKINS_TEAM_NAME cannot be "common"'
assert env.JENKINS_TEAM_NAME in ['data-science', 'engineering', 'devops'], 'JENKINS_TEAM_NAME must be one of: data-science, engineering, devops'
final String teamJobDslDir = "${projectDir}/jenkins-controllers/${env.JENKINS_TEAM_NAME}/src/dsl/groovy"
final String commonJobDslDir = "${projectDir}/jenkins-controllers/${commonJobsDir}/src/dsl/groovy"
node('controller-agent') {
stage('Process Job DSL') {
jobDsl(
additionalParameters: [
ROOT_FOLDER: rootFolder,
TEAM: env.JENKINS_TEAM_NAME
],
targets: "${commonJobDslDir}/**/*.groovy\n${teamJobDslDir}/**/*.groovy"
)
}
}
Team-Specific Job DSL Examples
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#team-specific-job-dsl-examples)
Data Science Team Jobs
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#data-science-team-jobs)
File: jenkins-controllers/data-science/src/dsl/groovy/dataScienceJobs.groovy
String rootFolder = ROOT_FOLDER ?: ''
String team = TEAM ?: 'data-science'
// ML Experiment folder structure
folder("${rootFolder}/ml-experiments") {
displayName('ML Experiments')
description('Machine learning model development and experimentation')
}
// Model Training Pipeline
pipelineJob("${rootFolder}/ml-experiments/model-training") {
displayName('Model Training Pipeline')
parameters {
stringParam('MODEL_NAME', 'default-model', 'Name of the model to train')
choiceParam('ALGORITHM', ['xgboost', 'random-forest', 'neural-network'], 'ML Algorithm')
stringParam('DATASET_VERSION', 'latest', 'Dataset version to use')
booleanParam('ENABLE_HYPERPARAMETER_TUNING', false, 'Enable hyperparameter optimization')
}
definition {
cpsScm {
scm {
git {
remote {
url('https://github.com/your-org/ml-models.git')
credentials('git-credentials')
}
scriptPath('jenkins-controllers/data-science/src/main/groovy/ml-experiments/model-training-pipeline.groovy')
}
}
}
}
}
// Model Deployment Pipeline
pipelineJob("${rootFolder}/model-deployment/model-serving") {
displayName('Model Serving Deployment')
parameters {
stringParam('MODEL_NAME', '', 'Model name from MLflow registry')
stringParam('MODEL_VERSION', '', 'Model version to deploy')
choiceParam('DEPLOYMENT_TARGET', ['staging', 'production', 'a-b-test'], 'Deployment target')
choiceParam('SERVING_PLATFORM', ['sagemaker', 'kubernetes', 'lambda'], 'Serving platform')
}
definition {
cpsScm {
scm {
git {
scriptPath('jenkins-controllers/data-science/src/main/groovy/model-deployment/model-serving.groovy')
}
}
}
}
}
Engineering Team Jobs
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#engineering-team-jobs)
File: jenkins-controllers/engineering/src/dsl/groovy/engineeringJobs.groovy
String rootFolder = ROOT_FOLDER ?: ''
// Application deployment with multiple strategies
pipelineJob("${rootFolder}/applications/app-deployment") {
displayName('Application Deployment Pipeline')
parameters {
stringParam('APPLICATION_NAME', '', 'Application name to deploy')
stringParam('VERSION', '', 'Version to deploy')
choiceParam('ENVIRONMENT', ['development', 'staging', 'production'], 'Target environment')
choiceParam('DEPLOYMENT_STRATEGY', ['rolling', 'blue-green', 'canary'], 'Deployment strategy')
booleanParam('RUN_SMOKE_TESTS', true, 'Run smoke tests after deployment')
}
definition {
cpsScm {
scm {
git {
scriptPath('jenkins-controllers/engineering/src/main/groovy/applications/deployment-pipeline.groovy')
}
}
}
}
}
// E2E Testing Pipeline
pipelineJob("${rootFolder}/testing/e2e-testing") {
displayName('End-to-End Testing Suite')
parameters {
choiceParam('TEST_SUITE', ['smoke', 'regression', 'full', 'performance'], 'Test suite to run')
choiceParam('ENVIRONMENT', ['development', 'staging'], 'Environment to test against')
stringParam('BROWSER', 'chrome', 'Browser for UI tests')
booleanParam('PARALLEL_EXECUTION', true, 'Run tests in parallel')
}
definition {
cpsScm {
scm {
git {
scriptPath('jenkins-controllers/engineering/src/main/groovy/testing/e2e-testing.groovy')
}
}
}
}
}
DevOps Team Jobs
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#devops-team-jobs)
File: jenkins-controllers/devops/src/dsl/groovy/devopsJobs.groovy
String rootFolder = ROOT_FOLDER ?: ''
// Infrastructure Pipeline
pipelineJob("${rootFolder}/infrastructure/terraform-deployment") {
displayName('Terraform Infrastructure Pipeline')
parameters {
choiceParam('ACTION', ['plan', 'apply', 'destroy'], 'Terraform action')
choiceParam('WORKSPACE', ['development', 'staging', 'production'], 'Terraform workspace')
stringParam('TERRAFORM_VERSION', '1.5.0', 'Terraform version to use')
booleanParam('AUTO_APPROVE', false, 'Auto-approve apply (dev only)')
}
definition {
cpsScm {
scm {
git {
scriptPath('jenkins-controllers/devops/src/main/groovy/infrastructure/terraform-pipeline.groovy')
}
}
}
}
}
// Kubernetes Management
pipelineJob("${rootFolder}/platform-engineering/k8s-deployment") {
displayName('Kubernetes Cluster Management')
parameters {
choiceParam('CLUSTER', ['dev-cluster', 'staging-cluster', 'prod-cluster'], 'Target cluster')
choiceParam('ACTION', ['deploy', 'update', 'rollback', 'scale'], 'Kubernetes action')
stringParam('NAMESPACE', 'default', 'Target namespace')
stringParam('MANIFEST_PATH', 'k8s/', 'Path to Kubernetes manifests')
}
definition {
cpsScm {
scm {
git {
scriptPath('jenkins-controllers/devops/src/main/groovy/platform-engineering/kubernetes-deployment.groovy')
}
}
}
}
}
Team Configuration Management
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#team-configuration-management)
Teams can have their own configuration while sharing common patterns:
File: src/com/example/jenkins/config/TeamConfig.groovy
package com.example.jenkins.config
class TeamConfig {
Map teams = [
'data-science': [
tools: ['python', 'mlflow', 'jupyter'],
platforms: ['sagemaker', 'kubernetes'],
notifications: [slack: '#ml-builds'],
docker: [registry: 'ml-registry.company.com']
],
'engineering': [
tools: ['java', 'node', 'docker'],
platforms: ['kubernetes', 'lambda'],
notifications: [slack: '#app-builds'],
docker: [registry: 'app-registry.company.com']
],
'devops': [
tools: ['terraform', 'ansible', 'kubectl'],
platforms: ['aws', 'kubernetes'],
notifications: [slack: '#infra-builds', email: 'devops@company.com'],
docker: [registry: 'infra-registry.company.com']
]
]
Map getTeamConfig(String team) {
if (!teams.containsKey(team)) {
throw new IllegalArgumentException("Unknown team: ${team}")
}
return teams[team]
}
}
Testing Your Shared Library
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#testing-your-shared-library)
Testing is crucial for maintaining reliable shared libraries. We use JenkinsPipelineUnit with Spock framework.
Unit Test Example
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#unit-test-example)
File: test/unit/groovy/com/example/jenkins/shell/BashSpec.groovy
package com.example.jenkins.shell
import spock.lang.Specification
import spock.lang.Unroll
class BashSpec extends Specification {
Script mockSteps
Bash bash
def setup() {
mockSteps = GroovyMock()
}
def 'should throw exception when script is null'() {
given:
bash = new Bash(mockSteps)
when:
bash.formatScript(null)
then:
thrown(NullPointerException)
}
@Unroll
def 'should set fail-fast to #expected when failFast=#enabled'() {
given:
bash = new Bash(mockSteps, false, false, enabled)
when:
String formattedScript = bash.formatScript("echo 'Hello'")
then:
formattedScript.contains(expected)
where:
enabled || expected
true || 'set -e'
false || 'set +e'
}
def 'should execute script successfully'() {
given:
bash = new Bash(mockSteps, false, false, true)
String testScript = "echo 'test'"
when:
bash('Test execution', testScript)
then:
1 * mockSteps.echo('Executing: Test execution')
1 * mockSteps.sh(_) >> 0
}
}
Testing Global Variables
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#testing-global-variables)
File: test/unit/groovy/com/example/jenkins/vars/LogSpec.groovy
package com.example.jenkins.vars
import com.lesfurets.jenkins.unit.BasePipelineTest
import org.junit.Before
import org.junit.Test
class LogSpec extends BasePipelineTest {
@Override
@Before
void setUp() throws Exception {
super.setUp()
// Mock Jenkins steps
helper.registerAllowedMethod('ansiColor', [String, Closure], { String key, Closure body ->
body()
})
helper.registerAllowedMethod('echo', [String], { String message ->
println(message)
})
}
@Test
void 'test basic log call'() {
def log = loadScript('vars/log.groovy')
log.call('Test message')
assertJobStatusSuccess()
}
@Test
void 'test log info convenience method'() {
def log = loadScript('vars/log.groovy')
log.info('Info message')
assertJobStatusSuccess()
}
}
Running Tests
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#running-tests)
# Run all tests
./gradlew test
# Run specific test
./gradlew test --tests "BashSpec"
# Generate coverage report
./gradlew jacocoTestReport
# Report: build/reports/jacoco/test/html/index.html
Job DSL and Seed Jobs
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#job-dsl-and-seed-jobs)
Job DSL allows you to define Jenkins jobs as code, making your CI/CD infrastructure reproducible and version-controlled.
Seed Job Pipeline
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#seed-job-pipeline)
The seed job is a special pipeline that creates and manages other Jenkins jobs using the team-based architecture.
File: jobs/jobSeed.groovy
// Team-based seed job pipeline - runs on Jenkins controllers to create/update jobs
final String projectDir = 'demo-repository/jobs'
final String commonJobsDir = 'common'
// Team variables that must be set on the Jenkins controller
assert env.JENKINS_TEAM_NAME, 'JENKINS_TEAM_NAME must be set (data-science, engineering, devops)'
assert env.JENKINS_TEAM_NAME != commonJobsDir, 'JENKINS_TEAM_NAME cannot be "common"'
assert env.JENKINS_TEAM_NAME in ['data-science', 'engineering', 'devops'], 'JENKINS_TEAM_NAME must be one of: data-science, engineering, devops'
assert env.BRANCH_NAME, 'BRANCH_NAME must be set'
final Boolean isMainBranch = env.BRANCH_IS_PRIMARY == 'true'
final String branchFolderName = env.BRANCH_NAME.replaceAll('/', '-')
final String rootFolder = isMainBranch ? '' : "PROTOTYPE-JOBS/${branchFolderName}"
// Paths to Job DSL scripts
final String teamJobDslDir = "${projectDir}/jenkins-controllers/${env.JENKINS_TEAM_NAME}/src/dsl/groovy"
final String commonJobDslDir = "${projectDir}/jenkins-controllers/${commonJobsDir}/src/dsl/groovy"
node('controller-agent') {
stage('Checkout') {
checkout(
changelog: true,
poll: false,
scm: [
$class: 'GitSCM',
branches: [[name: "*/${env.BRANCH_NAME}"]],
userRemoteConfigs: [[
credentialsId: 'github-pat',
url: 'https://github.com/your-org/jenkins-shared-library.git'
]]
]
)
}
stage('Process Job DSL') {
echo "Processing Job DSL scripts for team: ${env.JENKINS_TEAM_NAME}"
jobDsl(
additionalParameters: [
ROOT_FOLDER: rootFolder,
TEAM: env.JENKINS_TEAM_NAME
],
sandbox: false, // Requires Script Security for Job DSL to be disabled
additionalClasspath: [
"${projectDir}/src/lib",
'src' // Include shared library classes
].join('\n'),
failOnMissingPlugin: true,
failOnSeedCollision: true,
removedConfigFilesAction: 'DELETE',
removedJobAction: isMainBranch ? 'DELETE' : 'IGNORE',
removedViewAction: isMainBranch ? 'DELETE' : 'IGNORE',
targets: "${commonJobDslDir}/**/*.groovy\n${teamJobDslDir}/**/*.groovy",
unstableOnDeprecation: true
)
}
stage('Summary') {
echo """
========================================
Job DSL Processing Complete
========================================
Team: ${env.JENKINS_TEAM_NAME}
Branch: ${env.BRANCH_NAME}
Is Main Branch: ${isMainBranch}
Root Folder: ${rootFolder ?: '(top level)'}
========================================
""".stripIndent()
}
}
Job DSL Script Example
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#job-dsl-script-example)
File: jobs/jenkins-controllers/common/src/dsl/groovy/buildJobs.groovy
// Job DSL script to create build jobs
String rootFolder = ROOT_FOLDER ?: ''
String environment = ENVIRONMENT ?: 'development'
folder("${rootFolder}/build-jobs") {
displayName('Build Jobs')
description('Automated build jobs for applications')
}
pipelineJob("${rootFolder}/build-jobs/app-build") {
displayName('Application Build')
parameters {
stringParam('GIT_BRANCH', 'main', 'Git branch to build')
choiceParam('BUILD_TYPE', ['debug', 'release'], 'Build type')
booleanParam('RUN_TESTS', true, 'Run unit tests')
}
properties {
disableConcurrentBuilds()
buildDiscarder {
strategy {
logRotator {
numToKeepStr('50')
daysToKeepStr('30')
}
}
}
}
triggers {
scm('H/5 * * * *') // Poll every 5 minutes
}
definition {
cpsScm {
scm {
git {
remote {
url('https://github.com/your-org/your-app.git')
credentials('git-credentials')
}
branches('main', 'develop')
scriptPath('Jenkinsfile')
}
}
}
}
}
// Multibranch pipeline
multibranchPipelineJob("${rootFolder}/build-jobs/app-multibranch") {
displayName('Application Multibranch Build')
branchSources {
git {
id('app-multibranch')
remote('https://github.com/your-org/your-app.git')
credentialsId('git-credentials')
includes('main develop feature/* bugfix/*')
}
}
orphanedItemStrategy {
discardOldItems {
numToKeep(10)
}
}
}
Job Templates Library
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#job-templates-library)
File: jobs/src/lib/JobTemplates.groovy
package lib
class JobTemplates {
/**
* Create a standard microservice build job.
*/
static void createMicroserviceBuildJob(def dslFactory, String rootFolder, Map config) {
String jobName = "${rootFolder}/microservices/${config.name}"
dslFactory.pipelineJob(jobName) {
displayName(config.displayName ?: config.name)
description(config.description ?: "Build job for ${config.name}")
parameters {
stringParam('GIT_BRANCH', config.defaultBranch ?: 'main', 'Branch to build')
booleanParam('DEPLOY_TO_DEV', true, 'Deploy to development')
}
properties {
disableConcurrentBuilds()
}
triggers {
githubPush()
}
definition {
cps {
script("""
@Library('my-shared-lib@main') _
pipeline {
agent any
stages {
stage('Build') {
steps {
buildApp(
language: '${config.language}',
buildTool: '${config.buildTool}'
)
}
}
stage('Docker') {
steps {
buildDockerImage(
imageName: '${config.dockerImage}'
)
}
}
}
}
""".stripIndent())
}
}
}
}
/**
* Create folder structure for a team.
*/
static void createTeamFolder(def dslFactory, String rootFolder, Map config) {
String teamFolder = "${rootFolder}/${config.teamName}"
dslFactory.folder(teamFolder) {
displayName(config.displayName ?: config.teamName)
description("Jobs for ${config.teamName} team")
}
['build', 'deploy', 'utilities'].each { subfolder ->
dslFactory.folder("${teamFolder}/${subfolder}") {
displayName(subfolder.capitalize())
}
}
}
}
Usage:
import lib.JobTemplates
String rootFolder = ROOT_FOLDER ?: ''
JobTemplates.createTeamFolder(this, rootFolder, [
teamName: 'platform-team',
displayName: 'Platform Team'
])
JobTemplates.createMicroserviceBuildJob(this, rootFolder, [
name: 'user-service',
language: 'java',
buildTool: 'gradle',
dockerImage: 'company/user-service'
])
Production Deployment Jobs
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#production-deployment-jobs)
File: jobs/jenkins-controllers/production/src/dsl/groovy/productionJobs.groovy
String rootFolder = ROOT_FOLDER ?: ''
pipelineJob("${rootFolder}/production-deployments/deploy-app") {
displayName('Deploy to Production')
parameters {
stringParam('VERSION', '', 'Version to deploy')
stringParam('GIT_TAG', '', 'Git tag to deploy')
}
properties {
disableConcurrentBuilds()
authorizationMatrix([
'hudson.model.Item.Build:production-deployers'
])
}
definition {
cps {
script('''
@Library('my-shared-lib@main') _
pipeline {
agent any
stages {
stage('Approval') {
steps {
timeout(time: 24, unit: 'HOURS') {
input(
message: 'Approve deployment?',
submitter: 'production-approvers'
)
}
}
}
stage('Deploy') {
steps {
deployToK8s(
namespace: 'production',
version: params.VERSION
)
}
}
}
}
'''.stripIndent())
}
}
}
Advanced Patterns
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#advanced-patterns)
Pattern 1: Configuration as Code
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#pattern-1-configuration-as-code)
File: src/com/example/jenkins/config/PipelineConfig.groovy
package com.example.jenkins.config
class PipelineConfig {
Map environments = [
development: [
kubernetes: [namespace: 'dev', cluster: 'dev-cluster'],
docker: [registry: 'registry.dev.company.com'],
notifications: [slack: '#dev-builds']
],
production: [
kubernetes: [namespace: 'production', cluster: 'prod-cluster'],
docker: [registry: 'registry.company.com'],
notifications: [slack: '#prod-deployments', email: 'team@company.com']
]
]
Map getEnvironmentConfig(String environment) {
if (!environments.containsKey(environment)) {
throw new IllegalArgumentException("Unknown environment: ${environment}")
}
return environments[environment]
}
}
Pattern 2: Plugin Wrapper
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#pattern-2-plugin-wrapper)
File: vars/withKubernetes.groovy
/**
* Wrapper for Kubernetes operations with automatic cleanup.
*/
def call(Map config, Closure body) {
String namespace = config.namespace ?: 'default'
String cluster = config.cluster
String credentialsId = config.credentialsId ?: 'k8s-credentials'
try {
withCredentials([file(credentialsId: credentialsId, variable: 'KUBECONFIG')]) {
sh """
kubectl config use-context ${cluster}
kubectl config set-context --current --namespace=${namespace}
"""
body()
}
} finally {
sh 'rm -f $KUBECONFIG'
}
}
Usage:
withKubernetes(cluster: 'production', namespace: 'apps') {
sh 'kubectl get pods'
sh 'kubectl apply -f deployment.yaml'
}
Pattern 3: Dynamic Pipeline Generation
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#pattern-3-dynamic-pipeline-generation)
File: vars/dynamicPipeline.groovy
/**
* Generates pipeline dynamically based on repository structure.
*/
def call(Map config) {
List<String> services = findServices()
pipeline {
agent any
stages {
stage('Parallel Builds') {
steps {
script {
Map parallelStages = [:]
services.each { service ->
parallelStages[service] = {
stage(service) {
dir(service) {
buildApp()
runTests()
}
}
}
}
parallel parallelStages
}
}
}
}
}
}
List<String> findServices() {
def services = []
def dirs = findFiles(glob: '**/package.json')
dirs.each { file ->
services.add(file.path.split('/')[0])
}
return services.unique()
}
Best Practices
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#best-practices)
1. Versioning and Tagging
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#1-versioning-and-tagging)
// ❌ Bad - uses latest, unpredictable
@Library('my-shared-lib') _
// ✅ Good - uses specific version
@Library('my-shared-lib@v1.2.3') _
// ✅ Good - uses branch for development
@Library('my-shared-lib@develop') _
2. Error Handling
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#2-error-handling)
def call(Map config) {
try {
validateConfig(config)
performAction(config)
} catch (Exception e) {
log.error("Failed: ${e.message}")
currentBuild.result = 'FAILURE'
throw e
} finally {
cleanup()
}
}
private void validateConfig(Map config) {
List<String> required = ['param1', 'param2']
List<String> missing = required.findAll { !config.containsKey(it) }
if (missing) {
throw new IllegalArgumentException("Missing: ${missing.join(', ')}")
}
}
3. Documentation Standards
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#3-documentation-standards)
Document all global variables with .txt files:
NAME
myStep - Does something useful
SYNOPSIS
myStep(config)
PARAMETERS
config (Map):
- param1 (String, required): Description
- param2 (Integer, optional, default: 10): Description
EXAMPLES
myStep(param1: 'value')
4. Keep Functions Small
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#4-keep-functions-small)
// ❌ Bad - doing too much
def deployApplication(config) {
buildApp()
runTests()
buildDockerImage()
deployToK8s()
}
// ✅ Good - focused steps
def buildAndTest(config) {
buildApp(config)
runTests(config)
}
def deployApp(config) {
buildDockerImage(config)
deployToK8s(config)
}
5. Use @NonCPS for Non-Serializable Code
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#5-use-noncps-for-non-serializable-code)
import groovy.transform.Field
import com.cloudbees.groovy.cps.NonCPS
@Field static final Map CONFIG = [:]
@NonCPS
def processData(List data) {
return data.collect { it * 2 }.sum()
}
def call(data) {
def result = processData(data)
echo "Result: ${result}"
}
6. Credential Management
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#6-credential-management)
def call(Map config) {
withCredentials([
usernamePassword(
credentialsId: config.credentialsId,
usernameVariable: 'USER',
passwordVariable: 'PASS'
)
]) {
// Never echo credentials
sh 'docker login -u $USER -p $PASS registry.company.com'
}
}
7. Code Quality with CodeNarc
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#7-code-quality-with-codenarc)
File: config/codenarc/codenarcMain.groovy
ruleset {
description 'CodeNarc rules for Jenkins shared library'
ruleset('rulesets/basic.xml')
ruleset('rulesets/braces.xml')
ruleset('rulesets/naming.xml')
LineLength {
length = 120
}
MethodSize {
maxLines = 50
}
}
Enterprise Collaboration
Central Platform Team Model
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#central-platform-team-model)
In larger organizations, platform teams create common Jenkins libraries for all teams.
Benefits:
- ✅ Standardization: Consistent deployment practices
- ✅ Reduced duplication: No redundant pipeline code
- ✅ Faster onboarding: New projects use battle-tested pipelines
- ✅ Centralized improvements: Updates benefit all teams
Contribution Model
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#contribution-model)
Application teams contribute back to central libraries:
// Platform team: base functionality
// vars/deployToKubernetes.groovy
def call(Map config) {
// Standard Kubernetes deployment
}
// App team: specialized deployment
// vars/deployToOpenShift.groovy
def call(Map config) {
deployToKubernetes(config + [platform: 'openshift'])
}
Team-Specific Customization
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#team-specific-customization)
Teams can use central + custom libraries:
// Use central library
@Library('central-platform-library@v2.1.0') _
// Add team-specific library
@Library('team-payments-library@main') __
pipeline {
agent any
stages {
stage('Build') {
steps {
standardBuild(language: 'java') // Central
}
}
stage('Deploy') {
steps {
deployPaymentService(env: 'staging') // Team-specific
}
}
}
}
Unit Testing Importance
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#unit-testing-importance)
Unit testing shared libraries is critical:
- Code Reliability: Catch bugs before they hit production
- Safe Refactoring: Change code confidently
- Prevent Widespread Issues: Bugs in shared libraries affect many pipelines
Investment Worth Making: While testing requires time, it's an investment in stability and maintainability of your entire CI/CD ecosystem.
Next Steps
[](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/advanced-guide.md#next-steps)
- Explore the reference documentation for API details
- Check the demo repository for working examples
- Review main tutorial for foundational concepts
Updated on: 02/11/2025
Thank you!