Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Input step with timeout which continues with default settings using Jenkins pipeline

Description of desired Jenkins pipeline:

  • Wait 1 minute for input ("Is this a release build? yes/no")
    • If input is yes then do a release type build (with build number and deployment)
    • If it times out or user said no then do a testing build
    • If user pressed Abort do normal abort

My current code is:

try {
    timeout(1) {
        input message: 'Do you want to release this build?',
              parameters: [[$class: 'BooleanParameterDefinition',
                            defaultValue: false,
                            description: 'Ticking this box will do a release',
                            name: 'Release']]
    }
} catch (err) {
    def hi = err.getCauses()
    echo "Exception thrown:\n ${hi}"

    echo err.getLocalizedMessage()
    echo err.getCause()
    echo err.toString()
    echo err.getClass().getName()
}

But this gives identical (as far as I can tell) behaviour and caught errors for user pressed "Abort" and input timed out.

Here is the output for timed out:

[Pipeline] timeout
[Pipeline] {
[Pipeline] input
Input requested
[Pipeline] }
[Pipeline] // timeout
[Pipeline] echo
Exception thrown:
 [org.jenkinsci.plugins.workflow.support.steps.input.Rejection@5ac94906]
[Pipeline] echo
null
[Pipeline] echo
null
[Pipeline] echo
org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
[Pipeline] echo
org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
[Pipeline] End of Pipeline
Finished: SUCCESS

When I press 'Abort' it is the same except for the hex after Rejection@

It would be great if the input step could optionally continue with default options after a timeout.

EDIT: Added more print to the error to try to determine it's type

like image 490
Harry Mallon Avatar asked Jul 26 '16 18:07

Harry Mallon


2 Answers

I have implemented similar behaviour recently.
This declarative pipeline code requries BRANCH_TO_BUILD parameter to be provided on start (only if it is started manually, otherwise default value will be used) then interactive input for the Git branch is activated.
So user has several options:

  • keep no action (default value will be used)
  • confirm default value
  • input new value
  • abort execution pressing [Abort]

And yes, remember to confirm Groovy functions as Blazej wrote

pipeline {
    agent none
    
    parameters {
        string(name: 'BRANCH_TO_BUILD', defaultValue: "develop", description: 'GIT branch to build')
    }   
  
    environment { 
        GIT_URL = 'ssh://user@git/repo.git'
        BRANCH_TO_BUILD_DEFAULT = 'develop'
        BRANCH_TO_BUILD_REQUESTED = "${params.BRANCH_TO_BUILD}"
    }
  

    stage('Configure the build') {
        agent none
        steps {
            echo "Prompt a user for the branch to build (default: ${BRANCH_TO_BUILD_DEFAULT})"
            script {
                try {
                    timeout(time:30, unit:'SECONDS') {
                    BRANCH_TO_BUILD_REQUESTED = input(
                        message: 'Input branch to build', 
                        parameters: [
                                [$class: 'TextParameterDefinition', 
                                 defaultValue: BRANCH_TO_BUILD_DEFAULT, 
                                 description: 'Branch name', name: 'Enter branch name (or leave default) and press [Proceed]:']
                            ])
                        echo ("User has entered the branch name: " + BRANCH_TO_BUILD_REQUESTED)
                    }
                } catch(err) { // timeout reached or input Aborted
                    def user = err.getCauses()[0].getUser()
                        if('SYSTEM' == user.toString()) { // SYSTEM means timeout
                            echo ("Input timeout expired, default branch will be used: " + BRANCH_TO_BUILD_DEFAULT)
                            BRANCH_TO_BUILD_REQUESTED = BRANCH_TO_BUILD_DEFAULT
                        } else {
                            echo "Input aborted by: [${user}]"
                            error("Pipeline aborted by: [${user}]")
                        }
                }
            }
        }
    }
    
    stage('Checkout') {
        agent{node {label 'worker-1'}}
            
        steps {
            echo "Checkout will be done for Git branch: ${BRANCH_TO_BUILD_REQUESTED}"
            checkout([$class: 'GitSCM', branches: [[name: "*/${BRANCH_TO_BUILD_REQUESTED}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[url: ${GIT_URL]}]])
            }
    }
    
}
like image 116
Leonid Samarkin Avatar answered Sep 30 '22 20:09

Leonid Samarkin


You could extract the information about the user that rejected from the Exception cause. org.jenkinsci.plugins.workflow.support.steps.input.Rejection has a getUser() method (which returns 'SYSTEM' for a timeout and full user name for an abort).

try {
    timeout(time: 15, unit: 'SECONDS') {
        input message: 'Do you want to release this build?',
              parameters: [[$class: 'BooleanParameterDefinition',
                            defaultValue: false,
                            description: 'Ticking this box will do a release',
                            name: 'Release']]
    }
} catch (err) {
    def user = err.getCauses()[0].getUser()
    echo "Aborted by:\n ${user}"
}

Do note that this requires an approval for the groovy sandbox (Manage Jenkins > In-process Script Approval).

like image 28
hakamairi Avatar answered Sep 30 '22 19:09

hakamairi