Skip to content

Commit a08f1d5

Browse files
Willem BorgesiusWillem Borgesius
authored andcommitted
Undo extending all Declarations from GenericPipelineDeclaration (this adds unwanted properties)
Remove GenericPipelineDeclaration implementation of getProperty. Instead implement propertyMissing method to fallback to env and params. Append test to use env var before pipeline closure Remove duplicate method executeOn (use executeWith instead) Remove name conflicts between JenkinsFile closures and Declaration fields
1 parent dff6f47 commit a08f1d5

20 files changed

+181
-160
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class InterceptingGCL extends GroovyClassLoader {
1111
metaClazz.invokeMethod = helper.getMethodInterceptor()
1212
metaClazz.static.invokeMethod = helper.getMethodInterceptor()
1313
metaClazz.methodMissing = helper.getMethodMissingInterceptor()
14+
metaClazz.propertyMissing = helper.getPropertyMissingInterceptor()
1415
metaClazz.getEnv = {return binding.env}
1516
// find and replace script method closure with any matching allowed method closure
1617
metaClazz.methods.forEach { scriptMethod ->
@@ -73,4 +74,4 @@ class InterceptingGCL extends GroovyClassLoader {
7374

7475
return cls;
7576
}
76-
}
77+
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,20 @@ class PipelineTestHelper {
232232
return methodMissingInterceptor
233233
}
234234

235+
def propertyMissingInterceptor = { String propertyName ->
236+
if (binding.hasVariable("params") && (binding.getVariable("params") as Map).containsKey(propertyName)) {
237+
return (binding.getVariable("params") as Map).get(propertyName)
238+
}
239+
if (binding.getVariable("env") && (binding.getVariable("env") as Map).containsKey(propertyName)) {
240+
return (binding.getVariable("env") as Map).get(propertyName)
241+
}
242+
throw new MissingPropertyException(propertyName)
243+
}
244+
245+
def getPropertyMissingInterceptor() {
246+
return propertyMissingInterceptor
247+
}
248+
235249
def callIfClosure(Object closure, Object currentResult) {
236250
if (closure instanceof Closure) {
237251
currentResult = callClosure(closure)

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

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ 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
8+
import static com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration.executeWith
79
import static groovy.lang.Closure.DELEGATE_FIRST
810

911
@ToString(includePackage = false, includeNames = true, ignoreNulls = true)
10-
class AgentDeclaration extends GenericPipelineDeclaration {
12+
class AgentDeclaration {
1113

1214
String label
1315
DockerAgentDeclaration docker
@@ -16,7 +18,6 @@ class AgentDeclaration extends GenericPipelineDeclaration {
1618
String dockerfileDir
1719
Boolean reuseNode = null
1820
String customWorkspace
19-
def binding = null
2021

2122
def label(String label) {
2223
this.label = label
@@ -35,7 +36,7 @@ class AgentDeclaration extends GenericPipelineDeclaration {
3536
}
3637

3738
def docker(String image) {
38-
this.docker = new DockerAgentDeclaration().with { it.image = image; it }
39+
this.docker({ -> this.image = image })
3940
}
4041

4142
def docker(@DelegatesTo(strategy = DELEGATE_FIRST, value = DockerAgentDeclaration) Closure closure) {
@@ -62,18 +63,6 @@ class AgentDeclaration extends GenericPipelineDeclaration {
6263
this.dockerfileDir = dir
6364
}
6465

65-
def getCurrentBuild() {
66-
return binding?.currentBuild
67-
}
68-
69-
def getEnv() {
70-
return binding?.env
71-
}
72-
73-
def getParams() {
74-
return binding?.params
75-
}
76-
7766
def execute(Object delegate) {
7867
def agentDesc = null
7968

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

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class DeclarativePipeline extends GenericPipelineDeclaration {
88
List<Closure> options = []
99

1010
Closure triggers
11-
ParametersDeclaration params = null
11+
ParametersDeclaration parameters = null
1212

1313
DeclarativePipeline() {
1414
properties.put('any', 'any')
@@ -24,10 +24,6 @@ class DeclarativePipeline extends GenericPipelineDeclaration {
2424
}
2525
}
2626

27-
def propertyMissing(String name, arg) {
28-
29-
}
30-
3127
def options(@DelegatesTo(DeclarativePipeline) Closure closure) {
3228
options.add(closure)
3329
}
@@ -37,20 +33,20 @@ class DeclarativePipeline extends GenericPipelineDeclaration {
3733
}
3834

3935
def parameters(Object o) {
40-
this.params = new ParametersDeclaration().with { it.label = o; it }
36+
this.parameters = new ParametersDeclaration().with { it.label = o; it }
4137
}
4238

4339
def parameters(@DelegatesTo(strategy=DELEGATE_FIRST, value=ParametersDeclaration) Closure closure) {
44-
this.params = createComponent(ParametersDeclaration, closure)
40+
this.parameters = createComponent(ParametersDeclaration, closure)
4541
}
4642

4743
def execute(Object delegate) {
4844
super.execute(delegate)
4945
this.options.forEach {
50-
executeOn(delegate, it)
46+
executeWith(delegate, it)
5147
}
5248
this.agent?.execute(delegate)
53-
executeOn(delegate, this.triggers)
49+
executeWith(delegate, this.triggers)
5450
this.stages.entrySet().forEach { e ->
5551
e.value.execute(delegate)
5652
}

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

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

3+
34
import static groovy.lang.Closure.DELEGATE_FIRST
45

56
abstract class GenericPipelineDeclaration {
@@ -14,24 +15,14 @@ abstract class GenericPipelineDeclaration {
1415
static <T> T createComponent(Class<T> componentType, @DelegatesTo(strategy = DELEGATE_FIRST) Closure<T> closure) {
1516
// declare componentInstance as final to prevent any multithreaded issues, since it is used inside closure
1617
final def componentInstance = componentType.newInstance()
17-
def rehydrate = closure.rehydrate(componentInstance, closure, componentInstance)
18+
def rehydrate = closure.rehydrate(closure, componentInstance, componentInstance)
1819
if (binding && componentInstance.hasProperty('binding') && componentInstance.binding != binding) {
1920
componentInstance.binding = binding
2021
}
2122
rehydrate.call()
2223
return componentInstance
2324
}
2425

25-
static <T> T executeOn(@DelegatesTo.Target Object delegate,
26-
@DelegatesTo(strategy = DELEGATE_FIRST) Closure<T> closure) {
27-
if (closure) {
28-
def cl = closure.rehydrate(delegate, delegate, delegate)
29-
cl.resolveStrategy = DELEGATE_FIRST
30-
return cl.call()
31-
}
32-
return null
33-
}
34-
3526
static <T> T executeWith(@DelegatesTo.Target Object delegate,
3627
@DelegatesTo(strategy = DELEGATE_FIRST) Closure<T> closure) {
3728
if (closure) {
@@ -71,40 +62,19 @@ abstract class GenericPipelineDeclaration {
7162
this.stages.put(name, createComponent(StageDeclaration, closure).with { it.name = name; it })
7263
}
7364

74-
def getProperty(String propertyName) {
75-
def metaProperty = this.metaClass.getMetaProperty(propertyName)
76-
if (metaProperty) {
77-
return metaProperty.getProperty(this)
78-
} else {
79-
if (binding?.hasProperty(propertyName) || binding?.hasVariable(propertyName)) {
80-
return binding.getProperty(propertyName)
81-
}
82-
if (binding?.hasVariable("params") && (binding?.getProperty("params") as Map).containsKey(propertyName)) {
83-
return (binding?.getProperty("params") as Map).get(propertyName)
84-
}
85-
if (binding?.hasVariable("env") && (binding?.getProperty("env") as Map).containsKey(propertyName)) {
86-
return (binding?.getProperty("env") as Map).get(propertyName)
87-
}
88-
def metaMethod = this.metaClass.getMetaMethod("propertyMissing", propertyName)
89-
if (metaMethod) {
90-
metaMethod.invoke(this, propertyName)
91-
} else {
92-
throw new MissingPropertyException(name)
93-
}
94-
}
95-
}
96-
9765
def execute(Object delegate) {
9866
// set environment
9967
if (this.environment) {
100-
def env = delegate.binding.env
101-
// let access env and currentBuild properties in environment closure
102-
env.env = env
103-
env.currentBuild = delegate.binding.currentBuild
104-
105-
def cl = this.environment.rehydrate(env, delegate, this)
106-
cl.resolveStrategy = DELEGATE_FIRST
107-
cl.call()
68+
Binding subBinding = new Binding()
69+
subBinding.metaClass.invokeMissingProperty = { propertyName ->
70+
delegate.getProperty(propertyName)
71+
}
72+
subBinding.metaClass.setProperty = { String propertyName, Object newValue ->
73+
(delegate.env as Map).put(propertyName, newValue)
74+
}
75+
def envClosure = this.environment.rehydrate(subBinding, delegate, this)
76+
envClosure.resolveStrategy = DELEGATE_FIRST
77+
envClosure.call()
10878
}
10979
}
11080

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

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

3+
import static com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration.createComponent
34
import static groovy.lang.Closure.DELEGATE_FIRST
4-
//import static com.lesfurets.jenkins.unit.declarative.DeclarativePipeline.executeOn
55

6-
class ParallelDeclaration extends GenericPipelineDeclaration {
6+
class ParallelDeclaration {
77

8+
Map<String, StageDeclaration> stages = [:]
89
boolean failFast
910

1011
ParallelDeclaration(boolean failFast) {
@@ -21,7 +22,6 @@ class ParallelDeclaration extends GenericPipelineDeclaration {
2122
}
2223

2324
def execute(Object delegate) {
24-
super.execute(delegate)
2525
this.stages.entrySet().forEach { e ->
2626
e.value.execute(delegate)
2727
}

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

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

33

4-
class ParametersDeclaration extends GenericPipelineDeclaration {
4+
class ParametersDeclaration {
5+
Binding binding
56

6-
void setParams(String key, Object val) {
7-
Map params = this.params
8-
if (params != null && (!params.containsKey(key))) {
9-
params[key] = val
7+
void setParams(String key, Object defaultValue) {
8+
if (!binding.hasVariable("params")) {
9+
binding.setVariable("params", [:])
10+
}
11+
if (!binding.params.containsKey(key)) {
12+
binding.params[key] = defaultValue
1013
}
1114
}
1215

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

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

3-
import static com.lesfurets.jenkins.unit.declarative.DeclarativePipeline.executeOn
3+
import static com.lesfurets.jenkins.unit.declarative.DeclarativePipeline.executeWith
44

55
class PostDeclaration {
66

@@ -59,48 +59,48 @@ class PostDeclaration {
5959
def currentBuild = delegate.currentBuild.result
6060
def previousBuild = delegate.currentBuild?.previousBuild?.result
6161
if (this.always) {
62-
executeOn(delegate, this.always)
62+
executeWith(delegate, this.always)
6363
}
6464

6565
switch (currentBuild) {
6666
case 'SUCCESS':
67-
executeOn(delegate, this.success)
67+
executeWith(delegate, this.success)
6868
break
6969
case 'FAILURE':
70-
executeOn(delegate, this.failure)
70+
executeWith(delegate, this.failure)
7171
break
7272
case 'ABORTED':
73-
executeOn(delegate, this.aborted)
73+
executeWith(delegate, this.aborted)
7474
break
7575
case 'UNSTABLE':
76-
executeOn(delegate, this.unstable)
76+
executeWith(delegate, this.unstable)
7777
break
7878
}
7979

8080
if(currentBuild != previousBuild && this.changed)
8181
{
82-
executeOn(delegate, this.changed)
82+
executeWith(delegate, this.changed)
8383
}
8484
if(currentBuild != 'SUCCESS' && this.unsuccessful)
8585
{
86-
executeOn(delegate, this.unsuccessful)
86+
executeWith(delegate, this.unsuccessful)
8787
}
8888
if(this.fixed){
8989
if(currentBuild == 'SUCCESS' && (previousBuild == 'FAILURE' || previousBuild == 'UNSTABLE'))
9090
{
91-
executeOn(delegate, this.fixed)
91+
executeWith(delegate, this.fixed)
9292
}
9393
}
9494
if(this.regression)
9595
{
9696
if((currentBuild == 'FAILURE' || currentBuild == 'UNSTABLE') && previousBuild == 'SUCCESS'){
97-
executeOn(delegate, this.regression)
97+
executeWith(delegate, this.regression)
9898
}
9999
}
100100

101101
// Cleanup is always performed last
102102
if(this.cleanup){
103-
executeOn(delegate, this.cleanup)
103+
executeWith(delegate, this.cleanup)
104104
}
105105
}
106106

0 commit comments

Comments
 (0)