I have jenkinsfile with defined Globals varible for timeout
class Globals {
static String TEST_TIMEOUT = ""
}
I am using functions from shared library
I am using the global variable to set a timeout for function. Since the shared library used by other projects that doesn't define the Globals variable I defined environment variable in the function file to be used as default value for time out.
env.TESTS_TIME_OUT="10080"
Then in function I want to check if Globals variable exists, I want to use the value as time out, if not the to use the default value.
if(Globals.TEST_TIMEOUT){
env.TESTS_TIME_OUT= "${Globals.TEST_TIMEOUT}"
}
timeout(time: "${env.TESTS_TIME_OUT}", unit: 'MINUTES') {
.
.
.
}
I`ve done it before with success on env parameters, but this time I am getting an error
No such field found: field java.lang.Class TEST_TIMEOUT
Any ideas how to solve this ? Or Any other way to check if Globals variable exists ?
Thank you
You can catch groovy.lang.MissingPropertyException which will be thrown if either Globals or Globals.TEST_TIMEOUT does not exist:
try {
env.TESTS_TIME_OUT = Globals.TEST_TIMEOUT
}
catch( groovy.lang.MissingPropertyException e ) {
env.TESTS_TIME_OUT = "10080"
}
You could even move this pattern into a generic function...
def getPropOrDefault( Closure c, def defaultVal ) {
try {
return c()
}
catch( groovy.lang.MissingPropertyException e ) {
return defaultVal
}
}
... which could be called like this:
env.TESTS_TIME_OUT = getPropOrDefault({ Globals.TEST_TIMEOUT }, '10080')
This could be useful if there are many different globals that you want to treat similar. Safes you from writing many try/catch blocks.
The closure is required to make sure that the expression Globals.TEST_TIMEOUT will be evaluated inside of the try/catch block of getPropOrDefault instead of before the function call.
Related
void main() {
doStuff("foo");
}
void doStuff(String myString) {
String myString = "bar";
print(myString); //prints "bar"
}
The above executed in the dartpad yields "bar", the local variable is used instead of the parameter in the last line. If instead of an argument myString were an instance variable of a class, we could access the original myString with this.myString to print "foo". Is there an analogous way to access an argument to a function after a homonymous local variable has been declared?
No.
For local variables, you are expected to be able to rename any local variable which shadows the variable you want to access, so there is no scope override.
For instance variables, you can use this.x, for static variables you can use ClassName.x, for an imported top-level name, you can import the library with a fresh prefix name and access it as prefix.x, and for public top-level variable of the current library, you can, if all else fails, import that library with a prefix too and use:
// library foo.dart
import "foo.dart" as toplevel; // <- this library!
// ...
int foo = 42;
// ...
int method(int foo) {
return toplevel.foo + foo; // Wohoo
For local variables, you just have to rename the one that's shadowing the variable you want. Since nobody can see local variables from outside the method, no-one will ever know.
Is it possible to have a single .groovy file that has some utility functions defined and have one of those functions call another in that file?
note: for context, this is being used for Jenkins Pipeline library under vars folder. I wanted to have a function used for param validation call another function in the same groovy script file.
i.e. have the someFunction make use of the doSomething function, some pseudo code below.
//utils.groovy
def doSomething(def a) {
def aPrime = a
if (a == 'somethingSpecial') {
//handle it
//some logic goes here
aPrime = b
}
return aPrime
}
def someFunction(def x) {
y = doSomething(x);
more stuff.. using y
return someResult
}
def dodad() {
...
}
def whatsIt(){
...
}
In my actual code I get error like No signature of method: groovysh_evaluate.myCommonFunct() is applicable for argument types: () values: []
Nevermind this does work.
I got the error when I tried to run the contents of the file locally in groovysh. But no errors when it ran in the Jenkins pipeline
Currently I'm trying to register findFiles step.
My set up is as follows:
src/
test/
groovy/
TestJavaLib.groovy
vars/
javaLib.groovy
javaApp.jenkinsfile
Inside TestJavaApp.groovy I have:
...
import com.lesfurets.jenkins.unit.RegressionTest
import com.lesfurets.jenkins.unit.BasePipelineTest
class TestJavaLibraryPipeline extends BasePipelineTest implements RegressionTest {
// Some overridden setUp() which loads shared libs
// and registers methods referenced in javaLib.groovy
void registerPipelineMethods() {
...
def fileList = [new File("testFile1"), new File("testFile2")]
helper.registerAllowedMethod('findFiles', { f -> return fileList })
...
}
}
and my javaLib.groovy contains this currently failing part:
...
def pomFiles = findFiles glob: "target/publish/**/${JOB_BASE_NAME}*.pom"
if (pomFiles.length < 1) { // Fails with java.lang.NullPointerException: Cannot get property 'length' on null object
error("no pom file found")
}
...
I have tried multiple closures returning various objects, but everytime I get NPE.
Question is - how to correctly register "findFiles" method?
N.B. That I'm very new to mocking and closures in groovy.
Looking at the source code and examples on GitHub, I see a few overloads of the method (here):
void registerAllowedMethod(String name, List<Class> args = [], Closure closure)
void registerAllowedMethod(MethodSignature methodSignature, Closure closure)
void registerAllowedMethod(MethodSignature methodSignature, Function callback)
void registerAllowedMethod(MethodSignature methodSignature, Consumer callback)
It doesn't look like you are registering the right signature with your call. I'm actually surprised you aren't getting a MissingMethodException with your current call pattern.
You need to add the rest of the method signature during registration. The findFiles method is taking a Map of parameters (glob: "target/publish/**/${JOB_BASE_NAME}*.pom" is a map literal in Groovy). One way to register that type would be like this:
helper.registerAllowedMethod('findFiles', [Map.class], { f -> return fileList })
I also faced the same issue. However, I was able to mock the findFiles() method using the following method signature:
helper.registerAllowedMethod(method('findFiles', Map.class), {map ->
return [['path':'testPath/test.zip']]
})
So I found a way on how to mock findFiles when I needed length property:
helper.registerAllowedMethod('findFiles', [Map.class], { [length: findFilesLength ?: 1] })
This also allows to change findFilesLength variable in tests to test different conditions in pipeline like the one in my OP.
Ran into this while doing a refactor. Calls to getProperties() were causing our CPU usage to spike. What we discovered is that if you have a getter without an associated attribute, when you make a call to getProperties() that getter is called over 1000 times. The fix/workaround is obvious and we know it has something to do with metaprogramming but why is this happening (what point in the groovy source)? See groovy script code below:
class tester {
int count = 0
public getVar() {
println count++ + " getVar() called!"
return var
}
}
def t = new tester()
t.getProperties()
println "done!"
You should see getVar() called over 1000 times. 1068 to be exact for us.
The question has probably already been answered in the comments but I dug a little deeper to also answer the "what point in the groovy source" part.
When you call getProperties() on the instance of tester Groovy will do its magic and finally call DefaultGroovyMethods#getProperties(Object) which (in Groovy 2.4.7) looks like this:
public static Map getProperties(Object self) {
List<PropertyValue> metaProps = getMetaPropertyValues(self); // 1
Map<String, Object> props = new LinkedHashMap<String, Object>(metaProps.size());
for (PropertyValue mp : metaProps) {
try {
props.put(mp.getName(), mp.getValue()); // 2
} catch (Exception e) {
LOG.throwing(self.getClass().getName(), "getProperty(" + mp.getName() + ")", e);
}
}
return props;
}
First, Groovy determines the meta properties of the given object (see 1). This will return three properties:
var: getter only (getVar()), no setter, no field
class: getter only (inherited from Object), no setter, no field
count: getter, setter (both generated by Groovy) and field
You can easily verify this by calling t.getMetaPropertyValues().
Next, Groovy tries to get the current value of each property and puts it in a map (see 2). When it reaches var, it remembers that var has a getter (namely getVar()) and calls it. getVar() however, returns var again. For Groovy, this is the exact same property as determined in the first step. Once again, it calls its getter getVar() and the endless loop begins.
At some point, depending on the JVM, this results in a StackOverflowError, which is exactly what this site is all about :-D
When I run this java code, i am able to get the values of variables define outside the function, but i am unable to get the values of variable define inside the function. how to access these variable values?
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;
public class JSFunctionTest {
public static void main(String args[]) {
String code = "var name='nc',global_a = 'jill'; " + "\n"+
"function myfunc(b) { " + "\n"+
"var local_a = 1;" + "\n"+
"global_a = 'jack';" + "\n"+
" return b;" + "\n"+
"}";
Context context = Context.enter();
context.setGeneratingDebug(true);
context.setOptimizationLevel(-1);
Scriptable scope = context.initStandardObjects();
context.evaluateString(scope, code, "code", 1, null);
//getting values of varables
System.out.println("var name:"+scope.get("name", scope));
System.out.println("var global_a:"+scope.get("global_a", scope));
System.out.println("var local_a:"+scope.get("local_a", scope));//not found becase function wasnt run
//calling the function.
Object fObj = scope.get("myfunc", scope);
if (!(fObj instanceof Function)) {
System.out.println("myfunc is undefined or not a function.");
} else {
Object functionArgs[] = { "nc" };
Function f = (Function)fObj;
Object r = f.call(context, scope, scope, functionArgs);
String report = "myfunc('nc') = " + Context.toString(r);
//trying to access global and local a after calling function
System.out.println("var global_a:"+scope.get("global_a", scope));//values is changed, because this is defined out side the function.
System.out.println("var local_a:"+scope.get("local_a", scope));// still not found,after running the function.
System.out.println(report);
}
}
}
I was able to resolve this, by implementing a debugger using the debug API in Rhino.
Implement your own debugger and debugframe classes.
Hook them to your context using setDebugger() method
in the DebugFrame class, I have implemented. cache the scope object in the onEnter method.
in the onLineChange method, you can get the local variables using ScriptableObject.getProperty() passing the cache scope object and giving the names
In ECMAScript, functions create their own scope. Outside the global scope, it's the only way to create new ones. See Rhino Scopes and Contexts for an example similar to yours.
The thing is that ECMAScript is a dynamic language (especially when optimization level is set to interpreted mode). This means the interpreter does not know in advance what it will encounter. The function's scope is only created/evaluated when the code is actually executed. So you can't evaluate a piece of code and query for variables inside a scope that isn't executed.
The question is why would you want to do that in practice? For debugging, you can step into the code and inspect the scopes, you should be able to see it.