A deep dive into Jenkins job parameters as code, with both runtime AND UI validation
Skip to the end of this post for just the code examples, without any of the explanations.
Let’s say you have a job which facilitates self service. You accept all sorts of parameters. One day, a developer opens a ticket saying “the job is broken! Please help asap!” So, like any good devops engineer, you drop your own work, spend some time debugging only to find… the parameter name was wrong. You fix the typo, run a new build and voila, the job passes, never having been broken at all. “What dumb users,” you giggle to yourself. “*I* would NEVER do something so stupid!”
Well, you will, and I will, and so will everyone else. That’s why we need code to validate all user inputs, and yep, that’s exactly what we’ll be doing today.
First off: You need to be using a Shared Library. These are key for code reusability in Jenkins, and parameters (and their validations) are no exception.
In case you aren’t already familiar, there is a directory called “vars” inside the shared library. Once you import the shared library to your pipeline, you can then access any variable or function defined in any .groovy file under the vars directory.
I won’t be explaining how to create and set up a shared library in Jenkins; there are already lots of guides covering this. Once you have the library set up (and be sure to use the modern SCM option when you set it up), you will be able to import the library.
To import the shared library to your Jenkinsfile, do:
@Library('MySharedLibrary@library-repo-branch') _
pipeline { // As you can see, the library is the very first line in the file.
The next step is setting parameters in the Jenkinsfile. Let’s take a moment and discuss how that’s done:
environment {
SKIP_STAGES = "${params.REFRESH_PARAMETERS}"
}
stages {
stage('Setup Parameters') {
//run only if refresh_parameters checked
when {
environment (name: 'SKIP_STAGES', value: 'true')
}
steps {
script {
println('INFO: This run will not run other stages')
currentBuild.description = "REFRESH PARAMETERS"
properties([
parameters([
booleanParam(
name: 'REFRESH_PARAMETERS',
defaultValue: false,
description: 'Read Jenkinsfile and exit.'
),
string(name: 'SERVER_NAME', required: true),
string(name: 'OS_IMAGE', defaultValue: 'ubuntu-24'),
]
])
jenkinsGeneric.haltBuildWithSuccess('Refreshed parameters and quit')
}
}
}
The most interesting thing in this first little snippet is the SKIP_STAGES environment variable. What happens is that when you go to the “build job” screen, the first parameter is a checkbox. If the checkbox is selected, and you build the job, the Setup Parameters
stage runs. Because the parameter is set to false by default, and because the whole stage has a when
clause, we can decide when to refresh our parameters, essentially loading them from the Jenkinsfile, while not wasting time doing this on each build.
The next thing of note is the function haltBuildWithSuccess
at the end — read more about it in this post. There’s quite a bit of overlap with this one, so here is the function, to be used anywhere you like:
def haltBuildWithSuccess(String stopReason = 'Build halted programmatically with SUCCESS status') {
currentBuild.rawBuild.@result = Result.SUCCESS
def cause = new CauseOfInterruption.UserInterruption(stopReason)
throw new FlowInterruptedException(Result.SUCCESS, false, cause)
}
Okay, so now we know how to set parameters in the Jenkinsfile. Onwards, to the shared parameters!
In my shared library, I have a vars file called sharedParameters.groovy.
As one might assume, sharedParameters is a shared library vars file which returns parameters which are used in many jobs, and it looks a little something like this:
def userSeparator(styling = 'color: whitesmoke; background: PaleVioletRed; text-align: center; font-weight: bold;', text = 'User Parameters'){
[$class: 'ParameterSeparatorDefinition',
name: 'USER_HEADER',
sectionHeader: text,
separatorStyle: 'border: 0;',
sectionHeaderStyle: styling
]
}
def refreshParameters() {
[booleanParam(
name: 'REFRESH_PARAMETERS',
defaultValue: false,
description: 'Read Jenkinsfile and exit.'
)]
}
def branchName(String defaultBranch = 'main') {
[
[
string(
name: 'BRANCH_NAME',
defaultValue: defaultBranch,
description: 'Which branch of Jenkins pipeline to deploy'
)
],
paramValidator('BRANCH_NAME')
]
}
def username() {
[
[$class: 'ChoiceParameter',
choiceType: 'PT_SINGLE_SELECT',
filterLength: 1,
filterable: false,
name: 'USERNAME',
script: [
$class: 'GroovyScript',
script: [
classpath: [],
sandbox: false,
script: '''\
try {
"[hudson.model.User.current().getId().toUpperCase()]"
}
catch(Exception e) {
return [e.toString()]
}
'''
]
]
],
paramValidator('USERNAME')
]
}
Naturally, there are a whole lot more parameters here in real life.
Remember that these vars files are simply groovy files containing functions. Each function defined in the sharedParameters file simply returns a list element including a valid parameter. Why a list, you may ask? Because ChoiceParameters return their selection as a list, even if only a single element.
With all that in mind, we can now move all of our reusable parameters into the sharedParameters file, and call them from our Jenkinsfiles:
stages{
stage('Setup parameters') {
//run only if REFRESH_PARAMETERS checked
when {
environment (name: 'SKIP_STAGES', value: 'true')
}
steps {
script {
println('INFO: This run will not run other stages')
currentBuild.description = "REFRESH PARAMETERS"
properties([
parameters([
sharedParameters.refreshParameters(),
sharedParameters.branchName('main'), // specifies what branch of a jenkinsfile will be run
string(name: 'SERVER_NAME'),
].flatten())
])
jenkinsGeneric.haltBuildWithSuccess('Refreshed parameters and quit')
}
}
}
Okay, so we have set our parameters as callable functions in a shared library, and now we want to validate them.
We have another file under vars, and this one is called paramValidator.groovy.
This file is a bit complicated, so before we get into exactly what’s in it and how it works, let’s go over what we need to happen at this step:
- Fail Early.
We don;t want a situation where an incorrect parameter can cause an error after a few minutes of runtime — we want the job to fail immediately. Ideally, it would not even run at all. Therefore, the first step is at the UI level — we need a way to prevent the user from even running the build at all, if the parameters are incorrect.
We do this by adding a DynamicReferenceParameter
immediately after the parameter which we are validating. This parameter is invisible, it has no name or value, but it can still be used reactively to the parameter we are validating. Here’s what it looks like in practice:
Not only does this immediately tell the user that something is wrong, we also set the invisible parameter’s type to ET_FORMATTED_HTML, which we use to hide the build button from the UI.
That’s all well and good, but what if the user calls the job programmatically, or hits rebuild and changes the parameters? That’s where runtime validations come in.
The way that the paramValidator file works is that it has a call
function, which runs if the file is called with no specific function. This function returns the invisible HTML parameter, and it looks like this:
def call(String paramName) {
return [$class: 'DynamicReferenceParameter',
choiceType: 'ET_FORMATTED_HTML',
referencedParameters: paramName,
omitValueField: true,
description: '',
name: '',
randomName: 'choice-parameter-245311171714082',
script: [
$class: 'GroovyScript',
fallbackScript: [
classpath: [],
sandbox: false,
script: ""
],
script: [
classpath: [],
sandbox: true,
script: validateParams(paramName, 'UI')
]
]
]
}
Notice how other than setting it to be mostly invisible and giving it a type, we also call a function validateParams(). This is where the magic happens.
@Field final String hideBuildButton = '<style>.jenkins-button--primary, #yui-gen2-button { display: none; }</style>'
@Field final String hiddenInput = "<input type='hidden' name='value' value='XXXXXXXXXXXXXXXXXXXXXXXXXXXX'>"
def validateParams(String paramName, String paramSender='code') {
String paramScript
String okMsg
String errorMsg
String paramValidityChecker
switch (paramName) {
case "BRANCH_NAME":
okMsg = 'Branch name looks OK'
errorMsg = 'No branch selected.'
paramValidityChecker = "if ( ${paramName} == '' || ${paramName} == 'error' )"
break
case "USERNAME":
okMsg = 'Username seems OK'
errorMsg = 'No Username. Are you logged in?'
paramValidityChecker = "if ( ${paramName} == '' || ${paramName} == 'error' )"
break
}
// Checks if param is OK as defined above in the switch case. If not, it will immediately return an error with the message we set earlier.
// This is run only from the parameters stage, which means that the logic in paramScript gets run BEFORE runtime, within the referenced parameters
if ( paramSender == 'UI' ) {
// This is a string builder and we directly continue the 'if' statement which is stored in $paramValidityChecker, and concat both the curly braces and the logic.
paramScript = """\
okMsg = '$okMsg'
$paramValidityChecker {
errorMsg = "$errorMsg"
""".stripIndent() // The rest of the logic and the closing brace are in the return statement below.
return """
$paramScript
return \"\"\"\
$hideBuildButton
<span style='color:red'>❌ \$errorMsg</span>
$hiddenInput
\"\"\".trim().stripIndent()
}
return \"\"\"
<span style='color:green'>✅ \$okMsg</span>
$hiddenInput
\"\"\"
""".stripIndent()
} else {
// This is run by any validation not in the parameters stage - IE these get run at runtime and not before it.
paramValue = "${params[paramName]}" // This is to get the value of the parameter, since in a 'code' we don't have access to the referenced paramneter like we do with 'UI'
paramValidityChecker = paramValidityChecker.replaceAll(paramName, "'" + paramValue + "'") // We actually only want to check the value, we don't care about the parameter name
// This finalizes the conditional logic, and finishes using the conditional string we built earlier in the switch/case
def runtimeValidityEvaluator = """
$paramValidityChecker {
return("errorMsg")
} else {
return("okMsg")
}
"""
env.errorMsg = errorMsg
// this is what actually evaluates whether the parameter is valid or not, and prints an OK message if the parameter didn't throw an error
Eval.me(runtimeValidityEvaluator) == 'okMsg' ? println(okMsg) : error(env.errorMsg)
}
}
Whenever this function is called, it accepts an argument paramName. This argument is checked against a switch case statement. Based on the parameter name we receive, we apply different validations, and output different error and success messages. However, at this point, we have not actually executed the validation code, only set it into a variable called paramValidityChecker. This is a string, which will eventually make its way into the script section of the job parameter.
In this example, we have only done very simple validations. Further on’ Ill also discuss more complex ones. For now, let’s understand how this switch is used.
As mentioned, paramValidityChecker is simply a string containing groovy code. Notice that it is not actually syntactically correct — the code cuts out immediately after an if clause, without even closing it.
After adding our cases to the switch, we need to validate the value we received. Again, this same validation must be applied both at runtime, and before runtime, at the parameter selectionBuild with Parameters screen.
The call function is the one that gets run from the UI, and it passes the second argument which is needed by validateParams() — essentially telling it not to apply the validation, but rather return it to the parameter. In this case, that means it is never run at all — only when a user clicks “build with parameters” will the validator code be run. The relevant piece of the function is this:
paramScript = """\
okMsg = '$okMsg'
$paramValidityChecker {
errorMsg = "$errorMsg"
""".stripIndent()
Here, we’ve simply continued building our if code block from the switch statement from above (isng the BRANCH_NAME param as an example):
okMsg = 'Branch name looks OK'
errorMsg = 'No branch selected.'
paramValidityChecker = "if ( ${paramName} == '' || ${paramName} == 'error' )"
This way, paramScript will contain:
okMsg = '$okMsg'
if ( ${paramName} == '' || ${paramName} == 'error' ) {
errorMsg = "$errorMsg"
At this point our code is beginning to take shape, but we still aren’t done. We still have to do something with the error message:
return """
$paramScript
return \"\"\"\
$hideBuildButton
<span style='color:red'>❌ \$errorMsg</span>
$hiddenInput
\"\"\".trim().stripIndent()
}
return \"\"\"
<span style='color:green'>✅ \$okMsg</span>
$hiddenInput
\"\"\"
""".stripIndent()
See all the escaping? That’s because we are generating code which will eventually be the parameter’s script.
The first return statement will return the entire if block, containing the final string, which is now fully built, looking like this:
okMsg = '$okMsg'
if ( ${paramName} == '' || ${paramName} == 'error' ) {
errorMsg = "$errorMsg"
return """
$hideBuildButton
<span style='color:red'>❌ $errorMsg</span>
$hiddenInput
}
return """
<span style='color:green'>✅ $okMsg</span>
$hiddenInput
"""
As you can see, the final generated code is quite readable, and this is the script within the invisible, reactive parameter:
Now, on to runtime validation. As you’ll recall, paramValidator accepts a flag which can contain ‘code’ or ‘ui’. We’ve already seen how UI is handled. So what happens if we want to run the validation during the build?
This is the “else” clause in the middle of paramValidator, and this one is similar but easier to understand.
We don’t need to build convoluted statements with HTML or anything, we just need to execute the code. So first we finish building the if clause string from the switch case above, into a variable called runtimeValidityEvaluator…
if ( paramSender == 'UI' ) {
// discussed above
}
else {
// This is run by any validation not in the parameters stage - IE these get run at runtime and not before it.
paramValue = "${params[paramName]}" // This is to get the value of the parameter, since in a 'code' we don't have access to the referenced paramneter like we do with 'UI'
paramValidityChecker = paramValidityChecker.replaceAll(paramName, "'" + paramValue + "'") // We actually only want to check the value, we don't care about the parameter name
// This finalizes the conditional logic, and finishes using the conditional string we built earlier in the switch/case
def runtimeValidityEvaluator = """
$paramValidityChecker {
return("errorMsg")
} else {
return("okMsg")
}
"""
// runtimeValidityEvaluator will contain:
okMsg = '$okMsg'
if ( ${paramName} == '' || ${paramName} == 'error' ) {
return("errorMsg")
}
else {
return("okMsg")
}
// Notice that we return string literals, which indicate the result
…And then we run it!
env.errorMsg = errorMsg
// this is what actually evaluates whether the parameter is valid or not, and prints an OK message if the parameter didn't throw an error
Eval.me(runtimeValidityEvaluator) == 'okMsg' ? println(okMsg) : error(env.errorMsg)
If the runtimeValidityEvaluator equals the literal string okMsg, we just print that message. If not, we throw an error right away.
Therefore, to validate a parameter at runtime, all we need to do is this:
stage('Parameters Check') {
steps {
script {
paramValidator.emptyParameterChecker(['PARAM_NAME', 'OTHER_PARAM_NAME'])
paramValidator('BRANCH_NAME')
}
}
}
It is important to note that some code will not run inside the Eval statement, because it is a very limited environment which does not have access to the jenkins classpath — so you can’t import things like Jenkins.model, or hudson.* . So, for code that uses that kind of thing, you need to build the paramValidityChecker conditionally:
paramValidityChecker = '''\
'''
if (paramSender == 'UI') {
paramValidityChecker += '''
import hudson.model.User
import jenkins.*
import jenkins.model.*
import hudson.*
import hudson.model.*
def getApiToken (credId) {
tokenCredId = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.Credentials.class,
Jenkins.instance,
null,
null
).find{it.id == "${credId}"}
return tokenCredId.secret.getPlainText()
}
rancherToken = getApiToken("''' + globals.RANCHER_RND_ADMIN_BEARER_TOKEN_CRED_ID + '''")
bitbucketToken = getApiToken("''' + globals.BUILDUSER_BITBUCKET_API_TOKEN_CRED_ID + '''")
'''
} else {
withCredentials([
string(credentialsId: globals.RANCHER_RND_ADMIN_BEARER_TOKEN_CRED_ID, variable: 'rancherToken'),
string(credentialsId: globals.BUILDUSER_BITBUCKET_API_TOKEN_CRED_ID, variable: 'bitbucketToken')
]) {
paramValidityChecker += """
rancherToken = '$rancherToken'
bitbucketToken = '$bitbucketToken'
"""
}
}
The emptyParameterChecker function is not complex; it just iterates over a list of parameters and makes sure they are not empty. This is mainly only useful for parameters which are not in the shared library.
def emptyParameterChecker(List paramsToCheck) {
env.errorMsg = ""
paramsToCheck.each { paramName ->
def paramValue = params."${paramName}" // Access the parameter dynamically by its name, even though we didn't actually pass the value to this function
if (!paramValue || paramValue.toString().isEmpty() || paramValue == 'null') {
env.errMsg += "The parameter ${paramName} is empty or undefined.\n"
}
}
if (env.errorMsg) {
error(env.errorMsg)
}
}
Some notes:
With paramValidator, we are eventually returning a list of parameters consisting of the actual parameter, and the invisible validator parameter. So we need to flatten the Jenkinsfile’s list of parameters:
properties([
parameters([
sharedParameters.refreshParameters(),
sharedParameters.branchName('feature/DVPS-9717-helm-vm'),
sharedParameters.userSeparator('color: whitesmoke; background: PaleVioletRed; text-align: center; font-weight: bold;'),
sharedParameters.username(),
string(name: 'SERVER_TYPE', defaultValue: 'srv'),
paramValidator.unhideBuild()
].flatten())
])
Another important thing to note is that if any parameters fail validation, you won’t be able to run the job to refresh parameters because the build button will be hidden. That’s why we have yet another function in paramValidator:
// This allows the "build" button to appear when "refresh_parameters" is selected
def unhideBuild() {
return [$class: 'DynamicReferenceParameter',
choiceType: 'ET_FORMATTED_HTML',
referencedParameters: 'REFRESH_PARAMETERS',
omitValueField: true,
description: '',
name: '',
randomName: 'choice-parameter-245311171714082',
script: [
$class: 'GroovyScript',
fallbackScript: [
classpath: [],
sandbox: false,
script: ""
],
script: [
classpath: [],
sandbox: true,
script: '''\
if (REFRESH_PARAMETERS) {
return '<style>.jenkins-button--primary, #yui-gen2-button { display: block; }</style>'
}
'''
]
]
]
}
Lastly, we can also have complex validations, not only the simple ones we’ve use as examples. Pretty much any groovy code is OK here:
case "RAM":
okMsg = 'Requested RAM OK'
errorMsg = 'RAM must be an integer between 1 and 32.'
paramValidityChecker = """\
boolean isValidNumber(resource) {
def isNum = ( resource.isInteger() ) ? true : false
if (!isNum) {
return false
} else if ( (resource.toInteger() > 0) && (resource.toInteger() < 32) ) {
return true
} else {
return false
}
}
if ( ${paramName} == '' || !isValidNumber(${paramName}) )
""".stripIndent()
break
case "IP":
okMsg = 'IP Address looks OK'
errorMsg = 'IP address was incorrectly formatted'
paramValidityChecker = """\
boolean validIPAddress(String ipAddress) {
def regexPattern = ~/\\d+\\.\\d+\\.\\d+\\.\\d+/
def matcher = (ipAddress =~ regexPattern)
def containsIP = ( matcher.find() ) ? true : false
return containsIP
}
if ( ${paramName} == '' || !validIPAddress(${paramName}) )
""".stripIndent()
break
I’ve even gone so far as to use a binary on the jenkins master to dynamically validate whether a selected project is valid:
case "RANCHER_PROJECT":
paramValidityChecker = '''\
import hudson.model.User
import jenkins.*
import jenkins.model.*
import hudson.*
import hudson.model.*
bearerTokenCredId = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.Credentials.class,
Jenkins.instance,
null,
null
).find{it.id == "''' + globals.POC_RANCHER_ADMIN_BEARER_TOKEN_CRED_ID +'''"}
bearerToken = bearerTokenCredId.secret.getPlainText()
rancherCli = "''' + globals.RANCHER_CLI_PATH + '''"
rancherUrl = "''' + globals.POC_RANCHER_URL + '''"
rancherClusterId = "''' + globals.POC_RANCHER_CLUSTER_ID + '''"
rancherSystemProjectId = "''' + globals.POC_RANCHER_SYSTEM_PROJECT_ID + '''"
rancherContext = "${rancherClusterId}:${rancherSystemProjectId}"
rancherLoginCommand = "${rancherCli} login ${rancherUrl} --token ${bearerToken} --skip-verify --context ${rancherContext}"
'''+"""
rancherLoginCommand.execute()
def getProjectsOutputCommand = rancherCli + ' projects list | grep -v -e "Default" -e "System" -e "ID" | awk \\'{print \$2}\\''
def projects = ['bash', '-c', getProjectsOutputCommand].execute()in.text
def projectsList = projects.toLowerCase().split('\\n').toList()
if ( ${paramName} == '' || ${paramName} == 'error' || !projectsList.contains(${paramName}.toLowerCase()) )
""".stripIndent()
okMsg = 'Valid Project'
errorMsg = 'The Project ${' + paramName + ".toLowerCase()} is not present in your projects: \${projectsList.toString()}"
break
You can really implement any custom logic you want.
TLDR complete code samples:
vars/paramValidator.groovy
:
#!/usr/bin/env groovy
import groovy.transform.Field
def emptyParameterChecker(List paramsToCheck) {
env.errorMsg = ""
paramsToCheck.each { paramName ->
def paramValue = params."${paramName}" // Access the parameter dynamically by its name, even though we didn't actually pass the value to this function
if (!paramValue || paramValue.toString().isEmpty() || paramValue == 'null') {
env.errMsg += "The parameter ${paramName} is empty or undefined.\n"
}
}
if (env.errorMsg) {
error(env.errorMsg)
}
}
@Field final String hideBuildButton = '<style>.jenkins-button--primary, #yui-gen2-button { display: none; }</style>'
@Field final String hiddenInput = "<input type='hidden' name='value' value='XXXXXXXXXXXXXXXXXXXXXXXXXXXX'>"
def validateParams(String paramName, String paramSender='code') {
String paramScript
String okMsg
String errorMsg
String paramValidityChecker
switch (paramName) {
case "BRANCH_NAME":
okMsg = 'Branch name looks OK'
errorMsg = 'No branch selected.'
paramValidityChecker = "if ( ${paramName} == '' || ${paramName} == 'error' )"
break
case "USERNAME":
okMsg = 'Username seems OK'
errorMsg = 'No Username. Are you logged in?'
paramValidityChecker = "if ( ${paramName} == '' || ${paramName} == 'error' )"
break
default:
errorMsg = "The parameter '${paramName}' was passed to the shared library at paramValidator.validateParams(), but does not have an associated validation. Please add a case for it."
paramValidityChecker = "if ( true )"
break
}
// Checks if param is OK as defined above in the switch case. If not, it will immediately return an error with the message we set earlier.
// This is run only from the parameters stage, which means that the logic in paramScript gets run BEFORE runtime, within the referenced parameters
if ( paramSender == 'UI' ) {
// This is a string builder and we directly continue the 'if' statement which is stored in $paramValidityChecker, and concat both the curly braces and the logic.
paramScript = """\
okMsg = '$okMsg'
$paramValidityChecker {
errorMsg = "$errorMsg"
""".stripIndent() // The rest of the logic and the closing brace are in the return statement below.
return """
$paramScript
return \"\"\"\
$hideBuildButton
<span style='color:red'>❌ \$errorMsg</span>
$hiddenInput
\"\"\".trim().stripIndent()
}
return \"\"\"
<span style='color:green'>✅ \$okMsg</span>
$hiddenInput
\"\"\"
""".stripIndent()
} else {
// This is run by any validation not in the parameters stage - IE these get run at runtime and not before it.
paramValue = "${params[paramName]}" // This is to get the value of the parameter, since in a 'code' we don't have access to the referenced paramneter like we do with 'UI'
paramValidityChecker = paramValidityChecker.replaceAll(paramName, "'" + paramValue + "'") // We actually only want to check the value, we don't care about the parameter name
// This finalizes the conditional logic, and finishes using the conditional string we built earlier in the switch/case
def runtimeValidityEvaluator = """
$paramValidityChecker {
return("errorMsg")
} else {
return("okMsg")
}
"""
env.errorMsg = errorMsg
// this is what actually evaluates whether the parameter is valid or not, and prints an OK message if the parameter didn't throw an error
Eval.me(runtimeValidityEvaluator) == 'okMsg' ? println(okMsg) : error(env.errorMsg)
}
}
// This allows the "build" button to appear when "refresh_parameters" is selected
def unhideBuild() {
return [$class: 'DynamicReferenceParameter',
choiceType: 'ET_FORMATTED_HTML',
referencedParameters: 'REFRESH_PARAMETERS',
omitValueField: true,
description: '',
name: '',
randomName: 'choice-parameter-245311171714082',
script: [
$class: 'GroovyScript',
fallbackScript: [
classpath: [],
sandbox: false,
script: ""
],
script: [
classpath: [],
sandbox: true,
script: '''\
if (REFRESH_PARAMETERS) {
return '<style>.jenkins-button--primary, #yui-gen2-button { display: block; }</style>'
}
'''
]
]
]
}
def call(String paramName) {
return [$class: 'DynamicReferenceParameter',
choiceType: 'ET_FORMATTED_HTML',
referencedParameters: paramName,
omitValueField: true,
description: '',
name: '',
randomName: 'choice-parameter-245311171714082',
script: [
$class: 'GroovyScript',
fallbackScript: [
classpath: [],
sandbox: false,
script: ""
],
script: [
classpath: [],
sandbox: true,
script: validateParams(paramName, 'UI')
]
]
]
}
vars/sharedParameters.groovy
:
#!/usr/bin/env groovy
def userSeparator(styling = 'color: whitesmoke; background: PaleVioletRed; text-align: center; font-weight: bold;', text = 'User Parameters'){
[$class: 'ParameterSeparatorDefinition',
name: 'USER_HEADER',
sectionHeader: text,
separatorStyle: 'border: 0;',
sectionHeaderStyle: styling
]
}
def refreshParameters() {
[booleanParam(
name: 'REFRESH_PARAMETERS',
defaultValue: false,
description: 'Read Jenkinsfile and exit.'
)]
}
def branchName(String defaultBranch = 'master') {
[
[
string(
name: 'BRANCH_NAME',
defaultValue: defaultBranch,
description: 'Which branch of Jenkins pipeline to deploy'
)
],
paramValidator('BRANCH_NAME')
]
}
Jenkinsfile
:
@Library('MySharedLibrary') _
pipeline {
agent {
label 'buildmachines'
}
options {
timestamps()
timeout(time: 3, unit: 'MINUTES')
ansiColor('xterm')
}
environment {
SKIP_STAGES = "${params.REFRESH_PARAMETERS}"
}
stages {
stage('Setup Parameters') {
//run only if refresh_parameters checked
when {
environment (name: 'SKIP_STAGES', value: 'true')
}
steps {
script {
println('INFO: This run will not run other stages')
currentBuild.description = "REFRESH PARAMETERS"
properties([
parameters([
sharedParameters.refreshParameters(),
sharedParameters.branchName('feature/using-shared-library'),
sharedParameters.userSeparator('color: whitesmoke; background: PaleVioletRed; text-align: center; font-weight: bold;'),
sharedParameters.username(),
string(name: 'SERVER_NAME', defaultValue: 'srv'),
string(name: 'SERVER_ID', defaultValue: 'srv'),
sharedParameters.k8sProject(),
paramValidator.unhideBuild()
].flatten())
])
jenkinsGeneric.haltBuildWithSuccess('Refreshed parameters and quit')
}
}
}
stage('Parameters Check') {
steps {
script {
paramValidator.emptyParameterChecker(['SERVER_NAME', 'SERVER_ID'])
paramValidator('K8S_PROJECT')
// Error if CPU or RAM is not an integer within the allowed range. Cuuently both are set to 1-32 but each can be changed separately.
paramValidator('RAM')
paramValidator('CPU')
}
}
}
stage('Run actual pipeline stages here...') {
}
}
post {
always {
println('Cleaning up')
cleanWs()
}
}
}