Skip to content

Commit fd171b4

Browse files
committed
Simplify class interception
1 parent e6ca1a8 commit fd171b4

16 files changed

+174
-167
lines changed

src/main/groovy/com/lesfurets/jenkins/unit/InterceptingGCL.groovy

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class InterceptingGCL extends GroovyClassLoader {
1212
metaClazz.static.invokeMethod = helper.getMethodInterceptor()
1313
metaClazz.methodMissing = helper.getMethodMissingInterceptor()
1414
metaClazz.propertyMissing = helper.getPropertyMissingInterceptor()
15-
metaClazz.getEnv = {return binding.env}
15+
metaClazz.getEnv = { return binding.env }
1616
// find and replace script method closure with any matching allowed method closure
1717
metaClazz.methods.forEach { scriptMethod ->
1818
def signature = method(scriptMethod.name, scriptMethod.nativeParameterTypes)
@@ -67,10 +67,7 @@ class InterceptingGCL extends GroovyClassLoader {
6767
return super.loadClass(name)
6868
}
6969

70-
// Copy from this.parseClass(GroovyCodeSource, boolean)
71-
cls.metaClass.invokeMethod = helper.getMethodInterceptor()
72-
cls.metaClass.static.invokeMethod = helper.getMethodInterceptor()
73-
cls.metaClass.methodMissing = helper.getMethodMissingInterceptor()
70+
interceptClassMethods(cls.metaClass, helper, binding)
7471

7572
return cls;
7673
}

src/main/groovy/com/lesfurets/jenkins/unit/PipelineTestHelper.groovy

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,9 @@ class PipelineTestHelper {
183183
return callClosure(intercepted.value, args)
184184
}
185185
// if not search for the method declaration
186-
MetaMethod m = delegate.metaClass.getMetaMethod(name, args)
186+
MetaMethod metaMethod = delegate.metaClass.getMetaMethod(name, args)
187187
// ...and call it. If we cannot find it, delegate call to methodMissing
188-
def result = (m ? this.callMethod(m, delegate, args) : delegate.metaClass.invokeMissingMethod(delegate, name, args))
188+
def result = (metaMethod ? this.callMethod(metaMethod, delegate, args) : delegate.metaClass.invokeMissingMethod(delegate, name, args))
189189
return result
190190
}
191191

@@ -233,6 +233,9 @@ class PipelineTestHelper {
233233
}
234234

