> ## Knowledge Base Index
> Fetch the complete knowledge base index at: https://support.stacktrack.com/sitemap.xml
> Use this file to discover available pages before exploring further.
> Pure-Markdown content can be obtained by appending a '.md' suffix to the content URLs listed in the sitemap (without the trailing slash).

# Jenkins Shared Library Tutorial - Advanced Guide

> **Prerequisites**: Complete the [main tutorial](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/README.md) first to understand the basics.
This guide covers advanced topics for mastering Jenkins Shared Libraries.

## Table of Contents

1. [Team-Based Architecture](/en/article/jenkins-shared-library-tutorial-advanced-guide-xpeg0c/#2-team-based-architecture)
2. [Testing Your Shared Library](/en/article/jenkins-shared-library-tutorial-advanced-guide-xpeg0c/#2-testing-your-shared-library)
3. [Job DSL and Seed Jobs](https://support.stacktrack.com/en/article/jenkins-shared-library-tutorial-advanced-guide-xpeg0c/#2-job-dsl-and-seed-jobs)
4. [Advanced Patterns](/en/article/jenkins-shared-library-tutorial-advanced-guide-xpeg0c/#2-best-practices)
5. [Best Practices](#best-practices)
6. [Enterprise Collaboration](/en/article/jenkins-shared-library-tutorial-advanced-guide-xpeg0c/#2-enterprise-collaboration)

## 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

```
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

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


#### 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

**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

**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

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

Testing is crucial for maintaining reliable shared libraries. We use **JenkinsPipelineUnit** with **Spock** framework.

### 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

**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

```
# 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

Job DSL allows you to define Jenkins jobs as code, making your CI/CD infrastructure reproducible and version-controlled.

### 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

**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

**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
**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
### 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

**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

**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


### 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

```
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

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

```
// ❌ 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

```
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

```
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

**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

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

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
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
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
* Explore the [reference documentation](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/docs/reference.md) for API details
* Check the [demo repository](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/demo-repository) for working examples
* Review [main tutorial](https://github.com/Servana/jenkins-shared-library-tutorial/blob/main/README.md) for foundational concepts