Skip to content
Permalink
Browse files

[JENKINS-38331] Very preliminary version of per-stage agent config

Honestly, I'm doing this for JENKINS-38284 more, but I needed some
section to actually have be per-stage to test it, so...tada?

This is literally the result of three hours of slamming my head
against the wall over stupid mistakes, so I'm fairly sure there are
still a plethora of such mistakes in here. But I'm pretty sure it
works - I just added the JSON version and conversion for
perStageAgentConfig to this and the tests are actively running as I
type this, but I got impatient and made a commit now. So ha.
  • Loading branch information
abayer committed Sep 22, 2016
1 parent b385ba5 commit 385940d33c4184cb5f5947c00c45d7ed57566c47
Showing with 474 additions and 27 deletions.
  1. +21 −4 src/main/groovy/org/jenkinsci/plugins/pipeline/modeldefinition/ast/ModelASTStage.groovy
  2. +83 −0 src/main/groovy/org/jenkinsci/plugins/pipeline/modeldefinition/ast/ModelASTStageConfig.groovy
  3. +37 −0 src/main/groovy/org/jenkinsci/plugins/pipeline/modeldefinition/model/ClosureContentsChecker.groovy
  4. +8 −0 src/main/groovy/org/jenkinsci/plugins/pipeline/modeldefinition/model/Stage.groovy
  5. +71 −0 src/main/groovy/org/jenkinsci/plugins/pipeline/modeldefinition/model/StageConfig.groovy
  6. +26 −0 src/main/groovy/org/jenkinsci/plugins/pipeline/modeldefinition/parser/JSONParser.groovy
  7. +74 −8 src/main/groovy/org/jenkinsci/plugins/pipeline/modeldefinition/parser/ModelParser.groovy
  8. +18 −0 src/main/groovy/org/jenkinsci/plugins/pipeline/modeldefinition/validator/ModelValidator.groovy
  9. +3 −1 ...main/java/org/jenkinsci/plugins/pipeline/modeldefinition/model/MethodMissingWrapperWhitelist.java
  10. +13 −0 src/main/resources/ast-schema.json
  11. +27 −4 src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/ClosureModelTranslator.groovy
  12. +11 −9 src/main/resources/org/jenkinsci/plugins/pipeline/modeldefinition/ModelInterpreter.groovy
  13. +2 −1 src/test/java/org/jenkinsci/plugins/pipeline/modeldefinition/AbstractModelDefTest.java
  14. +14 −0 src/test/java/org/jenkinsci/plugins/pipeline/modeldefinition/AgentTest.java
  15. +26 −0 src/test/resources/json/perStageConfigAgent.json
  16. +40 −0 src/test/resources/perStageConfigAgent.groovy
@@ -19,7 +19,10 @@ import org.jenkinsci.plugins.pipeline.modeldefinition.validator.ModelValidator
@EqualsAndHashCode(callSuper = true)
@SuppressFBWarnings(value="SE_NO_SERIALVERSIONID")
public final class ModelASTStage extends ModelASTElement {
public static final List<String> possibleKeys = ["config", "steps"]

String name
ModelASTStageConfig config
List<ModelASTBranch> branches = []

public ModelASTStage(Object sourceLocation) {
@@ -32,9 +35,13 @@ public final class ModelASTStage extends ModelASTElement {
branches.each { br ->
a.add(br.toJSON())
}
return new JSONObject()
.accumulate("name",name)
.accumulate("branches",a)
JSONObject o = new JSONObject()
o.accumulate("name",name)
o.accumulate("branches",a)
if (config != null) {
o.accumulate("config", config.toJSON())
}
return o
}

@Override
@@ -43,13 +50,19 @@ public final class ModelASTStage extends ModelASTElement {
branches.each { b ->
b?.validate(validator)
}
config?.validate(validator)
}

@Override
public String toGroovy() {
StringBuilder retString = new StringBuilder()
retString.append("stage(\"${name}\") {\n")

if (config != null) {
retString.append("config {\n")
retString.append(config.toGroovy())
retString.append("}\n")
retString.append("steps {\n")
}
if (branches.size() > 1) {
retString.append("parallel(\n")
List<String> branchStrings = branches.collect { b ->
@@ -61,6 +74,9 @@ public final class ModelASTStage extends ModelASTElement {
retString.append(branches.get(0).toGroovy())
}

if (config != null) {
retString.append("}\n")
}
retString.append("}\n")

return retString.toString()
@@ -72,5 +88,6 @@ public final class ModelASTStage extends ModelASTElement {
branches.each { b ->
b.removeSourceLocation()
}
config?.removeSourceLocation()
}
}
@@ -0,0 +1,83 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package org.jenkinsci.plugins.pipeline.modeldefinition.ast

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import net.sf.json.JSONArray
import net.sf.json.JSONObject
import org.jenkinsci.plugins.pipeline.modeldefinition.model.Stage
import org.jenkinsci.plugins.pipeline.modeldefinition.validator.ModelValidator

/**
* Represents configuration for an individual {@link ModelASTStage}
*
* @author Andrew Bayer
* @see ModelASTPipelineDef
*/
@ToString(includeSuper = true, includeSuperProperties = true)
@EqualsAndHashCode(callSuper = true)
@SuppressFBWarnings(value="SE_NO_SERIALVERSIONID")
public final class ModelASTStageConfig extends ModelASTElement {
ModelASTAgent agent

public ModelASTStageConfig(Object sourceLocation) {
super(sourceLocation)
}

@Override
public JSONObject toJSON() {
JSONObject a = new JSONObject()
if (agent != null) {
a.put("agent", agent.toJSON())
}
return new JSONObject().accumulate("config", a)
}

@Override
public void validate(ModelValidator validator) {
validator.validateElement(this)
agent?.validate(validator)
}

@Override
public String toGroovy() {
StringBuilder retString = new StringBuilder()
retString.append("config {\n")
if (agent != null) {
retString.append(agent.toGroovy())
}
retString.append("}\n")

return retString.toString()
}

@Override
public void removeSourceLocation() {
super.removeSourceLocation()
agent?.removeSourceLocation()
}
}
@@ -0,0 +1,37 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/


package org.jenkinsci.plugins.pipeline.modeldefinition.model

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings

/**
* Special wrapper for checking the contents of a {@link Closure}.
*
* @author Andrew Bayer
*/
@SuppressFBWarnings(value="SE_NO_SERIALVERSIONID")
public class ClosureContentsChecker extends MappedClosure<Object,ClosureContentsChecker> {
}
@@ -44,11 +44,19 @@ public class Stage implements StepBlockWithOtherArgs, Serializable {
@Whitelisted
StepsBlock closureWrapper

@Whitelisted
StageConfig config

@Whitelisted
public Stage(String n, StepsBlock w) {
this.name = n
this.closureWrapper = w
}

@Whitelisted
public Stage(String n, StepsBlock w, StageConfig c) {
this(n, w)
this.config = c
}

}
@@ -0,0 +1,71 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/


package org.jenkinsci.plugins.pipeline.modeldefinition.model

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted


/**
* Overriding configuration for a single {@link Stage}
*
* @author Andrew Bayer
*/
@ToString
@EqualsAndHashCode
@SuppressFBWarnings(value="SE_NO_SERIALVERSIONID")
public class StageConfig implements NestedModel, Serializable {
@Whitelisted
Agent agent

@Whitelisted
StageConfig agent(Agent a) {
this.agent = a
return this
}

@Whitelisted
StageConfig agent(Map<String,String> args) {
this.agent = new Agent(args)
return this
}

@Whitelisted
Agent getAgent() {
return agent
}

@Override
@Whitelisted
public void modelFromMap(Map<String,Object> m) {
m.each { k, v ->
this."${k}"(v)
}
}

}
@@ -39,6 +39,7 @@ import org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTNamedArgumentL
import org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTPositionalArgumentList
import org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTSingleArgument
import org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTStage
import org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTStageConfig
import org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTStages
import org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTStep
import org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTValue
@@ -149,6 +150,10 @@ class JSONParser {

stage.name = j.getString("name")

if (j.has("config")) {
stage.config = parseStageConfig(j.getJSONObject("config"))
}

j.getJSONArray("branches").each { b ->
JSONObject o = (JSONObject)b
stage.branches.add(parseBranch(o))
@@ -157,6 +162,27 @@ class JSONParser {

}

public @CheckForNull ModelASTStageConfig parseStageConfig(JSONObject j) {
ModelASTStageConfig config = new ModelASTStageConfig(j)

def sectionsSeen = new HashSet()

j.keySet().each { configName ->
if (!sectionsSeen.add(configName)) {
errorCollector.error(config, "Multiple occurrences of the stage config section '${configName}'")
}
switch (configName) {
case 'agent':
config.agent = parseAgent(j.getJSONObject("agent"))
break
default:
errorCollector.error(config, "Undefined stage config section '${configName}'")
}
}

return config
}

public @CheckForNull ModelASTBranch parseBranch(JSONObject j) {
ModelASTBranch branch = new ModelASTBranch(j)
branch.name = j.getString("name")

0 comments on commit 385940d

Please sign in to comment.
You can’t perform that action at this time.