Skip to main content
Version: 10.2.9

Implement continuous integration with Git and Jenkins

The guide details how you can create three basic Jenkins jobs to implement a Continuous Integration/Continuous Delivery (CI/CD) process. These jobs are as follows:

  • For testing Git commits
  • For releasing Business Process (BP) bundles to Nexus
  • For publishing BP bundles to server Control Tower

Actually, you need to create a single configurable Jenkins job with three parameters allowing to execute it in the three modes:

  • Build
  • Release
  • Deploy to CT

Required software

WorkFusion provides a CI/CD solution based on the technology stack:

If you want to use a toolset different from the one recommended above, it is your call to wire them together to establish an automated CI/CD process. The particular OpenJDK version is required to provide the compatibility of the CI/CD pipeline with WorkFusion-based development projects.

note

The current guide is created considering the usage of Ubuntu Linux as OS for the integration server where CI/CD tools are installed, configured, and executed. Hence, the commands below are for Ubuntu Linux. If you have any other Linux distribution, ask your system administrators to install the components.

The setup was tested on a simple server with 2 CPUs (3.1 GHz) and 4 GB of RAM.

Start with the following:

  1. Access the OS instance on the server via SSH using the terminal or a Putty SSH client.
  2. Download and install Azul Zulu OpenJDK 8.x.
tip

Mind that instances (servers) with installed Control Tower, Jenkins, and Nexus should be visible to each other (server IP addresses can be cross-"ping-ed").

Installing and configuring tools

Install Git

If you do not have an installed version control server to hold the project source code, you can set up Git version control on the same server as Jenkins.

You can install community versions of GitLab or a trial version of the Bitbucket server. This guide offers a simple Git-as-a-server installation.

Here's the easiest way of setting up a Git server. It is available via the Git protocol. The advantage of the method is that the protocol requires no authorization. Thus, if the server is public, the source is available to anyone who knows the URL.

To manually install Git as a service, follow the steps below:

  1. Install Git.

    sudo apt-get install git-core
  2. Confirm the installation.

    git --version

    In the response, you will see something similar to this, depending on the version of the installed package:

    git version 2.17.1

Configure Git SSH access

  1. Set up a home directory:

    sudo useradd -r -m -U -d /home/git -s /bin/bash git

    The user home directory is set to /home/git. All repositories are stored under this directory. No password is set for the "git" user. The login is available only using SSH keys.

  2. Switch to the "git" user by executing the su command:

    sudo su - git
  3. Run the following commands to create an SSH directory and set correct permissions:

    mkdir -p ~/.ssh && chmod 0700 ~/.ssh
  4. Create a file named ~/.ssh/authorized_keys that holds the authorized users' SSH keys:

    bash touch ~/.ssh/authorized_keys && chmod 0600 ~/.ssh/authorized_keys

The server setup is complete. You are now ready to create your first Git repository.

To initiate a new empty repository, run the following command under the "git" user:

git init --bare ~/projectname.git

Configure access to remote Git

To push local Git changes to the Git server, add the local user's SSH public key to the authorized_keys file of the remote "git" user.

If you already have an SSH key pair created in your local system, get a public key:

  • For Windows, find the id_rsa.pub file in your user_directory/ssh/.

  • For Linux, execute the following command:

    cat ~/.ssh/id_rsa.pub

Generate SSH key pair in Linux

To generate an SSH key pair, Linux users should follow the steps below:

  1. Open the terminal on your local computer and enter the following command:

    ssh-keygen -t rsa -b 4096 -C "your_email@domain.com"

    Associating the key with your email address helps you to identify the key later. You'll see a response similar to this:

    Generating a public/private rsa key pair. Enter file in which to save the key (/Users/username/.ssh/id_rsa):
  2. Press Enter to accept the default location and filename. If the .ssh directory doesn't exist, the system creates one for you.

  3. Enter and re-enter a passphrase when prompted. The whole interaction looks similar to this:

      Generating public/private rsa key pair.
    Enter file in which to save the key (/home/username/.ssh/id_rsa):
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in /home/username/.ssh/id_rsa.
    Your public key has been saved in /home/username/.ssh/id_rsa.pub.
    The key fingerprint is:
    SHA256:Up6KjbnEV4Hgfo75YM393QdQsK3Z0aTNBz0DoirrW+c username@klar
    The key\'s randomart image is:
    +---[RSA 2048]----+
    | . ..oo..|
    | . . . . .o.X.|
    | . . o. ..+ B|
    | . o.o .+ ..|
    | ..o.S o.. |
    | . %o= . |
    | @.B... . |
    | o.=. o. . . .|
    | .oo E. . .. |
    +----[SHA256]-----+

Generate SSH key pair in Windows

To generate an SSH key pair, Windows users should follow the steps below:

  1. Log in to your local computer as an Administrator.

  2. In the command prompt, run:

    ssh-keygen -t rsa -C "your_email@example.com"

    Associating the key with your email address helps you to identify the key later.

    Note that the ssh-keygen command is only available if you have already installed Git (with Git Bash). You'll see a response similar to this:

    Generating public/private rsa key pair. Enter file in which to save the key (c/Users/ASUS/.ssh/id_rsa):
  3. Press Enter to accept the default location and filename. If the .ssh directory doesn't exist, the system creates one for you.

  4. Enter and re-enter a passphrase when prompted. The whole interaction looks similar to this.

    Generating public/private rsa key pair.
    Enter file in which to save the key (/c/Users/ASUS/.ssh/id_rsa): /c/Users/ASUS/.ssh/
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in /c/Users/ASUS/.ssh/
    Your public key has been saved in /c/Users/ASUS/.ssh/
    The key fingerprint is:
    SHA256:jieniOIn20935n0awtn04n002HqEIOnTIOnevHzaI5nak ASUS@periwinkle
    The key\'s randomart image is:

    +---[RSA 2048]----+
    |*= =+. |
    |O*=.B |
    |+*o* + |
    |o +o. . |
    | ooo + S |
    | .o.ooo* o |
    | .+o+*oo . |
    | .=+.. |
    | Eo |
    +----[SHA256]-----+
  5. Copy the output from the cat command above and go back to the Git server console.

  6. On the server, open your text editor and paste the public key you copied from your local machine into the ~/.ssh/authorized_keys file:

    sudo nano /home/git/.ssh/authorized_keys
    note

    If running a command using a git user can require a password, you should run it with your login user with the sudo permissions. The entire public key text should be on a single line.

    The instruction assumes that the Git package is already installed on your local machine. If not, install it in the same way as explained in the previous sections.

  7. If you have an existing unversioned project, navigate to the project directory. If you are starting from scratch, create a project directory, navigate to it, and initialize a Git repository.

    cd /path/to/local/project
    git init .
  8. Add the git remote to your local repository.

    git remote add origin git@git_server_ip:projectname.git

Get external IP

To find out the external IP of an instance, use any of these commands if you have Internet access:

curl ifconfig.me
curl icanhazip.com
curl ipecho.net/plain
curl ifconfig.co

Otherwise, ask your system administrator about your internal server IP.

Now, you can create any file in this directory, commit it, and push to the remote repo using your favorite tool or terminal commands.

touch test_file
git add .
git commit -m "descriptive message"
git push -u origin master

Install GitLab and Bitbucket

As a Git server alternative, you can also install community versions of GitLab or a trial version of the Bitbucket server.

Create repositories for CI pipeline

For correct implementation of a CI pipeline, create two repositories:

  • For Jenkins pipeline libraries
  • For your AI Agent implementation

Create repo for Jenkins pipeline libraries

  1. Go to the server that hosts Git and create a remote repo:

    sudo su - git git init --bare ~/common-build-library.git
  2. On your local machine, create the same repo:

    mkdir common-build-library
    cd common-build-library/
    git init .
    git remote add origin git@git_server_ip:common-build-library.git
  3. Extract the contents of jenkins-common-libraries.zip to the newly created repo directory.

  4. Commit and push to the remote Git.

    git add .
    git commit -m "commit message"
    git push -u origin master

Create repo for AI Agent implementation

  1. Go to the server that hosts Git and then create a remote repo:

    sudo su - git
    git init --bare ~/usecase-project.git
  2. On your local machine, create the same repo:

    mkdir usecase-project
    cd usecase-project/
    git init .
    git remote add origin git@git_server_ip:usecase-project.git
  3. Create a project from the Archetype.

  4. Commit and push to remote Git.

    git add .
    git commit -m "commit message"
    git push -u origin master

Install and configure Jenkins

To install Jenkins, follow the steps below:

  1. Download the Jenkins installation package from https://jenkins.io/download/ and install it manually:

    curl -# -o jenkins_2.190.2_all.deb https://prodjenkinsreleases.blob.core.windows.net/debian-stable/jenkins_2.190.2_all.deb
    sudo apt install -f jenkins_2.190.2_all.deb

    Alternatively, use a repository:

    wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add - sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list' deb https://pkg.jenkins.io/debian-stable binary/ sudo apt-get update sudo apt-get install jenkins
  2. Change the default port by editing /etc/default/jenkins:

    nano /etc/default/jenkins
  3. Change the HTTP_PORT property. As a result, the file should contain the following:

    HTTP_PORT=$SELECTED_PORT_VALUE
  4. Save the file by pressing Ctrl+O and exit the file by pressing Ctrl+X.

Start Jenkins

  1. Run the command to start Jenkins.

    sudo systemctl start jenkins
    sudo systemctl status jenkins

    If everything goes well, the beginning of the output shows that the service is active and configured to start at boot.

    ● jenkins.service - LSB: Start Jenkins at boot time
    Loaded: loaded (/etc/init.d/jenkins; generated)
    Active: active (exited) since Mon 2018-07-09 17:22:08 UTC; 6min ago
    Docs: man:systemd-sysv-generator(8)
    Tasks: 0 (limit: 1153)
    CGroup: /system.slice/jenkins.service
  2. Optional: open the firewall, if required. By default, Jenkins runs on the 8080 port, so it's necessary to open the port using the ufw command.

    sudo ufw allow 8080
    sudo ufw status

    If ufw is inactive, the following commands allow OpenSSH and enable the firewall.

    sudo ufw allow 22
    sudo ufw allow OpenSSH
    sudo ufw enable

Configure Jenkins

  1. To set up your installation, open Jenkins on its default port, 8080, using your server domain name or IP address: http://your_server_ip_or_domain:8080.

    To find the external instance IP, use any of these commands if you have Internet access:

    curl ifconfig.me
    curl icanhazip.com
    curl ipecho.net/plain
    curl ifconfig.co

    Otherwise, ask your system administrator about your internal server IP.

  2. You should see the Unlock Jenkins screen that displays the location of the initial password.

    In the terminal window, use the cat command to display the password.

    sudo cat /var/lib/jenkins/secrets/initialAdminPassword
  3. Copy the 32-character alphanumeric password from the terminal, paste it into the Administrator password field, and click Continue.

  4. On the Customize Jenkins screen, click Install suggested plugins, which immediately begins the installation process.

When the installation is complete, you are prompted to set up the first administrative user. It’s possible to skip the step and continue as admin using the initial password used above, but our recommendation is to take a moment and create the user as described below:

info

The default Jenkins server is NOT encrypted, so the data submitted with this form is not protected. When you’re ready to use the installation, refer to How to Configure Jenkins with SSL Using an Nginx Reverse Proxy on Ubuntu 18.04. This protects the user credentials and the build information transmitted via the web interface.

  1. In the Create First Admin User window, enter the Username and Password for your user. Click Save and Continue.

  2. In the Instance Configuration window, enter the preferred Jenkins URL for your Jenkins instance. Confirm either the domain name for your server or your server’s IP address. For example, http://jenkins.example.com or http://203.0.113.0:8080.

  3. Click Save and Finish. You will see a confirmation page stating "Jenkins is Ready!".

  4. Click Start using Jenkins to open the Jenkins dashboard.

If you see an empty page after login, try restarting the Jenkins service with the following command:

sudo systemctl restart jenkins

Install Jenkins plugins

  1. In the left-side menu of the Jenkins main page, click Manage Jenkins > Manage Plugins.

  2. On the Available tab, find the following plugins using the search bar and select respective checkboxes:

    • Config File Provider plugin.
    • Rebuilder allows rebuilding a job using the same parameters.
    • Pipeline Utility Steps for extra capabilities in pipelines.
    • Badge plugin to improve error messaging (search query: "add badges").
    • Slack Notification plugin if you're planning to use Slack notifications.

Configure Maven and JDK in Jenkins

  1. On the Jenkins main screen, click Manage Jenkins > Global Tool Configuration.

  2. In the JDK section, specify the existing Maven installation and deselect Install Automatically. Set up JDK8 as Name.

    note

    JAVA_HOME should be set according to the system setup.

  3. In the Maven section, click Add Maven. By default, Maven is installed from the Apache site. Insert Maven3.6.3 as Name.

  4. Select Install automatically.

  5. In the Version dropdown, select 3.6.3.

  6. Click Save.

Create build job

Add build script to your codebase

  1. If you are starting a new project, use the Archetypes from the https://repository.workfusion.com/content/repositories/archetypes projects created from the latest versions of these Archetypes that already contain the build.groovy file with a pipeline.

  2. If you already have a codebase, add the build script manually:

    See code snippet
        @Library('common-build-library') _
    pipeline {

    agent any

    tools {
    jdk 'JDK8'
    maven 'Maven3.6.3'
    }

    parameters {
    booleanParam(name: 'DEPLOY_TO_CT', defaultValue: false, description: 'Deploy to Control Tower. False by default.')
    booleanParam(name: 'RELEASE', defaultValue: false, description: 'Release bundle and deploy it to nexus. Bundle will be deployed to nexus. False by default.')
    string(name: 'SLACK_CHANNEL', defaultValue: '', description: 'Slack channel for sending notifications about build status. IF empty - no slack notifications will be sent')
    string(name: 'EMAILS', defaultValue: '', description: 'Comma separated list of emails for sending notifications about build status. IF empty - no slack notifications will be sent')
    }

    options {
    buildDiscarder(logRotator(numToKeepStr: '10', daysToKeepStr: '60'))
    }

    stages {

    stage('Notify started') {
    steps {
    notifySlack("started (${buildCause()})", 'lightskyblue', this)
    notifyEmail("started (${buildCause()})", this)
    }
    }

    stage('Build') {
    when {
    expression { return !params.RELEASE }
    }
    steps {
    failWhen condition: readMavenPom(file: 'pom.xml').with {
    it.version?.trim()
    }, message: 'Root pom.xml file should contains version. Fix inconsistency in pom.xml.'

    buildWithMaven configId: 'maven-settings', goals: ['clean', 'install'], jvmParameters: [skipObfuscation: 'true']
    }
    }

    stage('deploy to CT') {
    when {
    expression { return params.DEPLOY_TO_CT }
    }
    steps {
    failWhen condition: readMavenPom(file: 'pom.xml').with {
    it.version?.trim()
    }, message: 'Root pom.xml file should contains version. Fix inconsistency in pom.xml.'

    failWhen condition: mavenVersion().endsWith('-SNAPSHOT'), message: 'Cannot deploy snapshot artifact. Fix project version in pom.xml.'

    // Place your bundle sub-module name here
    dir('package-folder-name') {
    buildWithMaven configId: 'maven-settings', clean: false, goals: ['bundle:import']
    }
    }
    }

    stage('Release') {
    when {
    expression { return params.RELEASE }
    }
    stages {
    stage('Build and Deploy release') {
    steps {
    failWhen condition: readMavenPom(file: 'pom.xml').with {
    it.version?.trim()
    }, message: 'Root pom.xml file should contains version. Fix inconsistency in pom.xml.'

    failWhen condition: mavenVersion().endsWith('-SNAPSHOT'), message: 'Cannot deploy snapshot artifact. Fix project version in pom.xml.'

    // Place your bundle sub-module name here
    dir('rpa-bundle-quickstart-test-package') {
    buildWithMaven configId: 'maven-settings', goals: ['clean', 'deploy']
    }
    }
    }

    stage('Make a tag and push') {
    steps {
    shellScript "git tag ${mavenVersion()}"
    shellScript 'git push --tags'
    }
    }
    }
    }

    }

    post {
    success {
    notifySlack('is successful', 'forestgreen', this)
    notifyEmail('is successful', this)
    }
    unstable {
    notifySlack('is unstable', 'red', this)
    notifyEmail('is unstable', this)
    }
    failure {
    notifySlack('failed', 'red', this)
    notifyEmail('failed', this)
    }
    aborted {
    notifySlack('was aborted', 'red', this)
    notifyEmail('was aborted', this)
    }
    }
    }

    def notifySlack(String buildMessage, String color, def script) {
    final String slackChannel = script.params.SLACK_CHANNEL
    if (slackChannel.isEmpty()) {
    return
    }
    withCredentials([string(credentialsId: 'slack_auth', variable: 'SLACK_AUTH_PSW')]) {
    script.slackMessage(buildMessage: buildMessage, color: color, token: SLACK_AUTH_PSW, channel: slackChannel)
    }
    }

    def notifyEmail(String buildMessage, def script) {
    final def env = script.env
    if (emails.isEmpty()) {
    return
    }
    script.emailext(
    subject: "'${env.JOB_NAME} [${env.BUILD_NUMBER}]' ${buildMessage} ",
    to: params.EMAILS,
    body: """
    '${env.JOB_NAME} [${env.BUILD_NUMBER}]' ${buildMessage} :
    Check console output at "${env.JOB_NAME} [${env.BUILD_NUMBER}]"

    """
    )

    }
  3. Add your bundle sub-module name in lines 54 and 75. Then, add the build.groovy file with the content to the root folder of your project, commit, and push it to the Git repository.

Configure credentials

  1. On the main Jenkins page, in the left menu, click Credentials.

  2. In the Stores scoped to Jenkins section, click Global Credentials.

  3. In the right-hand menu, click Add Credentials.

  4. If you are using a Git server with HTTPS access:

    1. In the Kind drop-down box, select Username with password.
    2. Type in your username and password for the Git account and credentials ID to have access to the credentials while configuring a build job. Then, click OK.
  5. If you are using a Git server with SSH access:

    1. Generate an SSH key pair for using it as Jenkins credentials.

    2. Create a directory for keeping the SSH RSA Keys file and navigate to the newly-created directory.

      mkdir -p ~/ssh-rsa-keys && cd ~/ssh-rsa-keys
    3. Create SSH RSA Keys in the PEM file format inside the newly created directory.

      ssh-keygen -t rsa -b 4096 -C "git ssh keys" -f gitcreds.pem
    4. Enter a passphrase if asked or leave it blank.

    5. Upon completion, the command creates two files: private key and public key. The one that has the PUB file extension refers to the public key file whereas the other is the private key file. Get the public key and copy it.

      cat gitcreds.pem.pub
    6. Paste to the authorized_keys list.

      sudo su - git nano .ssh/authorized_keys
    7. Go to the private key and copy the value.

      cat gitcreds.pem
    8. Select configuring access via SSH, use the username, private key, and passphrase generated during Git setup. Use the gitcreds.pem content as a private key from the previous item.

Create new directory for handling Jenkins common libraries

  1. On the main Jenkins page, click New Item.
  2. Enter the folder name and select Folder.
  3. Click OK.

Add jenkins-common-libraries to created directory

  1. Go to the newly created folder.

  2. Click Configure.

  3. In the Pipeline Libraries section, click Add.

  4. Insert common-build-library as the name and master as the default version.

  5. In the Retrieval method section, select Modern SCM.

  6. In the Source Code Management section, select Git.

  7. Enter the common-build-library.git repo URL (created earlier) and select git credentials from the list.

    tip

    If Git and Jenkins are hosted on the same system, use 127.0.0.1 as the Git server IP.

  8. Click Save.

Create config file for using in Maven build

Let's create all the necessary credentials to be used in a build:

  1. In the created folder, click Credentials in the left menu.

  2. Click Global > Add Credentials.

  3. Add the Control Tower deploy credentials:

    1. Select the Username with password credentials kind and insert your login and password to the Control Tower instance.

    2. Use control-tower as credentials ID.

    3. Click OK.

  4. Add Nexus repository credentials:

    1. Select Username with password credentials kind and insert your login and password to the Nexus Repository instance.

    2. Use nexus-repository as credentials ID.

    3. Click OK.

  5. Optional: add Slack credentials if Slack notifications are available and required. Select the Secret text credentials type and insert your Slack authentication token. Use slack_auth as credentials id. Click OK.

    ![](/img/assets/automation/odf/91391294.png)
  6. Add the Maven config file:

    1. Go to the created build folder and click Config Files.
    2. Click the Add a new Config link.
    3. Select Maven settings.xml.
    4. Enter maven-settings as ID and click Submit.
    5. In the Edit Configuration File window > Configuration, click Add for the Server Credentials item.
    6. Insert bcb-repository ServerId, select deploy credentials, and click Add.
    7. Insert wf-dependencies ServerId, select deploy credentials, and click Add.
    8. Insert control-tower ServerId, select deploy credentials, and click Add.
    9. Click Submit.

Create and run build job

  1. In the business-process-build folder, click Create new jobs.

  2. Enter a job name, select Multibranch Pipeline, and click OK.

  3. Enter Display Name for the job, for example, Build business process bundle.

  4. In the Branch Sources section, select Git.

  5. Add a link to the Git repository with your BP bundle and select git credentials.

    tip

    If Git and Jenkins are hosted on the same system, use 127.0.0.1 as the Git server IP.

  6. Insert build.groovy as Script Path.

  7. In the Scan Multibranch Pipeline Triggers, configure build scheduling. The interval should be according to your project requirements.

  8. On the first script launch, you get an error with the following stack trace:

Error message
    java org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use method hudson.model.Cause getShortDescription at org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.StaticWhitelist.rejectMethod(StaticWhitelist.java:262) at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:161) at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:158) at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:161.        at org.kohsuke.groovy.sandbox.impl.Checker$checkedCall$1.callStatic(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:56) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:194) at buildCause$_getBuildUser_closure1.doCall(buildCause.groovy:7) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:491.        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:321.        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022) at groovy.lang.Closure.call(Closure.java:414) at groovy.lang.Closure.call(Closure.java:430) at org.codehaus.groovy.runtime.DefaultGroovyMethods.collect(DefaultGroovyMethods.java:3202) at org.codehaus.groovy.runtime.DefaultGroovyMethods.collect(DefaultGroovyMethods.java:3172) at com.cloudbees.groovy.cps.CpsDefaultGroovyMethods.collect(CpsDefaultGroovyMethods.java:399) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:491.        at org.codehaus.groovy.runtime.metaclass.ReflectionMetaMethod.invoke(ReflectionMetaMethod.java:54) at org.codehaus.groovy.runtime.metaclass.NewInstanceMetaMethod.invoke(NewInstanceMetaMethod.java:56) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1213) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022) at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:47) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:160) at org.kohsuke.groovy.sandbox.GroovyInterceptor.onMethodCall(GroovyInterceptor.java:23) at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:107) at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:158) at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:161.        at org.kohsuke.groovy.sandbox.impl.Checker$checkedCall$1.callStatic(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:56) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:194) at buildCause.getBuildUser(buildCause.groovy:7) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:491.        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:321.        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1213) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022) at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:42) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:160) at org.kohsuke.groovy.sandbox.GroovyInterceptor.onMethodCall(GroovyInterceptor.java:23) at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:157) at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:158) at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:161.        at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17) at buildCause.call(buildCause.groovy:2) at WorkflowScript.run(WorkflowScript:26) at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.delegateAndExecute(ModelInterpreter.groovy:140) at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.executeSingleStage(ModelInterpreter.groovy:663) at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.catchRequiredContextForNode(ModelInterpreter.groovy:398) at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.catchRequiredContextForNode(ModelInterpreter.groovy:396) at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.executeSingleStage(ModelInterpreter.groovy:662) at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:291) at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.toolsBlock(ModelInterpreter.groovy:542) at ___cps.transform___(Native Method) at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:86) at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:113) at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:83) at sun.reflect.GeneratedMethodAccessor495.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:491.        at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72) at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:76) at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30) at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.fixName(PropertyishBlock.java:66) at sun.reflect.GeneratedMethodAccessor501.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:491.        at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72) at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21) at com.cloudbees.groovy.cps.Next.step(Next.java:83) at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174) at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163) at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:129) at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:268) at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:18) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:51) at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:186) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:370) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:93) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:282) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:270) at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:67) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131) at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28) at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)

To solve the error, keep doing the following actions until the build successfully passes. The build script contains several Groovy calls that are now allowed by default.

  1. To allow it, go to the Jenkins main page and, in the left menu, select Manage Jenkins.
  2. In the Manage Jenkins menu, click In-process Script Approval.
  3. Click Approve for any existing approval requests.

After all the required signatures are approved, the list should contain the following lines:

java field hudson.model.Run project method hudson.model.Cause getShortDescription method hudson.model.Run getCauses method org.apache.maven.model.Model getVersion method org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper getRawBuild staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods grep java.util.List

Notes and possible issues

  1. Check if the connections between the Jenkins instance and Control Tower are established. Otherwise, the publish to CT build step fails.
  2. Check if the connections between the Jenkins instance and Nexus are established. Otherwise, the release build step fails.
  3. If you are using a setup with Git and Jenkins on a single machine or using a simple Git setup with only SSH authorization, the release step can fail.
Error message
        @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:VwutoGKAXnaG1/RQ8HXhOY3RcaDV4WZepmQzxmj1Kws.
contact your system administrator.
Add correct host key in /var/lib/jenkins/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /var/lib/jenkins/.ssh/known_hosts:1
remove with:
ssh-keygen -f "/var/lib/jenkins/.ssh/known_hosts" -R "127.0.0.1"
ECDSA host key for 127.0.0.1 has changed and you have requested strict checking.
Host key verification failed.
This means that Jenkins cannot be authorized via SSH and push a tag. To solve this, run the following command on an instance (you can find this command in an error message).
ssh-keygen -f "/var/lib/jenkins/.ssh/known_hosts" -R "127.0.0.1"

The IP can be changed depending on the Git server deploy point.