Popular Posts

Jenkins Basics

Jenkins Build Parameters

Jenkins is the widely adopted open source continuous integration tool. You can orchestrate any application deployments using Jenkins with a wide range of plugins and native Jenkins workflows. In This Tutorial we will be demonstrates interesting features of jenkins pipeline.

In this tutorial declarative pipeline syntax will be used.

Note
official documentation for jenkins pipeline syntax

Jenkins Build Parameters

Build Parameters makes jenkins job more dynamic in nature ,which prompt user before triggering the job. Following different types of build parameters that jenkins supports.

build_parameters.groovy
node {
    env.GRADLE_USER_HOME = "${workspace}/.gradle" // pipeline specific env variable
}

pipeline { agent { label "${params.AGENT}" }

    parameters {
        string(name: 'AGENT', defaultValue: 'node-1 || node-2 ')
        choice(name: 'BRANCH', choices: ['master', 'develop'])
        booleanParam(name: 'RUN_TESTS', defaultValue: true)
        password(name: 'PASSWORD', defaultValue: 'SECRET')
        text(name: 'DESCRIPTION', defaultValue: 'description')
        extendedChoice(name: 'OPTIONS', defaultValue: 'foo', description: '', descriptionPropertyValue: '', multiSelectDelimiter: ',', quoteValue: true, saveJSONParameterToFile: false, type: 'PT_CHECKBOX', value: 'foo,bar', visibleItemCount: 2)
    }

    stages {
        stage('One') {
            steps {
                print 'Running stage one'
            }
        }

        stage('Two') {
            steps {
                print 'Running stage two'
            }
        }
    }

}

Invoking Downstream Job with Build Parameters

In Jenkins CI-CD Pipeline , a parent job can trigger child job with build parameters.

invoke_downstream_job.groovy
node { env.GRADLE_USER_HOME = "${workspace}/.gradle" }

pipeline {
    agent any

    parameters {
        string(name: 'AGENT', defaultValue: 'node-1||node-2 ')
        choice(name: 'BRANCH', choices: ['master', 'develop'])
        booleanParam(name: 'RUN_TESTS', defaultValue: true)
        password(name: 'PASSWORD', defaultValue: 'SECRET')
        text(name: 'DESCRIPTION', defaultValue: 'description')
    }

    stages {
        stage('Trigger Test Job') {
            when {
                expression {
                    // Conditional flow
                    return params.RUN_TESTS
                }
            }
            steps {
                script {
                    def jobResult = build job: "integration_tests",
                            propagate: true,
                            wait: true,
                            quietPeriod: 2,
                            parameters: [
                                    string(name: 'BRANCH', value: params.BRANCH),
                                    booleanParam(name: 'RUN_TESTS', value: params.RUN_TESTS),
                                    string(name: 'AGENT', value: params.AGENT)]

                }
            }
        }
    }

}
Tip
propagate true means child job result sends back to parent, wait true means , parent waits until child job completes.

Reading Job results from child Job

When Job-Parent invokes Job-Child , Job-Child can send result back to parent using enviroment variables.

job-child.groovy
pipeline {
    agent any
    stages {
        stage('ChildJob Stage'){
            steps { // run you job work
                // set env variable which is available to caller (parent job)
                env.setProperty("ARTIFACT_VERSION", 'GENERATED_ARTIFACT_VERSION') //(1)
            }
         }
    }
}
  1. Add env variable in the child job

job-parent.groovy
pipeline {

    agent any

    stages {
        stage('Parent Job') {

            steps {

                script {

                    def jobResult = build job: "integration_tests",
                            propagate: true,
                            wait: true,
                            quietPeriod: 2,
                            parameters: [
                                    string(name: 'BRANCH', value: params.BRANCH),
                                    booleanParam(name: 'RUN_TESTS', value: params.RUN_TESTS),
                                    string(name: 'AGENT', value: params.AGENT)
                            ]

                    def envVars = jobResult.getBuildVariables() // (2)
                    print "Received ARTIFACT_VERSION " + envVars['ARTIFACT_VERSION'] //(3)

                }
            }
        }
    }
}
  1. Read env variables from child job through jobResult.getBuildVariables() method.

  2. Read key value map of env variables using envVars['ARTIFACT_VERSION'].

Global Tools

Install JDK as global tool and use it under pipeline.

