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

Cannot use function calls in shared library step

      When trying to implement a declarative pipeline inside of a shared library step, I'm finding that this only works if the pipeline is defined inside the "call" method.  As soon as I add a function call, I start seeing exceptions.

       

      Working code:

      def call() {
        pipeline {
          agent any
      
          stages {
            stage("Stage") {
              steps {
                echo "hi"
              }
            }
          }
        }
      } 

       

      Non-working code:

      def call() {
        execute()
      }
      
      def execute() {
        pipeline {
          agent any
      
          stages {
            stage("Stage") {
              steps {
                echo "hi"
              }
            }
          }
        }
      } 

       

      Error message:

      hudson.remoting.ProxyException: groovy.lang.MissingPropertyException: No such property: any for class

       

      For reasons beyond this post, we are trying to add some commonality and argument checking to our steps, which is why I'd like to be able to use that concept of the extra function call...

       

          [JENKINS-63290] Cannot use function calls in shared library step

          jglick - any thoughts?  I feel like you, and several others, would know this answer.  Perhaps this didn't get in front of the right eyes...

          Christopher Shannon added a comment - jglick - any thoughts?  I feel like you, and several others, would know this answer.  Perhaps this didn't get in front of the right eyes...

          Jesse Glick added a comment -

          I am afraid this is something specific to Declarative Pipeline which I know little about.

          Jesse Glick added a comment - I am afraid this is something specific to Declarative Pipeline which I know little about.

          Thanks for the quick response.  If there is someone who would make sense to tag, let me know.

          Christopher Shannon added a comment - Thanks for the quick response.  If there is someone who would make sense to tag, let me know.

          dnusbaum - any thoughts?  I think that this is might be an easy explanation from someone who knows the inner workings of declarative pipelines.  Otherwise I'm just stumped...

          Christopher Shannon added a comment - dnusbaum - any thoughts?  I think that this is might be an easy explanation from someone who knows the inner workings of declarative pipelines.  Otherwise I'm just stumped...

          Devin Nusbaum added a comment -

          I am not really familiar with how exactly Declarative is usable from shared libraries either. From a quick look at jenkinsci/pipeline-model-definition-plugin#193, which is the PR associated with JENKINS-46547, I see the following, which makes me think the current behavior may be intentional (see also this comment and its reply in the PR):

          This adds support for loading pipeline { ... } blocks from shared libraries. A call() method in a shared library "step" will now be able to include one or more pipeline { ... } blocks, though only one should be executed.

          Devin Nusbaum added a comment - I am not really familiar with how exactly Declarative is usable from shared libraries either. From a quick look at jenkinsci/pipeline-model-definition-plugin#193 , which is the PR associated with  JENKINS-46547 , I see the following, which makes me think the current behavior may be intentional (see also this comment and its reply in the PR): This adds support for loading pipeline { ... } blocks from shared libraries. A call() method in a shared library "step" will now be able to include one or more pipeline { ... } blocks, though only one should be executed.

          dnusbaum - that was extremely helpful - thank you!

          I now see that by design, only methods named call will be parsed for declarative pipelines.  Also, and where perhaps this is a small bug, only the first instance of call will be checked.

          Knowing all of this, here is a simplified view of where I think a bug exists, and where this section of code could be wrapped in a while loop to go through all call methods.  The use case is to support two methods of calling the same shared step: one with a Map, and one with no arguments (where default values would be used instead).

           

          Fails:

          def call() {
              call([])
          }
          
          def call(Map map) {
              pipeline {
                  ...
              }
          }

           

          Works:

          def call(Map map) {
              pipeline {
                  ...
              }
          }
          
          def call() {
              call([])
          }

           

          abayer - since you implemented this code, what do you think?

          Christopher Shannon added a comment - dnusbaum - that was extremely helpful - thank you! I now see that by design, only methods named call  will be parsed for declarative pipelines.  Also, and where perhaps this is a small bug, only the first instance of call  will be checked. Knowing all of this, here is a simplified view of where I think a bug exists, and where this section of code could be wrapped in a while loop to go through all call  methods.  The use case is to support two methods of calling the same shared step: one with a Map, and one with no arguments (where default values would be used instead).   Fails: def call() { call([]) } def call(Map map) { pipeline { ... } }   Works: def call(Map map) { pipeline { ... } } def call() { call([]) }   abayer - since you implemented this code, what do you think?

            Unassigned Unassigned
            w60001 Christopher Shannon
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: