Giter Site home page Giter Site logo

griddynamics / mpl Goto Github PK

View Code? Open in Web Editor NEW
155.0 22.0 95.0 123 KB

[IT-36925] Jenkins Shared Modular Pipeline Library

Home Page: https://blog.griddynamics.com/developing-a-modular-pipeline-library-to-improve-devops-collaboration/

License: Apache License 2.0

Groovy 98.03% Shell 1.25% Dockerfile 0.72%

mpl's Introduction

Modular Pipeline Library

CircleCI Gitter

CircleCI nightly LTS - testing MPL pipeline with the current LTS Jenkins every night

CircleCI nightly Latest - testing MPL pipeline with the current Latest Jenkins every night

Shared jenkins library with modular structure allow to write a simple pipeline modules, test it properly and use in any kind of pipelines.

Goals

  • Provide core to support flexible modular structure
  • Enable support for declarative & scripted pipelines
  • Ensure that nested libraries could reuse the MPL features
  • Allow module overrides from the project or nested libraries
  • Prepare set of simple & minimal basic pipelines
  • Make it easy to create tests for modules & pipelines

Documentation

This readme contains mostly technical information, if you need some overview - please check the next resources:

You also can check MPL Wiki to find additional info.

Dependencies

  • Jenkins >= 2.74 LTS
  • workflow-cps >= 2.44
  • workflow-job >= 2.15
  • workflow-cps-global-lib >= 2.8

Setup

Go to: Manage Jenkins --> Configure System --> Global Pipeline Libraries:

  • Name: mpl
    • Default Version: master
    • Load implicitly: false
    • Allow default version to be overridden: true
    • Include @Library changes in job recent changes: true
    • Retrieval method: Modern SCM
    • Source Code Management: Git
    • Project Repository: https://github.com/griddynamics/mpl.git
    • Behaviors: Discover branches, Discover tags

Usage

You can use MPL in 3 different ways - it's 3 layers of the library:

  • Pipeline - Standard pipelines implemented for you. Just use them for your project or as example for your custom pipeline.
  • Modules - Common steps you can find in each pipeline. Prepare your pipeline structure and just use the required modules.
  • Features - Some useful libraries that you can use. Prepare your own pipeline with custom modules and use just features from the library.

Jenkinsfile / Pipeline script

Just two lines to use default Master pipeline in your project Jenkinsfile or in the Jenkins Pipeline Script:

@Library('mpl') _
MPLPipeline {}

Pipelines

You can find pipelines in the MPL library interfaces: {MPL}/vars/MPL{Name}Pipeline.groovy files.

There is 2 ways to slightly reconfigure the provided standard pipeline:

  • Provide some configuration when you using pipeline in your jenkinsfile (see examples)
  • Override pipeline modules in the project (see Creating / Overriding steps modules section)

If both ways are not helping - just create your own pipeline definition in the Jenkinsfile and use MPL modules or create your own nested library with your standard pipelines.

Configuration

Usually configuration is initialized in the pipeline - it's calling MPLPipelineConfig interface with arguments:

  • body - Map/Closure with configuration from the Jenkinsfile
  • defaults - pipeline default values (could be overridden by Jenkinsfile)
  • overrides - pipeline hard values (could not be overridden by Jenkinsfile)

After that pipeline defining MPL object and use it's common functions to define the pipeline itself. Pipeline is calling MPLModule that calling the required module logic.

In the module we have a common predefined variables (like default steps, env, params, currentBuild...) and a new variable contains the pipeline/module configs: CFG. It's a special MPLConfig object that defines interface to get and set the properties. It's promising a number of things:

  • Get value will never throw exception
  • Unable to change values of CFG through get or clone
  • It's not related to the parent module or pipeline CFG - any changes could be only forwarded to the children module
  • You can get raw config Map/List - but they will act like a normal Map/List (could cause exceptions)
  • Set of the CFG value could cause exceptions in certain circumstances:
    • set improper List index (non-positive integer)
    • set sublevels for defined non-collections

MPLConfig object is not the usual Map - you have to use it with known key you defined before. That was introduced to make sure you will see what kind of configuration is used or required on each stage. So you will need to use it as def a = CFG.really_needed_data instead of just def a = CFG or for( a in CFG ) println(a) which will tell you much more useful information and simplify debug.

Use of the CFG object is quite simple. Imagine we have the next pipeline configuration:

[
  agent_label: '',
  val1: 4,
  val2: [
    val_nested: 'value',
    val_list: [1,2,3,4],
  ],
]
  • Get value of specific property:

    • CFG.val1 == CFG.'val1' == 4
    • CFG.'val2.val_nested' == 'value'
    • CFG.'val2.not_exist' == null
    • CFG.'val2.not_exist' ?: 'default' == 'default'
    • CFG.'val2.val_list.2' == 3
  • Get raw Map or List:

    • CFG.'val2.val_list' == [1,2,3,4]
    • CFG.val2 == [val_nested:'value',val_list:[1,2,3,4]]
  • Set value of a specific property:

    • CFG.val1 = 3; CFG.val1 == 3
    • CFG.'val2.val_nested' = 555; CFG.val2.val_nested == 555
  • Create new properties:

    • CFG.val4 = 'newval'; CFG.val4 == 'newval'
    • CFG.'val2.val_list.5' = 333; CFG.'val2.val_list' == [1,2,3,4,null,333]
  • Replace entire Map or List:

    • CFG.'val2.val_list' = null; CFG.val2 == [val_nested:'value',val_list:null]
    • CFG.val2 = [new_key:[4,3,2,1]]; CFG.val2 == [new_key:[4,3,2,1]]

So you got the point - hopefully this will be helpful and will allow you to create the great interfaces for your modules.

MPLModule return

MPLModule step running the specified module with CFG configuration and returns OUT configuration. OUT is always empty when a module just started and could be modified inside the module. So:

  • you can set some variable like "Module/SomeModule.groovy":
    OUT.'artifact.version' = 1
  • and use it in parent module "Module/Module.groovy" as:
    def version = MPLModule('Some Module').'artifact.version'
    echo "${version}"
    OUT.'artifact_info.artifact.version' = version

To modify the pipeline config with the module output - just use MPLPipelineConfigMerge step - we recommend to use it only in the pipeline step specification to concentrate any pipeline-related changes in the pipeline definition itself.