global_tools.groovy
pipeline {

    agent any

    options {
        timeout(time: 80, unit: 'MINUTES')// Max time to finish this job
    }

    tools {
        jdk 'jdk-11' //which will refer JDK at home/$USER/jenkins/tools/hudson.model.JDK/jdk-11
    }

}

Wait until block

wait_until.groovy
node { env.GRADLE_USER_HOME = "${workspace}/.gradle" }

pipeline {
    agent any

    stages {
        stage('Wait for') {

            steps {
                waitUntil {
                    script {

                        try {
                            sleep(time: 1, unit: "MINUTES")

                            def status = sh(returnStdout: true, script: """

                            docker inspect --format='{{.State.Health.Status}}' mydocker

                            """).trim()

                            (status == 'healthy')

                        } catch (e) {
                            e == 'error'
                        }

                    }
                }
            }
        }
    }

}

Edit properties/ json file within Jenkins

edit.groovy
def updateGradleProperties() {

  def fileText = readFile(file: "${env.WORKSPACE}/gradle.properties")
  fileText = (fileText =~ /mykey=.*/).replaceFirst("myvalue")
  writeFile(file: "${env.WORKSPACE}/gradle.properties", text: fileText)

}

def updateJson() {

  def inputFile = readFile(file: "${env.WORKSPACE}/my-custom.json")
  def manifestJSON = new JsonSlurper().parseText(inputFile)
  def builder = new JsonBuilder(manifestJSON)

  builder.content.'child' = 'value'

  String result = builder.toPrettyString()

  writeFile(file: "${env.WORKSPACE}/my-custom.json", text: result)

}

Jenkins Job kill forcibly

This article explains different ways to kill jenkins job forcibly.

How to push Code to Git repository from Jenkins

git-commit-push.groovy
stage("Commit") {
    steps {
        dir('myrepo') {

            sh("""
                    git checkout -b pipeline_${env.GIT_BRANCH}
                    git config user.name 'xxxxxx'
                    git config user.email 'xxxxxx@gmail.com'
                    git add -A
                    git diff-index --quiet HEAD || git commit -m 'Pipeline updated'
            """)
        }
    }
}



stage("Push") {

    environment {
        GIT_AUTH = credentials('github-credential-id')
    }

    steps {
        dir('myrepo') {

            sh("""
                git config --local credential.helper "!f() { echo username=\\$GIT_AUTH_USR; echo password=\\$GIT_AUTH_PSW; }; f"
                git push origin HEAD:pipeline_${env.GIT_BRANCH}
            """)

        }
    }
}

How to run parallel stages

parallel-stages.groovy
stage('Build Parallel') {

    parallel {

        stage('p1'){

        }

        stage('p2'){

        }

        stage('p3'){

        }

    }
}

Customized Jenkins Docker

Below Dockerfile helps you to build customized Jenkins with pre-installed theme and required plugins.

Dockerfile
from jenkins/jenkins:latest
#FROM openjdk

# skip Setup Wizard during first startup
ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false"

ENV JENKINS_USER=admin
ENV JENKINS_PASS=password

# COPY custom scripts into jenkin
COPY jenkins-security.groovy /usr/share/jenkins/ref/init.groovy.d/ #(1)
COPY jenkins-theme.groovy /usr/share/jenkins/ref/init.groovy.d/    #(2)

#sudo docker cp jenkins-material-theme.css 28b9421f3a56:/var/jenkins_home/userContent
COPY jenkins-material-theme.css /var/jenkins_home/userContent/    #(3)
RUN /usr/local/bin/install-plugins.sh simple-theme-plugin


# Distributed Builds plugins
RUN /usr/local/bin/install-plugins.sh ssh-slaves

# install Notifications and Publishing plugins
RUN /usr/local/bin/install-plugins.sh email-ext
RUN /usr/local/bin/install-plugins.sh mailer
RUN /usr/local/bin/install-plugins.sh slack

# Artifacts
RUN /usr/local/bin/install-plugins.sh htmlpublisher

# UI
RUN /usr/local/bin/install-plugins.sh greenballs
RUN /usr/local/bin/install-plugins.sh simple-theme-plugin

#Blue Ocean Pipeline
RUN /usr/local/bin/install-plugins.sh blueocean
RUN /usr/local/bin/install-plugins.sh blueocean-dashboard
RUN /usr/local/bin/install-plugins.sh blueocean-git-pipeline
RUN /usr/local/bin/install-plugins.sh blueocean-github-pipeline

