Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-37270

Provide more object oriented 'load'-step esque functionality

    XMLWordPrintable

    Details

    • Type: New Feature
    • Status: Resolved (View Workflow)
    • Priority: Minor
    • Resolution: Duplicate
    • Component/s: pipeline
    • Labels:
      None
    • Environment:
      Jenkins core 2.16, latest pipeline plugins
    • Similar Issues:

      Description

      It seems right now that there are 3 ways to share pipeline code:

      1. Writing a plugin
      2. Creating a global "master" library using the Pipeline Global Library plugin
      3. 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.

        Attachments

          Issue Links

            Activity

            Hide
            mkobit Mike Kobit added a comment -

            It looks like the new global workflow support makes this a lot simpler to reason about.

            The test support still isn't available, but I think that the underlying implicit requirements here have been satisfied, so I think this can be closed.

            Show
            mkobit Mike Kobit added a comment - It looks like the new global workflow support makes this a lot simpler to reason about. The test support still isn't available, but I think that the underlying implicit requirements here have been satisfied, so I think this can be closed.

              People

              Assignee:
              jglick Jesse Glick
              Reporter:
              mkobit Mike Kobit
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: