Jenkins pipelines definition

Understand how the Continuous Integration system works in Aura system in detail

Introduction

During the refactor phase, the way to declare the configuration of the different repositories has been redefined by trying to simplify the delivery/pipelines/Jenkinsfile file statement.

The main objective of the refactor is “to simplify”. This is attempted to achieve as follows:

  • All repositories must execute the same stages (predefined).
  • Repositories with a specific language should execute the same tasks in stages.
  • Scripts to execute tasks should be common and defined in jenkins-libraries-aura repository to be reused.

General structure project

The files associated with the continuous integration system are found in the delivery folder, which has the following structure:

delivery/
├── docker                          # Folder to Dockerfile
├── pipelines/Jenkinsfile.aura      # Jenkinsfile
└── scripts                         # Utility script for pipelines

Scripts added to the delivery/scripts folder should be specific tasks for this repository. Otherwise, the scripts should be in the resources/org/aura/script folder and that can be reused.

Add script to delivery/scripts only if it is completely necessary.

Jenkinsfile example

@Library(['aura']) _

auraPipeline {
    language = 'node'
}

The previous definition is sufficient for a nodeJS type repository to execute the default continuous integration tasks defined for an Aura nodejs project.

Definition of pipelines

Common libraries

Although it is possible to directly define the tasks to be executed with groovy here, there are a number of predefined scripts to run common tasks that can be used by including the aura and devops libraries:

@Library(['aura','devops']) _

Pipeline configuration

auraPipeline {
    slave,          // Slave where pipeline will be executed. Default: 'aura-bot-platform-14'
    nature,         // Pipeline nature: Default: 'standard' (the refactor nature)
    language,       // Language used by the pipeline
    artifacts,      // List of artifacts that need to be generated.
    stages,         // List of stages. Default: default stages
    modifiedStages, // List of modified stages.
    options,        // Pipeline options.
    postJobs        // Post execution jobs.
}

slave property

Slave property indicates the slave where Jenkins stages will be executed.

If a slave is not specified explicitly, aura-bot-platform-14 will be finally used.

nature property

The nature property indicates the definition of pipeline that will be executed on the list defined in ‘jenkins-libraries-aura’ project.

The simplification in the definition of pipelines has reduced the list to a single generic pipeline defined as standard.

It is still possible to execute existing pipelines, previous to refactor. Simply, the value of nature should indicate the pipeline to be executed.

This is deprecated in favor of the new standard pipeline.

language property

The language property helps the standard pipeline to execute the appropriate tasks depending on the language of the repository itself.

The system is prepared to handle repositories whose source code is written in a single main language.

artifacts property

List of artifacts that will be generated.

stages property

Although the standard pipeline defines a series of default stages depending on the type of ‘push’ that is done on the repository, this field allows you to define the stages manually.

modifiedStages property

In some cases, it is necessary to modify the configuration of some default stage in standard pipeline, without defining all the stages again (as we would do on the stages property).

For example, we can modify the test stage for the ‘pr’ type:

modifiedStages = [
    'pr': [
        new Stage(name: 'test', description: 'Test', options: [ skipLint: true] )
    ]
]

or modify the test stages for all types (pr, release, etc):

modifiedStages = [
    '*': [
        new Stage(name: 'test', description: 'Test', options: [ skipLint: true] )
    ]
]

options property

The following options are available:

Option Description type Default
deleteBuildOnSkip Delete build on skip boolean true
uploadGeneratedArtifacts Upload generated artifacts from ‘artifacts’ directory boolean false

postJobs property

Jenkins jobs that will be executed once the current job ends.

Defining artifacts

The artifacts are components that we can generate during the execution of the pipeline. All artifacts must extend from the Artifact class and depending on its type will generate one component or another.

Currently, there are only two types of components (although it can grow in the future): AuraComponent and AuraLibrary.

  • AuraComponent

A type component AuraComponent is used to generate a Docker image with the following configuration options:

Option Description type Default
name Component name String
version Version for the docker image String
envVersionVar Environment version variable (as AURA_BOT_VERSION) String
scripts List of names of configuration scripts List
initScripts List of names of initialization scripts List
buildArguments Docker build arguments List
dockerImageName Docker image name String
dockerFile Docker file name String ‘Dockerfile’
dockerPromotionTag Docker promotion tag String ’latest’

