To display the expressive power of the Jenkins build we show here how to create a Jenkins pipeline for a npm library. We focus on the differences apposed to the Java application pipeline we saw in an earlier post.

Angular test library

As of Angular 7 the Angular CLI has more support for creating libraries. We will use some commands to setup a test library with a working demo application. For the complete code see my github here.

ng new test-angular-library --create-application=false
cd test-angular-library
ng generate library lib --prefix=test
ng generate application demo

Now we only have to import the LibModule in the app.module.ts of the demo application. And edit the app.component.html to show our library component like this:

<h1>
  Welcome to {{ title }}!
</h1>
<test-lib></test-lib>

And for our upcoming pipeline we define some scripts in the package.json.

  "scripts": {
    "start": "ng serve --project=demo",
    "lint": "ng lint",
    "test": "ng test --project=lib --watch=false --code-coverage",
    "build": "ng build --project=lib",
    "build.demo": "ng build --project=demo",
    "publish": "npm publish dist/lib"
  },

Start your demo application with npm run start and we see our library component in action.

working homepage of app 1024x474 - NPM LIBRARY JENKINS

Npm pipeline

We will use a pipeline library for a template pipeline as discussed in this post on generic Jenkins pipelines. But now setup your github credentials globally.

github credentials in jenkins 1024x362 - NPM LIBRARY JENKINS

And with the creation of the Jenkins job choose Multibranch Pipeline and configure your repo with credentials.

npm library source setup jenkins 1024x498 - NPM LIBRARY JENKINS

With this setup we refer to a pipeline template from the Jenkinsfile in our Angular library.

@Library('jenkins-ci') _

npmLibraryPipeline()

And define the generic pipeline in our groovy library as vars/npmLibraryPipeline.groovy as we can see here.

Groovy functions

To keep our pipeline library DRY we can put code into separate functions. In our pipeline we see buildNpm() twice, referring to the call function in the vars/buildNpm.groovy file.

#!/usr/bin/groovy

def call() {
    stage('Build Npm') {
        container ('node') {
            sh(script: "node -pe \"require('./package.json').version\"", returnStdout: true)
            sh "npm install"
            sh "npm run lint"
            sh "npm run build"
            sh "npm run build.demo"
        }
    }
}

Moreover we can use this with the decorator pattern to execute some code enclosed by a setup of credentials as shown in src/GitUtils.groovy class.

def withGitCredentials(Closure closure) {
closure.setDelegate(this)
withCredentials([usernamePassword(credentialsId: 'github', usernameVariable: 'gitUser', passwordVariable: 'gitPassword')]) {
sh """
git config --global --replace-all credential.helper \'/bin/bash -c \"echo username=$gitUser; echo password=$gitPassword\"\'
git config --global user.name "$gitUser"
git config --global user.email "$gitUser@gmail.com"
"""
closure.call()
}
}

return this

Note that we can can execute the closure variable with the call() method.

Release build

A key feature of a library is that we build releases of it. A difference from the pipelines we saw earlier is that we defined a release branch as configuration variable in NpmLibraryPipelineConfig.groovy. Note that we set the default release branch to master.

class NpmLibraryPipelineConfig {
String nodeImage = 'node:11-stretch'
String releaseBranch = 'master'
}

If the branch in the build matches the release branch we not only build the branch but also release it. Here are the stages of this part:

stage('Initialize Release') {...}

stage('Bump Version') {...}

buildNpm()

stage('Publish Release') {...}

We won’t go in to the npm or git details here. What we will show here is the input step we defined to ask the user what kind of release is wanted.

releaseType = input(id: 'releaseTypeInput', message: 'Please specify release type', parameters: [
        [$class: 'ChoiceParameterDefinition', choices: 'patch\nminor\nmajor', description: 'releaseType', name: 'releaseType']
])

The build stops at this point and gives the user a choice a between patch/minor/major release. We store this choice in a variable to use this when bumping the version.

Now run the build (and select the release type you want in the second step)!

jenkins input modal in pipeline 1024x566 - NPM LIBRARY JENKINS

Hopefully you can now build and release you npm libraries with Jenkins. Happy releasing!