Environment variables manipulation - jenkins

When using:
echo "${env.PRODUCT_NAME}"
it will echo:
MyProdName
When using:
echo "${env.MyProdName_Key}"
it will echo:
123456789
I would like to use something as follows:
echo "${env.${env.PRODUCT_NAME}_Key}"
Is this possible? How?

In Bash this is termed as variable in direction
Try using variables to make it further simplified
PRODUCT_NAME=$(echo "${env.PRODUCT_NAME}")
This would assign PRODUCT_NAME=MyProdName
Similarly
MyProdName=$(echo "${env.MyProdName_Key}")
This would assign MyProdName=123456789
Now when you print PRODUCT_NAME value you will get
echo ${PRODUCT_NAME}
MyProdName
And adding '!' variable indirection will give you the value of another variable values
echo ${!PRODUCT_NAME}
123456789

Maybe this will help you somehow:
def env = [
PRODUCT_NAME:'MyProdName',
MyProdName_Key: 123456789,
]
println "${env[env.PRODUCT_NAME+'_Key']}"
env is Map in the example provided but it works in the exactly same way.

Important note, regardless of how you're deriving variables:
There's no need to use string interpolation if the only value in a
string is a variable itself. This just clutters your code.
Instead of:
echo "${env.PRODUCT_NAME}"
you can do:
echo.PRODUCT_NAME.
Additionally you can grab nested object values dynamically using bracket notation
def obj = [a: '1']
echo obj[a] // outputs '1'
Using these put together, you can do:
def prodName = env.PRODUCT_NAME //will set var prodName to "MyProdName"
echo env[prodName + '_Key'] //gets nested field with key "MyProdName_Key"
(Note: this is similar to Opal's answer, hopefully my breakdown helps)

Related

Is it possible to give multiple values as input in a string parameter in Jenkins job..?

Is it possible to give multiple values as input in a string parameter in the Jenkins job..?
If yes, what will be the syntax and how are we calling that in a for loop so the values take one after the other.?
This is for a declarative job in Jenkins.
Thank you for the help in advance
parameters {
string(name: "usernames", value: list.join (","), description: "enter the user names")
}
stages{
need the syntax for this --> //for user in usernames list
do
$echo ---> username
this username which print will be called in my curl command one after the other.
so please do help me with the right path
Generally it is only possible to pass one string.
That being said, since you are using strings you can encode whatever data you want in them.
Suppose you want to pass the pipeline a list of strings myList with values ['foo', 'bar', 'baz']. In the calling job you could simply do:
build ... parameters(string(name: "myString", value: myList.join(",")))
which passes 'foo, bar, baz' to the called job. There you could parse it out again:
params.myString.split(',') // results in ['foo', 'bar', 'baz']
To iterate over this, you could use a for-in loop or a list function like each or collect.
In order to iterate over all the elements you receive you can use the each method
stages {
stage("Iterate over parameters"){
script{
def userNames = params.userNamesString.split(',')
userNames.each { user ->
echo "$user"
}
}
}
}
Alternativly (instead of the userNames.each block you can just use a for-in statement:
for(userName in userNames){
echo "$userName"
}
For more informations on this please have a look at the links I included in my previous answer.

How can I force Jenkins Blue Ocean to display print output instead of "Print Message"?

In the below screenshot some debug entries display the output text (with - Print Message at the end) while others simply display Print Message. To view these you have to expand the step to see the output.
All lines are using the format print "TEXT HERE". I've tried using print, println, and echo. All have the same output.
Why do these sometimes display the message, while others force it into a collapsed section? Is it possible to configure this to always show? The normal non-Blue Ocean Jenkins interface displays fine but there is a lot of verbosity.
This seems to be a known issue:
https://issues.jenkins-ci.org/browse/JENKINS-53649
It looks like that BlueOcean does not handle the Groovy GStrings correctly. This is what I've observed:
A simple:
echo "hello world"
will work as expected and will display correctly.
Whereas a templated string with variables, like:
echo "hello ${some_variable}"
will hide the message under a "Print Message" dropdown.
See also this answer.
It appears that if echo uses a variable with value from params or environment (i.e. "params.*"), then step label gets "Print message" name instead of actual value being echoed. It does not matter if the variable itself is a String or not. Even explicitly converting the params value to String does not help.
String param_str
String text_var_2
parameters {
string(name: 'str_param', defaultValue: 'no value')
}
param_str = params.str_param.toString()
echo "string text in double quotes is ${param_str}"
echo "simple quoted string is here"
echo 'simple quoted string is here'
echo 'Single quoted with str ' + param_str + ' is here'
echo param_str
text_var_2 = 'Single quoted str ' + param_str + ' combined'
echo "GString global text2 is ${text_var_2}"
echo 'String global text2 is' + text_var_2
BlueOcean shows simple quoted strings in step label, but everything else as "Print message".
BlueOcean output
Note that 'normal' variables (strings, integers) are not included into this example, but they are also shown in the label normally. So if you have a code like this
def text_str = 'Some string'
def int_var = 1+2
echo text_str + ' is here'
echo int_var
These will be shown on the label.
And indeed it appears to be a known Jenkins issue as stated in a previous answer.
This is a known BlueOcean bug. The console output in the "classic" view interpolates variables correctly.
One workaround is to use the label parameter of the sh step:
def message = 'Hello World'
sh(script: "echo $message", label: message)
I tried lots of things and seems the moment an environment variable is going to be displayed, it uses Print Message instead the text.
Another workaround would be to split the multiline string into an array and iterate over it :-
String[] splitData = MULTI_LINE_STRING.split("\n");
for (String eachSplit : splitData) {
print(eachSplit);
}

How do I get lua string match to parse an environment variable string?

I have a config file parser written in lua.
I'd like to detect values that are environment variables and change them with os.getenv.
It's probably a bit ambitious because I can have values like
"a string with an embedded ${VARIABLE} in here"
or
"another string with an env $VARIABLE"
And I should probably allow escaping them with double $$ to allow a literal $.
How do I do this?
This is what I have so far, but it isn't right
local envvar = string.match(value, "%$([%w_]+)")
if envvar then
print("Envvar=", envvar)
value = value:gsub("(%$[%w_]+)", os.getenv(envvar))
end
For example, I can't figure out how to use the %b balance option here to properly match { } combinations. And make them optional. How do I make this work robustly?
In fact, I realise it's probably more complicated than this. What if more than one environment variable was specified?
local text = [[
Example: ${LANG}, $TEXTDOMAINDIR, $$10.00, $$LANG, $UNDEFINED
Nested braces: {{${SHELL}}}
]]
text = text:gsub('$%$','\0')
:gsub('${([%w_]+)}', os.getenv)
:gsub('$([%w_]+)', os.getenv)
:gsub('%z','$')
print(text)
--> Example: en_US.UTF-8, /usr/share/locale/, $10.00, $LANG, $UNDEFINED
--> Nested braces: {{/bin/bash}}

Accessing Ruby Hash value using a string

I have a ruby array like below
tomcats = [
'sandbox',
'sandbox_acserver',
'sandbox_vgw'
]
I need to pass the string as a hash index like below
tomcats.each do |tomcat_name|
obi_tomcat '#{tomcat_name}' do
Chef::Log::info("Creating tomcat instance - #{tomcat_name}")
Chef::Log::info("#{node['obi']['tomcat']['sandbox'][:name]}") // works
Chef::Log::info("#{node['obi']['tomcat']['#{tomcat_name}'][:name]}") // doesn't work
end
end
The last log throws an error since the access with #{tomcat_name} is nil. I'm new to ruby. How do I access with key as the tomcat_name ?
In normal code, you'd write:
node['obi']['tomcat'][tomcat_name][:name]
In a string interpolation (useless here, because it's the only thing in the string in this case), it is completely the same:
"#{node['obi']['tomcat'][tomcat_name][:name]}"
#{} only works in double quote, as "#{tomcat_name}".
But you don't need the syntax here, just use [tomcat_name] directly.
When I saw this question, I'm thinking whether ruby placeholder could be put inside other placeholder in string interpolation. And I found that ruby actually support it, and most interesting thing is that you don't need to escape the " inside the string.
Although it is not very useful in this case, it still works if you write as below:
Chef::Log::info("#{node['obi']['tomcat']["#{tomcat_name}"][:name]}")
Below is an simple example of placeholder inside other placeholder:
tomcats = [
'sandbox',
'sandbox_acserver',
'sandbox_vgw'
]
node = {
'sandbox_name' => "sandbox name",
'sandbox_acserver_name' => "sandbox_acserver name",
'sandbox_vgw_name' => "sandbox_vgw name",
}
tomcats.each do | tomcat |
puts "This is tomcat : #{node["#{tomcat}_name"]}"
end

how to understand this vim script?

The following is vim script from a vim plugin:
vim's syntax is a bit strange:
!exists("*s:SetVals"), why their is a starmark before s:?
function!, why there is a ! character?
&iskeyword, is this a variable, if yes, where it is defined?
what is s: and g:, what is the difference between them?
why let should be used? such as let &dictionary = g:pydiction_location, can i change it to be &dictionary = g:pydiction_location?
if !exists("*s:SetVals")
function! s:SetVals()
" Save and change any config values we need.
" Temporarily change isk to treat periods and opening
" parenthesis as part of a keyword -- so we can complete
" python modules and functions:
let s:pydiction_save_isk = &iskeyword
setlocal iskeyword +=.,(
" Save any current dictionaries the user has set:
let s:pydiction_save_dictions = &dictionary
" Temporarily use only pydiction's dictionary:
let &dictionary = g:pydiction_location
" Save the ins-completion options the user has set:
let s:pydiction_save_cot = &completeopt
" Have the completion menu show up for one or more matches:
let &completeopt = "menu,menuone"
" Set the popup menu height:
let s:pydiction_save_pumheight = &pumheight
if !exists('g:pydiction_menu_height')
let g:pydiction_menu_height = 15
endif
let &pumheight = g:pydiction_menu_height
return ''
endfunction
endif
1. !exists("*s:SetVals"), why their is a starmark before
s:?
The asterisk is special syntax for exists function, and it means that we are checking if there's an existing function called SetVals. The option iskeyword could be checked with exists("&iskeyword") and the ex command echo with exists(":echo")
See :h exists(
2. function!, why there is a ! character?
The exclamation point means that the function is to be replaced if it already exists.
See :h user-functions
3. &iskeyword, is this a variable, if yes, where it is defined?
That is a vim option. You can check if it's set with :set iskeyword?
4. what is s: and g:, what is the difference between them?
These define the scope of the following symbol. s: means that the symbol is local to the script, while g: means that the symbol will be global.
See :h internal-variables and for s: see :h script-variable
5. why let should be used? such as let &dictionary =
g:pydiction_location, can i change it to be &dictionary =
g:pydiction_location?
Vimscript is one of the languages that require variables to be declared with a keyword. I don't think there's a way to declare variables more easily than with let.
I can answer on a few of those but i'll start with a general comment inspired by your recent questions.
The answers to most of your questions are laid out very clearly in Vim's awesomely exhaustive documentation. If you are serious about using Vim you must know how to use it. Start with :help and read carefully. It pays. Trust me.
You can find the answer to all these subquestions in :help expression.
!exists("*s:SetVals"), why their is a starmark before s:?
See :help exists().
function!, why there is a ! character?
Without an exclamation mark, Vim won't replace the previous definition if you re-source your script.
&iskeyword, is this a variable, if yes, where it is defined?
That's how you test the value of a vim option in a script. See :help iskeyword.
what is s: and g:, what is the difference between them?
These are namespaces. See :help internal-variables
why let should be used? such as let &dictionary = g:pydiction_location, can I change it to be &dictionary = g:pydiction_location?
No you can't, :let is how you define or update a variable. Get used to it.
See :help eval.txt. It describes most of vimscript syntax.

Resources