Simplify Your Jenkins Pipelines by Reusing Common Code with Shared Libraries

In complex CI/CD environments, Jenkinsfiles often grow large and repetitive, especially when dealing with Android AOSP builds and artifact uploads. We end up duplicating shell scripts, credential setup, or deployment logic across multiple projects.

This post shows how to extract and reuse common code in Jenkins using Shared Libraries, focusing on modularity and maintainability, not reusing entire pipelines.


  1. Organize your repository

Structure your Git repo like this:

jenkins-pipelines/
├── Jenkinsfile
├── vars/
│   ├── buildAosp.groovy
│   └── uploadArtifacts.groovy

vars/ holds reusable Groovy functions. Each file defines a callable step (e.g., buildAosp()).


  1. Add shared functions

Create your Groovy functions in vars/.

vars/buildAosp.groovy:

def call(Map config = [:]) {
    docker.image(config.dockerImage ?: 'aosp-builder')
        .inside("-v ${config.ccachePath}:/ccache") {
        sshagent([config.sshCredential]) {
            sh """#!/bin/bash
                mkdir -p ~/.ssh
                chmod 700 ~/.ssh
                ssh-keyscan -p 29418 -H gerrit.maksonlee.com >> ~/.ssh/known_hosts
                repo init -u ${config.manifestUrl} -b ${config.branch}
                repo sync -c -j1
                source build/envsetup.sh
                lunch ${config.lunchTarget}
                m
            """
        }
    }
}

vars/uploadArtifacts.groovy:

def call(Map config = [:]) {
    def timestamp = new Date().format("yyyyMMdd.HHmmss", TimeZone.getTimeZone('UTC'))
    def fileItegRev = "${timestamp}-${env.BUILD_NUMBER}"
    def targetBasePath = "${config.repo}/${config.orgPath}/${config.module}/${config.baseRev}-${config.folderItegRev}"

    def specMap = [
        files: config.artifacts.collect {
            [
                pattern: it.pattern,
                target: "${targetBasePath}/${config.module}-${config.baseRev}-${fileItegRev}-${it.classifier}.${it.ext}"
            ]
        }
    ]

    echo "Uploading artifacts to: ${targetBasePath}"

    rtUpload(
        serverId: "artifactory",
        spec: groovy.json.JsonOutput.toJson(specMap),
        failNoOp: true
    )
}

  1. Register the repo as a Shared Library in Jenkins
  • Go to Manage Jenkins → System
  • Scroll to Global Trusted Pipeline Libraries
  • Click Add, and fill in:
FieldValue
Namejenkins-pipelines
Default Versionmain
Load Implicitlyleave unchecked
Allow Default Overriderecommended
SCMGit
Repository URLGit URL of this repo (e.g. GitHub)
CredentialsIf private, add credentials
Library Path(Leave blank)

Even if your Jenkinsfile is in the same repo, this step is required!


  1. Use the functions in your Jenkinsfile

Jenkinsfile:

@Library('jenkins-pipelines') _

pipeline {
    agent { label 'ssh-agent-with-docker' }

    environment {
        CCACHE_PATH = "/home/administrator/.cache/ccache"
    }

    stages {
        stage('Build AOSP') {
            steps {
                buildAosp(
                    ccachePath: env.CCACHE_PATH,
                    dockerImage: 'aosp-builder',
                    sshCredential: 'gerrit-ssh-maksonlee',
                    manifestUrl: 'ssh://maksonlee@gerrit.maksonlee.com:29418/platform/manifest',
                    branch: 'android-15.0.0_r30',
                    lunchTarget: 'aosp_arm64-trunk_staging-userdebug'
                )
            }
        }

        stage('Upload Artifacts') {
            steps {
                uploadArtifacts(
                    orgPath: 'com/maksonlee',
                    module: '1234',
                    baseRev: '003-vanilla-continuous',
                    folderItegRev: 'SNAPSHOT',
                    repo: 'product-snapshots',
                    artifacts: [
                        [pattern: 'out/target/product/generic_arm64/system.img', classifier: 'system', ext: 'img'],
                        [pattern: 'out/target/product/generic_arm64/vbmeta.img', classifier: 'vbmeta', ext: 'img'],
                        [pattern: 'out/target/product/generic_arm64/ramdisk.img', classifier: 'ramdisk', ext: 'img']
                    ]
                )
            }
        }
    }
}

Conclusion: Reuse Code, Not Pipelines

This approach isn’t about reusing entire Jenkinsfiles. It’s about reusing common code, build logic, artifact uploads, credential setup, across all your jobs.

By centralizing logic in vars/ and using @Library(...):

  • Your Jenkinsfiles become shorter and easier to maintain
  • You fix bugs once, and apply them everywhere
  • You scale your CI setup cleanly and consistently

If you’re maintaining more than one Jenkins job, this is the cleanest, most maintainable way forward.

2 thoughts on “Simplify Your Jenkins Pipelines by Reusing Common Code with Shared Libraries”

    1. Thank you so much for your kind words! I’m really glad to hear that you found the article clear and helpful. Let me know if there’s anything else you’d like to see covered!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top