re: How-To: Setup a unit-testable Jenkins shared pipeline library VIEW POST

TOP OF THREAD FULL DISCUSSION
re: Thanks for the article Adrian, I have a question - Since we are keeping the vars scripts as clean as possible do you know of any examples of how t...
 

Hi, thanks for your comment :D Let me try to answer some questions:

  • If your are using declarative pipeline scripts the git checkout should be handled for you and does not have to be part of your library.
  • Jenkinsfiles are just a collection of command-line calls to be executed on the build agent. Doing a build therefore depends on the technology stack used. E.g. building a .NET Framework project would include a command-line call to MSBuild, while a Rust program would call cargo build. The latter could look somewhat like this inside the library
class CargoBuilder implements Serializable {

    void build() {
        IStepExecutor steps = ContextRegistry.getContext().getStepExecutor()

        // on windows agents use steps.bat("...")
        int returnStatus = steps.sh("cargo build")
        if (returnStatus != 0) {
            steps.error("Cargo build failed.")
        }
    }
}

Inside your Jenkinsfiles instead of writing cargo build each time, you could just write build (if your var script is called build.groovy of course). This is a very basic example (and only saves a single word), but in a real world example, the library can streamline the build process inside your organization and abstract away some of the more complicated command-line calls (e.g. by setting specific build parameters by default, which in turn can be omitted inside the Jenkinsfile).

  • I would keep the var scripts concentrated to a single task, e.g. building, testing, running metrics, deploying artifacts etc. Let's assume we wrote var scripts for all of these tasks, ex_build.groovy, ex_test.groovy, ex_metrics.groovy and ex_deploy_artifacts.groovy. Any Jenkinsfile, which before might have been very long, filled with strange parameters, paths and commands, could (more or less) be reduced to this:
@Library('my-library@1.0') _

pipeline {
    agent any
    stages {
        stage('build') {
            steps {
                ex_build
            }
        }
        stage('test') {
            steps {
                ex_test
            }
        }
        stage('metrics') {
            steps {
                ex_metrics
            }
        }
        stage('deploy artifacts') {
            steps {
                ex_deploy_artifacts 'some/path/to/artifact'
            }
        }
    }
}

(of course, this is still simplified).

Imo, the whole challenge of writing Jenkins shared libraries is collecting and wrapping all command-line calls necessary for your builds and make fitting abstractions that simplify your Jenkinsfiles and streamline your organizations build process. In the beginning this can be very difficult. (To be honest, before I was tasked in setting up Jenkins pipelines, I almost had no clue, which parts were involved in building our software. For me "a build" was just pressing the green play button in Visual Studio 🙈).

So, in your case, I would probably take a long and good look at your current Jenkinsfiles, write down which tools (e.g. MSBuild, cargo, npm, dotnet, maven, gradle) are used and how (parameters passed to the tools, which commands repeat between Jenkinsfiles, etc.). As soon as you have a good understanding of the current build process, you can start to extract the command-line calls of these tools into your library by creating fitting var scripts (e.g. ex_build.groovy) which in turn call a unit-tested "build" class. This class simply wraps the command-line call to the build tool (with steps.sh("<the command>"); or if you are using windows-based build agents steps.bat("<the command>");). That's basically it.

I hope this wall of text clears things up a bit 😅 If not, don't be shy to ask any new questions 👍

 

Wow.. What a fantastic reply. You do make perfect sense. I will be following your advice tomorrow. Starting by trawling through our jenkinsfiles and many many bash scripts to see what we can DRY (so to speak)
Thank you for expanding with more examples and so much detail. It's also nice to hear you started from a similar place.

Many thanks again

Regards

Patrick

You do make perfect sense.

I don't hear that very often 😄 Glad I could help

code of conduct - report abuse