Parsing the command line in jenkins-cli groovy scripts - jenkins

I have written a groovy script to collect some statistics from my Jenkins server, which works ok in the default case.
However, when I want to pass options to it, I am getting trouble:
(1) The standard groovy CliBuilder exists, but fails to instantiate under jenkins-cli:
import jenkins.model.*
import groovy.util.CliBuilder
println("CliBuilder imported; calling constructor...")
def cli = new CliBuilder(usage: 'myscript.groovy [-halr] [name]')
results in
$ java -jar "jenkins-cli.jar" -s https://myjenkins1/ groovy myscript.groovy
CliBuilder imported; calling constructor...
ERROR: Unexpected exception occurred while performing groovy command.
java.lang.NoClassDefFoundError: org/apache/commons/cli/ParseException
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:195)
at RemoteClass.class$(RemoteClass)
at RemoteClass.$get$$class$groovy$util$CliBuilder(RemoteClass)
at RemoteClass.run(RemoteClass:4)
at groovy.lang.GroovyShell.runScriptOrMainOrTestOrRunnable(GroovyShell.java:266)
....
(2) the options starting with a dash are intercepted by jenkins-cli, instead of passing it to the script
$ java -jar "jenkins-cli.jar" -s https://myjenkins/ groovy ./myscript.groovy -h
ERROR: "-h" is not a valid option
java -jar jenkins-cli.jar groovy [SCRIPT] [ARGUMENTS ...] [--username VAL] [--password VAL] [--password-file VAL]
Executes the specified Groovy script.
SCRIPT : Script to be executed. File, URL or '=' to represent
stdin.
ARGUMENTS : Command line arguments to pass into script.
--username VAL : User name to authenticate yourself to Jenkins
--password VAL : Password for authentication. Note that passing a
password in arguments is insecure.
--password-file VAL : File that contains the password
Does it mean that the jenkins-cli groovy interface is meant only for simple tasks and should not handle complicated command lines?
Or are these known caveats with known workarounds?

A few issues here:
The jenkins-cli.jar requires groovy to be piped in via stdin.
Command line arguments are read via the args array
It does appear that args with a - are passed to the local jenkins-cli.jar and not the groovy script running on the server.
So given the following groovy script saved as cli.groovy:
println(args)
You would run it like this:
$ java -jar "jenkins-cli.jar" -s https://myjenkins/ groovy = foo bar baz bat < myscript.groovy
Which prints:
[foo, bar, baz, bat]

Related

Jenkins - Script to parse console output and set it as environment variable

I am into a scenario where I need to read the console output and find a specific string and set this as environment variable. This variable I would be using in input to run a different script in same job.
for example: my jenkins job's console would contain something like
build_id: 123456
Can somebody help in finding this number and pass it to input.environment variable to other script in same job?
I have looked into this answer but its not working, I am getting groovy errors while running it in post build groovy script.
Jenkins pipeline, is there a way to set environment variable from console output
Script I am using:
import jenkins.model.*
jenkins = Jenkins.instance
def consoleLog = Jenkins.getInstance().getItemByFullName(env.JOB_NAME).getBuildByNumber(Integer.parseInt(env.BUILD_NUMBER)).logFile.text
def buildId = (consoleLog =~ 'build_id="(.*)"')[0][1]
echo "build_id: $buildId"
env.build_id = buildId
Error I am getting:
ERROR: Failed to evaluate groovy script.
groovy.lang.MissingPropertyException: No such property: env for class: Script1
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:53)
at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:52)

What is use of sh ''' <command > ''' - three ticks - in a Jenkinsfile?

