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

load step fails to bind "complex" @Field defined variables

    XMLWordPrintable

    Details

    • Similar Issues:

      Description

      for more complex variables that are annotated with @Field, the load step fails to bind the variable into the Script class.

      For example:

      // a.groovy
      import groovy.transform.Field
      
      @Field
      def LOADED_BUILD_NUMBER = ${env.BUILD_NUMBER}
      
      return this
      
      // Jenkinsfile
      node() {
        def a = load('a.groovy')
        echo(${env.BUILD_NUMBER})
        echo(${a.LOADED_BUILD_NUMBER})
      }
      

      This example will fail. However, if you replace ${env.BUILD_NUMBER} with a simple type such as `3`, the load step will succeed.

       

      This seems to be related to the security update in workflow-cps v2.64 and the subsequent regression fix for @Field in v2.71.

        Attachments

          Activity

          Hide
          jglick Jesse Glick added a comment -

          Dee Kryvenko still sounds like you are overthinking this.

          there is certain state the loader library needs to read (example Git data like repo path/branch etc)

          is not (mutable) state, it is information which you can pass e.g. using withEnv.

          I can't embed too much into the DSL string itself due to infamous "Method code too large".

          You cannot too much into a single method. You can define as many methods as you like so long as each is a reasonable size.

          Anyway, it is hard to follow what you are really trying to accomplish, or how you thought you should accomplish it, but this is all a topic for the users’ list or Discourse or Stack Overflow or something. So far as @Field is concerned, the status remains: this sounds like a bug in a corner case; it is unlikely anyone is going to work on it due to the effort and the risk of other regressions.

          Show
          jglick Jesse Glick added a comment - Dee Kryvenko still sounds like you are overthinking this. there is certain state the loader library needs to read (example Git data like repo path/branch etc) is not (mutable) state , it is information which you can pass e.g. using withEnv . I can't embed too much into the DSL string itself due to infamous "Method code too large". You cannot too much into a single method . You can define as many methods as you like so long as each is a reasonable size. Anyway, it is hard to follow what you are really trying to accomplish, or how you thought you should accomplish it, but this is all a topic for the users’ list or Discourse or Stack Overflow or something. So far as @Field is concerned, the status remains: this sounds like a bug in a corner case; it is unlikely anyone is going to work on it due to the effort and the risk of other regressions.
          Hide
          llibicpep Dee Kryvenko added a comment -

          Jesse Glick - it is fairly simple actually - the pipeline generator needs to contribute stuff back to the state initiated in the loader to be consumed from the generated Jenkinsfile. As simple as that. And yes it IS one method - `evaluate` method so the entire Jenkinsfile should fit. Think of all the static resources in the pipeline that you'd need to pass from the generator via the loader to the actual steps.

          Show
          llibicpep Dee Kryvenko added a comment - Jesse Glick - it is fairly simple actually - the pipeline generator needs to contribute stuff back to the state initiated in the loader to be consumed from the generated Jenkinsfile. As simple as that. And yes it IS one method - `evaluate` method so the entire Jenkinsfile should fit. Think of all the static resources in the pipeline that you'd need to pass from the generator via the loader to the actual steps.
          Hide
          llibicpep Dee Kryvenko added a comment - - edited

          Project factory:

          library 'some-loader-lib@v1'
          loaderStep(this)
          

          Loader:

          def call(def jenkinsfile) {
              def context = Context.it() // data in singletone
              def output
              podTemplate(yaml: """
          apiVersion: v1
          kind: Pod
          metadata:
          spec:
            containers:
              - name: generator
                image: ...
                command:
                  - sleep
                args:
                  - 5m
          """) {
                  node(POD_LABEL) {
                      container('generator') {
                          writeJSON(file: 'input.json', pretty: 4, json: context.input)
                          output = readJSON(returnPojo: true, text: sh(returnStdout: true, script: 'cat input.json | generator').trim())
                      }
                  }
              }
              context.save(output.templates) // there is a whole bunch of heavy string resources like scripts and config files
              context.save(output.etc) // and some other stuff that might not be as heavy
              library output.lib // a library with collection of custom steps generator telling the loaded to load
              evaluate(output.dsl) // now this string evaluating there will call steps from the above and these steps needs access to the context, including templates and etc
          }
          

          Does it makes sense now?

          Show
          llibicpep Dee Kryvenko added a comment - - edited Project factory: library 'some-loader-lib@v1' loaderStep( this ) Loader: def call(def jenkinsfile) { def context = Context.it() // data in singletone def output podTemplate(yaml: """ apiVersion: v1 kind: Pod metadata: spec: containers: - name: generator image: ... command: - sleep args: - 5m """) { node(POD_LABEL) { container( 'generator' ) { writeJSON(file: 'input.json' , pretty: 4, json: context.input) output = readJSON(returnPojo: true , text: sh(returnStdout: true , script: 'cat input.json | generator' ).trim()) } } } context.save(output.templates) // there is a whole bunch of heavy string resources like scripts and config files context.save(output.etc) // and some other stuff that might not be as heavy library output.lib // a library with collection of custom steps generator telling the loaded to load evaluate(output.dsl) // now this string evaluating there will call steps from the above and these steps needs access to the context, including templates and etc } Does it makes sense now?
          Hide
          llibicpep Dee Kryvenko added a comment -

          Denys Digtiar with all the time I already wasted on fighting artificial issues and limitations - sorry, no. I am looking for ways to get off of Jenkins at this point asap - there's so many great open source kubernetes native alternatives out there today like Tekton that are not flawed and are not making their goal to artificially limit and cripple user experience so that a commercial offering really shines comparing to open source.

          Show
          llibicpep Dee Kryvenko added a comment - Denys Digtiar with all the time I already wasted on fighting artificial issues and limitations - sorry, no. I am looking for ways to get off of Jenkins at this point asap - there's so many great open source kubernetes native alternatives out there today like Tekton that are not flawed and are not making their goal to artificially limit and cripple user experience so that a commercial offering really shines comparing to open source.
          Hide
          jglick Jesse Glick added a comment -

          IIUC just use

          evaluate(output.dsl)(context)
          

          where the output of the DSL is something like

          { context ->
            // as before
          }
          
          Show
          jglick Jesse Glick added a comment - IIUC just use evaluate(output.dsl)(context) where the output of the DSL is something like { context -> // as before }

            People

            Assignee:
            Unassigned Unassigned
            Reporter:
            duemir Denys Digtiar
            Votes:
            1 Vote for this issue
            Watchers:
            3 Start watching this issue

              Dates

              Created:
              Updated: