Jenkins pipeline convert all parameters to lowercase - groovy

How can I convert all the parameters in a Jenkins pipeline to lowercase. Similar to trim, is there an attribute that one could add as part of the parameter declaration,
For trim, I have something like below,
parameters {
string defaultValue: '', description: 'Some dummy parameter', name: 'someparameter', trim: true
}
In my pipeline job, I have more than 10 string parameters and would like to convert them all to lowercase

Here's one approach:
pipeline {
agent any
parameters {
string ( name: 'testName', description: 'name of the test to run')
}
stages {
stage('only') {
environment {
TEST_NAME=params.testName.toLowerCase()
}
steps {
echo "the name of the test to run is: ${params.testName}"
sh 'echo "In Lower Case the test name is: ${TEST_NAME}"'
}
}
}
}

sh """ ${the_parameter.toLowerCase()} """
Need to use double quote so you have a GString
Put the toLowerCase() function call inside the brace for shell to refer back to groovy

Actually one can just do
VAR = "${VAR.toLowerCase()}"

Had to use this for my use case. It will not convert but it will prevent passing wrong value.
validatingString(name: "MYVAR",
defaultValue: "",
regex: /^[a-z0-9]+$/,
failedValidationMessage: "",
description: "")

Related

Groovy: Usage of 'it' with closures

I wonder how I can pass the implicit variable 'it' to the closure.
See the following code:
def myfunc(String name, Closure cl)
{
println("name: ${name}")
cl.call()
}
list = ['a', 'b']
list.each
{
println("it1: ${it}")
}
list.each
{
myfunc("f1")
{
println("it2: ${it}")
}
}
list.each
{
p ->
myfunc("f2")
{
println("p: ${p}")
}
}
The resulting output is:
it1: a
it1: b
name: f1
it2: null
name: f1
it2: null
name: f2
p: a
name: f2
p: b
How can I achieve that in the second version (f1/it2) the implicit variable it is passed to the closure? Currently it is "null".
I want to achieve to have 'a', 'b' within 'it' in the second version.
The background of the question is, that within a Jenkins Pipeline, the following code
mylist = ['a1', 'a2']
mylist.each {
dir ("xxxx") {
echo "it in xxxx is ${it}"
}
}
prints out the values 'a1' and 'a2' for it.
This does not fit to the understanding that it is bound to the outermost closure.
In case of Jenkins the behaviour seems to be different.
I want to achieve the very same behaviour and I am wondering how to do this.
Thanks for all feedback!
Best regards
Mathias
dir from jenkins is not a function - it's a jenkins Step and your groovy function example is not applicable.
you have to check if it's achievable from groovy-defined custom steps https://rubix.nl/jenkins-creating-a-custom-pipeline-step-in-your-library/
or think about custom plugin creation.
btw, here is a source of dir jenkins step: https://github.com/jenkinsci/workflow-basic-steps-plugin/blob/master/src/main/java/org/jenkinsci/plugins/workflow/steps/PushdStep.java

How can I replace text from a config.json file automatically by a variable in node js

Hi and thank you for your help
I have a config.json file that contains this:
{
"test": {
"hi": {
"text": "Hi ${user.name}"
}
}
}
and I have index.js file that contains:
var config = require('./config.json')
var user = {name: "Test", tag: "#1234")
console.log(`${config.test.hi.text}`) // Output: "Hi ${user.name}"
// Expected output: Hi Test
I want when you change in the config.json the user.name to something like user.tag its automatically replaces him without .replace() function
thank you for your help :D
When using Template literals, the expressions in the placeholders and the text between the backticks (` `) get passed to a function that concatenates the strings into a single string, replacing the values inside $(variable).
This process happens at the time you define the template and cannot be resolved later as you do in your code. Refer to the documentation: Template literals
It would be also a bad coding practise as if the user variable didn't exist in the index.js file it wouldn't give you a compile error, but a nasty runtime error.
The only way to do it is to have your template literal in reach of your variable scope, that means that the template literal can read the variable at the moment it's executed. If you want to have the user instance and the template in different files, you can use a callback function as this:
config.js
const callback = (user) => {
return `Hi ${user.name}`
}
const config = {
callback,
anotherConfig: {
hi: {
example: "This is another config"
}
}
}
export default config;
index.js
import config from './config.js';
const user = {name: "Test", tag: "#1234"};
console.log(config.callback(user))
Output
Hi Test

Populate choice parameter in jenkinsfile with list of folders in SCM repository

I've got a Jenkinsfile that drives a pipeline which the user must select a specific folder in a bitbucket repo to target. I want that choice parameter dropdown to be dynamically populated.
Currently, I've got the choice param list hardcoded as per this generic example:
choice(name: 'IMAGE', choices: ['workload-x','workload-y','workload-z'])
I wondered if this is possible from within the jenkinsfile itself, or whether I'd have to create a specific groovy script for this then call it. Either way I'm a bit lost as I'm pretty new to jenkins and have only just started working with Jenkinsfiles.
Some trial and error googling has allowed me to create a groovy script which returns an array of folder names in the repository using json slurper:
import groovy.json.JsonSlurper
import jenkins.model.Jenkins
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.Credentials.class,
Jenkins.instance,
null,
null
);
def credential = creds.find {it.id == "MYBITBUCKETCRED"}
if (!credential) { return "Unable to pickup credential from Jenkins" }
username = credential.username
pass = credential.password.toString()
def urlStr = "https://bitbucket.mydomain.com/rest/api/1.0/projects/MYPROJECT/repos/MYREPO/browse/"
HttpURLConnection conn = (HttpURLConnection) new URL(urlStr).openConnection()
String encoded = Base64.getEncoder().encodeToString((username + ":" + pass).getBytes("UTF-8"));
conn.setRequestProperty("Authorization", "Basic " + encoded);
conn.connect();
def slurper = new JsonSlurper()
def browseList = slurper.parseText(conn.getInputStream().getText())
def dfList = browseList.children.values.path.name.findAll {it.contains('workload-')}
return dfList
This returns a result as follows:
Result: [workload-a,workload-b,workload-c,workload-x,workload-y,workload-z]
However I'm unsure how then to call this in my Jenkinsfile in order to populate the dropdown.
Any help would be greatly appreciated.
you can do it this way (follow my example below) or make use of Active Choice Jenkins Plugins - because It allows some groovy scripting to prepare your choice
Note- The Choice parameter will be available after a first run.
def choiceArray = []
node {
checkout scm
def folders = sh(returnStdout: true, script: "ls $WORKSPACE")
folders.split().each {
//condition to skip files if any
choiceArray << it
}
}
pipeline {
agent any;
parameters { choice(name: 'CHOICES', choices: choiceArray, description: 'Please Select One') }
stages {
stage('debug') {
steps {
echo "Selected choice is : ${params.CHOICES}"
}
}
}
}
I used the previous example to load the list in the same build
I send the command output to a file, to be consumed in the next step
Here the jenkinsfile:
def choiceArray = []
pipeline {
agent any
parameters {
string defaultValue: '', description: 'PATH_to_scripts', name: 'SCRIPTPATH', trim: false
string defaultValue: '', description: 'Optional parameters', name: 'MOREparams', trim: false
}
stages {
stage('show available date') {
steps {
sh '''
echo $JENKINS_HOME
cd $JENKINS_HOME/scripts
./0_db_show_available.sh $DBlike $AWS_PROFILE $DATEFILTER > $JENKINS_HOME/scripts/lista.txt
echo "Show available date"
cat $JENKINS_HOME/scripts/lista.txt
'''
}
}
stage('Restore') {
steps {
script {
def folders = sh(returnStdout: true, script: "cat $JENKINS_HOME/scripts/lista.txt")
//load the array using the file content (lista.txt)
folders.split().each {
choiceArray << it
}
// wait for user input
def INPUT_DATE = input message: 'Please select date', ok: 'Next',
//generate the list using the array content
parameters: [ choice(name: 'CHOICES', choices: choiceArray, description: 'Please Select One') ]
}
}
}
}
}
samit-kumar-patel, thanks for first example, it helps me

Substitute values from property file in Jenkinsfile for dynamically set variables

I have a Jenkinsfile with multiple parameters that are environment-specific.
The values for those parameters are stored in a property file. I am trying to set the variables based upon the selected environment and then replace their values from the property files.
Jenkinsfile
ENVIRONMENT is a choice parameter having 2 values: ft, perf and pm as below in my Jenkinsfile
choice (
name: 'ENVIRONMENT',
choices: ['ft', 'perf','pm'],
description: 'please select the environment'
)
PROPERTY_FILE is another choice parameter as below
choice (
name: 'PROPERTY_FILE',
choices: ['jenkins/app.groovy'],
description: 'please select the property file'
)
app.groovy looks like:
Test_perf="Hello"
Test_ft="World"
Test_pm="Welcome"
Stages
stage('Load Environment Property File') {
steps {
script {
//sourcing user selected property file
load "${PROPERTY_FILE}"
def envName = "${PROPERTY_FILE}".tokenize(".")[0]
//it will set build description as description in Jenkins build history
env.envName=envName
currentBuild.description = "Env:${envName}"
}
}
}
//STAGE FOR WHICH I NEED HELP
stage('Set Variables Based upon environment name') {
steps {
script{
if ("${ENVIRONMENT}" == "perf" ){
var="\${Test_"+"${DEPLOYMENT_ENVIRONMENT}"+"}"
echo "${var}" //output is ${Test_pm} and is correct as the substitution happens.
//NOW, I AM TRYING TO echo "HELLO", i.e.; replacing the variable "${Test_perf}" stuffed inside "var" from the property file. However, since the property file is already loaded, it will not replace the key by its value from the property file.
} else if ("${ENVIRONMENT}" == "ft" ){
var="\${Test_"+"${DEPLOYMENT_ENVIRONMENT}"+"}"
echo "${var}" //output is ${Test_ft} and is correct as the substitution happens.
//NOW, I AM TRYING TO echo "World"
} else {
var="\${Test_"+"${DEPLOYMENT_ENVIRONMENT}"+"}"
echo "${var}" //output is ${Test_pm} and is correct as the substitution happens.
//NOW, I AM TRYING TO echo "Welcome"
}
}
}
}
Is there a way to further substitute the value from the property file. For e.g.; "${var}" expands to "${Test_pm}" and then "${Test_pm}" gets the value "Welcome" from the property file.
Please help.

How can I optimize switch-cases?

I've got a switch case like this:
def someString = 'hello1234bla'
// ...
switch (someString) {
case {it.contains('1234')}:
doSomething()
break
case {it.contains('2468')}:
doSomethingElse()
break
default:
throw new Exception("ERROR: Number not found")
break
}
This seems to be quite a lot of code for something so seemingly simple. All I want is to have different functions be executed when someString contains a specific substring. Is there no simpler way to do this, apart from maybe an if-else cascade?
This is pretty close to what the comments above suggest, but I'll write out a working example with indentation etc and perhaps it will be a bit more readable:
def someString = "hello1234bla"
def found = [
'1234': { println "do something" },
'2468': { println "do something else" }
].find { pattern, action ->
if (someString.contains(pattern)) { action(); true }
else false
}
if (!found) throw new Exception("ERROR: Number not found")
this executes the first matching action and throws an exception if no matches were found. If you need to execute an action for every match, replace the find call with a findAll call.
Another way of executing code based on a pattern in the string is the groovy String eachMatch method:
def someString = "hello1234blae"
someString.eachMatch(/1234/) { println "do something" }
someString.eachMatch(/2468/) { println "do something else" }
which uses regular expressions and runs the closure (the block in the curlies after the eachMatch call) once for every match. Thus:
someString.eachMatch(/e/) { println "runs twice" }
on the above string would execute twice as there are two 'e' characters in the string.

Resources