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

list.empty broken in pipeline scripts

    Details

    • Similar Issues:

      Description

      Since upgrading to Pipeline:Groovy 2.48, the .empty property of List objects gives very strange results, whose boolean value in particular is the reverse of the expected.

      When executing the following script as a pipeline (testet via "Replay" and replacing the existing script by this) gives weird output:

       Script

      x = [] as List
      println x
      println x.isEmpty()
      println x.empty
      x<<"hello"
      println x
      println x.isEmpty()
      println x.empty
      

      Expected output

      [Pipeline] echo
      []
      [Pipeline] echo
      true
      [Pipeline] echo
      true
      [Pipeline] echo
      [hello]
      [Pipeline] echo
      false
      [Pipeline] echo
      false
      [Pipeline] End of Pipeline
      

      Actual output

      [Pipeline] echo
      []
      [Pipeline] echo
      true
      [Pipeline] echo
      []
      [Pipeline] echo
      [hello]
      [Pipeline] echo
      false
      [Pipeline] echo
      [false]
      [Pipeline] End of Pipeline
      

      Downgrading the Pipeline:Groovy plugin to 2.47 fixes it; after upgrading again, the weird behaviour is back.

      Workaround

      For the moment, I can live with calling isEmpty() instead of accessing empty.

      further considerations

      I have not tested whether any other properties besides .empty are affected.

        Attachments

          Activity

          Hide
          fcodyc Cody Casterline added a comment -

          Yikes. We ran into this today too. It takes quite a long time to track down. "Surely, .empty isn't broken?"   We even tried it in the Groovy Console, but things work as expected there. It's just broken in pipelines?  :~(

          Show
          fcodyc Cody Casterline added a comment - Yikes. We ran into this today too. It takes quite a long time to track down. "Surely, .empty isn't broken?"   We even tried it in the Groovy Console, but things work as expected there. It's just broken in pipelines?  :~(
          Hide
          danielbeck Daniel Beck added a comment -

          Based on this report and https://github.com/jenkinsci/workflow-cps-plugin/compare/workflow-cps-2.47...workflow-cps-2.48 pinging Sam Van Oort, perhaps he has an idea. But the diff doesn't seem related at first glance.

          Show
          danielbeck Daniel Beck added a comment - Based on this report and https://github.com/jenkinsci/workflow-cps-plugin/compare/workflow-cps-2.47...workflow-cps-2.48 pinging Sam Van Oort , perhaps he has an idea. But the diff doesn't seem related at first glance.
          Hide
          svanoort Sam Van Oort added a comment -

          I really have no clue here, since as Daniel notes the only thing that changed is handling of unserializable step arguments.

          Um, Andrew Bayer do you have any clever ideas? You're stronger on Groovy quirks than I am I think.

          Show
          svanoort Sam Van Oort added a comment - I really have no clue here, since as Daniel notes the only thing that changed is handling of unserializable step arguments. Um, Andrew Bayer do you have any clever ideas? You're stronger on Groovy quirks than I am I think.
          Hide
          abayer Andrew Bayer added a comment -

          This feels like it’s related to https://github.com/jenkinsci/groovy-sandbox/pull/46 - getting script security to do the right thing consistently with properties/spread/getters is an annoyingly hairy area. I’ll take a look later this week.

          Show
          abayer Andrew Bayer added a comment - This feels like it’s related to https://github.com/jenkinsci/groovy-sandbox/pull/46 - getting script security to do the right thing consistently with properties/spread/getters is an annoyingly hairy area. I’ll take a look later this week.
          Hide
          dcsobral Daniel Sobral added a comment -

          I think you are right, Andrew Bayer, because I've noticed calls that do not end with parenthesis are just returning the object's value:

          def ald = []
          print "ald: " + ald
          print "ald.getClass: " + ald.getClass
          print "ald.class: " + ald.class
          print "ald.isEmpty: " + ald.isEmpty
          print "ald.empty: " + ald.empty
          echo "ald: ${ald}"
          echo "ald.getClass(): ${ald.getClass()}"
          echo "ald.class: ${ald.class}"
          echo "ald.isEmpty(): ${ald.isEmpty()}"
          echo "ald.empty: ${ald.empty}"
          
          ald: []
          [Pipeline] echo
          ald.getClass: []
          [Pipeline] echo
          ald.class: class java.util.ArrayList
          [Pipeline] echo
          ald.isEmpty: []
          [Pipeline] echo
          ald.empty: []
          [Pipeline] echo
          ald: []
          [Pipeline] echo
          ald.getClass(): class java.util.ArrayList
          [Pipeline] echo
          ald.class: class java.util.ArrayList
          [Pipeline] echo
          ald.isEmpty(): true
          [Pipeline] echo
          ald.empty: [] 

          If I had to guess, I'd say "empty" is not treating "isEmpty" as a getter (is vs get), and the failure case (no method or property) is doing some weird thing.

          Show
          dcsobral Daniel Sobral added a comment - I think you are right, Andrew Bayer , because I've noticed calls that do not end with parenthesis are just returning the object's value: def ald = [] print "ald: " + ald print "ald.getClass: " + ald.getClass print "ald.class: " + ald.class print "ald.isEmpty: " + ald.isEmpty print "ald.empty: " + ald.empty echo "ald: ${ald}" echo "ald.getClass(): ${ald.getClass()}" echo "ald.class: ${ald.class}" echo "ald.isEmpty(): ${ald.isEmpty()}" echo "ald.empty: ${ald.empty}" ald: [] [Pipeline] echo ald.getClass: [] [Pipeline] echo ald.class: class java.util.ArrayList [Pipeline] echo ald.isEmpty: [] [Pipeline] echo ald.empty: [] [Pipeline] echo ald: [] [Pipeline] echo ald.getClass(): class java.util.ArrayList [Pipeline] echo ald.class: class java.util.ArrayList [Pipeline] echo ald.isEmpty(): true [Pipeline] echo ald.empty: [] If I had to guess, I'd say "empty" is not treating "isEmpty" as a getter (is vs get), and the failure case (no method or property) is doing some weird thing.

            People

            • Assignee:
              Unassigned
              Reporter:
              hjholtz Hans-Jakob Holtz
            • Votes:
              2 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

              • Created:
                Updated: