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

Invoking properties / promotions / promotion twice results in inconsistent configuration

      When creating jobs via DSL we run them though a chain of decorators, relying heavily on the intelligent append/replace behavior of dsl elements.

      This works fine e.g. for the archiveArtifacts publisher.

      However when one invokes the promotion call twice like this:

                  job.with {
                              properties{
                                          promotions {
                                                  promotion {
                                                          name "First promotion"
      //...
                                                  }
                                          }
                              } 
                  }
      
                  job.with {              
                              properties{
                                          promotions {
                                                  promotion {
                                                          name "Second promotion"
      //...
                                                  }
                                          }
                              }                 
                   }       
      

       
      The result is:

      • if one views the web ui confiuguration form only the "Second promotion" is displayed
      • if one views the Promotion Status (buildUrl/promotion/) for the build or for the whole job only the "First promotion" is displayed
      • there are two "Promotion Status" links in the job sidebar and two badges (or how you call that) on the job status page
      • there is only a single "Promotion Status" link and badge on the build status page

          [JENKINS-43340] Invoking properties / promotions / promotion twice results in inconsistent configuration

          Jakub Bochenski created issue -
          Jakub Bochenski made changes -
          Description Original: Changing a {{textParam}} to \{\{validatingStringParameterDefinition}} like this:
          {code:java}
                                                                       manual('engineering') {
                                                                           parameters{
          -                                                                    textParam 'SOURCE'
          +                                                                    validatingStringParameterDefinition {
          +                                                                        name 'SOURCE'
          +                                                                        regex '^[0-9]+$'
          +                                                                        defaultValue ''
          +                                                                        failedValidationMessage ''
          +                                                                        description 'Commit to be merged into integration branch'
          +                                                                    }
                                                                           }
                                                                       }
          {code}
          results in:
          {code:java}
          java.lang.ClassCastException: java.lang.String cannot be cast to groovy.util.Node
          at hudson.plugins.promoted_builds.integrations.jobdsl.ManualConditionConverter.convertNode(ManualConditionConverter.java:63)
          at hudson.plugins.promoted_builds.integrations.jobdsl.ManualConditionConverter.marshal(ManualConditionConverter.java:48)
          at com.thoughtworks.xstream.core.AbstractReferenceMarshaller.convert(AbstractReferenceMarshaller.java:69)
          at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:58)
          at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:43)
          at com.thoughtworks.xstream.core.AbstractReferenceMarshaller$1.convertAnother(AbstractReferenceMarshaller.java:88)
          at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.writeItem(AbstractCollectionConverter.java:64)
          at com.thoughtworks.xstream.converters.collections.CollectionConverter.marshal(CollectionConverter.java:74)
          at com.thoughtworks.xstream.core.AbstractReferenceMarshaller.convert(AbstractReferenceMarshaller.java:69)
          at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:58)
          at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:43)
          at com.thoughtworks.xstream.core.AbstractReferenceMarshaller$1.convertAnother(AbstractReferenceMarshaller.java:88)
          at hudson.plugins.promoted_builds.integrations.jobdsl.JobDslPromotionProcessConverter.marshal(JobDslPromotionProcessConverter.java:73)
          at com.thoughtworks.xstream.core.AbstractReferenceMarshaller.convert(AbstractReferenceMarshaller.java:69)
          at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:58)
          at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:43)
          at com.thoughtworks.xstream.core.TreeMarshaller.start(TreeMarshaller.java:82)
          at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.marshal(AbstractTreeMarshallingStrategy.java:37)
          at com.thoughtworks.xstream.XStream.marshal(XStream.java:1026)
          at com.thoughtworks.xstream.XStream.marshal(XStream.java:1015)
          at com.thoughtworks.xstream.XStream.toXML(XStream.java:988)
          at com.thoughtworks.xstream.XStream.toXML(XStream.java:975)
          at hudson.plugins.promoted_builds.integrations.jobdsl.PromotionsExtensionPoint.notifyItemCreated(PromotionsExtensionPoint.java:78)
          at hudson.plugins.promoted_builds.integrations.jobdsl.PromotionsExtensionPoint.notifyItemUpdated(PromotionsExtensionPoint.java:136)
          at javaposse.jobdsl.plugin.JenkinsJobManagement.notifyItemUpdated(JenkinsJobManagement.java:575)
          at javaposse.jobdsl.plugin.JenkinsJobManagement.updateExistingItem(JenkinsJobManagement.java:501)
          at javaposse.jobdsl.plugin.JenkinsJobManagement.createOrUpdateConfig(JenkinsJobManagement.java:149)
          at javaposse.jobdsl.dsl.JobManagement$createOrUpdateConfig$10.call(Unknown Source)
          at javaposse.jobdsl.plugin.InterruptibleJobManagement.createOrUpdateConfig(InterruptibleJobManagement.groovy:37)
          at javaposse.jobdsl.dsl.JobManagement$createOrUpdateConfig$10.call(Unknown Source)
          at javaposse.jobdsl.dsl.AbstractDslScriptLoader$_extractGeneratedJobs_closure4.doCall(AbstractDslScriptLoader.groovy:187)
          at sun.reflect.GeneratedMethodAccessor9651.invoke(Unknown Source)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          at java.lang.reflect.Method.invoke(Method.java:498)
          at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
          at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
          at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
          at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
          at groovy.lang.Closure.call(Closure.java:414)
          at groovy.lang.Closure.call(Closure.java:430)
          at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2030)
          at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2015)
          at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2056)
          at org.codehaus.groovy.runtime.dgm$162.invoke(Unknown Source)
          at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:274)
          at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
          at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
          at javaposse.jobdsl.dsl.AbstractDslScriptLoader.extractGeneratedJobs(AbstractDslScriptLoader.groovy:180)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          at java.lang.reflect.Method.invoke(Method.java:498)
          at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:210)
          at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:59)
          at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:174)
          at javaposse.jobdsl.dsl.AbstractDslScriptLoader.extractGeneratedItems(AbstractDslScriptLoader.groovy:167)
          at javaposse.jobdsl.plugin.JenkinsDslScriptLoader.extractGeneratedItems(JenkinsDslScriptLoader.java:23)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          at java.lang.reflect.Method.invoke(Method.java:498)
          at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
          at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
          at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:384)
          at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
          at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:69)
          at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:182)
          at javaposse.jobdsl.dsl.AbstractDslScriptLoader$_runScripts_closure1.doCall(AbstractDslScriptLoader.groovy:60)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          at java.lang.reflect.Method.invoke(Method.java:498)
          at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
          at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
          at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
          at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
          at groovy.lang.Closure.call(Closure.java:414)
          at groovy.lang.Closure.call(Closure.java:430)
          at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2030)
          at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2015)
          at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2068)
          at org.codehaus.groovy.runtime.dgm$164.invoke(Unknown Source)
          at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:274)
          at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
          at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
          at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScripts(AbstractDslScriptLoader.groovy:45)
          at javaposse.jobdsl.plugin.ExecuteDslScripts.perform(ExecuteDslScripts.java:251)
          at hudson.tasks.BuildStepCompatibilityLayer.perform(BuildStepCompatibilityLayer.java:78)
          at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
          at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:779)
          at hudson.model.Build$BuildExecution.build(Build.java:206)
          at hudson.model.Build$BuildExecution.doRun(Build.java:163)
          at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:534)
          at hudson.model.Run.execute(Run.java:1728)
          at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
          at hudson.model.ResourceController.execute(ResourceController.java:98)
          at hudson.model.Executor.run(Executor.java:405)
          ERROR: java.lang.String cannot be cast to groovy.util.Node{code}
           
          New: When creating jobs via DSL we run them though a chain of decorators, relying heavily on the intelligent append/replace behavior of dsl elements.

          This works fine e.g. for the archiveArtifacts publisher.

          However when one invokes the {{promotion}} call twice like this:
          {code:java}
                      job.with {
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "First promotion"
          //...
                                                      }
                                              }
                                  }
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "Second promotion"
          //...
                                                      }
                                              }
                                  }
          }
          {code}
           
          The result is:
           - if one views the web ui confiuguration form only the "Second promotion" is displayed
           - if one views the Promotion Status ({{buildUrl/promotion/}}) only the "First promotion" is displayed
           - there are two "Promotion Status" links in the job sidebar


           
          Jakub Bochenski made changes -
          Attachment New: snap.png [ 36866 ]
          Jakub Bochenski made changes -
          Description Original: When creating jobs via DSL we run them though a chain of decorators, relying heavily on the intelligent append/replace behavior of dsl elements.

          This works fine e.g. for the archiveArtifacts publisher.

          However when one invokes the {{promotion}} call twice like this:
          {code:java}
                      job.with {
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "First promotion"
          //...
                                                      }
                                              }
                                  }
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "Second promotion"
          //...
                                                      }
                                              }
                                  }
          }
          {code}
           
          The result is:
           - if one views the web ui confiuguration form only the "Second promotion" is displayed
           - if one views the Promotion Status ({{buildUrl/promotion/}}) only the "First promotion" is displayed
           - there are two "Promotion Status" links in the job sidebar


           
          New: When creating jobs via DSL we run them though a chain of decorators, relying heavily on the intelligent append/replace behavior of dsl elements.

          This works fine e.g. for the archiveArtifacts publisher.

          However when one invokes the {{promotion}} call twice like this:
          {code:java}
                      job.with {
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "First promotion"
          //...
                                                      }
                                              }
                                  }
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "Second promotion"
          //...
                                                      }
                                              }
                                  }
          }
          {code}
           
          The result is:
           - if one views the web ui confiuguration form only the "Second promotion" is displayed
           - if one views the Promotion Status ({{buildUrl/promotion/}}) only the "First promotion" is displayed
           - there are two "Promotion Status" links in the job sidebar !snap.png!


           
          Jakub Bochenski made changes -
          Description Original: When creating jobs via DSL we run them though a chain of decorators, relying heavily on the intelligent append/replace behavior of dsl elements.

          This works fine e.g. for the archiveArtifacts publisher.

          However when one invokes the {{promotion}} call twice like this:
          {code:java}
                      job.with {
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "First promotion"
          //...
                                                      }
                                              }
                                  }
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "Second promotion"
          //...
                                                      }
                                              }
                                  }
          }
          {code}
           
          The result is:
           - if one views the web ui confiuguration form only the "Second promotion" is displayed
           - if one views the Promotion Status ({{buildUrl/promotion/}}) only the "First promotion" is displayed
           - there are two "Promotion Status" links in the job sidebar !snap.png!


           
          New: When creating jobs via DSL we run them though a chain of decorators, relying heavily on the intelligent append/replace behavior of dsl elements.

          This works fine e.g. for the archiveArtifacts publisher.

          However when one invokes the {{promotion}} call twice like this:
          {code:java}
                      job.with {
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "First promotion"
          //...
                                                      }
                                              }
                                  }
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "Second promotion"
          //...
                                                      }
                                              }
                                  }
          }
          {code}
           
          The result is:
           - if one views the web ui confiuguration form only the "Second promotion" is displayed
           - if one views the Promotion Status ({{buildUrl/promotion/}}) only the "First promotion" is displayed
           - there are two "Promotion Status" links in the job sidebar !snap.png|thumbnail!


           
          Jakub Bochenski made changes -
          Description Original: When creating jobs via DSL we run them though a chain of decorators, relying heavily on the intelligent append/replace behavior of dsl elements.

          This works fine e.g. for the archiveArtifacts publisher.

          However when one invokes the {{promotion}} call twice like this:
          {code:java}
                      job.with {
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "First promotion"
          //...
                                                      }
                                              }
                                  }
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "Second promotion"
          //...
                                                      }
                                              }
                                  }
          }
          {code}
           
          The result is:
           - if one views the web ui confiuguration form only the "Second promotion" is displayed
           - if one views the Promotion Status ({{buildUrl/promotion/}}) only the "First promotion" is displayed
           - there are two "Promotion Status" links in the job sidebar !snap.png|thumbnail!


           
          New: When creating jobs via DSL we run them though a chain of decorators, relying heavily on the intelligent append/replace behavior of dsl elements.

          This works fine e.g. for the archiveArtifacts publisher.

          However when one invokes the {{promotion}} call twice like this:
          {code:java}
                      job.with {
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "First promotion"
          //...
                                                      }
                                              }
                                  }
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "Second promotion"
          //...
                                                      }
                                              }
                                  }
          }
          {code}
           
          The result is:
           - if one views the web ui confiuguration form only the "Second promotion" is displayed
           - if one views the Promotion Status ({{buildUrl/promotion/}}) for the build or for the whole job only the "First promotion" is displayed
           - there are two "Promotion Status" links in the job sidebar and two badges (or how you call that) on the job status page !snap.png|thumbnail!
           - there is only a single "Promotion Status" link and badge on the build status page
          Jakub Bochenski made changes -
          Description Original: When creating jobs via DSL we run them though a chain of decorators, relying heavily on the intelligent append/replace behavior of dsl elements.

          This works fine e.g. for the archiveArtifacts publisher.

          However when one invokes the {{promotion}} call twice like this:
          {code:java}
                      job.with {
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "First promotion"
          //...
                                                      }
                                              }
                                  }
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "Second promotion"
          //...
                                                      }
                                              }
                                  }
          }
          {code}
           
          The result is:
           - if one views the web ui confiuguration form only the "Second promotion" is displayed
           - if one views the Promotion Status ({{buildUrl/promotion/}}) for the build or for the whole job only the "First promotion" is displayed
           - there are two "Promotion Status" links in the job sidebar and two badges (or how you call that) on the job status page !snap.png|thumbnail!
           - there is only a single "Promotion Status" link and badge on the build status page
          New: When creating jobs via DSL we run them though a chain of decorators, relying heavily on the intelligent append/replace behavior of dsl elements.

          This works fine e.g. for the archiveArtifacts publisher.

          However when one invokes the {{promotion}} call twice like this:
          {code:java}
                      job.with {
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "First promotion"
          //...
                                                      }
                                              }
                                  }
                      }

                      job.with {
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "Second promotion"
          //...
                                                      }
                                              }
                                  }
                       }
          {code}
           
          The result is:
           - if one views the web ui confiuguration form only the "Second promotion" is displayed
           - if one views the Promotion Status ({{buildUrl/promotion/}}) for the build or for the whole job only the "First promotion" is displayed
           - there are two "Promotion Status" links in the job sidebar and two badges (or how you call that) on the job status page !snap.png|thumbnail!
           - there is only a single "Promotion Status" link and badge on the build status page

          Merging the above code into a single promotions invocation fixes it:

                      job.with {
                                  properties{
                                              promotions {
                                                      promotion {
                                                              name "First promotion"
          //...
                                                      }
                                                      promotion {
                                                              name "Second promotion"
          //...
                                                      }
                                              }
                                  }                 
                       }       
          

          it's not that easy in our real setup though as the promotions are added by different parts of our code

          Jakub Bochenski added a comment - Merging the above code into a single promotions invocation fixes it: job.with { properties{ promotions { promotion { name "First promotion" //... } promotion { name "Second promotion" //... } } } } it's not that easy in our real setup though as the promotions are added by different parts of our code
          Oleg Nenashev made changes -
          Assignee Original: Oleg Nenashev [ oleg_nenashev ]

          Oleg Nenashev added a comment -

          Should be fixed by somebody as a part of JENKINS-44837

          Oleg Nenashev added a comment - Should be fixed by somebody as a part of JENKINS-44837
          Oleg Nenashev made changes -
          Epic Link New: JENKINS-44837 [ 182897 ]

            Unassigned Unassigned
            jbochenski Jakub Bochenski
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: