I am using branch name to pass it into build script. $(env.BRANCH_NAME).
I would like to manipulate the value before using it. For example in case we build from trunk I want suffix for the build output be empty but in case of branch I want it to be -branch name.
currently I am doing it by defining environment section.
environment {
OUTPUT_NAME_SUFFIX = ($(env.BRANCH_NAME) == 'trunk') ? '': $(env.BRANCH_NAME)
}
I am getting this error:
WorkflowScript: 4: Environment variable values must either be single quoted, double quoted, or function calls. # line 4, column 62.
(env.BRANCH_NAME) == 'trunk') ? '': $(en
^
What the best way to define variables and eval their values in scope of pipeline.
TIA
You can use string interpolation to evaluate the expression:
environment {
OUTPUT_NAME_SUFFIX = "${env.BRANCH_NAME == 'trunk' ? '': env.BRANCH_NAME}"
}
This will fix the error you're getting, however pipeline does not allow you to have environment variables that are of 0 length, aka empty string (JENKINS-43632).
That means that setting OUTPUT_NAME_SUFFIX to '' is like unseting it. You might want to precalculate the whole name of your output, so that your env variable is never an empty string.
I have solved it by adding following code. So far had no issues with empty strings.
stage('Set Environmnet'){
steps {
script {
if(BRANCH_NAME == 'trunk'){
env.OUTPUT_NAME_SUFFIX = ''
}else if (BRANCH_NAME.startsWith("branches")){
env.OUTPUT_NAME_SUFFIX = "-" + BRANCH_NAME.substring(BRANCH_NAME.lastIndexOf("/")+1)
}else{
env.OUTPUT_NAME_SUFFIX = ''
}
}
}
}
Related
I'm trying to grok the rules surrounding variables in Groovy/Jenkinsfiles/declarative syntax.
The generic webhook trigger captures HTTP POST content and makes them available as variables available to your Jenkinsfile. E.g.:
pipeline {
agent any
triggers {
GenericTrigger (
genericVariables: [
[ key: "POST_actor_name", value: "\$.actor.name" ]
],
token: "foo"
)
}
stages {
stage( "Set up" ) {
steps {
script {
echo "env var ${env.actor_name}"
echo "global var ${actor_name}"
}
}
}
}
If the HTTP POST content contains a JSON object with an actor_name field valued "foo", then this prints:
env var foo
global var foo
If the HTTP POST content does not contain the JSON field actor_name, then this prints
env var null
...then asserts/aborts with a No such property error.
Jenkins jobs also have a "this project is parameterized" setting, which seems to introduce yet another way to inject variables into your Jenkinsfile. The following Jenkinsfile prints a populated, parameterized build variable, an unpopulated one, and an intentionally nonexistent variable:
pipeline {
agent any
stages {
stage( "Set up" ) {
steps {
script {
echo "1 [${env.populated_var}]"
echo "2 [${env.unpopulated_var}]"
echo "3 [${env.dontexist}]"
echo "4 [${params.populated_var}]"
echo "5 [${params.unpopulated_var}]"
echo "6 [${params.dontexist}]"
echo "7 [${populated_var}]"
echo "8 [${unpopulated_var}]"
echo "9 [${dontexist}]"
}
}
}
}
}
The result is:
1 [foo]
2 []
3 [null]
4 [foo]
5 []
6 [null]
7 [foo]
8 []
...then asserts/aborts with a No such property error.
The pattern I can ascertain is:
env.-scoped variables will be NULL if they come from unpopulated HTTP POST content.
env.-scoped variables will be empty strings if they come from unpopulated parameterized build variables.
env.-scoped variables will be NULL if are nonexistent among parameterized build variables.
Referencing global-scoped variables will assert if they come from unpopulated HTTP POST content.
Referencing global-scoped variables will be be empty strings if they come from unpopulated parameterized build variables.
params.-scoped variables will be NULL if they if are nonexistent among parameterized build variables.
params.-scoped variables will be empty strings if they come from unpopulated parameterized build variables.
I have a few questions about this - I believe they are reasonably related, so am including them in this one post:
What is the underlying pattern/logic behind when a variable is NULL and when it is an empty string?
Why are variables available in different "scopes": env., params., and globally, and what is their relationship (why are they not always 1:1)?
Is there a way for unpopulated values in parameterized builds to be null-valued variables in the Jenkinsfile instead of empty strings?
Context: in my first Jenkinsfile project, I made use of variables populated by HTTP POST content. Through this, I came to associate a value's absence with the corresponding .env variable's null-ness. Now, I'm working with variables coming from parameterized build values, and when a value is not populated, the corresponding .env variable isn't null -- it's an empty string. Therefore, I want to understand the pattern behind when and why these variables are null versus empty, so that I can write solid and simple code to handle absence/non-population of values from both HTTP POST content and parameterized build values.
The answer is a bit complicated.
For 1 and 2:
First of all pipeline, stage, steps... are groovy classes. Everything in there is defined as object/variable.
env is an object that holds pretty much everything,
params holds all parameter ;)
They are both a Map, if you access an empty value it's empty, if you access an non existing one it's null.
The globals are variables itself and if you try to access a non existing the compiler complains.
For 3:
You can define "default" parameter:
pipeline {
agent any
stages {
stage( "Set up" ) {
steps {
script {
params = setConfig(params);
}
}
}
}
}
def merge(Map lhs, Map rhs) {
return rhs.inject(lhs.clone()) { map, entry ->
if (map[entry.key] instanceof Map && entry.value instanceof Map) {
map[entry.key] = merge(map[entry.key], entry.value)
} else {
map[entry.key] = entry.value
}
return map
}
}
def setConfig(givenConfig = [:]) {
def defaultConfig = [
"populated_var": "",
"unpopulated_var": "",
"dontexist": ""
];
effectiveConfig = merge(defaultConfig, givenConfig);
return effectiveConfig
}
I m a beginner, trying to use the switch case in the groovy pipeline.
I have defined parameter
ENV (choice parameter) with values test1,test2,test3,prod1,prod2,prod3
DISPLAY ( Active reactive parameter) with Referenced parameters as ENV
switch("$ENV") {
case "test*":
return ['True']
break
case "prod*":
return ['False']
break
default:
return ['Error in env selection']
break
}
When i give the test1 it works good whereas when i give pattern "test*" the code output is not as expected.
Kindly help me with the solution.
Thank you in advance.
You have an error in the regex pattern matching, see below the solution.
However, using a switch is quite old habit, is kept in the language only because of backward compatibility. Probably in a modern Groovy, you will never see a switch. I added a second solution, how I would solve this.
ENV = "prod1"
// classic solution using swtich
def SelectSwitch(value) {
switch(value) {
case ~/test.*/: return 'True'
case ~/prod.*/: return 'False'
default: return 'Error in env selection'
}
}
assert SelectSwitch(ENV) == 'False'
// modern approach using a map
def SelectMap(value) {
['test.*': 'True', 'prod.*': 'False' ]
.find { value ==~ it.key }
?.value
?: 'Error in env selection'
}
assert SelectMap(ENV) == 'False'
I am new to Jenkins pipeline scripting. I am developing a Jenkins pipeline in which the Jenkins code is as follows. The logic looks like this:
node{
a=xyz
b=abc
//defined some global variables
stage('verify'){
verify("${a}","${b}")
abc("${a}","${b}")
echo "changed values of a and b are ${a} ${b}"
}}
def verify(String a, String b)
{ //SOme logic where the initial value of a and b gets changed at the end of this function}
def verify(String a, String b){
//I need to get the changed value from verify function and manipulate that value in this function}
I need to pass the initial a and b(multiple) values to the verify function and pass the changed value on to the other function. I then need to manipulate the changed value, and pass it to the stage in the pipeline where echo will display the changed values. How can I accomplish all this?
Ok, here's what I meant:
def String verify_a(String a) { /* stuff */ }
def String verify_b(String b) { /* stuff */ }
node {
String a = 'xyz'
String b = 'abc'
stage('verify') {
a = verify_a(a)
b = verify_b(b)
echo "changed values of a and b are $a $b"
}
stage('next stage') {
echo "a and b retain their changed values: $a $b"
}
}
The easiest way I have found to pass variables between stages is to just use Environment Variables. The one - admittedly major - restriction is that they can only be Strings. But I haven't found that to be a huge issue, especially with liberal use of the toBoolean() and toInteger() functions. If you need to be passing maps or more complex objects between stages, you might need to build something with external scripts or writing things to temporary files (make sure to stash what you need if there's a chance you'll switch agents). But env vars have served me well for almost all cases.
This article is, as its title implies, the definitive guide on environment variables in Jenkins. You'll see a comment there from me that it's really helped me grok the intricacies of Jenkins env vars.
what is wrong with below code, comparing 2 strings in groovy
I am trying do the comparison between the 2 parameters in a single line to make it look tidier
if (params.dirname == ((params.path =~ ~/${params.dirname}/).with { matches() ? it[0] : null })) {
print success
}
Throwing Exception -
java.lang.NoSuchMethodError: No such DSL method 'matches' found among steps
There is no need to over-complicate your use case. According to:
params.dirname = hde, params.path = /usr/tmp/jenkins/hde/filename.txt or /usr/hde/jenkins/ing/filename.txt or any random path which has hde in it
you are trying to find if given string a contains substring b. It can be done using Java's method String.contains(String substring). Alternatively you can use regular expression for that, but String.contains() just looks a few times simpler to understand what is your intention. Consider following Groovy script:
def params = [
dirname: 'hde',
path: '/usr/tmp/jenkins/hde/filename.txt'
]
// Using String.contains()
if (params.path.contains(params.dirname)) {
println "Path '${params.path}' contains '${params.dirname}'"
}
// Using regular expression
if (params.path ==~ /(.*)${params.dirname}(.*)/) {
println "Path '${params.path}' contains '${params.dirname}'"
}
When you run it both if statements evaluates to true:
Path '/usr/tmp/jenkins/hde/filename.txt' contains 'hde'
Path '/usr/tmp/jenkins/hde/filename.txt' contains 'hde'
I am writing a powershell-v2.0 script. The script contains a function to set environment variable. The function is as follows:
function SetSvnEnvironmentVariable($path)
{
# Get the Path environment variable
$pathVar = [Environment]::GetEnvironmentVariable("Path","User")
# Check if path environment variable already contains the path to be added
if(-Not ($pathVar -like $path))
{
$pathVar += $path
[Environment]::SetEnvironmentVariable("Path",$pathVar, [System.EnvironmentVariableTarget]::User)
}
}
The $path variable contains the path to be added to the PATH environment variable.
The problem I am facing is, even though $path is a substring of $pathVar, the if condition always returns False.
Following are the values of $pathVar and $path.
$pathVar:
C:\Program Files (x86)\MATLAB\R2009b\bin\win32;C:\Program Files\TortoiseSVN\bin
$path:
;C:\Program Files\TortoiseSVN\bin
Using wildcard or regular expression matches for this kind of check bears the risk of getting false positives if the path already contains a subfolder of the folder you want to add. It's better to split the value of the environment variable at semicolons and use the -contains/-notcontains operator to check if the resulting array does or doesn't contain the item you want to add:
function SetSvnEnvironmentVariable($path)
{
$pathVar = [Environment]::GetEnvironmentVariable('Path', 'User')
if ($pathVar.Split(';') -notcontains $path))
{
$pathVar += ";$path"
[Environment]::SetEnvironmentVariable('Path', $pathVar, [EnvironmentVariableTarget]::User)
}
}
Note that $path should not be specified with a leading (or trailing) semicolon.
Using a wildcard fixed my problem. -like operator without a wildcard compared the strings if they were equal and hence always returned False.
By changing the if condition as follows, the if condition returns True:
if(-Not ($pathVar -like "*$path*"))
{
....
}