how to share data between groovy files? - groovy

I have one common groovy file that contains few const variables and functions...
and I also have more groovy files with pipelineJob that use the variables and functions from the common file
what is the best way to import all the data from the common file to the other files?

I have not tested this with Jenkins, but if Jenkins executes the Groovy script as if by invoking groovy -cp .... myScript.groovy it should work:
utils.groovy:
// notice there's no "def", otherwise the def would be local only
name = 'Joe'
class MyUtils {
static String greeting(String name) {
"Hello $name"
}
}
src/main.groovy
def shell = new GroovyShell(getBinding())
shell.evaluate(new File('utils.groovy'))
println MyUtils.greeting(name)
Running it:
$ groovy src/Main.groovy
Hello Joe
Because the Script base class by default also has an evaluate method, your can actually just call that instead of using a GroovyShell and the result should be identical:
src/main.groovy
evaluate(new File('utils.groovy'))
println MyUtils.greeting(name)
If it doesn't work it's because the Script base class has been changed , probably... the first approach should work in all cases.

Related

How imported class work in Groovy Closure when calling it?

I have a Groovy Closure which uses some imported class like:
import com.XXX
Closure test = { a -> XXX(a) }
test('some str')
How the imported class XXX work inside closure test since I never defined the XXX in test.
In this case delegate and owner are point to current script and still not figure out how import work.
Thanks
This example works, maybe look at how you specify the import statement's package structure:
assert org.apache.commons.lang3.text.WordUtils.capitalizeFully('groovy closure') == 'Groovy Closure'
import org.apache.commons.lang3.text.WordUtils
Closure test = { a -> WordUtils.capitalizeFully(a) }
assert test('groovy closure') == 'Groovy Closure'
I finally figured out this is a Java related question.
"import" key word in Java is kind of a syntax sugar which let you claim a class without full path name. And when the class file be compiled, class name will be replaced by full path of import by compiler.
So in my case, XXX will be compiled to com.XXX inside Closure(does not matter it is a Java or Groovy class), and it will work in any class which been called.

Jenkins pipeline: read values from another jenkinsfile

I use a shared jenkins library and clone another git repo from there. That repo contains a jenkinsfile similar to the follwing:
#!/usr/bin/env groovy
#Library('mylib')
import jLib.*
someStage{
myparam = someValue
}
I want to read "someValue".
Currently I'm doing this with a regexp but this way I can only retrieve a String and not more complex values like a map.
In the documentation of Shared jenkins libs values are loaded from a jenkinsfile the following way:
def call(body) {
// evaluate the body block, and collect configuration into the object
def config = [:]
body.resolveStrategy = Closure.DELEGATE_FIRST
body.delegate = config
body()
}
How can I extract values from the Jenkinsfile in the workspace in a similar manner? Where does the body come from?
Thank you for your time
I found a solution.
Map configFromJenkinsfile(jenkinsfile){
def jenkinsfileConfig = [:]
def matches = jenkinsfile =~ /(?s)\{(.*?)\}/
def exec = new GroovyShell(new Binding(jenkinsfileConfig)).evaluate(matches[0][1])
return jenkinsfileConfig;
}
I tested it with passing jenkinsFile as string (after using String projectJenkinsFile = readFile "Jenkinsfile")
I execute the part in the jenkinsfile with all the assignments (between '{' and '}') in a groovyshell with my map as binding. All assignments without type are caught in the binding and can be accessed.

SoapUI & Groovy - How to get properties from different TestCases using Run testCase

Sorry in advance. I am sure this is not a new question but I swear I've been looking for days and have tried several solutions but no one fits exactly what I need. I hope you guys can help me...
My problem:
I have a main script which sends bash commands to our server:
TestSuite: Tools;
TestCase: sendBashCommands;
TestStep: groovycript;
This test script is called by several test cases using "Run testCase". Each test case have a different bash command:
TestSuite: ServerInfo
TestCase: getServerVersion
Property: BashCommand="cat smt | grep Version"
TestStep: Run sendBashCommands
TestCase: getServerMessage
Property: BashCommand="cat smt | grep Message"
TestStep: Run sendBashCommands
...
On my sendBashCommands.groovyScript I have already tried the following:
//def bashCmd= context.expand( '${#BashCommand}' );
//it returns empty;
//def bashCmd= testRunner.testCase.getPropertyValue( "BashCommand" );
//it returns null;
//def bashCmd= context.getTestCase().getPropertyValue( "BashCommand" );
//it returns null;
def bashCmd = context.expand('${#TestCase#BashCommand}');
//it also returns empty;
Currently I use a solution which works with project properties but what I actually need is working with these properties on the level of the test case which is calling the sendBashCommand script. Is that possible? How could I do it?
I think you are doing it for maintenance purpose...
As per your approach, the result has to come as null or empty. Because your groovyscript cannot get the properties of other testcases directly. If you call a getProperty() Method directly, then it will refer to the current testStep's property. So the following approach could help you.
put the following code in your individual test cases, "getServerVersion" etc.
def currentProject = testRunner.testCase.testSuite.project
// the following is to store the names of the test suite and the test cases from which you want to call your main script
currentProject.setPropertyValue("TestSuiteName",testRunner.testCase.getTestSuite().getLabel().toString())
currentProject.setPropertyValue("TestCaseName", testRunner.getTestCase().getLabel().toString())
// call sendBashCommands here -> run sendBashCommands
put this code in your main groovy script (sendBashCommands.groovyscript)
def currentProject = testRunner.testCase.testSuite.project
def callingTestCase = currentProject.testSuites[currentProject.getPropertyValue("TestSuiteName")].testCases[currentProject.getPropertyValue("TestCaseName")]
def bashCmd = callingTestCase.getPropertyValue( "BashCommand" )
// to verify
log.info bashCmd
The project is common to all the test suites, so you have to use project property in any case, i.e., for your requirement :)
Enjoy :)

