Very basic question but I cannot find an answer:
I have the below code in a file g.groovy, and it functions in printing output:
#! /usr/env/groovy
def matchFiles = { match ->
new File(".").eachFile() {
if (it.name =~ match) {
println it
}
}
}
matchFiles('.groovy') prints ./g.groovy to screen.
But I want to capture the output of the closure in a variable and use it elsewhere, e.g.
def fileMatches = matchFiles('.groovy')
but cannot figure this out.
Tried changing println it to return it and then running
def fileMatches = matchFiles('.groovy')
fileMatches.println { it }
but this prints something like g$_run_closure2#4b168fa9
Any help is much appreciated, sorry for any incorrect nomenclature, very new to Groovy
according to the name matchFiles I assume you want to return all matched files
so, you have to define an array result variable where you are going to store each matched file
and then return this result variable after eachFile{...} closure
def matchFiles = { match ->
def result=[]
new File(".").eachFile {
if (it.name =~ match) {
result.add(it)
}
}
return result
}
println matchFiles(/.*/)
Related
Is there a way, i can access a variable outside the closure. The closure here is a stage in the Jenkinsfile. So, the snippet looks like this:
node('pool'){
try{
stage('init'){
def list = []
//some code to create the list
}
stage('deploy'){
//use the list create in the above stage/closure
}
}
catch(err){
//some mail step
}
}
With this code, i cannot access the list which was created in the first stage/closure.
How can i set to get this newly created list accessible to the next stage/closure?
#tim_yates.. with your suggestion. This works. It was easy at the end :)
node('pool') {
try {
def list = [] //define the list outside of the closure
stage('init') {
//some code to create/push elements in the list
}
stage('deploy') {
//use the list create in the above stage/closure
}
} catch (err) {
//some mail step
}
}
I know it's late, but worths mentioning that when you define a type or def (for dynamic resolution) you're creating a local scope variable that will be available only inside the closure.
If you omit the declaration the variable will be available to the whole script:
node('pool'){
try {
stage('Define') {
list = 2
println "The value of list is $list"
}
stage('Print') {
list += 1
echo "The value of list is $list"
}
1/0 // making an exception to check the value of list
}
catch(err){
echo "Final value of list is $list"
}
}
Returns :
The value of list is 2
The value of list is 3
Final value of list is 3
I have just started with spock. I have one functionality. where the java function makes an http call. As per functionality, the URI used in http call, must contain "loc" parameter and it should be only once.
I am writing Spock test case. I have written below snippet.
def "prepareURI" () {
given: "Search Object"
URI uri = new URI();
when:
uri = handler.prepareURI( properties) // it will return URI like http://example.com?query=abc&loc=US
then:
with(uri)
{
def map = uri.getQuery().split('&').inject([:]) {map, kv-> def (key, value) = kv.split('=').toList(); map[key] = value != null ? URLDecoder.decode(value) : null; map }
assert map.loc != null
}
}
From above snippet, my 2 tests got passed like
It should be exists
It should not be null
I want to check the count of "loc" query parameter. It should be passed exactly once. With map as above, If I pass "loc" parameter twice, map overrides the old value with 2nd one.
Does any one knows, how to access the query parameters as list, and in list I want to search the count of Strings which starts with "loc"
Thanks in advance.
Perhaps an example would be the best start:
def uri = new URI('http://example.com?query=abc&loc=US')
def parsed = uri.query.tokenize('&').collect { it.tokenize('=') }
println "parsed to list: $parsed"
println "count of 'loc' params: " + parsed.count { it.first() == 'loc' }
println "count of 'bob' params: " + parsed.count { it.first() == 'bob' }
println "count of params with value 'abc': " + parsed.count { it.last() == 'abc' }
prints:
$ groovy test.groovy
parsed to list: [[query, abc], [loc, US]]
count of 'loc' params: 1
count of 'bob' params: 0
count of params with value 'abc': 1
the problem, as you correctly noted, is that you can not put your params into a map if your intent is to count the number of params with a certain name.
In the above, we parse the params in to a list of lists where the inner lists are key, value pairs. This way we can call it.first() to get the param names and it.last() to get the param values. The groovy List.count { } method lets us count the occurences of a certain item in the list of params.
As for your code, there is no need to call new URI() at the beginning of your test as you set the value anyway a few lines down.
Also the with(uri) call is unnecessary as you don't use any of the uri methods without prefixing them with uri. anyway. I.e. you can either write:
def uri = new URI('http://example.com?query=abc&loc=US')
def parsed = uri.query.tokenize('&').collect { it.tokenize('=') }
or:
def uri = new URI('http://example.com?query=abc&loc=US')
uri.with {
def parsed = query.tokenize('&').collect { it.tokenize('=') }
}
(note that we are using query directly in the second example)
but there is not much point in using with if you are still prefixing with uri..
The resulting test case might look something like:
def "prepareURI"() {
given: "Search Object"
def uri = handler.prepareURI( properties) // it will return URI like http://example.com?query=abc&loc=US
when:
def parsed = query.tokenize('&').collect { it.tokenize('=') }
then:
assert parsed.count { it.first() == 'loc' } == 1
}
I've got a switch case like this:
def someString = 'hello1234bla'
// ...
switch (someString) {
case {it.contains('1234')}:
doSomething()
break
case {it.contains('2468')}:
doSomethingElse()
break
default:
throw new Exception("ERROR: Number not found")
break
}
This seems to be quite a lot of code for something so seemingly simple. All I want is to have different functions be executed when someString contains a specific substring. Is there no simpler way to do this, apart from maybe an if-else cascade?
This is pretty close to what the comments above suggest, but I'll write out a working example with indentation etc and perhaps it will be a bit more readable:
def someString = "hello1234bla"
def found = [
'1234': { println "do something" },
'2468': { println "do something else" }
].find { pattern, action ->
if (someString.contains(pattern)) { action(); true }
else false
}
if (!found) throw new Exception("ERROR: Number not found")
this executes the first matching action and throws an exception if no matches were found. If you need to execute an action for every match, replace the find call with a findAll call.
Another way of executing code based on a pattern in the string is the groovy String eachMatch method:
def someString = "hello1234blae"
someString.eachMatch(/1234/) { println "do something" }
someString.eachMatch(/2468/) { println "do something else" }
which uses regular expressions and runs the closure (the block in the curlies after the eachMatch call) once for every match. Thus:
someString.eachMatch(/e/) { println "runs twice" }
on the above string would execute twice as there are two 'e' characters in the string.
I would like to write a system groovy script which inspects the queued jobs in Jenkins, and extracts the build parameters (and build cause as a bonus) supplied as the job was scheduled. Ideas?
Specifically:
def q = Jenkins.instance.queue
q.items.each { println it.task.name }
retrieves the queued items. I can't for the life of me figure out where the build parameters live.
The closest I am getting is this:
def q = Jenkins.instance.queue
q.items.each {
println("${it.task.name}:")
it.task.properties.each { key, val ->
println(" ${key}=${val}")
}
}
This gets me this:
4.1.next-build-launcher:
com.sonyericsson.jenkins.plugins.bfa.model.ScannerJobProperty$ScannerJobPropertyDescriptor#b299407=com.sonyericsson.jenkins.plugins.bfa.model.ScannerJobProperty#5e04bfd7
com.chikli.hudson.plugin.naginator.NaginatorOptOutProperty$DescriptorImpl#40d04eaa=com.chikli.hudson.plugin.naginator.NaginatorOptOutProperty#16b308db
hudson.model.ParametersDefinitionProperty$DescriptorImpl#b744c43=hudson.mod el.ParametersDefinitionProperty#440a6d81
...
The params property of the queue element itself contains a string with the parameters in a property file format -- key=value with multiple parameters separated by newlines.
def q = Jenkins.instance.queue
q.items.each {
println("${it.task.name}:")
println("Parameters: ${it.params}")
}
yields:
dbacher params:
Parameters:
MyParameter=Hello world
BoolParameter=true
I'm no Groovy expert, but when exploring the Jenkins scripting interface, I've found the following functions to be very helpful:
def showProps(inst, prefix="Properties:") {
println prefix
for (prop in inst.properties) {
def pc = ""
if (prop.value != null) {
pc = prop.value.class
}
println(" $prop.key : $prop.value ($pc)")
}
}
def showMethods(inst, prefix="Methods:") {
println prefix
inst.metaClass.methods.name.unique().each {
println " $it"
}
}
The showProps function reveals that the queue element has another property named causes that you'll need to do some more decoding on:
causes : [hudson.model.Cause$UserIdCause#56af8f1c] (class java.util.Collections$UnmodifiableRandomAccessList)
How can I do this in Spock/groovy?
package org.jenkinsci.plugins
import hudson.matrix.*
import spock.lang.*
import org.junit.Rule
import org.jvnet.hudson.test.JenkinsRule
class xxxx extends Specification {
#Rule JenkinsRule rule = new JenkinsRule()
def 'matrix'() {
given:
def matrixProject = rule.createMatrixProject()
AxisList axl = new AxisList();
def axis = new TextAxis('TEST', "1", "2", "3")
axl.add(axis)
matrixProject.setAxes(axl)
expect: matrixProject.scheduleBuild2(0).get().logFile.text.contains("Some String!")
matrixProject.scheduleBuild2(0).get().getRuns().each(){
expect: it.logFile.text.contains("Another String")
}
}
}
specifically, how can I run a closure with a nested test? The "Another String" test doesn't work
Does this work?
def 'matrix'() {
given:
def matrixProject = rule.createMatrixProject()
def axis = new TextAxis('TEST', "1", "2", "3")
matrixProject.axes.add(axis)
expect:
with( matrixProject.scheduleBuild2(0).get() ) {
logFile.text.contains("Some String!")
runs.every { it.logFile.text.contains("Another String") }
}
}
}
Either use every instead of each, or use a nested assert.
I'm not sure if I understand your question well. However if by nested test you mean evaluating statement inside of each closure, why not just use assert
expect:
matrixProject.scheduleBuild2(0).get().logFile.text.contains("Some String!")
matrixProject.scheduleBuild2(0).get().getRuns().each() {
assert it.logFile.text.contains("Another String")
}
#tim_yates's approach also seems fine and it's more like Spock's way. I haven't tested it though.
EDIT
If you want be sure that all logFiles contain test string then use 'every' method as Peter suggested.
expect:
...
matrixProject.scheduleBuild2(0).get().getRuns().every {
it.text.contains('Another String')
}
Other approach, if you prefer to know how many logFiles don't contain test string on test fail count them and compare result size to zero:
expect:
...
matrixProject.scheduleBuild2(0).get().getRuns().count {
!it.text.contains('Another String')
} == 0
Yet another, if you like to know which files caused test to fail, get names of those which don't contain test string and compare that to an empty list:
expect:
...
matrixProject.scheduleBuild2(0).get().getRuns().findAll {
!it.text.contains('Another String')
}*.name == []