-
New Feature
-
Resolution: Duplicate
-
Minor
-
None
-
Jenkins core 2.16, latest pipeline plugins
It seems right now that there are 3 ways to share pipeline code:
- Writing a plugin
- Creating a global "master" library using the Pipeline Global Library plugin
- load ing a Groovy script
As a pipeline writer, I'd like to be able to load or "import" additional classes that allow me to modularize my Jenkinsfile into separate packages and classes that I have control and ownership of.
Current issues
Based on my experience, these are some of the issues we have ran into:
With load step
- load ed scripts cannot contain class , enum, or other types
- every script must return this, which can be easy to forget and sometimes hard to debug, especially newcomers
- difficult to test
Attempting to create a "DSL" with load ed script
One way I tried, was to have a load ed script have a method that would return a Map<String, Closure> as a workaround. Something along these lines:
Jenkinsfile
#!groovy properties([ [ $class: 'BuildDiscarderProperty', strategy: [ '$class': 'LogRotator', numToKeepStr: '20' ] ] ]) node { checkout scm final myScript = load 'myScript.groovy' final mike = myScript.withName('Mike') mike.sayHi() mike.sayHello() }
myScript.groovy
Map<String, Closure> withName(String name) { Closure sayHi = { -> say('Hi', name) } Closure sayHello = { -> say('Hello', name) } return [ sayHi: sayHi, sayHello: sayHello, ] } void say(String phrase, String name) { echo "$phrase, $name" } return this
When this is attempted to run, I kind of expected a script whitelist issue, but this exception was a little different than I expected:
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified method java.util.LinkedHashMap sayHi at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:113) at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:149) at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:146) at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:15) at WorkflowScript.run(WorkflowScript:19) at ___cps.transform___(Native Method) at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:55) at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:106) at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixName(FunctionCallBlock.java:74) at sun.reflect.GeneratedMethodAccessor712.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:58) at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:154) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:18) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:32) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable$1.call(SandboxContinuable.java:29) at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108) at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:29) at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:164) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:360) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$100(CpsThreadGroup.java:80) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:236) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:226) at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:47) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:112) at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28) 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:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)
With Global CPS
- requires committing and pushing a git repository to Jenkins
- can only have 1 "set" of global libraries which lends itself to the "Jenkins master"s being the controllers of the globally shared libraries
- consumers can't control the global dependency "version". must be version pushed to Jenkins
- difficult to test
Proposal
Provide an import-type step allows pipeline authors to write classes in a similar manner to the Pipeline Global Library plugin but can be easily loaded on the classpath.
- duplicates
-
JENKINS-31155 Workflow shared library improvements
- Closed