GStringImpl in groovy File() constructor

I am running into a bit of a strange error here when creating a new file object with a GStringImpl. If I create a new File (and then list files in that path) with a GStringImpl, I get an empty array, and no error, however if I just a normal string, I get a list of files... While that makes sense in a way I would think that there would be an error somewhere.
Example:
def thisIsAListOfFiles = new File("/absolute/fs/mount/point").listFiles()
def gString = "${StaticClass.propertyStringThatIsAnAbsoluteFilePath}"
def notAListOfFiles = new File(gString).listFiles()
Any thoughts on what is going on here? Is this the expected behavior?
More info:
Groovy Version: 2.1.3
Grails version: 2.2.2 (this is within a grails app of course)
Java version: OpenJDK Runtime Environment (IcedTea 2.3.9)
I start out with a properties file with a bunch of properties like this
com.mycompany.property = "/absolute/directory/path"
Because I cant easily inject grailsApplication into non grails classes (anything in /src/groovy for instance) I inject grailsApplication into bootstrap, and use groovy config slurper to read the properties file from the classpath and set then as static string values in a groovy class Config.groovy. That groovy class then has the static variables of all of the properties I need anywhere within the application.
Note: this is not an issue reading the properties files, or anything along those lines. I log the Config.filePathProperty right before the new File(var).listFiles() occurs and that value is set properly.
I'm pretty sure your static path is set incorrectly. I ran the following code as a test:
String path = '/etc/'
print "String ($path): "
println(new File(path).listFiles().size())
def gpath = "${path}"
print "GString ($gpath): "
println(new File(gpath).listFiles().size())
class Foo {
static String path = '/etc/'
}
print "GString static ($Foo.path): "
println(new File("${Foo.path}").listFiles().size())
And got this result (obviously your file count will vary):
String (/etc/): 122
GString (/etc/): 122
GString static (/etc/): 122
The only time I saw a null result was when the path was invalid, for example:
assert new File("does-not-exist").listFiles() == null
One thing you could do would be to eliminate the GString, which is unnecessary in your example:
def notAListOfFiles = new File(StaticClass.propertyStringThatIsAnAbsoluteFilePath).listFiles()
But I'm sure you'll find a typo in the variable or file path, or another similar issue.

Creating Global Groovy Closure

I'm trying to learn how to create a global closure in groovy (like the println closure). I have the following code:
a.groovy
def header = Tools.&header
header 'groovy script a'
b.groovy
def header = Tools.&header
header 'groovy script b'
tools.groovy
class Tools {
def static header(String str) {
println("\n${str}")
println("-" * 80)
}
}
I would like to avoid:
def header = Tools.&header
in every groovy script where I would like to use the Tools.header() (and just use header closure when I import the tools package). I tried to put the definition after the Tools class, but that did not work. Can this be done? Is there a better way to handle this?
EDIT: (using a metaClass and the evaluate method unless there is a simpler way to include an external script):
a.groovy
evaluate(new File("Tools.groovy"))
header 'groovy script a'
b.groovy
evaluate(new File("Tools.groovy"))
header 'groovy script b'
tools.groovy
Object.metaClass.header = {str ->
println("\n${str}")
println("-" * 80)
}
println is not actually a global closure. It's a method that is added to java.lang.Object using groovy metaprogramming. Because all classes extend Object - including the script class that wraps code run in the groovy console - println can be called from anywhere.
You can add your own methods to Object. Run this code in the Groovy console to see it in action:
// Add a global sayHello() method
Object.metaClass.sayHello = {-> println 'hello' }
// Try it out
sayHello()
import static Tools.header should do the trick. You don't need a closure in this case as you call simple method. If you'll have to pass header as a closure somewhere in your code of a.groovy or b.groovy the &header still could be used.

Resources