You can use MPLPipelineConfigMerge in the pipeline like this - the logic will put artifact key with value [version: 1] in the global configuration and you will be able to use `CFG.'artifact.version' in the following modules:

pipeline {
    ...
    steps {
        MPLPipelineConfigMerge(MPLModule('Some Module').artifact_info)
    }
    ...

Modules

MPL is mostly modules with logic. Basic features:

  • Simple groovy sandbox step files with all the pipeline features
  • Could be used in declarative & scripted pipelines
  • Override system with loop protection and simple nesting

In fact modules could be loaded from a number of places:

  • {ProjectRepo}/.jenkins/modules/{Stage}/{Name}{Stage}.groovy - custom modules for the project
  • {Library}/{SpecifiedModulesLoadPath}/modules/{Stage}/{Name}{Stage}.groovy - custom modules load path that added while init
  • {Library}/resources/com/griddynamics/devops/mpl/modules/{Stage}/{Name}{Stage}.groovy - library modules for everyone

If you will override module Build in your project repo, it will be used first. If you will try to require Build module from this overridden Build module - original library module will be used.

Check the usage examples & library modules to get some clue about the nesting system.

Creating / Overriding steps modules

If your project is special - you can override or provide aditional modules just for the project.

What do you need to do:

  1. Create a step file: {ProjectRepo}/.jenkins/modules/{Stage}/{Name}{Stage}.groovy (name could be empty)
  2. Fill the step with your required logic: you can use CFG config object & MPL functions inside the steps definition
  3. Use this step in your custom pipeline (or, if it's override, in standard pipeline) via MPLModule method.
  4. Provided custom modules will be available to use after the checkout of your project source only

For example: "Maven Build" steps have path modules/Build/MavenBuild.groovy and placed in the library - feel free to check it out.

Post Steps

MPL supports 2 useful poststep interfaces which allow you to store all the logic of module in the same file.

All the poststeps will be executed in LIFO order and all the exceptions will be collected & displayed in the logs.

MPLModulePostStep

Allow to set some actions that need to be executed right after the current module (doesn't matter it fails or not).

Could be useful when you need to collect reports or clean stage agent before it will be killed.

If module post step fails - it's fatal for the module, so the pipeline will fail (unlike general poststeps). All the poststeps for the module will be executed and errors will be printed, but module will fail.

  • {NestedLibModules}/Build/MavenBuild.groovy:
    MPLModulePostStep {
      junit 'target/junitReport/*.xml'
    }
    
    // Could fail but our poststep will be executed
    MPLModule('Maven Build', CFG)

MPLPostStep

General poststep interface usually used in the pipelines. Requires 2 calls - first one to define poststep in a module and second one to execute it and usually placed in the pipeline post actions.

When error occurs during poststeps execution - it will be printed in the log, but status of pipeline will not be affected.

  1. {NestedLibModules}/Deploy/OpenshiftDeploy.groovy:
MPLPostStep('always') {
  echo "OpenShift Deploy Decomission poststep"
}

echo 'Executing Openshift Deploy process'
  1. {NestedLib}/var/CustomPipeline.groovy:
def call(body) {
  // ...
  pipeline {
    // ...
    stages {
      // ...
      stage( 'Openshift Deploy' ) {
        steps {
          MPLModule()
        }
      }
      // ...
    }
    post {
      always {
        MPLPostStepsRun('always')
      }
      success {
        MPLPostStepsRun('success')
      }
      failure {
        MPLPostStepsRun('failure')
      }
    }
  }
}

Enforcing modules

To make sure that some of your stages will be executed for sure - you can add a list of modules that could be overrided on the project side. Just make sure, that you executing function MPLEnforce and provide list of modules that could be overriden in your pipeline script:

  • Jenkins job script:
    @Library('mpl') _
    
    // Only 'Build Maven' & 'Deploy' modules could be overriden on the project side
    MPLEnforce(['Build Maven', 'Deploy'])
    
    // ... Your enforced pipeline

Notices:

  • The function MPLEnforce could be executed only once, after that it will ignore any further executions.
  • This trick is really working only if you controlling the job pipeline scripts, with Jenkinsfile it's not so secure.

Nested libraries

MPL supporting the nested libraries to simplify work for a big teams which would like to use MPL but with some modifications.

Basically you just need to provide your vars interfaces and specify the mpl library to use it:

  • {NestedLib}/vars/MPLInit.groovy:
    def call() {
      // Using the latest release MPL and adding the custom path to find modules
      library('mpl')
      MPLModulesPath('com/yourcompany/mpl')
    }
  • {NestedLib}/vars/NestedPipeline.groovy:
    def call(body) {
      MPLInit() // Init the MPL library
      // ... Specifying the configs / pipelines and using modules etc.
    }

And after that and configuring the library for your jenkins (just put it after the mpl config) - you can use it in the project's Jenkinsfile (see examples).

Also you can override resources of the MPL library - but it's forever. You can't use MPL resource anymore if you will override it in the nested library.

You can cover the nested library with tests as well as MPL library - please check the nested library example on wiki page.

Release process

Jenkins shared libraries is just a repositories connected to the Jenkins Master instance. So you can use any branch/tag from the MPL or nested lib repo.

  • branch:18.04 - released version of the library. Can be used to pin the version.
  • branch:master - most fresh functions (and bugs) are here. You can use it for testing purposes.
  • branch:TICKET-1234 - feature branch, could be used for testing purposes.

Examples

Wiki page examples

Please check the wiki page to see some MPL examples: MPL Wiki

Standard Pipeline usage

If we fine with standard pipeline, but need to slightly modify options.

  • {ProjectRepo}/Jenkinsfile:
    @Library('mpl') _
    
    // Use default master pipeline
    MPLPipeline {
      // Pipeline configuration override here
      // Example: (check available options in the pipeline definition)
      agent_label = 'LS'                     // Set agent label
      modules.Build.tool_version = 'Maven 2' // Change tool for build stage
      modules.Test = null                    // Disable Test stage
    }

Use Standard Pipeline but with custom module

We fine with standard pipeline, but would like to use different deploy stage.

  • {ProjectRepo}/Jenkinsfile:
    @Library('mpl') _
    
    // Use default master pipeline
    MPLPipeline {}
  • {ProjectRepo}/.jenkins/modules/Deploy/Deploy.groovy:
    // Any step could be here, config modification, etc.
    echo "Let's begin the deployment process!"
    
    // Run original deployment from the library
    MPLModule('Deploy', CFG)
    
    echo "Deployment process completed!"

Custom Declarative Pipeline with mixed steps

  • {ProjectRepo}/Jenkinsfile:
    @Library('mpl') _
    
    pipeline {  // Declarative pipeline
      agent {
        label 'LS'
      }
      stages {
        stage( 'Build' ) {
          parallel {        // Parallel build for 2 subprojects
            stage( 'Build Project A' ) {
              steps {
                dir( 'subProjectA' ) {
                  MPLModule('Maven Build', [ // Using common Maven Build with specified configs
                    tool_version: 'Maven 2'
                  ])
                }
              }
            }
            stage( 'Build Project B' ) {
              steps {
                dir( 'subProjectB' ) {
                  // Custom build process (it's better to put it into the project custom module)
                  sh 'gradle build'
                  sh 'cp -a target my_data'
                }
              }
            }
          }
        }
      }
    }

Using nested library (based on MPL)

  • {ProjectRepo}/Jenkinsfile:
    @Library('nested-mpl') _
    
    NestedPipeline {
      // config here
    }

Contribution

Tests

We should be ensure that modules will not be broken accidentally, so tests is mandatory.

MPL supports MPLModule testing via slightly modified JenkinsPipelineUnit. You can find module tests (as well as modified base test classes & overridden requirements classes) in the test directory.

To run tests just execute mvn clean test - and it will compile the classes & execute tests for the modules.

Pipelines

MPL provided pipelines should be really simple, but could be improved with new best practices - so changes are always welcome.

Modules

If you have some interesting module - you for sure can prepare changes for existing module or a new module, write tests, create the pull-request, describe it - and after that this module could be approved to be included n the base library. If not - you always could use (or create) your own nested library to share this fancy module across your projects.

mpl's People

Contributors

kvmenshikov avatar sdkrach avatar sparshev avatar thetechoddbug avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mpl's Issues

mpl-nested example tests depend on mpl 1.0.0-SNAPSHOT

But I'm not sure in which repository to get the following dependency?

    <dependency>
        <groupId>com.griddynamics.devops</groupId>
        <artifactId>mpl</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <scope>test</scope>
    </dependency>

While we're on the topic of mpl-nested tests, the TODO section of mpl-nested.md still lists 'Tests using MPL testing framework', which gives the impression to somebody who clones the repository for the first time that the tests that are available when the repository is cloned are not up-to-date. But I guess they are and that line was simply left there when the tests were commited in 519fc6b3, right?

Helper miss method make job go fail

When I want to use Module's OUT to add param in CFG, like below,

        steps {
          MPLPipelineConfigMerge(MPLModule())
        }

jenkins's job go failure, the error message is attached below

groovy.lang.MissingMethodException: No signature of method: static com.griddynamics.devops.mpl.Helper.configEntrySet() is applicable for argument types: (java.util.LinkedHashMap) values: [[...]]]

I have view the source code, this error is caused by this line.
https://github.com/griddynamics/mpl/blame/master/src/com/griddynamics/devops/mpl/MPLConfig.groovy#L89
The missing method was remove on this #46 .
Because the method is missing, I have to uncomment the " Helper.configEntrySet(this.@config) ".
Finally, the job run well . But CFG seems no change after merging with OUT.
Can you have a look on this code?
And could you tell why CFG seems no change after merging with OUT?

Problems when trying out MPL

Hi, when trying out MPL I stumbled over two things. Don't know if these are bugs, it is more likely that I configured/used something wrong. Can you help please?

Setup: Jenkins test instance without any slave nodes, running with plugin 'Pipeline: Groovy 2.83' (contains org.jenkins-ci.plugins.workflow:workflow-cps:2.83 and com.cloudbees:groovy-cps:1.32). Using MPL branch master, commit 1ec0f57.

Problem 1: when running MPLPipeline with default configuration, the following exception occurs:

hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.join() is applicable for argument types: () values: []
Possible solutions: join(java.lang.String), min(), min(groovy.lang.Closure), min(java.util.Comparator), wait(), find()
	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:153)
	at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:161)
	at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:165)
	at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)
	at MPLModule.call(MPLModule.groovy:60)
	at MPLModule.call(MPLModule.groovy)
	at MPLPipeline.call(MPLPipeline.groovy:52)

Changing MPLModule.groovy@60 to def module_path = "modules/${base.last()}/${base.join(**''**)}.groovy" seems to fix it. But this seems strange to me. It looks like in Groovy there is no method with signature join(void) for lists. If this were true, how could the original line have ever worked? Did I miss something?

Problem 2: I fixed problem 1 with the modification above and run MPLPipeline with default configuration. There, the following exception occurs:

hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: org.jenkinsci.plugins.workflow.cps.CpsThread.getContextVariable() is applicable for argument types: (java.lang.Class, org.kohsuke.groovy.sandbox.impl.SandboxedMethodClosure, org.kohsuke.groovy.sandbox.impl.SandboxedMethodClosure) values: [class hudson.FilePath, org.kohsuke.groovy.sandbox.impl.SandboxedMethodClosure@523cd0e8, ...]
Possible solutions: getContextVariables()
	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:153)
	at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:161)
	at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:165)
	at org.kohsuke.groovy.sandbox.impl.Checker$checkedCall$3.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 com.griddynamics.devops.mpl.Helper.pathExists(Helper.groovy:148)
	at com.griddynamics.devops.mpl.Helper$pathExists$2.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 org.kohsuke.groovy.sandbox.impl.Checker$2.call(Checker.java:194)
	at org.kohsuke.groovy.sandbox.GroovyInterceptor.onStaticCall(GroovyInterceptor.java:35)
	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onStaticCall(SandboxInterceptor.java:186)
	at org.kohsuke.groovy.sandbox.impl.Checker$2.call(Checker.java:192)
	at org.kohsuke.groovy.sandbox.impl.Checker.checkedStaticCall(Checker.java:196)
	at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:103)
	at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)
	at MPLModule.call(MPLModule.groovy:66)
	at MPLModule.call(MPLModule.groovy)
	at MPLPipeline.call(MPLPipeline.groovy:52)

If this method is not found by Groovy runtime, then maybe I'm using the wrong cps plugin? However, I double checked: I'm using workflow-cps:2.83 and according to source code at github, getContextVariable with matching signature should be available. Can you give me advice what I'm missing?

Post-Module & Post-Stage execution

Right now MPL supports only post-pipeline execution steps, but seems it will be useful to introduce new mechanisms to have post-module & post-stage executions.

Example: to collect reports or artifacts before the stage-agent will be destroyed even if there is an error happened during module/stage execution.

Anyone else see benefits of such feature?

mergeMaps null overlay issue

Found that if I'm trying to provide pipeline configuration as a Map - I can't set modules.* to null to disable the required stage.

  • MPL Version: 18.06

  • Steps to reproduce:

    1. Create Jenkinsfile with the next content:
    MPLPipeline([
      modules: [
        Build: null
      ]
    ])
    
    1. Run the pipeline
  • Result:
    All the stages will be executed including Build stage

  • Expected result:
    Build stage should be skipped

Jenkins complains about CPS mismatch

We are currently evaluating this library as foundation for modularizing our Jenkins build pipelines. We defined a pipeline and stages similar to the MPLPipeline (https://github.com/MDSD-Tools/Build-JenkinsLibrary/tree/mdsdmodular). The pipeline itself works, the modules are called in the right order and the build succeeds for our migrated test project (https://github.com/MDSD-Tools/ThirdParty-Library/tree/modularPipeline).

Unfortunately, we see the following errors in the jenkins build log:
expected to call org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.evaluate but wound up catching Prepare.run; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/ (https://build.mdsd.tools/job/MDSD-Tools/job/ThirdParty-Library/job/modularPipeline/2/console) Prepare is a module of our pipeline (in fact a hierarchy of some modules), which is executed fine. Still, the error is logged for every module which is called by the pipeline or by other modules.

While the pipeline is working, we suspect Jenkins' CPS transformation is failing. We get the same log messages when running the pipeline of the MPL master branch. We configured Jenkins (LTS 2.176.1) to use the MPL library from your Github repository.

Is this a know bug? Are we maybe missing some Jenkins configuration? Are you aware of potential incompatibilities with recent Jenkins versions?

Ability to load pipeline input configuration from repo config file

Execution of the Jenkinsfile from the repository could expose credentials to end-user (for example create custom pipeline with using credentials in test stage and echo those creds as base64-encoded to build console).

Probably the only way to control the scripted pipeline with repo configuration - is to read config file (json, yaml or configslurper for some dynamics) from the repo without access to the pipeline steps.

It could look like this: Job with pipeline script:

@Library('mpl') _
MPLStrict {
  git = [url, creds, ...] // repo configs
  pipeline = 'pipeline_name' // pipeline to execute, if not set - get it from the repo config
}

In this step it will load the config file, parse it, and execute the required pipeline.

As result we need a common interface for that in MPL to allow to fortify the pipeline.

Pipeline fails on Jenkins restart

We have an input stage on lightweight worker which could be sitting very long until user input. So with job waiting for user input and after Jenkins restart if user confirms the input (press "Deploy") we get following error. If I moved out input from module to 'pipeline.groovy' it works, but I expect that some other long running stages might fail after Jenkins restart. It looks like after restart by some reason MPL loses track of activeModules.

We added some debug info so the lines number in stack trace are slightly different, error is happening in https://github.com/griddynamics/mpl/blob/master/vars/MPLModule.groovy#L100


# ./pipeline.groovy
def call(body) {
def MPL = MPLPipelineConfig(body, [modules: []])

pipeline {
    agent none
    stages {
      stage('init') {
        agent none
          steps {
            script { echo "init" }
        }
      }

      stage('user-input') {
        agent none
          steps {
               MPLModule("user-input")
              // If i move content from "user-input" module here everything works.
              //  input message: 'Deploy?', ok: 'Deploy'
          }
      }

      stage('something_else') {
        agent none
        steps {
          script {
            echo 'something_else'
          }
        }
      }
    }
  }
}

Jenkinsfile

@Library(['mpl-library']) _

pipeline {
  modules = [
  "user-input",
  ]
}

module

#user-input.groovy
 input message: 'Deploy?', ok: 'Deploy'

The error I got is :

java.util.NoSuchElementException: Cannot pop() an empty List
at org.codehaus.groovy.runtime.DefaultGroovyMethods.pop(DefaultGroovyMethods.java:8841)
at org.codehaus.groovy.runtime.dgm$483.doMethodInvoke(Unknown Source)
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 com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:20)
at com.griddynamics.devops.mpl.MPLManager.popActiveModule(MPLManager.groovy:247)
at MPLModule.call(MPLModule.groovy:104)
at MPLPipelineDeploy.call(MPLPipelineDeploy.groovy:285)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.delegateAndExecute(ModelInterpreter.groovy:138)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.executeSingleStage(ModelInterpreter.groovy:684)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.catchRequiredContextForNode(ModelInterpreter.groovy:418)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.catchRequiredContextForNode(ModelInterpreter.groovy:416)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.executeSingleStage(ModelInterpreter.groovy:682)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:281)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.toolsBlock(ModelInterpreter.groovy:567)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.toolsBlock(ModelInterpreter.groovy:566)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:271)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.withEnvBlock(ModelInterpreter.groovy:466)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.withEnvBlock(ModelInterpreter.groovy:465)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:270)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.withCredentialsBlock(ModelInterpreter.groovy:504)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.withCredentialsBlock(ModelInterpreter.groovy:503)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:269)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:316)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.inDeclarativeAgent(ModelInterpreter.groovy:612)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.inDeclarativeAgent(ModelInterpreter.groovy:611)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:313)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.stageInput(ModelInterpreter.groovy:379)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.stageInput(ModelInterpreter.groovy:378)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:312)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.inWrappers(ModelInterpreter.groovy:635)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.inWrappers(ModelInterpreter.groovy:634)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.evaluateStage(ModelInterpreter.groovy:252)
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.fixName(FunctionCallBlock.java:78)
at sun.reflect.GeneratedMethodAccessor462.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
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:185)
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)
Finished: FAILURE

Secondary run of the mvn without tests causes failure

Looks like generateTestStubs mojo makes impossible to just deploy the already built artifacts.
For example:

$ mvn clean install
...
[INFO] BUILD SUCCESS
$ mvn -DskipTests package
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ mpl ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 16 source files to /Users/tkmakyv/Work/git/mpl/target/classes
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[7,52] package com.lesfurets.jenkins.unit.global.lib does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[7,1] static import only from classes and interfaces
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[8,52] package com.lesfurets.jenkins.unit.global.lib does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[8,1] static import only from classes and interfaces
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[9,35] package org.assertj.core.api does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[9,1] static import only from classes and interfaces
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/com/griddynamics/devops/mpl/testing/MPLTestBase.java:[11,37] package com.lesfurets.jenkins.unit does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/com/griddynamics/devops/mpl/testing/MPLTestHelper.java:[11,37] package com.lesfurets.jenkins.unit does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/com/griddynamics/devops/mpl/testing/MPLTestHelper.java:[15,62] package com.lesfurets.jenkins.unit does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[16,33] package org.junit does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[17,11] package org.junit does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[18,11] package org.junit does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[19,11] package org.junit does not exist
[INFO] 13 errors
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.969 s
[INFO] Finished at: 2019-08-17T11:36:30-07:00
[INFO] Final Memory: 39M/385M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project mpl: Compilation failure: Compilation failure:
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[7,52] package com.lesfurets.jenkins.unit.global.lib does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[7,1] static import only from classes and interfaces
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[8,52] package com.lesfurets.jenkins.unit.global.lib does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[8,1] static import only from classes and interfaces
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[9,35] package org.assertj.core.api does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[9,1] static import only from classes and interfaces
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/com/griddynamics/devops/mpl/testing/MPLTestBase.java:[11,37] package com.lesfurets.jenkins.unit does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/com/griddynamics/devops/mpl/testing/MPLTestHelper.java:[11,37] package com.lesfurets.jenkins.unit does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/com/griddynamics/devops/mpl/testing/MPLTestHelper.java:[15,62] package com.lesfurets.jenkins.unit does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[16,33] package org.junit does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[17,11] package org.junit does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[18,11] package org.junit does not exist
[ERROR] /Users/tkmakyv/Work/git/mpl/target/generated-sources/groovy-stubs/test/BuildTest.java:[19,11] package org.junit does not exist
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
zsh: exit 1     mvn -B -DskipTests package

Second command fails, because stubs requires additional tests packages, that will not be used if skipTests is defined.

We actually don't need these test stubs - so it's better to remove them.

MplConfig singleton

Hi,

Why does every module create a new MplConfig instance instead of provides unique instance?

In some modules I need update config and reflecting on the next modules.

Tks

Defaults are lost in case you use them with closure.

Hello,
I'm trying to understand the purpose of 'defaults' in MplConfig, seems they are being overridden if I use closure in JenkinsFile:

MPLPipeline {
modules = [
     "schema": [:]
}

in MPLPipeline I call MPLPIpelineConfig as:

def MPL = MPLPipelineConfig(body, [
           modules [
             "schema": [some-aegs: "test"]
           ]
  ])

Expecting that eventually in MPLModule I'll get merged values of closures body from Jenkinsfile and defaults from MPLCPipelineConfig. But modules from Jenkinsfile always wins and no merging happens due to call body(), so modules just copied from Jenkinsfile. Meanwhile if I use Map in JenkinsFile it merged with defaults

Was it done intentionally and I'm missing something and/or MPLPipelineConfig supposed to be changed to meet my needs or it's just a bug? :)

[Question] How to pass my own configs to pipeline

Hi @sparshev ,

I'm new to Jenkins pipeline and Groovy. I am trying to create my own pipeline and therefore I have this question: can I somehow make my pipeline "inherit" from MPL, or how can I pass my own configs to my pipeline?

For example:
Jenkinsfile

@Library('my-pipeline-lib') _

MyPipeline {
    project = [
            name: 'infra-java-lib',
            major_version: '1.0.0'
    ]
    build = [
            builder: 'maven'
    ]
    deploy = [
            type: 'nexus'
    ]
    modules.Test = null
}

MyPipeline.groovy

def call(body) {
    // init MPL library
    MPLInit()

    // Execute the pipeline
    pipeline {
        agent {
            label Configuration.AGENT_LABEL
        }
        stages {
            stage('Build') {
                steps {
                    echo "====++++executing Build++++===="
                    script {
                        if (CFG.build.builder == 'maven') {    **// <---------------- How do I retrieve the configs I passed?**
                            docker.withRegistry(Configuration.CDC_REGISTRY, Configuration.DDEC_WRITE_CREDENTIAL) {
                                docker.image(Configuration.BUILDER_IMAGE_MAVEN).inside {
                                    MPLModule('Maven Build', CFG)
                                }
                            }
                        }
                    }
                }
            }
            stage('Deploy') {
                steps {
                    echo "====++++executing Deploy++++===="
                    script {
                        if (CFG.deploy.type == 'nexus') {
                            docker.withRegistry(Configuration.CDC_REGISTRY, Configuration.DDEC_WRITE_CREDENTIAL) {
                                docker.image(Configuration.BUILDER_IMAGE_MAVEN).inside {
                                    MPLModule('Nexus Deploy', CFG)
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

I know this looks dumb, but I've been stuck here for days trying to understand all this T_T. I also went through all the examples in mpl.wiki repo and found few that help. I really appreciate if you could explain it a little bit.

Thank you for your great work on MPL!

Tests: Script loading global vars overrides registerAllowedMethod

When the MPLModule or any other script loads - it can override the registerAllowedMethod with included vars steps Global Vars. This behavior don't allow to mock the custom steps we don't need to test.

Proposed way to fix: override function registerAllowedMethod(MethodSignature methodSignature, Closure closure) and check existence of such allowed method by isMethodAllowed before adding the data to allowedMethodCallbacks. This function is used by the internal helper setGlobalVars and with changes will not allow to override already set mocks.
Also it will be possible to override the allowed methods manually using registerAllowedMethod(String name, List<Class> args = [], Closure closure) helper method.

Nested library unit testing

MPL supports unit testing, but for the nested library it's hard because there is no examples of the pom file & classes. We need to create some and update MPL to support such feature.

Active modules list cannot be used as a stack in parallel builds

When running parallel builds there is a concern about how the active modules list is maintained. Currently, it is used as a stack in MPLModule.groovy

pushing as
try {
MPLManager.instance.pushActiveModule(module_path)
Helper.runModule(module_src, module_path, [CFG: Helper.flatten(cfg)])
}

poping as
finally {
.........
MPLManager.instance.popActiveModule()
}

when executing parallelly, the active module list is the same for all branches. so there might be instances where one branch will pop an active module that was pushed by another branch.
Therefore should we use active modules list as just a list instead of a stack? We just need to remove the module from the list by giving the module path as follow

in MPLManager.groovy change popActiveModule

public popActiveModule(String path) {
if(activeModules.contains(path)){
activeModules -= path
}
}

MPLManager.instance.<any api> is throwing null Pointer

Hi Sergei,

I checked out the mpl framework hosted in this repo.
However was not able to run below instructions.

@Library('mpl') _
MPLPipeline {}

Error:
java.lang.NullPointerException
at com.cloudbees.groovy.cps.impl.CpsCallableInvocation.invoke(CpsCallableInvocation.java:51)

It seems invoking @singleton Mgr class is throwing exception.

Env:
Using: Jenkins 2.176.2

Note: Similar issue reported in https://stackoverflow.com/questions/52609080/jenkins-scripted-pipeline-singleton-null-pointer-exception

Can you please suggest the fix.

Thanks and Regards,
Amitesh

Question - MPLPostStep fails

Below is the POST checkout step i modified , if this runs all i see is the below error

MPLPostStep('always') {
  echo "Checkout in Progress"
}

MPLModule('Default Checkout', CFG)

java.util.NoSuchElementException: Cannot access last() element from an empty List

i even added some displays this is what i see , body comes in null is that expected ?

inside Post Step : always
[Pipeline] echo
Checkout in Progress
[Pipeline] echo (hide)
body : null

Demo video links in wiki broken?

When browsing the MPL wiki, the links at main page, section 'Overview and Demo Videos', seem to be broken. Youtube displays error message "video unavailable - uploader closed account". Are there any alternative locations to view these videos?

Virtual modules

Could be useful to simple test new modules functional, debugging or easy way to kickstart with the MPL.

// Defining virtual module
MPLVirtualModule('Build') {
  // Closure with all the features of usual module
  echo "Hihi, I'm the virtual module"
  MPLModule('Build', CFG) // Executing upper level Build module
}

pipeline {
  ...
  stages {
    stage( 'Build' ) {
      MPLModule() // will execute virtual module first
    }
    ...
  }
}

MPL config passthrough

Description

MPL stage modules right now is independent - that means no possible interaction between not-connected modules (parent can pass CFG to child, but child can't respond and pipeline-level modules can't interact with each other).

So there should be a good way to allow such interaction without messing configs around.

Solutions

GLOBAL Map

Looks like messy solution that will allow cross-pipeline store for configuration values.
For example:

  • MPLModule Build:
    // Build module 
    sh "mvn clean package"
    GLOBAL.arifacts.app = 'target/app-1.0.0-SNAPSHOT.jar'
  • MPLModule Deploy:
    // Deploy module
    sh "scp '${GLOBAL.artifacts.app}' user@host:/artifacts/app.jar"

Like that. Seems not very good - but maybe could be handy for simple tasks. Modules will use GLOBAL as common storage of some cross-pipeline values and other modules could use their defined values.

IN & OUT Maps

Modules stores their internal values as usual, but if need to out something - they could store it in OUT storage. Other modules will see this data as IN values. Only OUT values could be modified to save data from the module, IN changes will be ignored:

  • MPLModule Build:
    // Build module 
    sh "mvn clean package"
    OUT.arifacts.app = 'target/app-1.0.0-SNAPSHOT.jar'
  • MPLModule Deploy:
    // Deploy module
    sh "scp '${IN.Build.artifacts.app}' user@host:/artifacts/app.jar"

It could be easy to understand what is required for input and what will be produced for output.
Module after execution could return OUT as result - so the parents could use it as their's results.

Need to think about what to store in IN - any module output or just top modules output...

Return OUT config

So we already have CFG config (acting as input) - probably that could be useful to add such output OUT interface:

  • Pipeline:
    def build_out
    pipeline {
      ...
      stage( 'Build' ) {
        steps {
          MPLModule('Checkout')
          MPLPipelineConfigMerge(MPLModule('Build'))
        }
      }
      stage( 'Deploy' ) {
        steps {
          MPLModule()
        }
      }
      ...
    
  • MPLModule Build:
    // Build module
    
    OUT.'artifact.version' = MPLModule('MavenBuild').'maven.version'
  • MPLModule MavenBuild:
    // MavenBuild module
    OUT.'maven.version' = readMavenPom().getVersion().replace('-SNAPSHOT', "-${BUILD_DATETIME}-${currentBuild.number}")
    ...
  • MPLModule Deploy:
    echo "${CFG.'artifact.version'}"

Here we modifying the global MPL pipeline config with the Build module output ('artifact.version') that was set from the MavenBuild module 'maven.version' return. So the modules and user could control what to use and we have no issues with a hidden logic of modifying the global scope.

I think this one is slightly more complicated than a global scope but will help us to standardize and define the modules interfaces (input and output). With a huge pipelines that will be easier to understand the execution logic and why the variable have not the expected value.

Suggestion for configuration

This is another approach to enhance the config (similar to #10).

I would suggest a "default config" object which contains all possible config keys and defaults.

Modules must have a method to add to this default config. Adding the same "path" twice is an error but it should be possible to check for an existing path (so two modules can cooperate and still be optional).

This way, modules don't need code like

CFG.'maven.tool_version' ?: 'Maven 3'

because 'Maven 3' will be the default value. Reading unknown keys should throw an exception (-> typo in library)

The step which parses the project's config options from the should throw exceptions for unknown keys/paths to catch typos.

After merging the project and default config, the result should be logged in Jenkins to allow to find mistakes.

I'm also not fond of the CFG.'xxx.yyy' syntax. With the default config as path supplier, it should be possible to implement a nested config using nested Maps which would then allow to pass inner maps around so the code would become independent of the path.

In my builds, I'm calling Maven several times (build with unit tests, site, deploy without tests). Using nested configs, I can create a shared Maven config (default JDK & Maven tool) but I can also tweak the options passed to each individual Maven invocation like additional profiles to activate or system properties. As an example, I can:

        config {
            build {
                addAfter 'install', 'foo'
            }
        }

to get mvn [...] clean install foo sonar:sonar as command line or I can

        config {
            maven {
                property('foo', params['foo'])
            }
        }

to add -Dfoo=[...] to every Maven invocation.

My current code depends on a hand-written config builder class for each nested config object. That way, I can support things like addAfter(). I'm looking into ways to change this so modules can easily define their default config.

Overriding Modules in MPL

@sparshev How can we override few options in MPL, let's say in the build stage (Build module) we have the command ./gradlew clean build it won't be always clean build for gradle right?
If we want to give the flexibility to the users like in the Build stage or test stage they can sometimes run their own commands. Also they can specify the system parameters during the builds, like the environment profiles, etc.

There's a snippet which I found

@Library('mpl@release') _

// Use default master pipeline
MPLPipeline {
  // Pipeline configuration override here
  // Example: (check available options in the pipeline definition)
  agent_label = 'LS'                     // Set agent label
  modules.Build.tool_version = 'Maven 2' // Change tool for build stage
  modules.Test = null                    // Disable Test stage
}

Here we are overriding the tool version right
Similarly to override the shell commands
Please let me know, ANy help is appreciated

Add new Stage in nested library

Hello!! First of all... I love this project! I am migrating every pipeline of our organization. I've been looking for this kind of modular/composable/awesome Jenkins Shared library organization for a long time. Congratz!!

My problem is that I am trying to create a new pipeline in a nested library with a new stage like this.


stage('StaticCodeAnalysis') {
    when { expression { MPLModuleEnabled() } }
    steps {
        MPLModule()
    }
}

I am getting the following log message in Jenkins Stage "StaticCodeAnalysis" skipped due to when conditional

How can I "register" a new stage? I don't get how MPLModuleEnabled works.

Thans in advance!

Unable to run MPLModule with agent none

When agent is not set, fileExists() step couldn't be used anyhow and raising exception that prevents further execution. Probably it will be good to create own fileExists that will not print anything to the console and will not be executed without an agent.

Can we have a top-level getter for cron similar to agent_label?

In our setup, some pipelines require a custom cron:

triggers {
  cron('@weekly')
}

We already have a setup in which no cron is defined by default, and some project pipelines can override that. However, I would like to replicate this with MPL, because MPL brings a lot more flexibility than the templates we are currently working with.

Do I get this right that because that property is top-level such as agent_label, then a getter would be needed in MPLManager? What are you thoughts on adding it?

Jenkins Plugin

Have you ever thought about converting mpl into a Jenkins plugin?

FlowInterruptedException should not be wrapped

Currently, all exceptions which occur during module execution are wrapped inside a MPLModuleException. Unfortunately, this also occurs for org.jenkinsci.plugins.workflow.steps.FlowInterruptedException which is used by Jenkins to abort a running build (e. g. manually aborted by the user or timeouts). Since the exception which is caught in the end by Jenkins is of a different type as expected, Jenkins interprets it as a build failure.

An excerpt of a current log file with an timeout occuring during build:

[Pipeline] End of Pipeline
com.griddynamics.devops.mpl.MPLModuleException: Found error during execution of the module 'library:MDSD.tools Lib/resources/tools/mdsd/devops/pipeline/stages/impl/constraintBuild/modules/Build/Build.groovy':
org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
Finished: FAILURE

when the exception is not wrapped the log looks like:

[Pipeline] End of Pipeline
Timeout has been exceeded
Finished: ABORTED`

Passing pipeline CFG as env variable in build environment

Is there any way to export the pipeline config defined by MPL to environment variable?

I have use case to enable/disable some auxilary service (like database, redis, kafka, etc) if we want to build apps that need them in testing phase. I want the apps to be able to parse the setting from env var and connect to the right port/db/whatever.

For now, I manually define the env var for each of the config. Something like this:

void injectIntegrationSettingToEnv(Map config) {
    env.'test_integration_postgresql_enabled' = config.test.integration.postgresql.enabled
    env.'test_integration_postgresql_username' = config.test.integration.postgresql.username
    env.'test_integration_postgresql_password' = config.test.integration.postgresql.password
    env.'test_integration_postgresql_database' = config.test.integration.postgresql.database
    env.'test_integration_postgresql_port' = config.test.integration.postgresql.port
    env.'test_integration_postgresql_host' = config.test.integration.postgresql.host
}

Handy configuration

Description

Current flatten configuration is not so clear:

  • Requires to put sublevels into quotes:
    if( CFG.'some.key.sublevel' ) {
      echo 'Sublevel value exising'
    }
  • Disallow to store Maps as usual:
    assert 'sublevel' not in CFG.'some.key' // some.key is not defined
  • Looks not great...

So I think there could be a way to handle this bad things and make configuration more durable.

Map with default

def getMapDefault() {
  [:].withDefault {
    getMapWithDefault()
  }
}

config = getMapDefault()

// Now it's possible to get infinity level of the submaps
config.some.key.sublevel = 3
println "${config}" // [some:[key:[sublevel:3]]]

But it has at least one issue:

  • Any undefined value will be equal [:] - and it's true for any Map stored in the config. So there is no more null values by default.

MPLConfig object

Specially prepared class that stores the pipeline configuration and handling improper gets - it should determine how much levels we need and only for the last one return null by default... Probably could be handled by groovy, but who know...

jenkins ruby-runtime plugin

hi,

after upgrade openshift platform in 3.11.153 version, i want to upgrade my jenkins project.
i built my new custom image of jenkins-2-rhel7 in 3.11.153 version like i did in 3.9.60.
in 3.9.60, plugin ruby-runtime works fine.
here, when i tried to start my docker image by a docker run i received these errors :

SEVERE: Failed Inspecting plugin /var/lib/jenkins/plugins/ruby-runtime.jpiSEVERE: Failed Inspecting plugin /var/lib/jenkins/plugins/ruby-runtime.jpijava.io.IOException: Failed to expand /var/lib/jenkins/plugins/ruby-runtime.jpi at hudson.ClassicPluginStrategy.explode(ClassicPluginStrategy.java:478) at hudson.ClassicPluginStrategy.createPluginWrapper(ClassicPluginStrategy.java:174) at hudson.PluginManager$1$3$1.run(PluginManager.java:431) at org.jvnet.hudson.reactor.TaskGraphBuilder$TaskImpl.run(TaskGraphBuilder.java:169) at org.jvnet.hudson.reactor.Reactor.runTask(Reactor.java:296) at jenkins.model.Jenkins$5.runTask(Jenkins.java:1095) at org.jvnet.hudson.reactor.Reactor$2.run(Reactor.java:214) at org.jvnet.hudson.reactor.Reactor$Node.run(Reactor.java:117) 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)Caused by: Error while expanding /var/lib/jenkins/plugins/ruby-runtime.jpijava.util.zip.ZipException: archive is not a ZIP archive at org.apache.tools.ant.taskdefs.Expand.expandFile(Expand.java:190) at org.apache.tools.ant.taskdefs.Expand.execute(Expand.java:132) at hudson.ClassicPluginStrategy.unzipExceptClasses(ClassicPluginStrategy.java:550) at hudson.ClassicPluginStrategy.explode(ClassicPluginStrategy.java:475) ... 10 moreCaused by: java.util.zip.ZipException: archive is not a ZIP archive at org.apache.tools.zip.ZipFile.positionAtEndOfCentralDirectoryRecord(ZipFile.java:771) at org.apache.tools.zip.ZipFile.positionAtCentralDirectory(ZipFile.java:707) at org.apache.tools.zip.ZipFile.populateFromCentralDirectory(ZipFile.java:452) at org.apache.tools.zip.ZipFile.(ZipFile.java:214) at org.apache.tools.ant.taskdefs.Expand.expandFile(Expand.java:168) ... 13 more

