• Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Critical Critical
    • workflow-cps-plugin
    • Jenkins LTS 1.580.2 and workflow-plugin 1.1. Both are the latest versions at the time of this writing. Tested on RHEL 6 with OpenJDK 1.7 and Fedora 21 with OpenJDK 1.8.

      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

          [JENKINS-26481] Mishandling of binary methods accepting Closure

          Code changed in jenkins
          User: R. Tyler Croy
          Path:
          content/blog/2017/08/2017-09-08-enumerators-in-pipeline.adoc
          http://jenkins-ci.org/commit/jenkins.io/3ed6f8445ded8ddafec2e0e01b71ced9af0c6e7d
          Log:
          Add a nice little blog post about the despised JENKINS-26481

          SCM/JIRA link daemon added a comment - Code changed in jenkins User: R. Tyler Croy Path: content/blog/2017/08/2017-09-08-enumerators-in-pipeline.adoc http://jenkins-ci.org/commit/jenkins.io/3ed6f8445ded8ddafec2e0e01b71ced9af0c6e7d Log: Add a nice little blog post about the despised JENKINS-26481

          Code changed in jenkins
          User: R. Tyler Croy
          Path:
          content/blog/2017/08/2017-09-08-enumerators-in-pipeline.adoc
          http://jenkins-ci.org/commit/jenkins.io/89792a0c8e0a3850f95ec5fe24bbc89f962fb7ed
          Log:
          Merge pull request #1120 from rtyler/enumerators

          Add a nice little blog post about the despised JENKINS-26481

          Compare: https://github.com/jenkins-infra/jenkins.io/compare/1c5922c91f13...89792a0c8e0a

          SCM/JIRA link daemon added a comment - Code changed in jenkins User: R. Tyler Croy Path: content/blog/2017/08/2017-09-08-enumerators-in-pipeline.adoc http://jenkins-ci.org/commit/jenkins.io/89792a0c8e0a3850f95ec5fe24bbc89f962fb7ed Log: Merge pull request #1120 from rtyler/enumerators Add a nice little blog post about the despised JENKINS-26481 Compare: https://github.com/jenkins-infra/jenkins.io/compare/1c5922c91f13...89792a0c8e0a

          Lucas Cimon added a comment -

          Thank you for fixing this !

          Lucas Cimon added a comment - Thank you for fixing this !

          Guys, it will be cool if you update documentation on https://jenkins.io/doc/pipeline/examples/ page, because bug was fixed and doc right now is confusing novice users

          >Due to limitations in Workflow - i.e., JENKINS-26481 - it's not really possible to use Groovy closures or syntax that depends on closures, so you can't do the Groovy standard of using .collectEntries on a list and generating the steps as values for the resulting entries. You also can't use the standard Java syntax for For loops - i.e., "for (String s: strings)" - and instead have to use old school counter-based for loops.

          Ulad Muraveika added a comment - Guys, it will be cool if you update documentation on https://jenkins.io/doc/pipeline/examples/ page, because bug was fixed and doc right now is confusing novice users >Due to limitations in Workflow - i.e., JENKINS-26481 - it's not really possible to use Groovy closures or syntax that depends on closures, so you can't do the Groovy standard of using .collectEntries on a list and generating the steps as values for the resulting entries. You also can't use the standard Java syntax for For loops - i.e., "for (String s: strings)" - and instead have to use old school counter-based for loops.

          Jesse Glick added a comment -

          murme good catch. Could you file an issue for this in the WEBSITE project? Of course if you have the time to do it, we welcome PRs updating documentation. (In the case of code samples, this means testing that the proposed syntax actually works in current releases.)

          Jesse Glick added a comment - murme good catch. Could you file an issue for this in the WEBSITE project? Of course if you have the time to do it, we welcome PRs updating documentation. (In the case of code samples, this means testing that the proposed syntax actually works in current releases.)

          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 )

          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!

          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!

          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.

           

          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.  

          Jesse Glick added a comment -

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

          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 }
          

          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 }

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

              Created:
              Updated:
              Resolved: