Jenkins Pipeline Syntax: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
Line 174: Line 174:


<syntaxhighlight lang="groovy">
<syntaxhighlight lang="groovy">
   sh """
   stage.sh """
     LOGDIR=${fileName}-logs
     LOGDIR=${fileName}-logs
     mkdir -p \${LOGDIR}/something
     mkdir -p \${LOGDIR}/something

Revision as of 22:18, 7 April 2020

External

Internal

Scripted Pipeline

 node('some-worker-label') {
 
     echo 'Pipeline logic starts'
 
     stage('Build') {
        // ...
     }
     stage('Test') {
        // ...
     }
     stage('Deploy') {
        // ...
     }

Parallel Stages

stage("tests") {

    parallel(

        "unit tests": {

             // run unit tests 
         },
         "coverage tests": {

             // run coverage tests
         }
     )
}

Declarative Pipeline

 pipeline { 
     agent any 
     options {
         skipStagesAfterUnstable()
     }
     stages {
         stage('Build') { 
             steps { 
                 sh 'make' 
             }
         }
         stage('Test'){
             steps {
                 sh 'make check'
                 junit 'reports/**/*.xml' 
             }
         }
         stage('Deploy') {
             steps {
                 sh 'make publish'
             }
         }
     }
 }

Environment Variables

BUILD_TAG

It is an environment variable that contains job name, branch name, build number.

JOB_NAME

JOB_BASE_NAME

Parameters

https://wiki.jenkins.io/display/JENKINS/Parameterized+Build

A parameter enables the pipeline to prompt the user for a piece of information to be passed into the build. Each parameter has a "Name" and a "Value", which depends on the parameter type. A "Default Value" can be specified. The name-value pairs will be exported as environment variables when the build starts, allowing subsequent parts of the build configuration (such as build steps) to access those values using the following syntax:

${PARAMETER_NAME}

The parameter values can also be retrieved in a Jenkinsfile with the following syntax:

properties([
  ...
  parameters([
    string(
      name: 'branch',
      defaultValue: 'develop',
      description: 'Branch name or branch head\' SHA1 hash to be used to run this build on.'
    ),
    string(
      name: 'artifact version',
      description: 'The version of the artifact (ex: 1.0.0-build.1)'
    ),
    text(
      name: 'Test Packages,
      defaultValue: 'test-package-1',
    )
 ])
])

They can be reported, for debugging purposes, as follows:

params.get(propertyName)

Each parameter should have a unique name. Spaces are not permitted in parameter names.

When the build is parameterized, the "Build Now" control will be replaced with "Build with Parameters", where users will be prompted to specify values for each defined parameter. If they choose not to do anything, the build will start with the "Default Value". If the build is started automatically, the "Default Value" is used, unless the build triggering function provides the corresponding values, as follows:

build(
  job: "IntegrationTesting",
  parameters: [
    string(name: 'branch', value: serverSha),
    string(name: 'branchName', value: branch)
  ] + artifacts.keySet().sort().collect({ name ->
          echo "name: ${name}, value: ${artifacts[name]['artifact']}"
          string(name: name, value: artifacts[name]['artifact'])
    }),
    quietPeriod: 0,
    wait: true,
    propagate: true
)

When a parameterized build is in the queue, attempting to start another build of the same project will only succeed if the parameter values are different, or if the Execute concurrent builds if necessary option is enabled.

TODO

TODO:

  • TODO_nw3td What is the relationship between the parameters declared in the pipeline's UI and the parameters declared in the pipleline's Jenkinsfile?
  • TODO_n88Y6 Establish the precedence between a defaultValue declared in the "parameter" section in Jenkinsfile and one declared for the same parameter in the UI. It seems the file value influences the UI value.

Parameters Types

String

Multi-Line String Parameter

File Parameter

Pipeline Steps

https://jenkins.io/doc/pipeline/steps/

node

https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#-node-allocate-node

Allocates an executor or a node, typically a worker, and run the enclosed code in the context of the workspace of that worker. Node may take a label name, computer name or an expression.

The labels are declared on workers when they are defined in the master configuration, in their respective "clouds".

sh

https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#-sh-shell-script

Shell Script.

The metacharacter $ must be escaped: \${LOGDIR}, unless it refers to a variable form the Groovy context.

Example:

  stage.sh """
    LOGDIR=${fileName}-logs
    mkdir -p \${LOGDIR}/something
  """.stripIndent()

ws

https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#-ws-allocate-workspace

Allocate workspace.

build

https://jenkins.io/doc/pipeline/steps/pipeline-build-step/

This is how a main pipeline launches in execution a subordinate pipeline.

This is how we may be able to return the result: https://support.cloudbees.com/hc/en-us/articles/218554077-How-to-set-current-build-result-in-Pipeline

junit

https://jenkins.io/doc/pipeline/steps/junit/#-junit-archive-junit-formatted-test-results

Jenkins understands the JUnit test report XML format (which is also used by TestNG). To use this feature, set up the build to run tests, which will generate their test reports into a local agent directory, then specify the path to the test reports in Ant glob syntax to the JUnit plugin pipeline step junit

stage.junit **/target/*-report/TEST-*.xml

Jenkins uses this step to ingest the test results, process them and provide historical test result trends, a web UI for viewing test reports, tracking failures, etc.

Basic Steps

These basic steps are used invoking on stage.. In a Jenkinsfile, and inside a stage, invoke on this. or simply invoking directly, without qualifying.

dir

https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#-dir-change-current-directory

Change current directory.

echo

error

https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#error-error-signal

readFile

https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#readfile-read-file-from-workspace

Read a file from the workspace.

def versionFile = readFile("${stage.WORKSPACE}/terraform/my-module/VERSION")

stash

https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#stash-stash-some-files-to-be-used-later-in-the-build

input

https://jenkins.io/doc/pipeline/steps/pipeline-input-step/

In its basic form, renders a "Proceed"/"Abort" input box with a custom message. Selecting "Proceed" passes the control to the next step in the pipeline. Selecting "Abort" throws a org.jenkinsci.plugins.workflow.steps.FlowInterruptedException, which produces "gray" pipelines.

input(
    id: 'Proceed1',
    message: 'If the manual test is successful, select \'Proceed\'. Otherwise, you can abort the pipeline.'
)

timeout

https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#-timeout-enforce-time-limit

Upon timeout, an org.jenkinsci.plugins.workflow.steps.FlowInterruptedException is thrown from the closure that is being executed, and not from the timeout() invocation. The code shown below prints "A", "B", "D":

timeout(time: 5, unit: 'SECONDS') {

     echo "A"

     try {

           echo "B"

           doSometing(); // this step takes a very long time and will time out

           echo "C"
     }
     catch(org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) {

            // if this exception propagates up without being caught, the pipeline gets aborted

           echo "D"
     }
}

writeFile

https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#writefile-write-file-to-workspace

Core

https://jenkins.io/doc/pipeline/steps/core/

archiveArtifacts

https://jenkins.io/doc/pipeline/steps/core/#-archiveartifacts-archive-the-artifacts

fingerprint

Obtaining the Current Pipeline Build Number

def buildNumber = currentBuild.rawBuild.getNumber()

FlowInterruptedException

throw new FlowInterruptedException(Result.ABORTED)

Navigating the Project Model Hierarchy

String branch="..."
String projectName = JOB_NAME.substring(0, JOB_NAME.size() - JOB_BASE_NAME.size() - 1)
WorkflowMultiBranchProject project = Jenkins.instance.getItemByFullName("${projectName}")
if (project == null) {
  ...
}
WorkflowJob job = project.getBranch(branch)
if (job == null) {
  ...
}
WorkflowRun run = job.getLastSuccessfulBuild()
if (run == null) {
  ...
}
List<Run.Artifact> artifacts = run.getArtifacts()
...

Passing an Environment Variable from Downstream Build to Upstream Build

Upstream build:

...
def result = build(job: jobName,  parameters: params, quietPeriod: 0, propagate: true, wait: true);
result.getBuildVariables()["SOME_VAR"]
...

Downstream build:

env.SOME_VAR = "something"

@NonCPS

https://www.devopscat.tech/2018/10/what-is-noncps-in-jenkins-pipeline/