Example:

    artifacts = [
        new AuraComponent(
            name: "aura-bot", 
            version: "\$BOT_UC_VERSION", 
            dockerImageName: "aura/aura-bot-uc", 
            dockerFile: "Dockerfile", 
            scripts: ["librariesListFile.sh", "cfBotPlatformVersion.sh"], 
            buildArguments: ["BOT_BASE_VERSION=\$BOT_BASE_VERSION", "UC_VERSION=\$UC_VERSION", "UC_REVISION=\$PRODUCT_REVISION"]),
    ]
  • AuraLibrary

A type component AuraLibrary is used in repositories containing several libraries (multi-repository). In this way, it is possible to execute the pipeline for each of the libraries defined in the list of components.

If a multi-repository follows the structure of adding each library within the “packages” directory, the stages in standard pipeline are able to automatically get the library list, so in most cases it is not necessary to define configuration by hand.

In case you need to define the library list, the following options are available:

Option Description type Default
name Component name String
path Component path (Ex. packages/my-library) String
versionStrategy Version strategy: distag, old String distag

Example:

    artifacts = [
        new AuraLibrary( name: "aura-json-schema-generator", path: "packages/aura-json-schema-generator")
    ]

How to define my own stages?

The standard pipeline defines the following stages by default:

// Default stages
'default': [
    'pr'     : [
        new Stage(name: 'decrypt', description: 'Decrypt'),
        new Stage(name: 'initialization', description: 'Initialization'),
        new Stage(name: 'build', description: 'Build'),
        new Stage(name: 'test', description: 'Test')
    ],
    'release': [
        new Stage(name: 'checkSkip', description: 'Checkout skip'),
        new Stage(name: 'decrypt', description: 'Decrypt'),
        new Stage(name: 'initialization', description: 'Initialization'),
        new Stage(name: 'build', description: 'Build'),
        new Stage(name: 'test', description: 'Test'),
        new Stage(name: 'versioning', description: 'Versioning'),
        new Stage(name: 'publish', description: 'Publish'),
        new Stage(name: 'promote', description: 'Promote'),
        new Stage(name: 'deploy', description: 'Deploy')
    ]
]

Although the standard pipeline supplies the previous list of stages by default, it is possible to define stages manually, indicating in the repository that stages will be executed for each type.

There are two different ways to do this:

  • Modify or add stages on the standard pipeline. For this you must use the modifiedStages property. If a stage is defined with the name of an existing one, it is becoming overwritten. In case the added stage has a name different from the existing default stage, the new stage will be added in the execution.

  • Refine completely the list of stages to be executed. As indicated above in the options, the stages property allows you to define the list of stages that will be executed.

Example to execute only the test stage in the ‘pr’ type:

stages = [
    'pr': [
        new Stage(name: 'test', description: 'Test')
    ]
]

What tasks are executed for each stages?

Each Stage executes a series of task based on the value of the language property.

Node

Stage Description
checkSkip* Perform a check to know if it can do skip of the build.
decrypt* Decrypt files that need it.
initialization Gets versions for AuraComponent type artifacts.
build Run node/build.sh script for all Library type components (the scripts can get libraries automatically).
test Run node/test.sh script for all Library type components (the scripts can get libraries automatically). After execution, reports are generated for: Test, Coverage and LiNT.
versioning Run node/versioning.sh script for all Library type components (the scripts can get libraries automatically).
publish If the onlyPack option is added, the npmPack.sh script will be executed. Otherwise, the publish.sh script will be executed.
promote* For each AuraComponent type artifact performs a docker tag and push command
deploy* For each AuraComponent type artifact performs a deployment for the component

The value * at the end of stage’s name indicates that it is a default stage and it has not been modified for the node language.

Scripts used in the execution process for the node language:

node
├── build.sh        # Execute "npm install".
├── npmPack.sh      # Execute "npm install", "npm pack" and move the generated packages to the _artifacts_ folder.
├── publish.sh      # Check if it is not published and runs "npm install" and "npm publish".
├── test.sh         # Execute "npm run coverage-jenkins" and "npm run lint-jenkins".
└── versioning.sh   # Detects changes in the library to increase version (only if publishConfig exists in package.json)