Error in email template for Robot framework when using multiple script blocks in pipeline - email

Im using Jenkins in Windows 10 with pipeline script running a robot script and then sending a email with the results.
The template I'm using is this opne
I've tried using different setups in the jenkinsfile (including using a scripted version) but basically this works:
pipeline {
agent any
stages {
stage('Build') {
steps {
script{
bat "robot -v store:${storeID} -v testType:${testType} -v site:${pageID} -v productName: previews.robot"
}
}
}
}
post {
always{
script{
step(
[
$class : 'RobotPublisher',
outputPath : '.',
outputFileName : 'output.xml',
reportFileName : 'report.html',
logFileName : 'log.html',
disableArchiveOutput: false,
passThreshold : 50,
unstableThreshold : 40,
otherFiles : "*.png",
]
)
def emailBody = '''${SCRIPT, template="robot.template"}'''
emailext body: emailBody,
subject: "[JENKINS BUILD]",
recipientProviders: [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']]
}
archiveArtifacts '*.html, *.xml, *.png'
}
}
}
But if I add another stage with some scripting, as for example, change the build name, then I will get a template error.
Pipeline that generates error:
pipeline {
agent any
stages {
stage('Init'){
steps{
script{
def name = ""
switch(testType){
case "newProduct":
def tmpProduct = pageID.split("/")
productName = tmpProduct[tmpProduct.size()-1]
name= storeID+": New Product ("+productName+")"
break
case "newHomepage":
name = storeID+": New Homepage"
break
case "newBlog":
name = storeID+": New Blog Post"
break
case "cosmetics":
name = storeID+": UI Changes"
break
default:
name = "Test type empty"
break
}
currentBuild.displayName = name
}
}
}
stage('Build') {
steps {
script{
bat "robot -v store:${storeID} -v testType:${testType} -v site:${pageID} -v productName: previews.robot"
}
}
}
}
post {
always{
script{
step(
[
$class : 'RobotPublisher',
outputPath : '.',
outputFileName : 'output.xml',
reportFileName : 'report.html',
logFileName : 'log.html',
disableArchiveOutput: false,
passThreshold : 50,
unstableThreshold : 40,
otherFiles : "*.png",
]
)
def emailBody = '''${SCRIPT, template="robot.template"}'''
emailext body: emailBody,
subject: "[JENKINS BUILD]",
recipientProviders: [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']]
}
archiveArtifacts '*.html, *.xml, *.png'
}
}
}
The name of the build is changed correctly and the script runs to the end without issues BUT in the email and console output I can see a template error:
Exception raised during template rendering: Cannot get property 'simpleName' on null object
java.lang.NullPointerException: Cannot get property 'simpleName' on null object
Any Pointers? I would really like to make a pipeline more rich but I will stay with the basic if I can't solve this problem...

Modify robot.template as below,which solved this problem.
if( action && (action.class.simpleName.equals("RobotBuildAction") ) )

Related

How to view script output (specifically PowerShell) from a Jenkinsfile?

I'm pretty new to Jenkins, so not totally clear on how to assign/read variables.
I have a jenkinsfile with a couple stages and a bunch of steps. In one of the steps, I want to run a PowerShell script but it isn't accomplishing the intent. The problem is, when I'm in Jenkins and I go to the Console Output to troubleshoot why the PowerShell script isn't working, I don't see any of the output from the powershell script, I just see this:
[Pipeline] {
[Pipeline] powershell (Test PowerShell Script)
[Pipeline] }
Here's a trimmed-down version of my code:
stages {
stage('Stage 1') {
agent { node {
label "Windows"
customWorkspace "D:\\Path"
}}
steps {
dir('Directory') {
withCredentials(
[usernameColonPassword(
credentialsId: 'credential1',
variable: 'BasicCred'
)]
) {
powershell(
label: 'Test PowerShell Script',
returnStdout: true,
script: 'echo Test'
)
}
}
}
}
}
I tried using the code provided in this Jenkins article:
steps {
dir('Directory') {
withCredentials(
[usernameColonPassword(
credentialsId: 'credential1',
variable: 'BasicCred'
)]
) {
def msg = powershell(
label: 'Test PowerShell Script',
returnStdout: true,
script: 'echo Test'
)
println msg
}
}
}
This threw an error:
WorkflowScript: 135: Expected a step # line 135, column 25.
def msg = powershell(
^
I also tried putting it inside a node:
steps {
dir('Directory') {
node {
withCredentials(
[usernameColonPassword(
credentialsId: 'credential1',
variable: 'BasicCred'
)]
) {
def msg = powershell(
label: 'Test PowerShell Script',
returnStdout: true,
script: 'echo Test'
)
println msg
}
}
}
}
But it threw an error that the node is missing a label, and when I tried adding a label it threw another error.
So what's the right way to go about this? I just want to capture the output from the PowerShell script and see it so I can troubleshoot why it isn't working.

Jenkins dynamic choice parameter to read a ansible host file in github

I have an ansible host file that is stored in GitHub and was wondering if there is a way to list out all the host in jenkins with choice parameters? Right now every time I update the host file in Github I would have to manually go into each Jenkins job and update the choice parameter manually. Thanks!
I'm assuming your host file has content something similar to below.
[client-app]
client-app-preprod-01.aws-xxxx
client-app-preprod-02.aws
client-app-preprod-03.aws
client-app-preprod-04.aws
[server-app]
server-app-preprod-01.aws
server-app-preprod-02.aws
server-app-preprod-03.aws
server-app-preprod-04.aws
Option 01
You can do something like the one below. Here you can first checkout the repo and then ask for the user input. I have implemented the function getHostList() to parse the host file to filter the host entries.
pipeline {
agent any
stages {
stage('Build') {
steps {
git 'https://github.com/jglick/simple-maven-project-with-tests.git'
script {
def selectedHost = input message: 'Please select the host', ok: 'Next',
parameters: [
choice(name: 'PRODUCT', choices: getHostList("client-app","ansible/host/location"), description: 'Please select the host')]
echo "Host:::: $selectedHost"
}
}
}
}
}
def getHostList(def appName, def filePath) {
def hosts = []
def content = readFile(file: filePath)
def startCollect = false
for(def line : content.split('\n')) {
if(line.contains("["+ appName +"]")){ // This is a starting point of host entries
startCollect = true
continue
} else if(startCollect) {
if(!line.allWhitespace && !line.contains('[')){
hosts.add(line.trim())
} else {
break
}
}
}
return hosts
}
Option 2
If you want to do this without checking out the source and with Job Parameters. You can do something like the one below using the Active Choice Parameter plugin. If your repository is private, you need to figure out a way to generate an access token to access the Raw GitHub link.
properties([
parameters([
[$class: 'ChoiceParameter',
choiceType: 'PT_SINGLE_SELECT',
description: 'Select the Host',
name: 'Host',
script: [
$class: 'GroovyScript',
fallbackScript: [
classpath: [],
sandbox: false,
script:
'return [\'Could not get Host\']'
],
script: [
classpath: [],
sandbox: false,
script:
'''
def appName = "client-app"
def content = new URL ("https://raw.githubusercontent.com/xxx/sample/main/testdir/hosts").getText()
def hosts = []
def startCollect = false
for(def line : content.split("\\n")) {
if(line.contains("["+ appName +"]")){ // This is a starting point of host entries
startCollect = true
continue
} else if(startCollect) {
if(!line.allWhitespace && !line.contains("[")){
hosts.add(line.trim())
} else {
break
}
}
}
return hosts
'''
]
]
]
])
])
pipeline {
agent any
stages {
stage('Build') {
steps {
script {
echo "Host:::: ${params.Host}"
}
}
}
}
}
Update
When you are calling a private repo, you need to send a Basic Auth header with the access token. So use the following groovy script instead.
def accessToken = "ACCESS_TOKEN".bytes.encodeBase64().toString()
def get = new URL("https://raw.githubusercontent.com/xxxx/something/hosts").openConnection();
get.setRequestProperty("authorization", "Basic " + accessToken)
def content = get.getInputStream().getText()

AWS EMR, Submit python pyspark script as step using terraform

I have successfully created an EMR cluster using terraform, as per terraform documentation, it's specified on how to submit a step to EMR as a jar
https://www.terraform.io/docs/providers/aws/r/emr_cluster.html#step-1
step {
action_on_failure = "TERMINATE_CLUSTER"
name = "Setup Hadoop Debugging"
hadoop_jar_step {
jar = "command-runner.jar"
args = ["state-pusher-script"]
}
}
where as documentation for adding a pyspark script as a step is missing.
Does anyone has experience adding pyspark script as EMR step using terraform ?
A common way to do this is to copy a script from S3 and use command-runner.jar to execute the script. (I don't know that it's ideal...)
step = [
{
name = "Copy script"
action_on_failure = "CONTINUE"
hadoop_jar_step {
jar = "command-runner.jar"
args = ["aws", "s3", "cp", "s3://path/to/script.py", "/home/hadoop/"]
}
},
{
name = "Run script"
action_on_failure = "CONTINUE"
hadoop_jar_step {
jar = "command-runner.jar"
args = ["bash", "/home/hadoop/script.py"]
}
},
]
Here is a working example of using hadoop_jar_step.
step = [
{
action_on_failure = "TERMINATE_CLUSTER"
name = "Setup Hadoop Debugging"
hadoop_jar_step = [
{
jar = "command-runner.jar"
args = [
"state-pusher-script"
]
main_class = ""
properties = {}
}
]
}
]
Contains workaround for https://github.com/hashicorp/terraform-provider-aws/issues/20911
Change args to your spark-submit command.

jenkins pipeline - both of groovy and powershell variables in powershell command

I trying to define powershell variable inside jenkins pipeline with the WORKSPACE variable in value. Is there a way to do this?
stage ('BUILD') {
steps {
powershell ("""Write-Output ${WORKSPACE}\\One\\Two\\""")
}
}
Output:
[Pipeline] powershell
18:18:15 C:\buildenv\Jenkins\workspace\project\One\Two\
[Pipeline] }
[Pipeline] // stage
That's nice. Now i need to wrap it into variable:
stage ('BUILD') {
steps {
powershell ("""$name02=${WORKSPACE}\\One\\Two\\""")
}
}
Output now:
groovy.lang.MissingPropertyException: No such property: name02 for class: groovy.lang.Binding
at groovy.lang.Binding.getVariable(Binding.java:63)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:264)
at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:288)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:292)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:268)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:268)
at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29)
at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
at WorkflowScript.run(WorkflowScript:50)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.delegateAndExecute(jar:file:/C:/buildenv/Jenkins/plugins/pipeline-model-definition/WEB-INF/lib/pipeline-model-definition.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:134)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.executeSingleStage(jar:file:/C:/buildenv/Jenkins/plugins/pipeline-model-definition/WEB-INF/lib/pipeline-model-definition.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:679)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.catchRequiredContextForNode(jar:file:/C:/buildenv/Jenkins/plugins/pipeline-model-definition/WEB-INF/lib/pipeline-model-definition.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:414)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.catchRequiredContextForNode(jar:file:/C:/buildenv/Jenkins/plugins/pipeline-model-definition/WEB-INF/lib/pipeline-model-definition.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:412)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.executeSingleStage(jar:file:/C:/buildenv/Jenkins/plugins/pipeline-model-definition/WEB-INF/lib/pipeline-model-definition.jar!/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy:678)
name02=''
pipeline {
agent any
stages{
stage ('BUILD') {
steps {
script{
name2 = powershell label: '', returnStdout: true, script: "return \"${Workspace}\\One\\Two\\\""
}
}
}
stage ('Print') {
steps {
echo "name2 = ${name2}"
}
}
}
}
pipeline {
agent any
stages{
stage ('BUILD') {
steps {
script{
powershell """
\$5name2 = "${Workspace}\\One\\Two\\"
Write-Output "name2 = \$5name2"
"""
}
}
}
}
}
def result = powershell returnStdout: true, script: '''
$result = ${WORKSPACE}\\One\\Two\\
return $result
'''

How to pass a parameter to a powershell script in a jenkins pipeline

How do I pass my variable VAR_A to an embedded powershell script in a jenkins pipeline ?
e.g.
def VAR_A = 'test'
def mystatus = powershell(returnStatus: true, script: '''
Write-Host "My result: '$VAR_A'" '''
withEnv(["VAR_A=test"]) {
def mystatus = powershell(returnStatus: true, script: '''
Write-Host "My result: '$VAR_A'" '''
}
both result with following output
My result: ''
Note : I prefer to define my powershell script in the jenkinsfile to keep things simple.
Try this:
node {
powershell '''
$VAR_A = 'test'
Write-Host "My result: '$VAR_A'"
'''
withEnv(["VAR_A=envtest"]) {
powershell '''
Write-Host "My result is empty: '$VAR_A'"
Write-Host "My env result: '$env:VAR_A'"
'''
}
}
The output is:
My result: 'test'
My result is empty: ''
My env result: 'envtest'
This was tested on Jenkins 2.73.1.
Note that:
$VAR_A = 'test' is declared within the first powershell '''...'''
env: is required to access environment variables (see about_Environment_Variables in the Microsoft Docs)