How do I import a class using GroovyScript and Jenkins? - jenkins

I have the following in a groovy file...
// jenkins/Application.groovy
package jenkins
class Application{
String name
Application(name){
this.name = name
}
}
I am trying to import it and I have tried these but none seem to work. These are all in jenkins/Test.groovy
final GroovyScriptEngineImpl engine = (GroovyScriptEngineImpl) this.scriptingEngines.getEngineByName("groovy");
GroovyClassLoader classLoader = engine.getClassLoader();
classLoader.parseClass(new GroovyCodeSource("./jenkins/Application.groovy"))
engine.setClassLoader(classLoader)
This gives..
Script1.groovy: 17: unable to resolve class Application
Then I tried...
// jenkins/Application.groovy
// Added
return { Application }
// jenkins/Test.groovy
app = load "./jenkins/Application.groovy"
def dna = new app.Application("blah")
and I get...
Script1.groovy: 11: unable to resolve class app.Application
How do I import a call in a Jenkins GroovyScript?
Update
I changed my code to the following (and moved into a domain folder)...
app = load "./jenkins/domain/Application.groovy"
def dna = app.newInstance([name:"blah"] as Object[])
When I run I get...
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods newInstance java.lang.Class java.lang.Object[]

the idea
you could return from loaded script - the class (not an instance)
then to create new instance you could call class.newInstance( Object [] argList )
http://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Class.html#newInstance(java.lang.Object[])
so, theoretically this should work:
./jenkins/Application.groovy
class Application{
String name
Application(name){
this.name = name
}
}
return Application.class
pipeline:
def app = load "./jenkins/Application.groovy"
def dna = app.newInstance( "blah" )

Related

In a Jenkins shared library infrastructure, how do I import class in another file?

I'm using Jenkins shared library plugin and have the following structure
src/com/domain/service/baseClass.groovy
" /subClass.groovy
I have this in baseClass.groovy
class BaseClass {
Integer port = 5000
String name = null
}
and I want to be able to do this in subClass.groovy
import com.domain.service.baseClass
class SubClass extends BaseClass {
String name = 'myName'
}
def printValues()
SubClass sc = new SubClass()
println "Name: $sc.name, Port: $sc.port"
}
The idea is I want to define common attributes in my BaseClass and reuse (e.g. port) or override (e.g., name) them in my SubClass. You know - OOD. I can have several sub classes all inheriting from BaseClass.
Then in my Jenkins pipeline job config page, I do (I set up 'my-repo' as a shared library in my system configuration)
node('linux-node') {
#library('my-repo')
def sb = new com.domain.service.subClass()
sb.printValues()
}
When I run this pipeline, I get the following. Does the shared library support this kind of hierarchy?
subClass.groovy: 3: unable to resolve class BaseClass
Use the package definition in class files
package com.domain.service
class BaseClass {
Integer port = 5000
String name = null
}
and
package com.domain.service
import com.domain.service.baseClass
class SubClass extends BaseClass {
String name = 'myName'
}

Jenkins: Calling a GLOBAL library from a FOLDER library

I have a global library, which is normally loaded thusly:
#Library('pipelineUtilities')
def utils = new com.booty.jenkins.libraries.pipelineUtilities()
I have a folder library (in the vars directory), which looks like this:
#!groovy
class vars {
public static String gitAuthorization = "Basic TEzZmVGMH...lZMTNmZUYwZWU="
}
I hate hardcoding stuff like that, so I want to use a util function called getBasicAuth()
public String getBasicAuth(String account, String password){
String userPass = account + ":" + password
String basicAuth = "Basic "+ userPass.getBytes().encodeBase64()
return basicAuth
}
When I try to just use the #Library without actually using a library
#!groovy
#Library('pipelineUtilities')
class vars {
public static String gitAuthorization = "Basic TEzZmVGMH...lZMTNmZUYwZWU="
}
there is no problem, but nothing interesting really happens, of course, we just processed the #library annotation.
However:
#!groovy
#Library('pipelineUtilities')
def utils = new com.booty.jenkins.libraries.pipelineUtilities()
class vars {
private String serviceAccount = "xxxxyyyy"
private String serviceAccountPassword = "yyyyzzzzzz"
public String gitAuthorization = utils.getBasicAuth(serviceAccount, serviceAccountPassword)
}
does not pass the def utils = new com..... step, let alone call utils.getBasicAuth(). What it does is crash in some mysterious way.
So - 2 questions:
how do I put a try/catch block inside my code so i can see what went wrong in the #library section
How do I call a global library from within a folder library...
Alas, it is all so counter intuitive :-(
Thanks, .a.

Gpars withPool method called from Pipeline

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.

Null Pointer exception when calling service method from controller

I have a method in service class which has to be called from the controller. Both the controller and the service class codes are as below.
folder grails-app/services, file FileFactoryService.groovy
package edu.rev.document
import grails.transaction.Transactional
Class FileFactoryService{
Document document = new Document() // Domain object
def build(byte[] fileArray){
String str = new String(fileArray, "UTF-8") // UTF encoding as invoice may contain negative values
String[] lines = str.split("\\r?\\n")
document.version = lines[0].substring(0,1)
document.name = lines[1].substring(0,25)
}
return document.properties.collect()
}
Controller Code: folder: grails-app/controllers, file: FileController.groovy
package edu.rev.document
Class FileController{
def fileFactoryService
def save(){
def file = request.getFile('file')
if(file.empty) {
flash.message = "File cannot be empty"
} else {
def myList = fileService.build(file.getBytes())
}
}
The error thrown is
NullPointer exception when processing [POST]/../save
Cannot invoke method build() on NULL object
Can you please point me to the mistake I might be committing? Let me know if you need any other information
EDIT:This is the code. Just a heads up, the same logic when taken out of the service and implemented in the controller itself works perfectly alright. One more thing, when I use the "." operator inside the service (say document.), it doesnt show may any auto complete options like document.name.
Posting all of your code helps in finding the error. This line in your controller class
def myList = fileService.build(file.getBytes())
should be
def myList = fileFactoryService.build(file.getBytes())
In your controller class, you declared the service as :
def fileService
But the name of your service class is :
Class FileFactoryService
For Grails dependency injection to work, you need to name the variable like your class name :
def fileFactoryService
Then this should work.

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