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

Offer "Build with Parameters" on first build when declarative Jenkinsfile found

    XMLWordPrintable

    Details

    • Similar Issues:

      Description

      By default a branch project will automatically run the first build, with no parameters, so params will just pick up any default values. You have the option to suppress the automatic first build, but this does not give you any way to enter parameters for it (at least in the UI; perhaps possible via CLI/REST), since Jenkins does not know what the parameters are going to be until it starts running. But in the case of Declarative we could in principle inspect the Jenkinsfile when the branch project is created (via SCMFileSystem) and determine the parameter definitions by static parsing without actually running.

      More generally, if Declarative is in use and there are properties, we could set all the project properties when the branch project is created, even if the first build is run automatically. (Though I would suggest that the automatic first build should be automatically suppressed if there is a ParametersDefinitionProperty.)

        Attachments

          Issue Links

            Activity

            Hide
            timblaktu Tim Black added a comment -

            Felipe Santos I like your slick 2-liner solution. I'm just not yet convinced that I'm ready to switch paradigms from using params to using environment variables in my pipelines.

            Show
            timblaktu Tim Black added a comment - Felipe Santos I like your slick 2-liner solution. I'm just not yet convinced that I'm ready to switch paradigms from using params to using environment variables in my pipelines.
            Hide
            tomw Tom added a comment -

            In terms of fixing this, how about an opt-in solution for well-behaved Jenkinsfiles (I guess enabled as a behaviour for multi-branch builds or similar)

            If set, it would update the build options and parameters:

            1. when a job (e.g. branch/PR) is first created
            2. when triggered manually using a 'Refresh pipeline from source' option or similar
            3. In an ideal world: whenever the pipeline file changes (i.e. by seeing if the Jenkinsfile has changed after a commit/poll and processing it before triggering the build) - this would fix the annoying off-by-one problem where get part of your pipeline state from the previous build.

            To run, the server would evaluate the Jenkins file, but not execute the node or stage parts (or even execute the DSL for them - the closures could be ignored). You'd just need a custom Groovy execution context to run the script in that just handled pipeline, parameters, options and top level properties. This should be possible for both declarative and scripted pipelines (for a scripted pipeline, you'd need a properties block at the top level, since node blocks would not be executed). Is there any security or other theoretical issue with executing the Jenkinsfile in this way, or is it very hard to implement?

            If it only worked with declarative pipelines, that would probably be fine for most people (including me).

            I think a 90% solution with some restrictions would be great, and a lot better than no solution!

             

            Show
            tomw Tom added a comment - In terms of fixing this, how about an opt-in solution for well-behaved Jenkinsfiles (I guess enabled as a behaviour for multi-branch builds or similar) If set, it would update the build options and parameters: when a job (e.g. branch/PR) is first created when triggered manually using a 'Refresh pipeline from source' option or similar In an ideal world: whenever the pipeline file changes (i.e. by seeing if the Jenkinsfile has changed after a commit/poll and processing it before triggering the build) - this would fix the annoying off-by-one problem where get part of your pipeline state from the previous build. To run, the server would evaluate the Jenkins file, but not execute the node or stage parts (or even execute the DSL for them - the closures could be ignored). You'd just need a custom Groovy execution context to run the script in that just handled pipeline , parameters , options and top level properties . This should be possible for both declarative and scripted pipelines (for a scripted pipeline, you'd need a properties block at the top level, since node blocks would not be executed). Is there any security or other theoretical issue with executing the Jenkinsfile in this way, or is it very hard to implement? If it only worked with declarative pipelines, that would probably be fine for most people (including me). I think a 90% solution with some restrictions would be great, and a lot better than no solution!  
            Hide
            funeeldy marlene cote added a comment -

            Thank you Felipe! it works with the one caveat that the first build will always be the default choice. Less confusing for our developers, but it would be great to have a "real" solution.

            Show
            funeeldy marlene cote added a comment - Thank you Felipe! it works with the one caveat that the first build will always be the default choice. Less confusing for our developers, but it would be great to have a "real" solution.
            Hide
            bsquizz Brandon Squizzato added a comment - - edited

            I'll also share the solution I came up with to deal with this.

            All of our Jenkinsfile pipeline jobs have a parameter defined in them called 'RELOAD'. This allows a user to check the box for 'RELOAD' and run the build. By default, its value is false.

            p = []
            // Add a param option for simply reloading this job
            p.add(
                [
                    $class: 'BooleanParameterDefinition',
                    name: "RELOAD", defaultValue: false, description: "Reload the job's config and quit"
                ]
            )
            
            // add other job parameters to 'p'...
            
            properties([parameters(p)])
            

             
            The Jenkinsfile pipeline jobs then later call a function that checks for the presence of this RELOAD parameter. This function should be called after your Jenkinsfile has defined job options/parameters/etc. but BEFORE the pipeline actually "builds" or "tests" anything. That way, if RELOAD is true, the build will update the job's configuration, but not actually run the job logic and just abort.

            def checkForReload() {
                // Exit the job if the "reload" box was checked
                if (params.RELOAD) {
                    echo "Job is configured to reload pipeline script and exit. Aborting."
                    currentBuild.description = "reload"
                    currentBuild.result = "ABORTED"
                    error("Job is configured to reload pipeline script and exit. Aborting.")
                }
            }
            

            On the JobDSL script that the seed job loads, we define the RELOAD parameter in JobDSL and set it to true by default. We then call 'queue' to cause the build to run one time when the seed job loads this config.

            pipelineJob("some-job") {
                // sets RELOAD=true for when the job is 'queued' below
                parameters {
                    booleanParam('RELOAD', true)
                }
            
                // other job config here
            
                // queue the job to run so it re-downloads its Jenkinsfile
                queue("some-job")
            }
            

            The end result is that the seed job will parse the JobDSL, run the build with RELOAD=true, which will cause the Jenkinsfile to get downloaded/executed – all of the properties/configs from the Jenkinsfile will be loaded – but then the 'checkForReload' function causes the job to abort before it actually runs the build/test. Since the Jenkinsfile also defines the RELOAD parameter with a default of false – subsequent runs of this build with NOT have 'RELOAD' checked unless a user manually checks the box.

            Show
            bsquizz Brandon Squizzato added a comment - - edited I'll also share the solution I came up with to deal with this. All of our Jenkinsfile pipeline jobs have a parameter defined in them called 'RELOAD'. This allows a user to check the box for 'RELOAD' and run the build. By default, its value is false. p = [] // Add a param option for simply reloading this job p.add( [ $class: 'BooleanParameterDefinition' , name: "RELOAD" , defaultValue: false , description: "Reload the job's config and quit" ] ) // add other job parameters to 'p' ... properties([parameters(p)])   The Jenkinsfile pipeline jobs then later call a function that checks for the presence of this RELOAD parameter. This function should be called after your Jenkinsfile has defined job options/parameters/etc. but BEFORE the pipeline actually "builds" or "tests" anything. That way, if RELOAD is true, the build will update the job's configuration, but not actually run the job logic and just abort. def checkForReload() { // Exit the job if the "reload" box was checked if (params.RELOAD) { echo "Job is configured to reload pipeline script and exit. Aborting." currentBuild.description = "reload" currentBuild.result = "ABORTED" error( "Job is configured to reload pipeline script and exit. Aborting." ) } } On the JobDSL script that the seed job loads, we define the RELOAD parameter in JobDSL and set it to true  by default. We then call 'queue' to cause the build to run one time when the seed job loads this config. pipelineJob("some-job") { // sets RELOAD=true for when the job is 'queued' below parameters { booleanParam('RELOAD', true) } // other job config here // queue the job to run so it re-downloads its Jenkinsfile queue("some-job") } The end result is that the seed job will parse the JobDSL, run the build with RELOAD=true, which will cause the Jenkinsfile to get downloaded/executed – all of the properties/configs from the Jenkinsfile will be loaded – but then the 'checkForReload' function causes the job to abort before it actually runs the build/test. Since the Jenkinsfile also defines the RELOAD parameter with a default of false – subsequent runs of this build with NOT have 'RELOAD' checked unless a user manually checks the box.
            Hide
            borisivan boris ivan added a comment -

            Brandon Squizzato that's the same thing we did too, though our parameter is "loadParamsAndAbort"

            Show
            borisivan boris ivan added a comment - Brandon Squizzato that's the same thing we did too, though our parameter is "loadParamsAndAbort"

              People

              Assignee:
              Unassigned Unassigned
              Reporter:
              jglick Jesse Glick
              Votes:
              143 Vote for this issue
              Watchers:
              153 Start watching this issue

                Dates

                Created:
                Updated: