Gpars withPool method called from Pipeline - jenkins

I have my GParsPool.withPool implemented in 'PreVerifymanager.groovy' as below.
import groovyx.gpars.GParsPool
public class PreVerifyManager {
static final THREADS = 3;
public void callMe() {
PreVerifyManager pf = new PreVerifyManager()
def apps = ["App1","App2","App3"]
GParsPool.withPool(PreVerifyManager.THREADS) {
apps.eachParallel {
pf.CreateFile(it)
}
}
}
public void CreateFile(String path){
path = "D:\\"+path+".txt";
println(path)
File file = new File(path)
file.write("Some text")
}
}
This works fine in my IDE with main method of PreVerifyManager. But when I remove the main method and call the method callMe on the object of PreVerifyManager created in Pipeline script, its not working.
Pipeline script as below:
node {
def PreVerifyManagerObj
stage 'TibcoConfig'
echo 'Reading Tibco configuration!'
println "****************INSIDE PIPELINE****************"
def parent = getClass().getClassLoader()
def loader = new GroovyClassLoader(parent)
PreVerifyManagerObj = loader.parseClass(new File("D://Tibco_Automation//src//com//meet//PreVerifyManager.groovy")).newInstance()
PreVerifyManagerObj.callMe()
}
Its basically, I'm integrating the GParsPool.withPool implementation with Pipeline scripting. Any input is appreciated.

The issue got resolved. You have to load all objects referred in your class into Pipeline script box, before you call your actual method.

Related

How can I mock a method an external script uses?

This is specific to Jenkins but hoping there is a generic groovy feature that can help me here.
I have a groovy script (myCustomStep.grooy) I want to unit test. It MUST be written like it is below (it cannot be a class). It will include methods that are available during Jenkins run time but not locally and I want to mock them out.
Here is one of these scripts and a corresponding test. How do I mock out echo without modifying myCustomStep.groovy?
# vars/myCustomStep.grooy
def call(Map config) {
def paramOne = config.paramOne
echo paramOne
}
class MyCustomStepTest {
// I tried to define it here but I get "No signature of method: myCustomStep.echo()"
def echo(message) {
println "$message"
}
#Test
public void "sdfsdfsdf"() throws Exception {
def aaa = new GroovyShell().parse( new File( 'vars/myCustomStep.groovy' ) )
aaa deployment: "sdlfsdfdsf"
}
}
I can't have myCustomStep.grooy accept echo as an argument. Is there a way to monkey patch echo into the myCustomStep namespace?
EDIT: I found a simple solution but now I want to know how I can attach methods to myCustomStep for all tests instead of having to redefine for every test. I tried to do this in a #Before method (using junit) but the myCustomStep obj wasn't available to the tests.
class MyCustomStepTest {
def myCustomStep = new GroovyShell().parse( new File( 'vars/myCustomStep.groovy' ) )
#Test
public void "sdfsdfsdf"() throws Exception {
// how can I attach this once for use by all my tests?
myCustomStep.echo = { String message -> println "$message" }
myCustomStep deployment: "sdlfsdfdsf"
}
}
EDIT:
I was just confused about where to instantiate the object. Looks like I just need to create the object outside of the #before method and then update it inside of it.
#Before
public void setUp() throws Exception {
myCustomStep.echo = { String message -> println "$message" }
}
def myCustomStep = new GroovyShell().parse( new File( 'vars/myCustomStep.groovy' ) )
You could put echo in the binding using something like this:
Binding b = new Binding()
b.echo = { println "Hello There" }
def shell = new GroovyShell(b)
def aaa = shell.parse( new File( 'ars/myCustomStep.groovy' ) )
aaa deployment: "sdlfsdfdsf"

Jenkins scripted Pipeline: How to apply #NonCPS annotation in this specific case

I am working on a scripted Jenkins-Pipeline that needs to write a String with a certain encoding to a file as in the following example:
class Logger implements Closeable {
private final PrintWriter writer
[...]
Logger() {
FileWriter fw = new FileWriter(file, true)
BufferedWriter bw = new BufferedWriter(fw)
this.writer = new PrintWriter(bw)
}
def log(String msg) {
try {
writer.println(msg)
[...]
} catch (e) {
[...]
}
}
}
The above code doesn't work since PrintWriter ist not serializable so I know I got to prevent some of the code from being CPS-transformed. I don't have an idea on how to do so, though, since as far as I know the #NonCPS annotation can only be applied to methods.
I know that one solution would be to move all output-related code to log(msg) and annotate the method but this way I would have to create a new writer every time the method gets called.
Does someone have an idea on how I could fix my code instead?
Thanks in advance!
Here is a way to make this work using a log function that is defined in a shared library in vars\log.groovy:
import java.io.FileWriter
import java.io.BufferedWriter
import java.io.PrintWriter
// The annotated variable will become a private field of the script class.
#groovy.transform.Field
PrintWriter writer = null
void call( String msg ) {
if( ! writer ) {
def fw = new FileWriter(file, true)
def bw = new BufferedWriter(fw)
writer = new PrintWriter(bw)
}
try {
writer.println(msg)
[...]
} catch (e) {
[...]
}
}
After all, scripts in the vars folder are instanciated as singleton classes, which is perfectly suited for a logger. This works even without #NonCPS annotation.
Usage in pipeline is as simple as:
log 'some message'

How do I import a Groovy class into a Jenkinfile?

How do I import a Groovy class within a Jenkinsfile? I've tried several approaches but none have worked.
This is the class I want to import:
Thing.groovy
class Thing {
void doStuff() { ... }
}
These are things that don't work:
Jenkinsfile-1
node {
load "./Thing.groovy"
def thing = new Thing()
}
Jenkinsfile-2
import Thing
node {
def thing = new Thing()
}
Jenkinsfile-3
node {
evaluate(new File("./Thing.groovy"))
def thing = new Thing()
}
You can return a new instance of the class via the load command and use the object to call "doStuff"
So, you would have this in "Thing.groovy"
class Thing {
def doStuff() { return "HI" }
}
return new Thing();
And you would have this in your dsl script:
node {
def thing = load 'Thing.groovy'
echo thing.doStuff()
}
Which should print "HI" to the console output.
Would this satisfy your requirements?

Access variable from config.groovy( in conf directory) inside a quartz job

I have a hashmap in config.groovy which i want to access from a Quartz Job in groovy
Map<String,Map<String, String>> projectname.config.Map1 = new HashMap<String, Map<String, String>>();
which i want to access inside the Quartz Job below:
import projectname.grails-app.conf.*;
class TrialJob {
static triggers = {
simple repeatInterval: 10000l // execute job once in 5 seconds
}
def execute() {
def Application
Map<String,Map<String, String>> Holder = Application.projectname.config.Map1
log.info()
}
}
If you declare the map in Config.groovy with
projectname.config.Map1 = []
(presumably you'll also want to put something in the map), then you should be able to retrieve it from your job class as shown below
import org.codehaus.groovy.grails.commons.GrailsApplication
class TrialJob {
GrailsApplication grailsApplication
static triggers = {
simple repeatInterval: 10000l // execute job once in 5 seconds
}
def execute() {
Map<String,Map<String, String>> map = grailsApplication.config.projectname.config.Map1
}
}

How to export environment variable from Jenkins Build Flow Plugin?

From the called build flow job, I've tried both:
build.environment['AOEU'] = 'aoeu' // callee would `println called.environment['AOEU']`
and:
upstream.environment['AOEU'] = 'aoeu' // callee would `println build.environment['AOEU']`
with no luck.
I fought a lot with that too and found no clean way to do it. I finally used EnvInjectPlugin in some ugly way to do this.
def buildEnv = build.getEnvVars();
varsToAdd = [:]
// add here your custom properties
buildEnv.putAll(varsToAdd)
import org.jenkinsci.plugins.envinject.EnvInjectPluginAction
def envInjectAction = build.getAction(EnvInjectPluginAction.class);
envInjectAction.overrideAll(buildEnv)
... the EnvInject plugin did the magic
I first tried to implement EnvironmentContributingAction
and add it as build.addAction(...) but did not work for me for unknown reason.
Be sure to set 'Flow run needs a workspace' in the called job.
#NoelYap: I can't comment on Hristo's answer, but it's the correct answer. The missing detail is that importing EnvInject only works if your job has the 'Flow run needs a workspace' option selected.
A simpler version based on Michael's solution
import hudson.model.*
def setEnvVariable(final String key, final String value) {
Thread.currentThread().getCurrentExecutable()
.addAction(new ParametersAction(new StringParameterValue(key, value))
);
}
setEnvVariable("THIS_ENV_VAR", "Hello World")
The variable is then available in the post-build actions.
An old question I know, but this is how i get around it. The beautiful part is this code works well in Jenkins both within the system evaluated groovy and within the Build FLow Job DSL.
Just drop the import statements when running it from the System Groovy job/console as they are already available.
As a bonus this class also helps get the environment variable regardless of the Groovy context. Still in the build flow you should favor build.environment.get it is more natural.
Note: 'Flow run needs a workspace' should be checked.
//Import the required bindings for a Build Flow DSL
import hudson.model.AbstractBuild
import hudson.model.EnvironmentContributingAction
import hudson.EnvVars
//Drop the above if running with a System Groovy Console/Job
class Job {
static def getVariable(String key) {
def config = new HashMap()
def thr = Thread.currentThread()
def build = thr?.getCurrentExecutable()
def envVarsMap = build.parent.builds[0].properties.get("envVars")
config.putAll(envVarsMap)
return config.get(key)
}
static def setVariable(String key, String value) {
def build = Thread.currentThread().getCurrentExecutable()
def action = new VariableInjectionAction(key, value)
build.addAction(action)
build.getEnvironment()
}
static def setVariable(String key, Integer value) {
setVariable(key, value.toString())
}
}
class VariableInjectionAction implements EnvironmentContributingAction {
private String key
private String value
public VariableInjectionAction(String key, String value) {
this.key = key
this.value = value
}
public void buildEnvVars(AbstractBuild build, EnvVars envVars) {
if (envVars != null && key != null && value != null) {
envVars.put(key, value);
}
}
public String getDisplayName() { return "VariableInjectionAction"; }
public String getIconFileName() { return null; }
public String getUrlName() { return null; }
}
Job.setVariable("THIS_ENV_VAR", "Hello World")
Will set the environment variable THIS_ENV_VAR to "Hello World"

Resources