Run groovy script from bash script - bash

I want to run a Groovy script from within bash script.
I have a groovy script that is creating a variable I need from jenkins. (The whole CI is written in bash for some reason).
I need to run it in groovy because I can't reproduce it in bash.
So my bash code looks like:
LAST_SUCCESSFUL_BUILD_DATE=$(groovy scripts/jenkins-lastbuild-date.groovy)
The groovy script is in the folder scripts, and it's like this:
#!/usr/bin/env groovy
import jenkins.model.Jenkins
def envVars = Jenkins.instance.getGlobalNodeProperties()[0].getEnvVars()
// the job name is a global Jenkins variable, so I get it from there
def item = Jenkins.instance.getItem(envVars['JOB_NAME'])
def ff=item.getLastSuccessfulBuild()
println ff.getTime().format("yyyy-MM-dd")
but when I run it I get the error
line 254: groovy: command not found
any ideas? I need to get the date from the last successful commit.

It seems like a problem with environmental variables, as you're trying to localise groovy using env in the shebang.
I'd make two things:
Get details where groovy is installed
Go to the server and try to run:
mbp:~ jhartman$ which groovy
/usr/local/bin/groovy
Then replace the 1st line of your script with the exact location:
#!/usr/local/bin/groovy
import jenkins.model.Jenkins
Best regards,
Jarek

Related

How to create GitHub environment variables with object-like syntax to test a bash script

I'm currently coding a shell script for my GitHub Workflow and I want to test it locally.
However, it depends on an env variable provided by GitHub that consists of multiple nested segments, like a Javascript object for example.
my-bash-file.sh
PAYLOAD=${github.event.client_payload}
echo "$PAYLOAD"
How would I declare and inject such a kind of env variable locally when calling my script?
While you can define environment variables containing dots you won't be able to reference them from bash as identifiers can consist only of alphanumeric characters and underscores.
However, you can access them using other languages, like python. Call it my-python for example:
#! /usr/bin/env python3
import os
payload=os.environ['github.event.client_payload']
print(f'payload={payload}')
invoking it as
env github.event.client_payload=hello ./my-python
produces
payload=hello
I think I understand what you're trying to do. You're running a shell script as part of a GitHub action that looks something like this:
jobs:
my-job:
runs-on: ubuntu-latest
steps:
- name: Install pre-commit
run: |
PAYLOAD=${github.event.client_payload}
echo "$PAYLOAD"
The best solution is to not reference github template variables directly in your shell script. Write it like this instead:
jobs:
my-job:
runs-on: ubuntu-latest
steps:
- name: Install pre-commit
env:
PAYLOAD: "${github.event.client_payload}"
run: |
echo "$PAYLOAD"
This keeps the github template variable out of your script and instead uses it to set the PAYLOAD environment variable before the script runs. If you want to run the same script locally, you would just need to set the same PAYLOAD environment variable.
The examples here show a script embedded in the GitHub workflow; that's because there's no way to use a template variable embedded in a script file as you've shown in your question. If your workflow tried to run a script my-bash-file.sh that contained:
#!/bin/sh
PAYLOAD=${github.event.client_payload}
echo "$PAYLOAD"
It would fail with:
my-bash-file.sh: line 2: ${github.event.client_payload}: bad substitution

How can i pass bash variable into groovy?

I am trying to write a jenkinsfile to run a job via pipeline. My requirement to pass a varriable's value from shell to groovy. My jenkinsfile is in grrovy language but i am using shell command somewhere.
Thanks in advance
So, "a way" but perhaps not "the way" to do this would be to have the shell step write the value to a file:
sh 'echo "${NEEDED_VALUE} > needed.value.txt'
then pick that value up in groovy:
script {
def neededValue = readFile('needed.value.txt')
// do something with the value here
}

change Jenkins shell for only one pipeline

How can I make Jenkins use Bash rather than its native shell for just one Jenkins pipeline/Jenkinsfile? Does the "agent" help me to do this?
I wrote a shell script for deployment but some of the parameters contain whitespace which messes up the resulting command I generate by losing some args. I've found how to avoid this problem by globally configuring Jenkins shell type to be Bash. But when I change the global shell type, my other Jenkins pipelines that use the Jenkins docker plugin syntax get broken when they use the 'sh' command within a docker container. My workaround is to ping pong the global setting for shell type depending on which Jenkins build I want to run. Its a royal PITA.
I'm embarrassed to say all I needed was a shebang.
My Jenkinsfile runs a custom (bash) shell script, using Jenkin's sh command, like in the following:
sh "./deploy.sh \"arg1\" \"arg 2\" \"arg3\""
In order to force deploy.sh to run within Bash, the contents of deploy.sh need to include #!/bin/bash on the first line, as in:
#!/bin/bash
echo "deploy args: $#"
Regardless, I think there should be a way to tell a Jenkins pipeline that it should run with specific settings, like sh=bash.

How to write a simple interpreter wrapper?

I have a couple of scripts for remote control of a server. Those scripts all need some environment variables set. My idea is to write a simple interpreter wrapper which first sets the variables and then calls the actual interpreter.
I tried as follows:
One of the scripts:
#! ../common/pywrapper.sh
import argparse
import parse_shell_vars
# ....and some more lines
The wrapper (../common/pywrapper.sh relative to the scripts):
#!/bin/bash
# echo params just to see what's going on
echo $#
# here would be some more configuration
python3.5 $#
Now, when I invoke the script, I get:
$ ./my_script.py param1 param2
./my_script.py: line 3: import: command not found
./my_script.py: line 4: import: command not found
How can I properly create an "interpreter wrapper"?
Remark: I know that I could export the variables in a previously-run configuration script or install them globally by some initialization script of the shell. But I think a wrapper is a good solution in this case, because I can start the scripts directly on any machine without previously installing something. Plus the scripts are self explaining for someone reading them. No guessing about required installation steps. All configuration and installation can be done by editing the wrapper.
#! ../common/pywrapper.sh
import argparse
You are mixing Python and shell. Use a Python interpreter in the shebang line for Python scripts.
Suggest doing this entirely in Python. Simpler and more portable to have one scripting language rather than several. You can get and modify environment variables with os.environ.

jenkins - how to pass a value from bash to groovy?

I'm working on a jenkins install with two script components. The bash bits run first and then groovy. I'd like to be able to pass a value (property? Other?) from the bash script->groovy script.
Is this possible? Do I need to write the value to a property file and read it back in groovy?
EDIT: my goal from this was to generate a build # in bash and pass this to groovy so I could set the description and build # in the jenkins display. It appears that groovy isn't available on the build server so I'm looking for another direction. Currently experimenting with the 'postbuild' plugin and the 'env-inject' plugin. Open to suggestions.
Here are a few things to consider to make this successful:
Make sure you're trying to accomplish this with one "Execute shell" in Jenkins or from a script.
Export the shell variable so that the variable will be present in the child process that will execute your groovy script.
# foo.sh
export foo=bar
groovy myscript.groovy
# myscript.groovy
def env = System.getenv()
String myvar=env['foo']
println myvar
Running foo.sh should produce the following:
./foo.sh
bar
If for some reason you prefer not to export the variable (there may be good and valid reasons for this), you can still explicitly pass the variable to the groovy script as a "system property":
# foo.sh
foo=bar
groovy -Dfoo="$foo" yourscript.groovy
# yourscript.groovy
String yourvar = System.properties['foo']
println yourvar
which produces the following results:
$ ./foo.sh
bar
$
I just worked on this problem for days and thought I might share what I discovered. I had to access a variable in a groovy file from a .sh file and had difficulty at first grabbing the variable. There is a simple way to do it, though. Here's what I did:
In your bash file, save the value in a variable. Then in the groovy script, do this:
variableToGet = sh(returnStdout: true, script: """
. ${DIRECTORY}/bash_file.sh
echo \$VARIABLE
""").trim()
Hope this helps. This problem was a good challenge! It's important to note, however, that standard out will return a String, regardless of what type of variable you are grabbing. If you need to use an integer value, you can then use the integer value with Integer.parseInt(variableToGet)
The best way is setting an environment variable to share the information from bash into groovy. You could pipe things as well using standard in/out as well.
So if you are setting the env in a bash script it wont be available outside of that script. Instead of doing a bash script put the script inline in your command in jenkins. Run your bash code then call the groovy script.
Something like below
#do somebash scripting
VARIABLE="something"
#call your groovy code
groovy util.groovy
your groovy code (util.groovy):
String variable = env['VARIABLE']

Resources