i tried so to start the image directly in openshift and the error is the same.

in openshift, i set these environment variables :

JENKINS_JAVA_OVERRIDES ==> -Dhudson.model.UpdateCenter.never=true -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85

i saw in several post or report issues that i can add this variable : -Dhudson.ClassicPluginStrategy.noBytecodeTransformer=true

for me it not solved my problem.
someone can help me ?

thanks a lot
ludo

java.lang.NullPointerException while building

description: i am getting null pointer exception while i am trying to tried to run the MPL-build example

issue seems pretty much similar to #35

the jenkins dependencies we are using
Jenkins 2.212
workflow-cps 2.44 2.78
workflow-job 2.36
workflow-cps-global-lib 2.15

this is the error we are getting

java.lang.NullPointerException
at com.cloudbees.groovy.cps.impl.CpsCallableInvocation.invoke(CpsCallableInvocation.java:57)
at com.cloudbees.groovy.cps.impl.PropertyishBlock$ContinuationImpl.get(PropertyishBlock.java:79)
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.GeneratedMethodAccessor382.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
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:185)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:405)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$400(CpsThreadGroup.java:96)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:317)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:281)
at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:67)
at java.util.concurrent.FutureTask.run(Unknown Source)
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(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Can you suggest the changes or fixes?

Issue with module from project

When i use module from project repo i get error

hudson.remoting.ProxyException: com.griddynamics.devops.mpl.MPLModuleException: Found error during execution of the module '.jenkins/modules/Build/Build.groovy#null':
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
.jenkins/modules/Build/Build.groovy: 1: unexpected token: @ @ line 1, column 30.
   sun.nio.ch.ChannelInputStream@4886b758
                                ^

1 error

	at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
	at org.codehaus.groovy.control.ErrorCollector.addFatalError(ErrorCollector.java:150)
	at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:120)
	at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:132)
	at org.codehaus.groovy.control.SourceUnit.addError(SourceUnit.java:350)
	at org.codehaus.groovy.antlr.AntlrParserPlugin.transformCSTIntoAST(AntlrParserPlugin.java:144)
	at org.codehaus.groovy.antlr.AntlrParserPlugin.parseCST(AntlrParserPlugin.java:110)
	at org.codehaus.groovy.control.SourceUnit.parse(SourceUnit.java:234)
	at org.codehaus.groovy.control.CompilationUnit$1.call(CompilationUnit.java:168)
	at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:943)
	at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:605)
	at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:581)
	at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:558)
	at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
	at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
	at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
	at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
	at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.doParse(CpsGroovyShell.java:142)
	at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.parse(CpsGroovyShell.java:113)
	at groovy.lang.GroovyShell.evaluate(GroovyShell.java:584)
	at groovy.lang.GroovyShell.evaluate(GroovyShell.java:623)
	at groovy.lang.GroovyShell.evaluate(GroovyShell.java:604)
	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:498)
	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
	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.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 com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:20)
	at com.griddynamics.devops.mpl.Helper.runModule(Helper.groovy:245)
	at MPLModule.call(MPLModule.groovy:86)
	at MPLModule.call(MPLModule.groovy)
	at WorkflowScript.run(WorkflowScript:13)

