Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

use groovy to add an additional parameter to a jenkins job

We've got a set of groovy scripts that our users invoke in their jenkinsfile that sets some common job properties. However, we haven't been able to figure out how to preserve their existing parameters when we do this update.

snippet of our groovy code:

def newParamsList = []
def newbool = booleanParam(defaultValue: false, description: "deploy", name: "deploy_flag")
newParamsList.add(newbool)
def newParams = parameters(newParamsList)
properties([ //job property declaration
    jobProperties,
    disableConcurrentBuilds(),
    newParams,
    addSchedule,
  ])

However, this overwrites the parameter definitions, so if the user had specified a different parameter definition in their jenkins file before invoking our groovy, it's been wiped out.

I can get access to the existing parameters using currentBuild.rawBuild.getAction(ParametersAction), but if I understand correctly, I need the ParameterDefinition not the ParameterValue in order to set the property. I tried currentBuild.rawBuild.getAction(ParametersDefinitionProperty.class) thinking I could use that like ParametersAction, but it returns null.

Is it possible to get the parameter definitions inside the groovy being called from a Jenkinsfile? Or is there a different way that would let us add an additional parameter to the job without wiping out the existing ones currently defined in the jenkinsfile?

like image 959
Jon B Avatar asked Feb 23 '18 16:02

Jon B


3 Answers

So the way we do this, is treat it all like a simple list, then join them together. So jenkinsfile's first get a list from the shared library, before adding their own to the list and then they set the params (not the shared library)

Repos jenkinsfiles do this:

#!groovy
@Library('shared') _

// Call shared libaray for common params
def paramList = jobParams.listParams ([
    "var1": "value",
    "var2": "value2"
])
// Define repo specific params
def addtionalParams = [
    booleanParam(defaultValue: false, name: 'SOMETHING', description: 'description?'),
    booleanParam(defaultValue: false, name: 'SOMETHING_ELSE', description: 'description?'),
]
// Set Jenkins job properties, combining both
properties([
    buildDiscarder(logRotator(numToKeepStr: '20')),
    parameters(paramList + addtionalParams)
])

// Do repo stuff

Our shared library looks like this:

List listParams(def body = [:]) {
    //return list of parameters
    config = BuildConfig.resolve(body)

    // Always common params
    def paramsList = [
        choice(name: 'ENV', choices: ['dev', 'tst'].join('\n'), description: 'Environment'),
        string(name: 'ENV_NO', defaultValue: "1", description: 'Environment number'),
    ]

    // Sometimes common params, switch based on jenkinsfile input
    def addtionalParams = []

    switch (config.var1) {
        case 'something':
        case 'something2':
            addtionalParams = [
                choice(name: 'AWS_REGION', choices: ['us-west-2'].join('\n'), description: 'AWS Region to build/deploy'),
            ]
            break
        case 'something3':
            addtionalParams = [
                string(name: 'DEBUG', defaultValue: '*', description: 'Namespaces for debug logging'),
            ]
            break
    }

    return paramsList + addtionalParams
}
like image 171
metalisticpain Avatar answered Sep 23 '22 21:09

metalisticpain


We did the following groovy code to retrieve the parameters definitions and add new parameters to existing ones (we don't have any knowledge about what the user will put as parameters). If you have something more simple, I take it:

boolean isSupported = true
// nParamsis the List of new parameters to add //
Map initParamsMap = this.initializeParamsMap(nParams)
currentBuild.rawBuild.getParent().getProperties().each { k, v ->
    if (v instanceof hudson.model.ParametersDefinitionProperty) {
        // get each parameter definition
        v.parameterDefinitions.each { ParameterDefinition paramDef ->
            String param_symbol_name = null
            // get the symbol name from the nested DescriptorImpl class
            paramDef.class.getDeclaredClasses().each {
                if(it.name.contains('DescriptorImpl')){
                    param_symbol_name = it.getAnnotation(Symbol).value().first()
                }
            }
            // ...  processing... //
            if( !initParamsMap.containsKey(paramDef.name) ) {
                //Valid parameter types are booleanParam, choice, file, text, password, run, or string.
                if (param_symbol_name == 'choice') {
                    String defaultParamVal = paramDef.defaultParameterValue == null ? null : paramDef.defaultParameterValue.value
                    tempParams.add(
                            "$param_symbol_name"(name: paramDef.name,
                                    defaultValue: defaultParamVal,
                                    description: paramDef.description,
                                    choices: paramDef.choices)
                    )
                } else if (param_symbol_name == 'run') {
                    logError {"buildParametersArray does not support yet already existing RunParameterDefinition " +
                            "in current job parameters list, so the job parameters will not be modified"}
                    isSupported = false
                } else {
                    tempParams.add(
                            "$param_symbol_name"(name: paramDef.name,
                                    defaultValue: paramDef.defaultParameterValue.value,
                                    description: paramDef.description)
                    )
                }
            }
        }
    }
}
if( isSupported) {
    properties([parameters(tempParams)])
}
like image 25
F. Pelucchi Avatar answered Sep 22 '22 21:09

F. Pelucchi


I think you can also do something like this:

// Get existing ParameterDefinitions
existing = currentBuild.rawBuild.parent.properties
    .findAll { it.value instanceof hudson.model.ParametersDefinitionProperty }
    .collectMany { it.value.parameterDefinitions }

// Create new params and merge them with existing ones
jobParams = [
    booleanParam(name: 'boolean_param', defaultValue: false)
    /* other params */
] + existing

// Create properties
properties([
    parameters(jobParams)
])

Note: But you should either run it in a non-sandboxed environment or use with @NonCPS

like image 20
Azat Avatar answered Sep 25 '22 21:09

Azat