I have a contants.groovy file as below
def testFilesList = 'test-package.xml'
def testdataFilesList = 'TestData.xml'
def gitId = '9ddfsfc4-fdfdf-sdsd-bd18-fgdgdgdf'
I have another groovy file that will be called in Jenkins pipeline job
def constants
node ('auto111') {
stage("First Stage") {
container('alpine') {
script {
constants = evaluate readTrusted('jenkins_pipeline/constants.groovy')
def gitCredentialsId = constants."${gitId}"
}
}
}
}
But constants."${gitId}" is says "cannot get gitID from null object". How do I get it?
It's because they are local variables and cannot be referenced from outside. Use #Field to turn them into fields.
import groovy.transform.Field
#Field
def testFilesList = 'test-package.xml'
#Field
def testdataFilesList = 'TestData.xml'
#Field
def gitId = '9ddfsfc4-fdfdf-sdsd-bd18-fgdgdgdf'
return this;
Then in the main script you should load it using load step.
script {
//make sure that file exists on this node
checkout scm
def constants = load 'jenkins_pipeline/constants.groovy'
def gitCredentialsId = constants.gitId
}
You can find more details about variable scope in this answer
Related
I am writing a terraform infrastructure pipeline, wherein I take multi-line string param from Jenkins, try to convert it to a map and pass it on to a terraform command.
Following is the code:
import groovy.json.JsonOutput
def parameters = env.params
def config
def service_map = [:]
def service_returned = [:]
node ("master"){
withEnv(['variable="test"', 'DB_ENGINE=sqlite']) {
stage('Input') {
config = readYaml text: "$parameters"
println(config)
config.each{ key, value ->
service_map = "$value"
service_returned = stringToMap(service_map)
println(service_returned)
}
}
stage('Terraform Plan') {
sh
"""
terraform init
terraform plan -var="instance=$service_returned"
"""
}
}
}
def stringToMap(service_string){
def map = [:]
service_string.split(" ").each { param ->
def nameAndValue = param.split(":")
map[nameAndValue[0]] = nameAndValue[1]
}
return map
}
When I print the service_returned map from the method "stringToMap". it gives a map like so:
{service="service", ec2_type="t2.micro"}
which is exactly what is need for terraform as a variable.
But the above code evaluates to this in the console output:
terraform plan -var='instance_ids=[service:"service", ec2_type:"t2.micro"]'
which does not work for terraform.
For reference, this is the input passed in Jenkins:
services:
service:"service"
ec2_type:"t2.micro"
What could be the reason for this?
Is there a way to use the same returned map in the shell module in above code?
there is a problem in terraform command line in your code. should be -var 'foo=bar'
and stringToMap returns not a correct go map syntax
import groovy.json.JsonOutput
//i assume you got this config from yaml
def config = [
services:[
service:"service",
ec2_type:"t2.micro"
]
]
//function that converts groovy plain map to a go lang representation of map
def map2go(map){
return "{"+map.collect{k,v-> "$k=${JsonOutput.toJson(v)}" }.join(",")+"}"
}
goMap = map2go(config.services)
sh """
terraform plan -var 'instance_ids=${goMap}'
"""
I'm trying to define variables in another groovy script that I want to use in my current script. I have two scripts like this:
script1.groovy
thing = evaluate(new File("script2.groovy"))
thing.setLocalEnv()
println(state)
script2.groovy
static def setLocalEnv(){
def state = "hi"
def item = "hey"
}
When I println(state), I get a missing property exception. Basically I want script2 to have config variables that I can load in the context of script1. How can I do this?
I'm not sure what/how you want to do exactly, but I guess you can achieve your goal using one of the class available in groovy dynamique scripting capabilities: groovy.lang.Binding or GroovyClassLoader or GroovyScriptEngine, here is an example using GroovyShell class:
abstract class MyScript extends Script {
String name
String greet() {
"Hello, $name!"
}
}
import org.codehaus.groovy.control.CompilerConfiguration
def config = new CompilerConfiguration()
config.scriptBaseClass = 'MyScript'
def shell = new GroovyShell(this.class.classLoader, new Binding(), config)
def script = shell.parse('greet()')
assert script instanceof MyScript
script.setName('covfefe')
assert script.run() == 'Hello, covfefe!'
This is one way to bind a variable to an external script file, more examples from the doc:
http://docs.groovy-lang.org/latest/html/documentation/guide-integrating.html
P.S. Loading external file can be done with GroovyClassLoader:
def gcl = new GroovyClassLoader()
def clazz2 = gcl.parseClass(new File(file.absolutePath))
Hope this helps.
I want to run some dynamic script with help of Groovyshell. But, i don't want to write new keyword in dynamic script. So, i thought of adding a CompilerConfiguration with Newify keyword. But, things are not working as expected.
CompilerConfiguration configuration = new CompilerConfiguration()
configuration.addCompilationCustomizers(
new ASTTransformationCustomizer(
[pattern: "[A-Za-z0-9].*"],
Newify
))
GroovyShell shell = new GroovyShell(profile, configuration)
Still i am getting error
Cannot find matching method sample#BoundingRegion(int, int, int, int)
where BoundingRegion is a class
Perhaps you need to provide more information. This works for me:
import org.codehaus.groovy.control.*
import org.codehaus.groovy.control.customizers.*
def script = '''
class Main {
static main(args) {
assert BigInteger.new(42).toString() == '42' // Ruby style
assert BigDecimal('3.14').toString() == '3.14' // Python style matching regex
}
}
'''
def configuration = new CompilerConfiguration()
configuration.addCompilationCustomizers(
new ASTTransformationCustomizer(
[pattern: "[A-Za-z0-9].*"],
Newify
))
new GroovyShell(configuration).evaluate(script)
I have prepared a test case in SoapUI Open Source which loops over values in csv file and sends request for each set of values (taken care of by groovy script). I want to modify it so each thread for each new iteration uses value from next row of csv file.
import com.eviware.soapui.impl.wsdl.teststeps.*
def testDataSet = []
def fileName = "C:\\sSHhrTqA5OH55qy.csv"
new File(fileName).eachLine { line -> testDataSet.add( line.split(",") ) }
def myProps = new java.util.Properties();
myProps = testRunner.testCase.getTestStepByName("Properties");
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context );
def testCase = testRunner.testCase;
def testStep = testCase.getTestStepByName("TestRequest");
testRunner = new com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner(testCase, null);
testStepContext = new com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext(testStep);
while (true) {
for ( i in testDataSet ) {
myProps.setPropertyValue("parameter0",i[0]);
myProps.setPropertyValue("username",i[1]);
myProps.setPropertyValue("parameter1",i[2]);
myProps.setPropertyValue("password",i[3]);
testStep.getTestRequest().setUsername(myProps.getPropertyValue("username"))
testStep.getTestRequest().setPassword(myProps.getPropertyValue("password"))
testStep.run(testRunner, testStepContext);
}
}
I want to modify this script so each thread from the pool gets unique (next) unused value from data source
I tried to use newFixedThreadPool from java.util.concurrent as suggested here (Concurrency with Groovy), however I can't get it to work - either requests are duplicated or SoapUI crashes (I am new to concurrency).
Can you please help me to get it right?
I think this would work for you:
while (true) {
for ( i in testDataSet ) {
def th = Thread.start(){
myProps.setPropertyValue("parameter0",i[0]);
myProps.setPropertyValue("username",i[1]);
myProps.setPropertyValue("parameter1",i[2]);
myProps.setPropertyValue("password",i[3]);
testStep.getTestRequest().setUsername(myProps.getPropertyValue("username"))
testStep.getTestRequest().setPassword(myProps.getPropertyValue("password"))
testStep.run(testRunner, testStepContext);
}
th.join()
}
So, new threads would be created on each loop.
If you wanted to test out if its working you could place loginfo(s) in the code...
log.info("Thread Id: " + Thread.currentThread().getId() as String)
I don't see your point. SoapUi already gives you a datasource test step that accepts a csv file as input.
So once you have all these values you can transfer the properties and run the test.
In Groovy Console I have this:
import groovy.util.*
import org.codehaus.groovy.runtime.*
def gse = new GroovyScriptEngine("c:\\temp")
def script = gse.loadScriptByName("say.groovy")
this.metaClass.mixin script
say("bye")
say.groovy contains
def say(String msg) {
println(msg)
}
Edit: I filed a bug report: https://svn.dentaku.codehaus.org/browse/GROOVY-4214
It's when it hits the line:
this.metaClass.mixin script
The loaded script probably has a reference to the class that loaded it (this class), so when you try and mix it in, you get an endless loop.
A workaround is to do:
def gse = new groovy.util.GroovyScriptEngine( '/tmp' )
def script = gse.loadScriptByName( 'say.groovy' )
script.newInstance().with {
say("bye")
}
[edit]
It seems to work if you use your original script, but change say.groovy to
class Say {
def say( msg ) {
println msg
}
}