Jenkinsfile syntax error: No such property - jenkins

I'm trying to test a binary with latest commit id in Jenkins. Error happens at send slack message stage:
def kResPath = "/tmp/res.json" // global variable, where json file is dumped to; declared at the very beginning of Jenkinsfile
def check_result_and_notify(tier, result) {
def kExpected = 3
def kSuccessSlackColor = "#00CC00"
message = "Test ${tier} result: ${result}\n"
def test_result = readJSON file: kResPath
// 0 means index, "benchmarks", "real-time" is the key
real_time = test_result["benchmarks"][0]["real_time"]
if (real_time > kExpected) {
message += String.format("real time = %f, expected time = %f", real_time, kExpected)
}
slackSend(color: ${kSuccessSlackColor}, message: message.trim(), channel: "test-result")
}
The json file looks like:
{
"benchmarks": [
{
"real_time": 4,
},
{
"real_time": 5,
}
],
}
The error message I've received is hudson.remoting.ProxyException: groovy.lang.MissingPropertyException: No such property: kResPath for class: WorkflowScript
Can someone tell me what's wrong with my code?
Is there any way I could test it locally so that I don't need to commit it every single time? I googled and find it needs server id and password, which I don't think accessible to me :(

Your kResPath variable is undefined in the scope of that function or method (unsure which based on context). You can pass it as an argument:
def check_result_and_notify(tier, result, kResPath) {
...
}
check_result_and_notify(myTier, myResult, kResPath)
and even specify a default if you want:
def check_result_and_notify(tier, result, kResPath = '/tmp/res.json')

Related

get String value from Jenkins console output

In the Jenkins output, I had the following assert error
but I need to get the String error from the error assert or any text. I'm using I'm My JenkinsFile:
def matcher = manager.getLogMatcher('.*Delete organization Account failed: *')
but generates the following error:
So I just want to check, that the log contains a specific string and if the texts exists make the build failed currentBuild.result = "FAILED", saving the text to send it by slack
You can put the condition in below way :
if (manager.logContains('.*Delete organization Account failed:*')) {
error("Build failed because of Delete organization Account..")
}
This is how it worked for me:
import hudson.model.*
node {
.....
if (Slack.toBoolean() ) {
def matcher = manager.getLogMatcher(".*Error.*")
if(matcher.matches()) {
pbn=matcher.group(0)
println pbn
slack_message = "`BUILD ERROR`: ${pbn} "
println slack_message
matcher = null // fix NotSerializableException
slackSend(channel: "#reports", message: slack_message, color: '#172530');
}
}
}

How to list culprit users when Jenkins build fails (sending by Slack)

How I can list all culprits users related to the broken builds since the last successful build and the current one?
Besides that, how to compile all this information and then send by Slack?
The script below describes how to configure the post processing step to send culprits users from history of broken builds.
#!groovy​
pipeline {
agent { label 'pipeline-maven'}
post {
failure {
script {
def userDetailsService = load("get-users-details.groovy")
env.slack_msg = userDetailsService.getFailedBuildHistory()
}
slackSend baseUrl: 'https://xxx.slack.com/services/hooks/jenkins-ci/',
channel: '#xxxx',
color: 'bad',
token: 'aIPJis6V4P9VOpTFhUtCQRRL',
message: "Broken build ${currentBuild.fullDisplayName}\n${slack_msg}"
}
}
}
The script below (get-users-details.groovy) is responsible to enumerate all culprits based on the previous broken build history.
import jenkins.model.Jenkins
def String getFailedBuildHistory() {
def message = ""
// Iterate over previous broken builds to find culprits
def fullName = "pipeline-test"
def jobData = Jenkins.instance.getItemByFullName(fullName)
def lastStableBuild = jobData.getLastStableBuild()
def lastBuildNumber = jobData.getLastBuild().getNumber() - 1 // We subtract the current executing build from the list
if (lastStableBuild != null && lastStableBuild.getNumber() != lastBuildNumber) {
def culpritsSet = new HashSet();
message += "Responsibles:\n"
// From oldest to newest broken build, since the last sucessful build, find the culprits to notify them
// The list order represents who is more responsible to fix the build
for (int buildId = lastStableBuild.getNumber() + 1; buildId <= lastBuildNumber; buildId++) {
def lastBuildDetails = Jenkins.getInstance().getItemByFullName(fullName).getBuildByNumber(buildId)
if (lastBuildDetails != null) {
lastBuildDetails.getCulpritIds().each({ culprit ->
if (!culpritsSet.contains(culprit)) {
message += " ${culprit} (build ${lastBuildDetails.getNumber()})\n"
culpritsSet.add(culprit)
}
})
}
}
}
// Complement the message with information from the current executing build
if (currentBuild.getCurrentResult() != 'SUCCESS') {
def culprits = currentBuild.changeSets.collectMany({ it.toList().collect({ it.author }) }).unique()
if (culprits.isEmpty()) {
// If there is no change log, use the build executor user
def name = currentBuild.getBuildCauses('hudson.model.Cause$UserIdCause').userName
message += " ${name} (current build ${currentBuild.getId()})"
} else {
// If there is change log, use the committer user
culprits.each({ culprit ->
message += " ${culprit} (current build ${currentBuild.getId()})"
})
}
}
return message
}
return [
getFailedBuildHistory: this.&getFailedBuildHistory
]

Verifying Jenkins calls while testing pipeline code

I am writing a Jenkins pipeline library, and am having some difficulties with mocking/validating an existing Jenkins pipeline step.
I am using jenkins-spock by homeaway to unit test, but I think my problem is more Spock related.
import com.homeaway.devtools.jenkins.testing.JenkinsPipelineSpecification
import com.company.pipeline.providers.BuildLogProvider
class PublishBuildLogSpec extends JenkinsPipelineSpecification {
BuildLogProvider buildLogProvider = Mock()
PublishBuildLog publishBuildLog
def setup () {
publishBuildLog = new PublishBuildLog(buildLogProvider: buildLogProvider)
explicitlyMockPipelineStep('writeFile')
}
def "Gets the log file contents for a specific job and build"() {
when:
"the call method is executed with the jobName and buildNumber parameters set"
publishBuildLog.call("JOBNAME", "42")
then:
"the getBuildLog on the buildLogProvider is called with those parameters"
1 * buildLogProvider.getBuildLog("JOBNAME", "42")
}
def "the contents of log file is written to the workspace"() {
given:
"getBuildLog returns specific contents"
def logFileText = "Example Log File Text"
buildLogProvider.getBuildLog(_, _) >> logFileText
when:
"publishBuildLog.call is executed"
publishBuildLog.call(_, _)
then:
"the specific contents is passed to the writeFile step"
1 * getPipelineMock("writeFile").call([file: _ , text: logFileText])
}
}
This is my unit test. I am attempting to say that writeFile is called with the text matching the contents of logFileText, ignoring what the other parameters are. I have tried numerous combinations, but always seem to get the same or similar response to response of:
Too few invocations for:
1 * getPipelineMock("writeFile").call([file: _ , text: "Example Log File Text"]) (0 invocations)
Unmatched invocations (ordered by similarity):
1 * (explicit) getPipelineMock("writeFile").call(['file':'filename', 'text':'Example Log File Text'])
This is to test this class
import com.company.pipeline.providers.BuildLogProvider
class PublishBuildLog {
BuildLogProvider buildLogProvider = new BuildLogProvider()
void setBuildLogProvider(BuildLogProvider buildLogProvider) {
this.buildLogProvider = buildLogProvider
}
def call(def jobName, def buildNumber) {
def contents = buildLogProvider.getBuildLog(jobName, buildNumber)
writeFile(file: "filename", text: contents)
}
}
I am at a loss as to how to validate this call. I have a lot of experience with Java and Junit, but I am relatively new to Spock.
How can I verify this?
For me your test passes. But there is one thing I find strange: You use jokers in a when: block where you should really use concrete parameters like in the first feature method:
when: "publishBuildLog.call is executed"
publishBuildLog.call(_, _)
Instead you should write:
when: "publishBuildLog.call is executed"
publishBuildLog.call("JOBNAME", "42")
For me this works just fine if I use this as a dummy class in order to make the code compile (because you did not provide the source code):
class BuildLogProvider {
def getBuildLog(def jobName, def buildNumber) {}
}

Can config slurper parse methods with map as input variable

I am trying to parse a groovy file using config slurper like this .
fileContents = '''deployment {
deployTo('dev') {
test = me
}
}'''
def config = new ConfigSlurper().parse(fileContents)
The above code works because the deployto('dev') is simply accepting a string. But I add an extra parameter to it , it fails with this exception:
fileContents = '''deployment {
deployTo('dev','qa') {
test = me
}
}'''
def config = new ConfigSlurper().parse(fileContents)
It fails with the following exception :
Caught: groovy.lang.MissingMethodException: No signature of method: groovy.util.ConfigSlurper$_parse_closure5.deployTo() is applicable for argument types: (java.lang.String, java.lang.String, script15047332444361539770645$_run_closure3$_closure10) values: [dev, postRun, script15047332444361539770645$_run_closure3$_closure10#6b8ca3c8]
Is there a way around reading this config file with extra args in a module?
You are almost there. In order to use list of values, please do the below change.
From:
deployTo('dev','qa')
To:
deployTo(['dev','qa'])
It would be:
def fileContents = '''deployment { deployTo(['dev','qa']) { test = me } }'''
def config = new ConfigSlurper().parse(fileContents)​

Grails External Configuration. Can't access to external variable. Getting always [:]

I can't have my 'folder' external variable working. Always I'm getting [:].
I'm developing on Grails under Windows (this is why the external configuration file looks like file:C:\path\to/file).
I'm using external configuration in another project without problems, in the same way that I'm showing below.
I have this:
Config.groovy:
environments {
development {
grails.config.locations = [ "file:${userHome}/.grails/${appName}-config.groovy" ]
}
}
myApp-config.groovy:
stats.feed.wsdl.folder = '/static'
Controller and Service:
class WsdlController {
def wsdlService
def index = {
wsdlService.getEventsSchedule()
}
}
class WsdlService {
def grailsApplication
def getEventsSchedule = {
println "Locations: ${grailsApplication.config.grails.config.locations}"
println "Folder: ${grailsApplication.config.stats.feed.wsdl.folder}"
}
}
Console:
Locations: [file:C:\Users\myUser/.grails/myApp-config.groovy]
Folder: [:]
Any clue?
Thanks!
Updated!
This is the whole myApp-config.groovy:
println 'Start'
stats.feed.wsdl.folder = "/stats"
println 1
stats.feed.wsdl.folder.events = "${stats.feed.wsdl.folder}/events"
println 2
stats.feed.wsdl.folder.teams = "${stats.feed.wsdl.folder}/teams"
println 'End'
This is not working, the console shows:
Start
1
But if I change the variable names, it works.
println 'Start'
stats.feed.wsdl.folder = "${playcall.static.resources.folder}/stats"
println 1
stats.feed.wsdl.events.folder = "${stats.feed.wsdl.folder}/events"
println 2
stats.feed.wsdl.teams.folder = "${stats.feed.wsdl.folder}/teams"
println 'End'
Console:
Start
1
2
End
You create a property and declared this as a string:
stats.feed.wsdl.folder = "/stats"
In that way you isnt't able to add subproperties. So, to keep something close to what you want, you can do this:
stats.feed.wsdl.folder.base = "/stats"
stats.feed.wsdl.folder.events = "${stats.feed.wsdl.folder.base}/events"
stats.feed.wsdl.folder.teams = "${stats.feed.wsdl.folder.base}/teams"

Resources