Module contain simple step like
echo "good job"

In library modules work fine

Jenkins = 2.223
workflow-cps = 2.80
workflow-job = 2.37
workflow-cps-global-lib = 2.16

Pipeline fails after latest changes

hudson.remoting.ProxyException: com.griddynamics.devops.mpl.MPLModuleException: Found error during execution of the module 'library:jenkins-mpl-library/resources/com/griddynamics/devops/mpl/modules/Build/Build.groovy#null':
com.griddynamics.devops.mpl.MPLModuleException: Found error during execution of the module 'library:jenkins-mpl-library/resources/com/griddynamics/devops/mpl/modules/Build/MavenBuild.groovy#null':
hudson.AbortException: No tool named Maven 3 found
	at org.jenkinsci.plugins.workflow.steps.ToolStep$Execution.run(ToolStep.java:162)
	at org.jenkinsci.plugins.workflow.steps.ToolStep$Execution.run(ToolStep.java:133)
	at org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution.lambda$start$0(SynchronousNonBlockingStepExecution.java:47)
	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)

My Jenkinsfile

def call(body) {
    MPLModulesPath('org/jenkins/pipeline/modules')
    ...
}

Generate reference documentation for modules and steps

Probably will be a good addition to the library a way to automatically generate/validate documentation (and module headers) out of used CFG / OUT variables. Need to check a way to do that automatically by using some existing (groovydoc?) framework.