235235
def propertyMissingInterceptor = { String propertyName ->
236+
if(binding.hasVariable(propertyName)){
237+
return binding.getVariable(propertyName)
238+
}
236239
if (binding.hasVariable("params") && (binding.getVariable("params") as Map).containsKey(propertyName)) {
237240
return (binding.getVariable("params") as Map).get(propertyName)
238241
}

src/main/groovy/com/lesfurets/jenkins/unit/declarative/AgentDeclaration.groovy

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ import com.lesfurets.jenkins.unit.declarative.agent.DockerAgentDeclaration
44
import com.lesfurets.jenkins.unit.declarative.agent.KubernetesAgentDeclaration
55
import groovy.transform.ToString
66

7-
import static com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration.createComponent
87
import static com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration.executeWith
9-
import static groovy.lang.Closure.DELEGATE_FIRST
108

119
@ToString(includePackage = false, includeNames = true, ignoreNulls = true)
1210
class AgentDeclaration {
@@ -23,7 +21,7 @@ class AgentDeclaration {
2321
this.label = label
2422
}
2523

26-
def node(@DelegatesTo(AgentDeclaration) Closure closure) {
24+
def node(Closure closure) {
2725
closure.call()
2826
}
2927

@@ -36,34 +34,37 @@ class AgentDeclaration {
3634
}
3735

3836
def docker(String image) {
39-
this.docker({ -> this.image = image })
37+
this.docker = new DockerAgentDeclaration().with{ da -> da.image = image; da }
4038
}
4139

42-
def docker(@DelegatesTo(strategy = DELEGATE_FIRST, value = DockerAgentDeclaration) Closure closure) {
43-
this.docker = createComponent(DockerAgentDeclaration, closure)
40+
def docker(Closure closure) {
41+
this.docker = new DockerAgentDeclaration();
42+
executeWith(this.docker, closure);
4443
}
4544

4645
def kubernetes(Object kubernetesAgent) {
4746
this.@kubernetes = kubernetesAgent as KubernetesAgentDeclaration
4847
}
4948

50-
def kubernetes(@DelegatesTo(strategy = DELEGATE_FIRST, value = KubernetesAgentDeclaration) Closure closure) {
51-
this.@kubernetes = createComponent(KubernetesAgentDeclaration, closure)
49+
def kubernetes(Closure closure) {
50+
this.@kubernetes = new KubernetesAgentDeclaration();
51+
def kubernetesDecl = this.@kubernetes
52+
executeWith(kubernetesDecl, closure)
5253
}
5354

5455
def dockerfile(boolean dockerfile) {
5556
this.dockerfile = dockerfile
5657
}
5758

58-
def dockerfile(@DelegatesTo(AgentDeclaration) Closure closure) {
59+
def dockerfile(Closure closure) {
5960
closure.call()
6061
}
6162

6263
def dir(String dir) {
6364
this.dockerfileDir = dir
6465
}
6566

66-
def execute(Object delegate) {
67+
def execute(Script script) {
6768
def agentDesc = null
6869

6970
if (label) {
@@ -84,6 +85,6 @@ class AgentDeclaration {
8485
else {
8586
throw new IllegalStateException("No agent description found")
8687
}
87-
executeWith(delegate, { echo "Executing on agent $agentDesc" })
88+
executeWith(script, { echo "Executing on agent $agentDesc" })
8889
}
8990
}

src/main/groovy/com/lesfurets/jenkins/unit/declarative/AnyOfDeclaration.groovy

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.lesfurets.jenkins.unit.declarative
22

3-
import static com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration.executeWith
4-
53
class AnyOfDeclaration extends WhenDeclaration {
64

75
List<String> branches = []
@@ -18,24 +16,24 @@ class AnyOfDeclaration extends WhenDeclaration {
1816
def expressions(delegate) {
1917
def exp_result;
2018
for (def exp in this.expressions) {
21-
exp_result = executeWith(delegate, exp)
19+
exp_result = exp.call()
2220
if (exp_result) {
2321
return true
2422
}
2523
}
2624
return false
2725
}
2826

29-
Boolean execute(Object delegate) {
27+
Boolean execute(Script script) {
3028
boolean br = false;
3129
boolean exp = false;
3230

3331
if (this.branches.size() > 0) {
34-
br = this.branches.contains(delegate.env.BRANCH_NAME)
32+
br = this.branches.contains(script.env.BRANCH_NAME)
3533
}
3634

3735
if (this.expressions.size() > 0) {
38-
exp = expressions(delegate)
36+
exp = expressions(script)
3937
}
4038

4139
return exp || br

src/main/groovy/com/lesfurets/jenkins/unit/declarative/DeclarativePipeline.groovy

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.lesfurets.jenkins.unit.declarative
22

3-
import static groovy.lang.Closure.*
4-
53
class DeclarativePipeline extends GenericPipelineDeclaration {
64

75
def properties = [:]
@@ -24,33 +22,37 @@ class DeclarativePipeline extends GenericPipelineDeclaration {
2422
}
2523
}
2624

27-
def options(@DelegatesTo(DeclarativePipeline) Closure closure) {
25+
def options(Closure closure) {
2826
options.add(closure)
2927
}
3028

31-
def triggers(@DelegatesTo(DeclarativePipeline) Closure closure) {
29+
def triggers(Closure closure) {
3230
this.triggers = closure
3331
}
3432

3533
def parameters(Object o) {
3634
this.parameters = new ParametersDeclaration().with { it.label = o; it }
3735
}
3836

39-
def parameters(@DelegatesTo(strategy=DELEGATE_FIRST, value=ParametersDeclaration) Closure closure) {
40-
this.parameters = createComponent(ParametersDeclaration, closure)
37+
def parameters(Closure closure) {
38+
this.parameters = new ParametersDeclaration()
39+
this.parameters.binding = closure.binding;
40+
executeWith(this.parameters, closure)
4141
}
4242

43-
def execute(Object delegate) {
44-
super.execute(delegate)
43+
def execute(Script script) {
44+
super.execute(script)
4545
this.options.forEach {
46-
executeWith(delegate, it)
46+
executeWith(script, it)
47+
}
48+
this.agent?.execute(script)
49+
if (this.triggers) {
50+
executeWith(script, this.triggers)
4751
}
48-
this.agent?.execute(delegate)
49-
executeWith(delegate, this.triggers)
5052
this.stages.entrySet().forEach { e ->
51-
e.value.execute(delegate)
53+
e.value.execute(script)
5254
}
53-
this.post?.execute(delegate)
55+
this.post?.execute(script)
5456
}
5557

5658
}

src/main/groovy/com/lesfurets/jenkins/unit/declarative/DeclarativePipelineTest.groovy

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,25 @@ import static com.lesfurets.jenkins.unit.MethodSignature.method
88
abstract class DeclarativePipelineTest extends BasePipelineTest {
99

1010
def pipelineInterceptor = { Closure closure ->
11-
GenericPipelineDeclaration.binding = binding
12-
GenericPipelineDeclaration.createComponent(DeclarativePipeline, closure).execute(delegate)
11+
def declarativePipeline = new DeclarativePipeline()
12+
def rehydratedPipelineCl = closure.rehydrate(declarativePipeline, closure.owner, closure)
13+
rehydratedPipelineCl.resolveStrategy
14+
rehydratedPipelineCl.call();
15+
declarativePipeline.execute(closure.owner)
1316
}
1417

1518
def paramInterceptor = { Map desc ->
1619
addParam(desc.name, desc.defaultValue, false)
1720
}
1821

19-
def stringInterceptor = { Map desc->
22+
def stringInterceptor = { Map desc ->
2023
if (desc) {
2124
// we are in context of paremetes { string(...)}
2225
if (desc.name) {
2326
addParam(desc.name, desc.defaultValue, false)
2427
}
2528
// we are in context of withCredentaials([string()..]) { }
26-
if(desc.variable) {
29+
if (desc.variable) {
2730
return desc.variable
2831
}
2932
}

src/main/groovy/com/lesfurets/jenkins/unit/declarative/GenericPipelineDeclaration.groovy

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,20 @@
11
package com.lesfurets.jenkins.unit.declarative
22

3-
4-
import static groovy.lang.Closure.DELEGATE_FIRST
5-
63
abstract class GenericPipelineDeclaration {
74

85
AgentDeclaration agent
96
Closure environment
107
Closure tools
118
PostDeclaration post
129
Map<String, StageDeclaration> stages = [:]
13-
static def binding = null
14-
15-
static <T> T createComponent(Class<T> componentType, @DelegatesTo(strategy = DELEGATE_FIRST) Closure<T> closure) {
16-
// declare componentInstance as final to prevent any multithreaded issues, since it is used inside closure
17-
final def componentInstance = componentType.newInstance()
18-
def rehydrate = closure.rehydrate(closure, componentInstance, componentInstance)
19-
if (binding && componentInstance.hasProperty('binding') && componentInstance.binding != binding) {
20-
componentInstance.binding = binding
21-
}
22-
rehydrate.call()
23-
return componentInstance
24-
}
2510

26-
static <T> T executeWith(@DelegatesTo.Target Object delegate,
27-
@DelegatesTo(strategy = DELEGATE_FIRST) Closure<T> closure) {
11+
static <T> T executeWith(Object delegate, Closure<T> closure, Integer resolveStrategy = Closure.DELEGATE_FIRST) {
2812
if (closure) {
29-
def cl = closure.rehydrate(delegate, delegate, delegate)
30-
cl.resolveStrategy = DELEGATE_FIRST
31-
return cl.call()
13+
closure.delegate = delegate;
14+
if(resolveStrategy) {
15+
closure.resolveStrategy = resolveStrategy
16+
}
17+
closure.call()
3218
}
3319
return null
3420
}
@@ -37,8 +23,9 @@ abstract class GenericPipelineDeclaration {
3723
this.agent = new AgentDeclaration().with { it.label = o; it }
3824
}
3925

40-
def agent(@DelegatesTo(strategy = DELEGATE_FIRST, value = AgentDeclaration) Closure closure) {
41-
this.agent = createComponent(AgentDeclaration, closure)
26+
def agent(Closure closure) {
27+
this.@agent = new AgentDeclaration();
28+
executeWith(this.@agent, closure)
4229
}
4330

4431
def environment(Closure closure) {
@@ -49,27 +36,29 @@ abstract class GenericPipelineDeclaration {
4936
this.tools = closure
5037
}
5138

52-
def post(@DelegatesTo(strategy = DELEGATE_FIRST, value = PostDeclaration) Closure closure) {
53-
this.post = createComponent(PostDeclaration, closure)
39+
def post(Closure closure) {
40+
this.post = new PostDeclaration();
41+
executeWith(this.post, closure)
5442
}
5543

56-
def stages(@DelegatesTo(DeclarativePipeline) Closure closure) {
44+
def stages(Closure closure) {
5745
closure.call()
5846
}
5947

60-
def stage(String stageName,
61-
@DelegatesTo(strategy = DELEGATE_FIRST, value = StageDeclaration) Closure closure) {
62-
this.stages.put(stageName, createComponent(StageDeclaration, closure).with { it.name = stageName; it })
48+
def stage(String stageName, Closure closure) {
49+
def stageDeclaration = new StageDeclaration(stageName)
50+
executeWith(stageDeclaration, closure);
51+
this.stages.put(stageName, stageDeclaration)
6352
}
6453

65-
def execute(Object delegate) {
54+
def execute(Script script) {
6655
Map envValuestoRestore = [:]
6756

6857
// set environment
6958
if (this.environment) {
70-
envValuestoRestore = initEnvironment(this.environment, delegate)
59+
envValuestoRestore = initEnvironment(this.environment, script)
7160
}
72-
resetEnvironment(envValuestoRestore, delegate)
61+
resetEnvironment(envValuestoRestore, script)
7362
}
7463

7564
public static Map initEnvironment(Closure environment, Object delegate) {
@@ -85,12 +74,12 @@ abstract class GenericPipelineDeclaration {
8574
(delegate.env as Map).put(propertyName, newValue)
8675
}
8776
def envClosure = environment.rehydrate(subBinding, delegate, this)
88-
envClosure.resolveStrategy = DELEGATE_FIRST
77+
envClosure.resolveStrategy = Closure.DELEGATE_FIRST
8978
envClosure.call()
9079
return envValuestoRestore
9180
}
9281

93-
public static resetEnvironment(LinkedHashMap envValuestoRestore, delegate) {
82+
public static resetEnvironment(Map envValuestoRestore, Object delegate) {
9483
envValuestoRestore.entrySet().forEach { entry ->
9584
def envMap = delegate.env as Map
9685
envMap.put(entry.getKey(), entry.getValue())

src/main/groovy/com/lesfurets/jenkins/unit/declarative/NotDeclaration.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package com.lesfurets.jenkins.unit.declarative
22

33
class NotDeclaration extends WhenDeclaration {
44

5-
Boolean execute(Object delegate) {
6-
return !super.execute(delegate)
5+
Boolean execute(Script script) {
6+
return !super.execute(script)
77
}
88
}
99

src/main/groovy/com/lesfurets/jenkins/unit/declarative/ParallelDeclaration.groovy

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
package com.lesfurets.jenkins.unit.declarative
22

3-
import static com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration.createComponent
4-
import static groovy.lang.Closure.DELEGATE_FIRST
5-
63
class ParallelDeclaration {
74

85
Map<String, StageDeclaration> stages = [:]
@@ -16,14 +13,15 @@ class ParallelDeclaration {
1613
this.failFast = false
1714
}
1815

19-
def stage(String name,
20-
@DelegatesTo(strategy = DELEGATE_FIRST, value = StageDeclaration) Closure closure) {
21-
this.stages.put(name, createComponent(StageDeclaration, closure).with{it.name = name;it} )
16+
def stage(String name, Closure closure) {
17+
def stageDeclaration = new StageDeclaration(name);
18+
GenericPipelineDeclaration.executeWith(stageDeclaration, closure);
19+
this.stages.put(name, stageDeclaration)
2220
}
2321

24-
def execute(Object delegate) {
22+
def execute(Script script) {
2523
this.stages.entrySet().forEach { e ->
26-
e.value.execute(delegate)
24+
e.value.execute(script)
2725
}
2826
}
2927

0 commit comments

Comments
 (0)