I have a Jenkinsfile which uses three tick marks surrounding a command to execute as in:
sh ''' command '''
We have no idea why three tick marks are required or what role they perform.
This syntax is seen in the Jenkinsfile doc set.
This has nothing at all to do with bash (in which triple-quotes have no special meaning at all), and everything to do with Groovy (the separate, non-bash interpreter that parses Jenkinsfiles).
In Groovy, but not in bash, strings must use triple-quotes to span multiple lines.
In the context of a sh directive in a Jenkinsfile, the content of your triple-quoted string is passed to a shell as a script to execute; however, the syntax is parsed by Groovy, so it's only Groovy that cares about the quotes themselves (as opposed to the quoted content).
Can you give more idea about what kind of command is it, is it a unix command or some script ?
The single quote and its variation like '''(3 ticks) as mentioned in question skip the variable expansion, and it could used to show what is being executed.
echo '''Updating JAVA_HOME variable :
export $JAVA_HOME="$NEW_JAVA_HOME" '''
However in your question, a command (some string) is enclosed between 3 ticks marks and sh tries to execute this command or script. One such example below
$ echo "echo hello" > /tmp/tesh.sh
$ sh '''/tmp/test.sh'''
hello

How to pass the parameter

I have a jenkins JOb which is calling the BAT file which contains the call for As java -jar testrunscripts/SQLWorkbench/sqlworkbench.jar -url=jdbc:as400:/;"translate binary"=true;naming=sql;libraries=; -driver=com.ibm.as400.access.AS400JDBCDriver -username=-password=-driverjar=E:\\\\resources\\lib\\jt400.jar -script='testrunscripts/HISTORYANDNEWDIFF.sql'
1-Jenkins Integrats the SQLWorkbench which calls the one sqlscript(HISTORYANDNEWDIFF.sql). which needs the dynamic table name required .
WbExport -file='E:\\TestingDATABASE\\history_XAXPGRFE.csv' -type=text -delimiter=',';
select * from %SOURCE%.XAXPGRFE where XPORIG='JAVAPGM'
How would pass the parameter to the query from the jenkins pipeline to bat file and then sql script
Your question is a bit unclear but try to call the bat script from your Jenkins job with a key value pair:
your_bat_script.bat param1=value1
and then in the bat script call the SQL Workbench /J script (HISTORYANDNEWDIFF.sql) using the -variable flag:
java -jar testrunscripts/SQLWorkbench/sqlworkbench.jar -url=jdbc:as400:/;"translate binary"=true;naming=sql;libraries=; -driver=com.ibm.as400.access.AS400JDBCDriver -username=-password=-driverjar=E:\\resources\lib\jt400.jar -script='testrunscripts/HISTORYANDNEWDIFF.sql -variable %1'
http://www.sql-workbench.net/manual/commandline.html#cmdline-vardef
%1 will contain param1=value1

Groovy script set number of executors

Please help me, I'm trying to change the number of executors on jenkins. When I'm running this code, it works:
import jenkins.model.Jenkins
Jenkins jenkins = Jenkins.getInstance()
jenkins.setNumExecutors(4)
jenkins.save()
When I use the next function:
void set_executors(int number) {
Jenkins jenkins = Jenkins.getInstance()
jenkins.setNumExecutors(number)
jenkins.save()
}
And running:
java -jar jenkins-cli.jar -s http://localhost:8080 groovy /var/lib/jenkins/executor.groovy set_executors 4
I'm getting:
groovy.lang.MissingMethodException: No signature of method:
Actions.set_executors() is applicable for argument types
(java.lang.String) values: [4]
Possible solutions: set_executors(int)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)
Please help!
When run from the command line, groovy passes arguments as strings. Your set_executors function is being called with a String argument instead of an integer as the function expects. You need to modify your code to accept a String argument and convert it to an integer.

Getting the build status in post-build script

I would like to have a post-build hook or similar, so that I can have the same output as e. g. the IRC plugin, but give that to a script.
I was able to get all the info, except for the actual build status. This just doesn't work, neither as a "Post-build script", "Post-build task", "Parameterized Trigger" aso.
It is possible with some very ugly workarounds, but I wanted to ask, in case someone has a nicer option ... short of writing my own plugin.
It works as mentioned with the Groovy Post-Build Plugin, yet without any extra quoting within the string that gets executed. So I had to put the actual functionality into a shell script, that does a call to curl, which in turn needs quoting for the POST parameters aso.
def result = manager.build.result
def build_number = manager.build.number
def env = manager.build.getEnvironment(manager.listener)
def build_url = env['BUILD_URL']
def build_branch = env['SVN_BRANCH']
def short_branch = ( build_branch =~ /branches\//).replaceFirst("")
def host = env['NODE_NAME']
def svn_rev = env['SVN_REVISION']
def job_name = manager.build.project.getName()
"/usr/local/bin/skypeStagingNotify.sh Deployed ${short_branch} on ${host} - ${result} - ${build_url}".execute()
Use Groovy script in post-build step via Groovy Post-Build plugin. You can then access Jenkins internals via Jenkins Java API. The plugin provides the script with variable manager that can be used to access important parts of the API (see Usage section in the plugin documentation).
For example, here's how you can execute a simple external Python script on Windows and output its result (as well as the build result) to build console:
def command = """cmd /c python -c "for i in range(1,5): print i" """
manager.listener.logger.println command.execute().text
def result = manager.build.result
manager.listener.logger.println "And the result is: ${result}"
For this I really like the Conditional Build Step plugin. It's very flexible, and you can choose which actions to take based on build failure or success. For instance, here's a case where I use conditional build step to send a notification on build failure:
You can also use conditional build step to set an environment variable or write to a log file that you use in subsequent "execute shell" steps. So for instance, you might create a build with three steps: one step to compile code/run tests, another to set a STATUS="failed" environment variable, and then a third step which sends an email like The build finished with a status: ${STATUS}
Really easy solution, maybe not to elegant, but it works!
1: Catch all the build result you want to catch (in this case SUCCESS).
2: Inject an env variable valued with the job status
3: Do the Same for any kind of other status (in this case I catch from abort to unstable)
4: After you'll be able to use the value for whatever you wanna do.. in this case I'm passing it to an ANT script! (Or you can directly load it from ANT as Environment variable...)
Hope it can help!
Groovy script solution:-
Here I am using groovy script plugin to take the build status and setting it to the environmental variable, so the environmental variable can be used in post-build scripts using post-build task plugin.
Groovy script:-
import hudson.EnvVars
import hudson.model.Environment
def build = Thread.currentThread().executable
def result = manager.build.result.toString()
def vars = [BUILD_STATUS: result]
build.environments.add(0, Environment.create(new EnvVars(vars)))
Postscript:-
echo BUILD_STATUS="${BUILD_STATUS}"
Try Post Build Task plugin...
It lets you specify conditions based on the log output...
Basic solution (please don't laugh)
#!/bin/bash
STATUS='Not set'
if [ ! -z $UPSTREAM_BUILD_DIR ];then
ISFAIL=$(ls -l /var/lib/jenkins/jobs/$UPSTREAM_BUILD_DIR/builds | grep "lastFailedBuild\|lastUnsuccessfulBuild" | grep $UPSTREAM_BUILD_NR)
ISSUCCESS=$(ls -l /var/lib/jenkins/jobs/$UPSTREAM_BUILD_DIR/builds | grep "lastSuccessfulBuild\|lastStableBuild" | grep $UPSTREAM_BUILD_NR)
if [ ! -z "$ISFAIL" ];then
echo $ISFAIL
STATUS='FAIL'
elif [ ! -z "$ISSUCCESS" ]
then
STATUS='SUCCESS'
fi
fi
echo $STATUS
where
$UPSTREAM_BUILD_DIR=$JOB_NAME
$UPSTREAM_BUILD_NR=$BUILD_NUMBER
passed from upstream build
Of course "/var/lib/jenkins/jobs/" depends of your jenkins installation

Resources