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

Mishandling of binary methods accepting Closure

    XMLWordPrintable

Details

    Description

      At least some closures are executed only once inside of Groovy CPS DSL scripts managed by the workflow plugin.

      Steps to reproduce:
      1. Create a new workflow with the following script:
      node {
      [1, 2, 3].each

      { println it }

      println "abc".replaceAll(/[a-z]/)

      { it.toUpperCase() }

      }
      2. Build the workflow

      Actual output:
      Started by user anonymous
      Running: Allocate node : Start
      Running on master in /var/lib/jenkins/jobs/testflow/workspace
      Running: Allocate node : Body : Start
      Running: Print Message
      1
      Running: Print Message
      A
      Running: Allocate node : Body : End
      Running: Allocate node : End
      Running: End of Workflow
      Finished: SUCCESS

      Expected output:
      Started by user anonymous
      Running: Allocate node : Start
      Running on master in /var/lib/jenkins/jobs/testflow/workspace
      Running: Allocate node : Body : Start
      Running: Print Message
      1
      Running: Print Message
      2
      Running: Print Message
      3
      Running: Print Message
      ABC
      Running: Allocate node : Body : End
      Running: Allocate node : End
      Running: End of Workflow
      Finished: SUCCESS

      Attachments

        Issue Links

          Activity

            murme or anyone having the time to fix this, please note that https://jenkins.io is fully backed by https://github.com/jenkins-infra/jenkins.io, so a PR there is the only thing needed to fix it.

            (Side note: not only guys can fix this issue )

            batmat Baptiste Mathus added a comment - murme or anyone having the time to fix this, please note that https://jenkins.io is fully backed by https://github.com/jenkins-infra/jenkins.io , so a PR there is the only thing needed to fix it. (Side note: not only guys can fix this issue )

            batmat, I'll do this, because I had funny time with digging around NonSerializable exceptions and have created small documentation file with all such cases for my team. Now it is time to share it

            Thanks for additional info and reminder!

            murme Ulad Muraveika added a comment - batmat , I'll do this, because I had funny time with digging around NonSerializable exceptions and have created small documentation file with all such cases for my team. Now it is time to share it Thanks for additional info and reminder!
            ilatypov Ilguiz Latypov added a comment - - edited

            Another limit is still annoying because it silently returns from a NonCPS method calling a CPS method.

             

                @NonCPS
                public static String readCurrentVersion(String fileContent) {
                    def xml = new XmlSlurper().parseText(deBOM(fileContent))
                    String retval = "${xml.metadata.version}"
                    xml = null
                    return retval
                }
            
                // Omitted @NonCPS here
                public static CharSequence deBOM(CharSequence s) {
                    [...]
                    return s
                }
            

            Calling readCurrentVersion from the above unexpectedly returned the entire fileContent.  This is probably another unexpected behaviour but seems worth mentioning in the documentation.

             

            ilatypov Ilguiz Latypov added a comment - - edited Another limit is still annoying because it silently returns from a NonCPS method calling a CPS method.   @NonCPS public static String readCurrentVersion( String fileContent) { def xml = new XmlSlurper().parseText(deBOM(fileContent)) String retval = "${xml.metadata.version}" xml = null return retval } // Omitted @NonCPS here public static CharSequence deBOM(CharSequence s) { [...] return s } Calling readCurrentVersion from the above unexpectedly returned the entire fileContent.  This is probably another unexpected behaviour but seems worth mentioning in the documentation.  
            jglick Jesse Glick added a comment -

            ilatypov this ought to have been addressed (in the form of a warning) by JENKINS-31314.

            jglick Jesse Glick added a comment - ilatypov this ought to have been addressed (in the form of a warning) by JENKINS-31314 .

            Whilst I can use the basic form of each, when I try the following structure it only loops once.  If I remove the "a, b" and reference as it[0] and it[1] it works:

             

            [p,q].transpose().each { a, b -> println a ; println b }
            
            falloutphil Philip Beadling added a comment - Whilst I can use the basic form of each, when I try the following structure it only loops once.  If I remove the "a, b" and reference as it [0] and it [1] it works:   [p,q].transpose().each { a, b -> println a ; println b }

            People

              jglick Jesse Glick
              dtschan Daniel Tschan
              Votes:
              108 Vote for this issue
              Watchers:
              137 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: