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

Cannot use function calls in shared library step

    XMLWordPrintable

    Details

    • Similar Issues:

      Description

      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...

       

        Attachments

          Issue Links

            Activity

            Hide
            w60001 Christopher Shannon added a comment -

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

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

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

            Show
            jglick Jesse Glick added a comment - I am afraid this is something specific to Declarative Pipeline which I know little about.
            Hide
            w60001 Christopher Shannon added a comment -

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

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

            Devin Nusbaum - 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...

            Show
            w60001 Christopher Shannon added a comment - Devin Nusbaum - 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...
            Hide
            dnusbaum 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.

            Show
            dnusbaum 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.
            Hide
            w60001 Christopher Shannon added a comment -

            Devin Nusbaum - 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([])
            }

             

            Andrew Bayer - since you implemented this code, what do you think?

            Show
            w60001 Christopher Shannon added a comment - Devin Nusbaum - 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([]) }   Andrew Bayer - since you implemented this code, what do you think?

              People

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

                Dates

                Created:
                Updated: