Add support for in_parallel sub-properties

See: https://github.com/spring-projects/sts4/issues/345

Signed-off-by: Kris De Volder <kdevolder@pivotal.io>
This commit is contained in:
Kris De Volder
2019-08-19 12:11:35 -07:00
parent 0714b6a693
commit 89ee405fdd
9 changed files with 152 additions and 13 deletions

View File

@@ -19,6 +19,7 @@ import org.springframework.ide.vscode.commons.yaml.path.YamlPath;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.ScalarNode;
import org.yaml.snakeyaml.nodes.SequenceNode;
/**
* Adapts a SnakeYaml ast node as a {@link DynamicSchemaContext} (so it
@@ -77,4 +78,8 @@ public class ASTDynamicSchemaContext extends CachingSchemaContext {
public boolean isMap() {
return mapNode!=null;
}
@Override
public boolean isSequence() {
return node instanceof SequenceNode;
}
}

View File

@@ -56,6 +56,11 @@ public interface DynamicSchemaContext {
public boolean isMap() {
return false;
}
@Override
public boolean isSequence() {
return false;
}
};
/**
@@ -98,5 +103,10 @@ public interface DynamicSchemaContext {
* Returns true if the current node is a Mapping node
*/
boolean isMap();
/**
* Returns true if the current node is a Sequence node
*/
boolean isSequence();
}

View File

@@ -81,6 +81,11 @@ public class SNodeDynamicSchemaContext extends CachingSchemaContext {
@Override
public boolean isMap() {
return !computeDefinedProperties().isEmpty();
}
@Override
public boolean isSequence() {
return false;
}

View File

@@ -38,6 +38,7 @@ import org.springframework.ide.vscode.commons.util.Renderables;
import org.springframework.ide.vscode.commons.util.ValueParser;
import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST;
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YBeanAndSequenceUnion;
import org.springframework.ide.vscode.commons.yaml.schema.constraints.Constraint;
import org.springframework.ide.vscode.commons.yaml.schema.constraints.Constraints;
import org.springframework.ide.vscode.commons.yaml.snippet.TypeBasedSnippetProvider;
@@ -168,19 +169,27 @@ public class YTypeFactory {
}
return new YBeanUnionType(name, beanTypes);
}
ArrayList<YBeanType> beans = new ArrayList<>(types.length);
ArrayList<YMapType> maps = new ArrayList<>(types.length);
ArrayList<YAtomicType> atoms = new ArrayList<>(types.length);
ArrayList<YSeqType> arrays = new ArrayList<>(types.length);
for (YType t : types) {
if (t instanceof YMapType) {
maps.add((YMapType) t);
} else if (t instanceof YAtomicType) {
atoms.add((YAtomicType) t);
} else if (t instanceof YSeqType) {
arrays.add((YSeqType) t);
} else if (t instanceof YBeanType) {
beans.add((YBeanType) t);
} else {
throw new IllegalArgumentException("Union of this kind of types is not (yet) supported: "+t);
}
}
if (atoms.size()==1 && maps.size()==1) {
if (atoms.size()==1 && maps.size()==1 && arrays.size()==0 && beans.size()==0) {
return new YAtomAndMapUnion(name, atoms.get(0), maps.get(0));
} else if (atoms.size()==0 && maps.size()==0 && arrays.size()==1 && beans.size()==1) {
return new YBeanAndSequenceUnion(name, beans.get(0), arrays.get(0));
}
throw new IllegalArgumentException("Union of this kind of types is not (yet) supported: "+types);
}
@@ -544,7 +553,6 @@ public class YTypeFactory {
this.isSeq = false;
return this;
}
}
@@ -836,6 +844,49 @@ public class YTypeFactory {
}
}
public class YBeanAndSequenceUnion extends AbstractType {
private String name;
private YBeanType bean;
private YSeqType seq;
public YBeanAndSequenceUnion(String name, YBeanType yBeanType, YSeqType ySeqType) {
this.name = name;
this.bean = yBeanType;
this.seq = ySeqType;
}
@Override
public YType inferMoreSpecificType(DynamicSchemaContext dc) {
if (dc.isMap()) {
return bean;
} else if (dc.isSequence()) {
return seq;
}
return super.inferMoreSpecificType(dc);
}
@Override
public String toString() {
if (name!=null) {
return name;
} else {
return "(" + bean +" | " + seq + ")";
}
}
@Override
public boolean isBean() {
return true;
}
@Override
public boolean isSequenceable() {
return true;
}
}
public static class YTypedPropertyImpl implements YTypedProperty, Cloneable {

View File

@@ -377,9 +377,18 @@ public class PipelineYmlSchema implements YamlSchema {
doStep,
tryStep
};
YBeanUnionType step = f.yBeanUnion("Step", stepTypes);
addProp(aggregateStep, "aggregate", f.yseq(step));
addProp(inParallelStep, "in_parallel", f.yseq(step));
YBeanType inParallelStepOptions = f.ybean("InParallelStepOptions");
addProp(inParallelStepOptions, "steps", f.yseq(step));
addProp(inParallelStepOptions, "limit", t_pos_integer);
addProp(inParallelStepOptions, "fail_fast", t_boolean);
addProp(inParallelStep, "in_parallel", f.yunion(null,
f.yseq(step),
inParallelStepOptions
));
addProp(doStep, "do", f.yseq(step));
addProp(tryStep, "try", step);

View File

@@ -0,0 +1,4 @@
*Optional*. Default is *false*. When enabled the parallel step will fail fast by returning as soon as any
sub-step fails. This means that running steps will be interrupted and pending steps will no longer be
scheduled.

View File

@@ -0,0 +1,6 @@
*Optional. Default is no limit*. A sempahore which limits the parallelism when executing the steps in a
`in_parallel` step. When set, the number of running steps will not exceed the limit.
When not specified `in_parallel` will execute all steps immediately, making the default behavior
identical to [aggregate](https://concourse-ci.org/aggregate-step.html).

View File

@@ -0,0 +1 @@
*Optional*. The steps to perform in parallel.

View File

@@ -315,7 +315,7 @@ public class ConcourseEditorTest {
"get: <*>"
, // ==============
"in_parallel:\n" +
" - <*>"
" <*>"
, // ==============
"put: <*>"
, // ==============
@@ -551,12 +551,68 @@ public class ConcourseEditorTest {
"- name: some-job\n" +
" plan:\n" +
" - in_parallel:\n" +
" - get: some-resource\n"
" limit: 2\n" +
" fail_fast: true\n" +
" steps:\n" +
" - get: some-resource\n"
);
editor.assertHoverContains("in_parallel", "Performs the given steps in parallel");
editor.assertHoverContains("limit", "sempahore which limits the parallelism");
editor.assertHoverContains("fail_fast", "step will fail fast");
}
@Test
public void inParallelStepReconcile() throws Exception {
Editor editor;
//old style... just a sequence of steps
editor = harness.newEditor(
"jobs:\n" +
"- name: some-job\n" +
" plan:\n" +
" - in_parallel:\n" +
" - get: some-resource\n"
);
editor.assertProblems(
"some-resource|does not exist"
);
//new style... object with a 'steps' property
editor = harness.newEditor(
"jobs:\n" +
"- name: some-job\n" +
" plan:\n" +
" - in_parallel:\n" +
" limit: not-a-number\n" +
" fail_fast: not-a-bool\n"+
" steps:\n" +
" - get: some-resource\n"
);
editor.assertProblems(
"not-a-number|NumberFormatException",
"not-a-bool|boolean",
"some-resource|does not exist"
);
}
@Test
public void inParallelStepCompletion() throws Exception {
Editor editor = harness.newEditor(
"jobs:\n" +
"- name: some-job\n" +
" plan:\n" +
" - <*>"
);
editor.assertCompletionWithLabel("in_parallel",
"jobs:\n" +
"- name: some-job\n" +
" plan:\n" +
" - in_parallel:\n" +
" <*>"
);
}
@Test
public void reconcileSimpleTypes() throws Exception {
Editor editor;
@@ -4232,14 +4288,6 @@ public class ConcourseEditorTest {
" plan:\n" +
" in_"
);
editor.assertCompletionWithLabel("- in_parallel",
"jobs:\n" +
"- name: build-docker-image\n" +
" serial: true\n" +
" plan:\n" +
" - in_parallel:\n" +
" - <*>"
);
}
@Test public void relaxedContentAssist_primary_properties() throws Exception{