I have a list foo = ['tea',''sugar','milk'] and col = ['black','white','pink'] what I am trying to do is nested loop
def foo = ['tea','sugar','milk']
def col = ['black','white','pink']
[foo, col].transpose().each { x, y ->
sh """aws deploy push --application-name "${x}" --source "${y}" """
}
Desired Result
--application-name "tea" --source "black"
--application-name "sugar" --source "white"
--application-name "milk" --source "pink"
the result I am getting
[Pipeline] script
[Pipeline] {
[Pipeline] echo
--application-name "[tea, black]" --source "null"
[Pipeline] echo
--application-name "[sugar, white]" --source "null"
[Pipeline] echo
--application-name "[milk, pink]" --source "null"
[Pipeline] }
[Pipeline] // script
[Pipeline] }
I want the list items in foo and col to be injected one by one to the above shell script
Is there a way where we can pass both list items at once to the above shell script
Ref Nested `each` loops in Groovy
Can we do something like (foo,col).each
or maybe using for loop for(x in foo && y in col)
Ref my Jenkinsfile
pipeline {
agent any
stages {
stage('hello'){
steps{
script{
def foo = ['tea','sugar','milk']
def col = ['black','white','pink']
[foo, col].transpose().each { x, y ->
sh """aws deploy push --application-name "${x}" --source "${y}" """
//echo """--application-name \"${x}\" --source \"${y}\" """
}
}
}
}
}
}
I believe transpose is the method you are after, to pair up the two lists, then you can iterate through the result:
[foo, col].transpose().each { x, y ->
...
}
UPDATE:
This is what I was aiming at. Note that some of the parameters are removed for brevity
def foo = ['tea','sugar','milk']
def col = ['black','white','pink']
[foo, col].transpose().each { x, y ->
println """--application-name "${x}" --source "${y}" """
}
results
--application-name "tea" --source "black"
--application-name "sugar" --source "white"
--application-name "milk" --source "pink"
Related
I have a Jenkins pipeline script and it has to read the contents from a properties one by one which is having as a key-value pair. I need to split key and value separately. Below are the properties and groovy file which I am using.
To be read file (mypropsfile.properties) :
product1=workspacename1:path1/path2/path3
product2=workspacename2:path1/path2/path3
product3=workspacename3:path1/path2/path3
My groovy file:
stage('readfromfile') {
steps {
script{
def readpropscontent = readProperties file: 'mypropsfile.properties'
echo 'readpropscontent ::: '+readpropscontent
for (String item : readpropscontent) {
echo "item ::: "+item
def readpropscontentfile2 = item.split("=")[0];
echo 'readpropscontentfile2 ::: '+readpropscontentfile2
}
}
}
}
Updated groovy file to split the value:
def readpropscontent = readFile file: 'mypropsfile.properties'
echo 'readpropscontent ::: '+readpropscontent
for (String item : readpropscontent.split('\n')) {
echo "item ::: "+item
def PropsFileValue = item.split("=")[1];
echo 'PropsFileValue ::: '+PropsFileValue
for (String splittingparams : PropsFileValue) {
def path1= splittingparams.split(":")[0];
echo 'path1::: '+path1
//def path2= splittingparams.split(":")[1];
//def path3= splittingparams.split("/")[1];
}
when I try to run it in Jenkins pipeline, I face the below issue:
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: java.util.AbstractMap$SimpleImmutableEntry.split() is applicable for argument types: (java.lang.String) values: [=]
Possible solutions: split(groovy.lang.Closure), wait(), wait(long), sprintf(java.lang.String, [Ljava.lang.Object;), getAt(java.lang.String), print(java.io.PrintWriter)
I don't want to hardcode the key to fetch its value, by reading the file line by line I need to get the key and value. Can someone provide the inputs to resolve this? Thank you !
The readProperties method returns a Map of properties. So you don't have to iterate to read them, simply use the key(name of the property) to extract the value for a specific property.
stage('readfromfile') {
steps {
script{
def readpropscontent = readProperties file: 'mypropsfile.properties'
echo 'readpropscontent ::: '+readpropscontent
echo "PROP1 :::: ${readpropscontent['product1']}"
echo "PROP2 :::: ${readpropscontent['product2']}"
echo "PROP3 :::: ${readpropscontent['product3']}"
}
}
}
Update 1
Printing all keys and values from properties.
stage('readfromfile') {
steps {
script{
def readpropscontent = readProperties file: 'mypropsfile.properties'
echo 'readpropscontent ::: '+readpropscontent
readpropscontent.each{ k,v ->
echo "KEY = $k :::: VAL = $v "
}
}
}
}
Update 2
Using readFile instead of readProperties
steps {
script{
def readpropscontent = readFile file: 'mypropsfile.properties'
echo 'readpropscontent ::: '+readpropscontent
for (String item : readpropscontent.split('\n')) {
echo "item ::: "+item
def readpropscontentfile2 = item.split("=")[0];
echo 'readpropscontentfile2 ::: '+readpropscontentfile2
}
}
}
I am trying to pass a loop variable to a shell script, but my shell script is getting an empty variable value
pipeline {
agent any
stages {
stage('Test') {
steps {
script {
elements = ['1', '2', '3', '4']
for (String val in elements){
echo val
check = sh (script: """bash ./check_access/check.sh ${val}""", returnStdout: true).trim()
echo "check: ${check}"
}
}
}
}
}
}
./check_access/check.sh
#!/bin/sh
echo "val: $val"
the result i get
18:13:30 1
18:13:31 + bash ./check_access/check.sh 1
18:13:31 check: val:
.
.
.
18:13:31 4
18:13:32 + bash ./check_access/check.sh 4
18:13:32 check: val:
desired result
bash ./check_access/check.sh 1
check: val: 1
.
.
.
bash ./check_access/check.sh 4
check: val: 4
Could you please help
Solution:
I pass val as the first parameter to my script. So I should use $1 inside the script, not $val
In Groovy/Jenkinsfile declarative syntax, why is the result of the boolean AND operation on dictionary, dictionary, and integer objects an integer instead of boolean true/false?
pipeline {
agent any
stages {
stage( "1" ) {
steps {
script {
a = [:]
a.a = [:]
a.a["a"] = "1"
a.a["b"] = "2"
echo "${a}"
echo "${a.a}"
echo "${a.a.size()}"
def my_bool = (a && a.a && a.a.size())
echo "my_bool ${my_bool}"
}
}
}
stage( "2" ) {
when {
expression { true == (a && a.a && a.a.size()) } // Fails because result is integer "2", not boolean "true"
}
steps {
script {
echo "hello, world!"
}
}
}
}
}
My biases from other programming languages led me to think that a && a.a && a.a.size() should implicitly be converted to a boolean value. The echo reveals that the value is integer 2.
What is the Jenkins/Groovy idiomatic way to deal with this? I.e. if a stage is conditional on "dictionaries being non-null and having nonzero size", what is the idiomatically correct/preferred way to write that conditional?
Update:
Note: the echo "my_bool ${my_bool}" statement prints "my_bool 2". This is with Jenkins version 2.222.3.
expression { a?.a?.size() }
or even
expression { a?.a }
I'm writing a code in groovy to read a file line by line and perform an action (for ex: build a code for a specific configuration) based on the information available in the line.
The following groovy code runs fine for me, except that i want to ignore or skip the first line or rather any line which starts with # or comment (//).
__SAMPLE_GROOVY_CODE__
input_file = '/home/user/inputFile.txt'
// read all the lines into a list, each line is an element in the list
File FH1 = new File(input_file)
def lines = FH1.readLines()
for (line in lines)
{
env.c_num = sh(returnStdout: true, script: "echo '${line}' | cut -d ':' -f 1").trim();
env.p_num = sh(returnStdout: true, script: "echo '${line}' | cut -d ':' -f 2").trim();
env.p_len = p_num.length();
println("INFO: Length is ${p_len} \n");
if(env.p_len != '0')
{
println ("INFO: Build is required !! \n");
println ("INFO: c_num is: ${c_num} \n");
println ("INFO: p_num is: ${p_num} \n");
// Code for build will come here..!!
}
else
{
println("INFO: Build is NOT required !! \n");
}
}
__INPUT_FILE__
$> cat /home/user/inputFile.txt
# Details of inputFile.txt
1234-A0: aa ab ac ad ae al
5678-B0:
2345-B0: ba
3456-B0:
4567-B0: ca
My usual way to submit a file is:
p4 submit –d “some description” filename
I could do:
p4 submit
and use the editor, but I always have many files open, so that method is inconvenient
Several times, I have mistakenly typed
p4 submit –d "some description"
(forgot the filename)
This submitted dozens of open files to production, with unintended consequences.
Time to panic and spend the afternoon doing damage control.
I would like to prevent p4 -d when the filename is not specified.
If you are using Linux you can define function in your .bashrs file that validates number of arguments and won't let you submit if you miss4th parameter.
function p4()
{
# validate what parameters are passed and if they are correct
# pass them to /opt/perforce/p4 ...
}
Thanks #pitseeker
I created a Perl wrapper "p4s" which checks the arguments and forwards the call to the real "p4 submit".
#!/usr/bin/perl
use warnings;
use strict;
use Capture::Tiny 'capture_merged';
die "Description and file is required!\n" if #ARGV < 2;
my ($description, #files) = #ARGV;
if ( -f $description ) {
die "It looks like you forgot the description before the filenames";
}
my $cmd;
my %summary;
print `date`;
for my $file (#files) {
if ( ! -f $file ) {
$summary{$file} = "File $file not found!";
next;
}
my $pwd = `pwd`;
chomp $pwd;
# print p4 filelog to screen
print `ls -l $file`;
$cmd = "p4 filelog $file | head -n 2";
$cmd = "p4 fstat -T 'headRev' $file";
print $cmd . "\n";
my $filelog = `$cmd`;
print "$filelog" . "\n";
$cmd = "p4 diff -sa $file";
my ($merged, $status) = Capture::Tiny::capture_merged {system($cmd)};
if ( ! $merged ) {
$summary{$file} = "Skipped since the local file does not differ from p4";
next;
}
# p4 submit
$cmd = "p4 submit -r -d \"$description\" $file";
print $cmd . "\n";
($merged, $status) = Capture::Tiny::capture_merged {system($cmd)};
chomp $merged;
print $merged . "\n";
if ( $merged =~ /No files to submit from the default changelist/ ) {
$summary{$file} = "$merged (You may need to 'p4 add' or 'p4 edit' this file)";
next;
}
$summary{$file} = "Success";
}
if ( scalar #files > 0 ) {
print "\nSummary:\n";
for my $file (#files) {
printf "%s %s\n", $file, $summary{$file};
}
}