Reporter: @Napo2k

Prepare automation to test the MPL

We need to make sure MPL is working over LTS & latest jenkins releases. I think CircleCI will be perfect together with jenkinsBro framework to configure jenkins & execute automatic tests.

  • Regular simple maven build
  • Running the jenkins instance with LTS version and execute mpl build pipeline using MPL
  • CI should be executed on each pull request change
  • CI executed on each master branch change
  • Bage, that showing the status
  • Nightly jenkins tests over latest/LTS jenkins

[BUG] Found error during execution the MPLPipeline on the latest jenkins

CI found the next error https://app.circleci.com/pipelines/github/griddynamics/mpl/75/workflows/93aabf7f-936a-4c72-aa58-4e38db286ebb/jobs/566 :

--&gt; setting agent port for jnlp
--&gt; setting agent port for jnlp... done
Started
Checking out git https://github.com/griddynamics/mpl.git into /var/jenkins_home/workspace/mpl-build@script to read Jenkinsfile
No credentials specified
Cloning the remote Git repository
Cloning repository https://github.com/griddynamics/mpl.git
 &gt; git init /var/jenkins_home/workspace/mpl-build@script # timeout=10
Fetching upstream changes from https://github.com/griddynamics/mpl.git
 &gt; git --version # timeout=10
 &gt; git fetch --tags --force --progress -- https://github.com/griddynamics/mpl.git +refs/heads/*:refs/remotes/origin/* # timeout=10
 &gt; git config remote.origin.url https://github.com/griddynamics/mpl.git # timeout=10
 &gt; git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
 &gt; git config remote.origin.url https://github.com/griddynamics/mpl.git # timeout=10
