function lines after httpRequest are not executed in groovy jenkins pipeline - jenkins

None of the lines after making httpRequest are getting executed. Everything else works fine in this function. What could be going wrong here?
However, network request is going fine and I am able to see the response in the console. httpRequest is being made via plugin
I've even tried CURL - but lines after curl are not executed.
#NonCPS
def doPRCommentBasedTesting() {
def causes = currentBuild.rawBuild.getCauses()
def commentURL
for(cause in causes) {
if (cause.class.toString().contains("GitHubPullRequestCommentCause")) {
commentURL = cause.getCommentUrl()
commentURL = commentURL.substring(commentURL.lastIndexOf("-") + 1)
println "This job was caused by job " + commentURL
def url1 = "https://<git_url>/api/v3/repos/<owner>/<repo>/issues/comments/" + commentURL
def commentText = httpRequest authentication: '<auth_cred>', url: url1, consoleLogResponseBody: true
println commentText
println commentText.getClass()
println "hello world, how are you doing today?"
}
else {
println "Root cause : " + cause.toString()
}
}
println "==============================="
return 0
}

A non cps function does not have the ability to pause in between because it runs in a go. You need to put network call into a different function that is not marked as nonCPS and then it will work. In general the nonCPS block should be very small and limited to code that cannot be serialised

Related

From deprecated cliOnline to OnlineNodeCommand

So I created this groovy script but read that the cliOnline() command is deprecated.
But I can't seem to figure out how to actually change my code to use hudson.model.Hudson.instance.OnlineNodeCommand()?
deprecated cliOnline
def nodes_checklist = ["PD100069", "PD100070", "PD100090", "PD10756"]; // List of nodes which should be turned online
def jenkinsNodes = jenkins.model.Jenkins.instance.getNodes() // Get all existing nodes on this Jenkins URL
for(def node_checker: nodes_checklist) {
for(def node: jenkinsNodes) {
if(node.getNodeName().contains(node_checker)) {
println "The node " + node.getNodeName() + "'s offline status: " + node.toComputer().isOffline()
if (node.toComputer().isOffline()){
println "Turning " + node.getNodeName() + " online"
node.toComputer().cliOnline() // If node is offline, turn it online
println node.getNodeName() + "'s online status: " node.toComputer().isOnline()
}
}
}
}
Does anyone know how to rewrite this to use the non-deprecated version?
If you look at this depricated method, it simply calls a non depricated method setTemporarilyOffline(boolean temporarilyOffline, OfflineCause cause). So not sure why this was depricated. Anyway instead of using cliOnline() you can use setTemporarilyOffline. Check the following.
node.getComputer().setTemporarilyOffline(false, null)
Some proper code with a proper cause. Cause is not really needed when setting the node online though.
import hudson.slaves.OfflineCause.UserCause
def jenkinsNodes = Jenkins.instance.getNodes()
for(def node: jenkinsNodes) {
if (node.getComputer().isTemporarilyOffline()){
node.getComputer().setTemporarilyOffline(false, null)
}
}
Setting to temporarily offline
UserCause cause = new UserCause(User.current(), "This is a automated process!!")
node.getComputer().setTemporarilyOffline(true, cause)

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) {}
}

Jenkins Pipeline Execute Multiple FreeStyleProjects in Parallel [duplicate]

The script is not iterating through all the values of the 'modules' array.
class Module {
public String name = '';
public Boolean isCustom = false;
public Module(String name, Boolean custom){
this.name = name;
this.isCustom = custom;
}
}
//creates array from the ext_module env var
modules = [];
EXT_MODULE.split(',').each {
modules.add(new Module(it, false));
}
println modules;
modules.each {
println "MODULE NAME ::::: ${it.name}"
if(it.isCustom)
{
println "install custom";
} else {
println "install non custom";
}
};
This is the result of the run. The array shows 4 elements, but the code inside the .each black only executes once.
Running: Print Message
[Module#71f09325, Module#e1ddb41, Module#7069a674, Module#1f68f952]
Running: Print Message
MODULE NAME ::::: puppetlabs-ntp
Running: Print Message
install non custom
Running: End of Workflow
Finished: SUCCESS
The messages "Running: Print Message" and "Running: End of Workflow" indicate that you are using the new workflow plugin: https://wiki.jenkins-ci.org/display/JENKINS/Workflow+Plugin. This plugin currently has a bug causing at least some Groovy iterations involving a closure to be aborted after one iteration: https://issues.jenkins-ci.org/browse/JENKINS-26481
The workaround is to simply use an old school for loop (code below).
Also, NonCPS is another workaround.
There is an open issue for this matter. See here: https://issues.jenkins-ci.org/browse/JENKINS-26481
Update, Oct 24th, 2016
/**
* Dumps environment varibles to the log, using an old school for loop.
*/
import com.cloudbees.groovy.cps.NonCPS
def version = '1.0'
#NonCPS
def dumpEnvVars() {
def str = "Dumping build environment variables...\n"
for (Map.Entry<String, String> entry : currentBuild.build().environment) {
str += " ${entry.key} = ${entry.value}\n"
}
echo str
}
return this;
As of yesterday, the new Pipeline plugin was delivered in version 2.0 and correct this problem.
.each closures now work, but .collect still only iterate once.

run something async in Grails 2.3

In My Grails service, there is a part of a method I wish to run asynchronously.
Following, the doc for 2.3.x http://grails.org/doc/2.3.0.M1/guide/async.html
I do
public class MyService {
public void myMethod() {
Promise p = task {
// Long running task
}
p.onError { Throwable err ->
println "An error occured ${err.message}"
}
p.onComplete { result ->
println "Promise returned $result"
}
// block until result is called
def result = p.get()
}
}
However, I want to execute mine without any blocking. The p.get() method blocks. How do I execute the promise without any sort of blocking. I don't care if myMethod() returns, it is a kinda of fire and forget method.
So, according to the documentation if you don't call .get() or .waitAll() but rather just make use of onComplete you can run your task without blocking the current thread.
Here is a very silly example that I worked up in the console to as a proof of concept.
import static grails.async.Promises.*
def p = task {
// Long running task
println 'Off to do something now ...'
Thread.sleep(5000)
println '... that took 5 seconds'
return 'the result'
}
p.onError { Throwable err ->
println "An error occured ${err.message}"
}
p.onComplete { result ->
println "Promise returned $result"
}
println 'Just to show some output, and prove the task is running in the background.'
Running the above example gives you the following output:
Off to do something now ...
Just to show some output, and prove the task is running in the background.
... that took 5 seconds
Promise returned the result

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