Possible to run multiline shell command/string in groovy/gradle? - jenkins

In gradle 7 I have created this method:
def shellCmd(String cmd) {
exec {
executable "sh"
args "-c", cmd
}
}
And this "pure" groovy version:
def shellCmd2(String cmd) {
def process = cmd.execute()
def output = new StringWriter(), error = new StringWriter()
process.waitForProcessOutput(output, error)
}
Which I call from another method e.g.:
def myMethod() {
shellCmd('ls -la')
}
I am now experimenting with getting it to work with multi-line (jenkins like) shell commands:
def myMethod() {
def cmd = """
for i in \$(ls -la); do
if [[ \$i == 'settings.gradle' ]]; then
echo "Found $i"
fi
done
"""
shellCmd(cmd)
}
but it fails with:
script '/home/user/samples/build.gradle': 47: Unexpected input: 'i' # line 47, column 5.
for i in $(ls -la); do
^
1 error
Probably I am breaking all the rules here but any input?
Also tried most of the suggestions here:
What's wrong with Groovy multi-line String?
but no luck so far.
Also based on the suggestion below I have tried to use shellCmd2 method (I am leaning towards using a plain groovy method for this to make it easier to debug outside of gradle) with:
def myMethod() {
def cmd = """
for i in \$(ls -la); do
if [ \$i = 'settings.gradle' ]; then
echo "Found \$i"
fi
done
"""
shellCmd2(cmd)
}
But that gives:
Caught: java.io.IOException: Cannot run program "for": error=2, No such file or directory
java.io.IOException: Cannot run program "for": error=2, No such file or directory
So seems the for keyword is now causing an issue.

There is nothing wrong with your multiline string. I had to change three things to make your code work:
Use single brackets [ and ]
Use single equal sign (=)
Escape the missing $i variable which was being interpreted as a Groovy variable.
You are using sh so you should only use POSIX compatible features.
Code:
def shellCmd(String cmd) {
exec {
executable "sh" // or use another shell like bash or zsh (less portable)
args "-c", cmd
}
}
def myMethod() {
def cmd = """
for i in \$(ls -la); do
if [ \$i = 'settings.gradle' ]; then
echo "Found \$i"
fi
done
"""
shellCmd(cmd)
}
You can compare with double brackets with shells like zsh and bash.

Related

Jetbrains Space shellScript variables

I'm trying to use bash variables in a shellScript in jetbrains space automation to no success.
My .space.kts is as follows;
job("mvn compile"){
container(displayName="mvn", image="maven:3.8.5-eclipse-temurin-17"){
shellScript {
content = """
FOO="bar"
echo $FOO
"""
}
}
}
in the above i'd expect "bar" to be echoed, but instead im getting the following error when this tries to run;
Dsl file '/tmp/16487320722162400386/.space.kts' downloaded in 1736 ms
Compiling DSL script /tmp/16487320722162400386/.space.kts...
downloading /home/pipelines-config-dsl-compile-container/space-automation-runtime.jar ...
[SUCCESSFUL ] com.jetbrains#space-automation-runtime;1.1.100932!space-automation-runtime.jar (71ms)
Compilation failed in 8.652797664s.
ERROR Unresolved reference: FOO (.space.kts:9:23)
Cleaned up the output folder: /tmp/16487320722162400386
DSL processing failed: Compilation exited with non zero exit code: 2. Exit code: 102
I had planned on parsing the branch name from JB_SPACE_GIT_BRANCH and storing it in a variable to use in a call to mvn to build and tag a container using Jib
Is there anyway that i can use variables within the content of a shellScript? or should/ can this be done in a different way?
You need to replace $ by ${"$"}:
job("mvn compile") {
container(displayName="mvn", image="maven:3.8.5-eclipse-temurin-17") {
shellScript {
content = """
FOO="bar"
echo ${"$"}FOO
"""
}
}
}
Or use a sh file file.sh like this:
FOO="bar"
echo $FOO
.
job("mvn compile") {
container(displayName="mvn", image="maven:3.8.5-eclipse-temurin-17") {
shellScript {
content = """
./file.sh
"""
}
}
}

run any command from configuration file

I write the shared library for jenkins where I have a method that read configuration file (yaml) and should execute commands based on the input.
example for configuration file
commands:
- name: command 1
command: "sh 'ls -la'"
- name: command 2
command: "readYaml file: 'demo.yaml'"
the method code
def command_executor(config){
config.commands.each { command ->
this.script.echo "running ${command.name} command"
// This is my problem how to run the command
command.command.execute().text
}
}
The above example is define in my class and I call it from /var/my_command_executer.groovy file
How I can run any command from the string parameter?
I found the below solution:
Create temporary groovy file the predefined method name that call to the command.
Load the temporary file in method and call the method.
Something like
def command_executor(config){
config.commands.each { command ->
this.script.echo "running ${command.name} command"
this.script.writeFile file: "temp.groovy" text: """
def my_command_executor(){
${command.command}
}
"""
def temp_command_executor = load "temp.groovy"
temp_command_executor.my_command_executor()
}
}

Access a groovy variable from within shell in Jenkins pipeline

This answer did not help me
Below is the method in groovy:
def analyze(repoName){
result= sh (
script: '''
cd ${WORKSPACE}/${BUILD_NUMBER}
cat > sonar-project.properties << EOF_$$
sonar.projectKey=ABC-$repoName
sonar.projectName=ABC
sonar.projectBaseDir=${WORKSPACE}/${BUILD_NUMBER}
EOF_$$
''',
returnStatus: true
) == 0
print "Creating file - Return status: ${result}"
}
where below line gives error:
sonar.projectKey=ABC-$repoName
properties file gets created with entry sonar.projectKey=ABC-
How to use groovy variable in sh() step?
You should double quotes for string interpolation and escape $ by \$ in following places:
${WORKSPACE} and ${BUILD_NUMBER}, you intent to use them as bash environment variable, rather than groovy variable
EOF_$$, you intent to use it literal meaning
Changed code:
def analyze(repoName){
result= sh (
script: """
cd \${WORKSPACE}/\${BUILD_NUMBER}
cat > sonar-project.properties << EOF_\$\$
sonar.projectKey=ABC-$repoName
sonar.projectName=ABC
sonar.projectBaseDir=\${WORKSPACE}/\${BUILD_NUMBER}
EOF_\$\$
""",
returnStatus: true
) == 0
print "Creating file - Return status: ${result}"
}
You should use double quotes for string interpolation, so just replace '''with """
And change EOF_$$ to EOF_\$\$

How to execute shell from Active Choices Plugin groovy script in Jenkins

I am trying to render information obtained from the shell in an active Active Choices parameter with a groovy script. I can easily access the shell from a groovy script in a jenkins pipeline with the sh method like this:
node()
{
sh 'git log ...'
}
But when I try this in the groovy script of Active choices, it crashes and the fallback script is executed.
Is it possible to switch to a node in this context and execute a shell command ?
Thanks for the help!
Here is sample snippet using the active choice plugin.
def command = $/aws ec2 describe-instances \
--filters Name=tag:Name,Values=Test \
--query Reservations[*].Instances[*].PrivateIpAddress \
--output text /$
def proc = command.execute()
proc.waitFor()
def output = proc.in.text
def exitcode= proc.exitValue()
def error = proc.err.text
if (error) {
println "Std Err: ${error}"
println "Process exit code: ${exitcode}"
return exitcode
}
//println output.split()
return output.tokenize()

Grails script and passing parameters using Groovy CLIBuilder?

I have created a very simple script and would like to pass arguments to the script.
like:
grails> helloworld -n Howdy
grails> helloworld -name Howdy
with the script:
target(main: 'Hello World') {
def cli = new CliBuilder()
cli.with
{
h(longOpt: 'help', 'Help - Usage Information')
n(longOpt: 'name', 'Name to say hello to', args: 1, required: true)
}
def opt = cli.parse(args)
if (!opt) return
if (opt.h) cli.usage()
println "Hello ${opt.n}"
}
I seem to fail in every attempt that i do. The script keeps complain about the -n option being not present.
When i debug the script the value op the args parameters looks like the values are rearranged.
When calling the script with :
grails> helloworld -n Howdy
the value of args inside the script is: Howdy -n
What am i missing here of doing wrong? Any suggestions?
Your problem is that you're running your code through grails shell. I've converted your code to CLI.groovy like this:
class CLI{
public static void main(String [] args){
def cli = new CliBuilder()
cli.with
{
h(longOpt: 'help', 'Help - Usage Information')
n(longOpt: 'name', 'Name to say hello to', args: 1, required: true)
}
def opt = cli.parse(args)
if (!opt) return
if (opt.h) cli.usage()
println "Hello ${opt.n}"
}
}
After that I'm using groovy command to run it from linux shell like that:
archer#capitan $ groovy CLI -n Daddy
It outputs:
archer#capitan $ groovy CLI -n Daddy
Hello Daddy
So it works like a charm.
I did a Google search for site:github.com grailsScript CliBuilder and came across:
https://github.com/Grails-Plugin-Consortium/grails-cxf/blob/master/scripts/WsdlToJava.groovy
That gave me the hint that the args variable needs to be formatted. Unfortunately it mutates -n Howdy into Howdy\n-n (not sure why the order is rearranged or the newline character is added).
The github page above has a doSplit() method to handle some of this, but it keeps the rearranged order. The best thing I've found is to remove the space between -n and Howdy, which will work with CliBuilder.
The following is what I have working:
target(main: 'Hello World') {
def cli = new CliBuilder()
cli.with
{
h(longOpt: 'help', 'Help - Usage Information')
n(longOpt: 'name', 'Name to say hello to', args: 1, required: true)
}
def ops = doSplit(args)
def opt = cli.parse(ops)
if (!opt) return
if (opt.h) cli.usage()
println "Hello ${opt.n}"
}
private doSplit(String string){
string.split(/(\n|[ ]|=)/).collect{ it.trim() }.findResults { it && it != '' ? it : null }
}
Run this with: helloworld -nHowdy

Resources