Fetching upstream changes from https://github.com/griddynamics/mpl.git
 &gt; git fetch --tags --force --progress -- https://github.com/griddynamics/mpl.git +refs/heads/*:refs/remotes/origin/* # timeout=10
 &gt; git rev-parse 4ca95b9d157c39ebaea063691bb247d390846aff^{commit} # timeout=10
Checking out Revision 4ca95b9d157c39ebaea063691bb247d390846aff (detached)
 &gt; git config core.sparsecheckout # timeout=10
 &gt; git checkout -f 4ca95b9d157c39ebaea063691bb247d390846aff # timeout=10
Commit message: "MPL-59 Fix for local project modules"
First time build. Skipping changelog.
Running in Durability level: MAX_SURVIVABILITY
Loading library mpl@4ca95b9d157c39ebaea063691bb247d390846aff
Attempting to resolve 4ca95b9d157c39ebaea063691bb247d390846aff from remote references...
 &gt; git --version # timeout=10
 &gt; git ls-remote -h -- https://github.com/griddynamics/mpl.git # timeout=10
Found match: refs/heads/master revision 4ca95b9d157c39ebaea063691bb247d390846aff
No credentials specified
Cloning the remote Git repository
Cloning with configured refspecs honoured and without tags
Cloning repository https://github.com/griddynamics/mpl.git
 &gt; git init /var/jenkins_home/workspace/mpl-build@libs/mpl # timeout=10
Fetching upstream changes from https://github.com/griddynamics/mpl.git
 &gt; git --version # timeout=10
 &gt; git fetch --no-tags --force --progress -- https://github.com/griddynamics/mpl.git +refs/heads/*:refs/remotes/origin/* # timeout=10
 &gt; git config remote.origin.url https://github.com/griddynamics/mpl.git # timeout=10
 &gt; git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
 &gt; git config remote.origin.url https://github.com/griddynamics/mpl.git # timeout=10
Fetching without tags
Fetching upstream changes from https://github.com/griddynamics/mpl.git
 &gt; git fetch --no-tags --force --progress -- https://github.com/griddynamics/mpl.git +refs/heads/*:refs/remotes/origin/* # timeout=10
Checking out Revision 4ca95b9d157c39ebaea063691bb247d390846aff (master)
 &gt; git config core.sparsecheckout # timeout=10
 &gt; git checkout -f 4ca95b9d157c39ebaea063691bb247d390846aff # timeout=10
Commit message: "MPL-59 Fix for local project modules"
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/mpl-build
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Checkout)
[Pipeline] { (MPL: Checkout/Checkout)
[Pipeline] { (MPL: Checkout/DefaultCheckout)
[Pipeline] checkout
No credentials specified
Cloning the remote Git repository
Cloning repository https://github.com/griddynamics/mpl.git
 &gt; git init /var/jenkins_home/workspace/mpl-build # timeout=10
Fetching upstream changes from https://github.com/griddynamics/mpl.git
 &gt; git --version # timeout=10
 &gt; git fetch --tags --force --progress -- https://github.com/griddynamics/mpl.git +refs/heads/*:refs/remotes/origin/* # timeout=10
 &gt; git config remote.origin.url https://github.com/griddynamics/mpl.git # timeout=10
 &gt; git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
 &gt; git config remote.origin.url https://github.com/griddynamics/mpl.git # timeout=10
Fetching upstream changes from https://github.com/griddynamics/mpl.git
 &gt; git fetch --tags --force --progress -- https://github.com/griddynamics/mpl.git +refs/heads/*:refs/remotes/origin/* # timeout=10
 &gt; git rev-parse 4ca95b9d157c39ebaea063691bb247d390846aff^{commit} # timeout=10
Checking out Revision 4ca95b9d157c39ebaea063691bb247d390846aff (detached)
 &gt; git config core.sparsecheckout # timeout=10
 &gt; git checkout -f 4ca95b9d157c39ebaea063691bb247d390846aff # timeout=10
Commit message: "MPL-59 Fix for local project modules"
[Pipeline] }
[Pipeline] }
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] { (MPL: Build/Build)
[Pipeline] { (MPL: Build/MavenBuild)
[Pipeline] tool
Invalid tool ID 3.6.1
[Pipeline] withEnv
[Pipeline] {
[Pipeline] sh
+ mvn -B '-DargLine=-Xmx1024m -XX:MaxPermSize=1024m' clean install
/var/jenkins_home/workspace/mpl-build@tmp/durable-5e268131/script.sh: line 1: mvn: not found
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] }
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Deploy)
Stage "Deploy" skipped due to earlier failure(s)
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Test)
Stage "Test" skipped due to earlier failure(s)
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Declarative: Post Actions)
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
hudson.remoting.ProxyException: com.griddynamics.devops.mpl.MPLModuleException: Found error during execution of the module 'library:mpl/resources/com/griddynamics/devops/mpl/modules/Build/Build.groovy#null':
com.griddynamics.devops.mpl.MPLModuleException: Found error during execution of the module 'library:mpl/resources/com/griddynamics/devops/mpl/modules/Build/MavenBuild.groovy#null':
hudson.AbortException: script returned exit code 127
	at org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep$Execution.handleExit(DurableTaskStep.java:658)
	at org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep$Execution.check(DurableTaskStep.java:604)
	at org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep$Execution.run(DurableTaskStep.java:548)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
	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)
Finished: FAILURE
Error found: testJenkinsfileBuild(MPLPipelineTest): Assertion failed: 

assert build.getResult().toString() == 'SUCCESS'
       |     |           |          |
       |     FAILURE     FAILURE    false
       mpl-build #1

Most probably it's some change in the jenkins, that break backward compatibility for tool system.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.