# Scaling
RUN /usr/local/bin/install-plugins.sh kubernetes


# https://www.hugeinc.com/articles/list-of-useful-jenkins-plugins
RUN /usr/local/bin/install-plugins.sh build-monitor-plugin
RUN /usr/local/bin/install-plugins.sh build-name-setter
RUN /usr/local/bin/install-plugins.sh build-pipeline-plugin
RUN /usr/local/bin/install-plugins.sh build-timeout


# testing
RUN /usr/local/bin/install-plugins.sh cobertura
RUN /usr/local/bin/install-plugins.sh jacoco
RUN /usr/local/bin/install-plugins.sh performance


# install Maven
USER root
#RUN apt-get update && apt-get install -y maven


USER jenkins
  1. jenkins-security.groovy file contains steps to create credentials and other initialization process.

  2. jenkins-theme.groovy file apply custom theme to Jenkins UI

  3. jenkins-material-theme.css custom CSS you can download from http://afonsof.com/jenkins-material-theme/

jenkins-security.groovy
#!groovy
import jenkins.model.*
import hudson.security.*
import jenkins.security.s2m.AdminWhitelistRule
import jenkins.install.InstallState
import com.cloudbees.plugins.credentials.impl.*
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.domains.*
import org.jenkinsci.plugins.plaincredentials.impl.*
import hudson.util.*

def env = System.getenv()
def instance = Jenkins.getInstance()

// able to read without login
def hudsonRealm = new HudsonPrivateSecurityRealm(false)
hudsonRealm.createAccount(env.JENKINS_USER, env.JENKINS_PASS)
instance.setSecurityRealm(hudsonRealm)
// use FullControlOnceLoggedInAuthorizationStrategy for jenkin version 3 and above
def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
// read on mode enabled?
strategy.setAllowAnonymousRead(false)
instance.setAuthorizationStrategy(strategy)
instance.save()

Jenkins.instance.getInjector().getInstance(AdminWhitelistRule.class).setMasterKillSwitch(false)
instance.setInstallState(InstallState.INITIAL_SETUP_COMPLETED)


// SMTP Configuration for Jenkins

def jenkinsLocationConfiguration = JenkinsLocationConfiguration.get()
jenkinsLocationConfiguration.setAdminAddress("Jenkins<xxxxxx@gmail.com>")
jenkinsLocationConfiguration.setUrl("https://codergists.blogspot.com")
jenkinsLocationConfiguration.save()

def desc = instance.getDescriptor("hudson.tasks.Mailer")
desc.setSmtpAuth("xxxxxx@gmail.com", "xxxxxx")
desc.setReplyToAddress("noreply@gmail.com")
desc.setSmtpHost("smtp.gmail.com")
desc.setUseSsl(true)
desc.setSmtpPort("587")
desc.setCharset("UTF-8")
desc.save()


// Jenkins Global Security Credentials
// Generate GIT access key xxxxxxxxxxxxxxxa41e1ab0502b2xxxxxxxxxxxxxxx

Credentials c = (Credentials) new UsernamePasswordCredentialsImpl(CredentialsScope.GLOBAL,"GitUsernamePwd", "GitUsernamePwd", "yourgitusername", "xxxxxxxxxxxxxxxa41e1ab0502b2xxxxxxxxxxxxxxx")
SystemCredentialsProvider.getInstance().getStore().addCredentials(Domain.global(), c)

Credentials c1 = (Credentials) new StringCredentialsImpl(CredentialsScope.GLOBAL,"GitSecretText","SecretText",Secret.fromString("xxxxxxxxxxxxxxxa41e1ab0502b2xxxxxxxxxxxxxxx"))
SystemCredentialsProvider.getInstance().getStore().addCredentials(Domain.global(), c1)
jenkins-theme.groovy
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.simpletheme.CssUrlThemeElement;

Jenkins jenkins = Jenkins.get()

def themeDecorator = jenkins.getExtensionList(org.codefirst.SimpleThemeDecorator.class).first()

// apply custom theme to jenkins UI
// content under userContent can be accissible through http://jenkins-host/userContent/jenkins-material-theme.css
themeDecorator.setElements([
  new CssUrlThemeElement('/userContent/jenkins-material-theme.css')
])
jenkins.save()

No comments:

Post a Comment