Skip to content

Commit

Permalink
Fix #28: values 'latest' and 'every' should be accepted for 'version'…
Browse files Browse the repository at this point in the history
… in getstep
  • Loading branch information
kdvolder committed Dec 13, 2017
1 parent 2e912df commit 3658f87
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.util;

import static org.assertj.core.api.Assertions.setAllowComparingPrivateFields;

import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.Callable;
Expand Down Expand Up @@ -150,4 +152,40 @@ public Throwable getExplanation() {
public PartialCollection<T> add(@SuppressWarnings("unchecked") T... values) {
return addAll(Arrays.asList(values));
}

public PartialCollection<T> addAll(PartialCollection<T> values) {
PartialCollection<T> merged = this.addAll(values.getElements());
if (!values.isComplete()) {
merged = merged.addUncertainty();
if (merged.getExplanation()==null && values.getExplanation()!=null) {
merged = merged.withExplanation(values.getExplanation());
}
}
return merged;
}

private PartialCollection<T> withExplanation(Throwable explanation) {
return new PartialCollection<>(knownElements, isComplete, explanation);
}

@Override
public String toString() {
StringBuilder s = new StringBuilder("PartialCollection(");
boolean first = true;
for (T e : knownElements) {
if (!first) {
s.append(", ");
}
s.append(e.toString());
first = false;
}
if (!isComplete) {
if (!first) {
s.append(", ");
}
s.append("...");
}
s.append(")");
return s.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,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;

/**
* Adapts a SnakeYaml ast node as a {@link DynamicSchemaContext} (so it
Expand All @@ -30,11 +31,13 @@ public class ASTDynamicSchemaContext extends CachingSchemaContext {
private MappingNode mapNode;
private YamlPath path;
private YamlFileAST ast;
private Node node;

public ASTDynamicSchemaContext(YamlFileAST ast, YamlPath path, Node node) {
this.ast = ast;
this.path = path;
this.mapNode = as(MappingNode.class, node);
this.node = node;
}

@SuppressWarnings("unchecked")
Expand All @@ -59,9 +62,19 @@ public IDocument getDocument() {
public YamlPath getPath() {
return path;
}

@Override
public YamlFileAST getAST() {
return ast;
}

@Override
public boolean isAtomic() {
return node instanceof ScalarNode;
}

@Override
public boolean isMap() {
return mapNode!=null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
public interface DynamicSchemaContext {

DynamicSchemaContext NULL = new DynamicSchemaContext() {

@Override
public Set<String> getDefinedProperties() {
return ImmutableSet.of();
Expand All @@ -46,15 +46,24 @@ public IDocument getDocument() {
public YamlPath getPath() {
return null;
}


@Override
public boolean isAtomic() {
return false;
}

@Override
public boolean isMap() {
return false;
}
};

/**
* Returns the enitre AST of the current document. May be null if the AST is not
* available (e.g. because of parsing errors)
*/
default YamlFileAST getAST() { return null; }

/**
* Returns the set of property names that are already defined in the current context.
* <p>
Expand All @@ -67,7 +76,7 @@ public YamlPath getPath() {
* properties are defined in the surrounding object.
*/
Set<String> getDefinedProperties();

/**
* Returns the IDocument the current context is in. This allows for some 'schemas' to have
* arbitrarily complex analysis of anyhting in the IDocument or even documents related
Expand All @@ -80,4 +89,14 @@ public YamlPath getPath() {
*/
YamlPath getPath();

/**
* Returns true if the current AST node is a scalar value
*/
boolean isAtomic();

/**
* Returns true if the current node is a Mapping node
*/
boolean isMap();

}
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,14 @@ public String toString() {
return "SNodeDynamicSchemaContext("+contextPath+")";
}

@Override
public boolean isAtomic() {
return false;
}

@Override
public boolean isMap() {
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.concurrent.Callable;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileException;
Expand All @@ -35,6 +36,7 @@
import org.springframework.ide.vscode.commons.util.Renderable;
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.constraints.Constraint;
import org.springframework.ide.vscode.commons.yaml.schema.constraints.Constraints;
Expand Down Expand Up @@ -153,9 +155,34 @@ public YBeanType ybean(String name, YTypedProperty... properties) {
return new YBeanType(name, properties);
}

public YBeanUnionType yunion(String name, YBeanType... types) {
public YBeanUnionType yBeanUnion(String name, YBeanType[] types) {
return (YBeanUnionType) yunion(name, types);
}

public YType yunion(String name, YType... types) {
Assert.isLegal(types.length>1);
return new YBeanUnionType(name, types);
if (Stream.of(types).allMatch(t -> t instanceof YBeanType)) {
YBeanType[] beanTypes = new YBeanType[types.length];
for (int i = 0; i < beanTypes.length; i++) {
beanTypes[i] = (YBeanType) types[i];
}
return new YBeanUnionType(name, beanTypes);
}
ArrayList<YMapType> maps = new ArrayList<>(types.length);
ArrayList<YAtomicType> atoms = 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 {
throw new IllegalArgumentException("Union of this kind of types is not (yet) supported: "+t);
}
}
if (atoms.size()==1 && maps.size()==1) {
return new YAtomAndMapUnion(name, atoms.get(0), maps.get(0));
}
throw new IllegalArgumentException("Union of this kind of types is not (yet) supported: "+types);
}

/**
Expand Down Expand Up @@ -763,6 +790,49 @@ public YType inferMoreSpecificType(DynamicSchemaContext dc) {
}
}

public class YAtomAndMapUnion extends AbstractType {

private String name;
private YAtomicType atom;
private YMapType map;

public YAtomAndMapUnion(String name, YAtomicType atom, YMapType map) {
this.name = name;
this.atom = atom;
this.map = map;
}

@Override
public String toString() {
return name;
}

@Override
public boolean isAtomic() {
return true;
}

@Override
public boolean isMap() {
return true;
}

@Override
public YType inferMoreSpecificType(DynamicSchemaContext dc) {
if (dc.isAtomic()) {
return atom;
} else if (dc.isMap()) {
return map;
}
return super.inferMoreSpecificType(dc);
}

@Override
public PartialCollection<YValueHint> getHintValues(DynamicSchemaContext dc) {
return atom.getHintValues(dc).addAll(map.getHintValues(dc));
}

}

public static class YTypedPropertyImpl implements YTypedProperty, Cloneable {

Expand Down Expand Up @@ -1001,5 +1071,4 @@ public YTypeFactory setSnippetProvider(TypeBasedSnippetProvider snippetProvider)
return this;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@

import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
Expand All @@ -34,7 +32,6 @@
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems;
import org.springframework.ide.vscode.commons.yaml.schema.BasicYValueHint;
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
import org.springframework.ide.vscode.commons.yaml.schema.SchemaContextAware;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.AbstractType;
Expand Down Expand Up @@ -99,7 +96,10 @@ public class PipelineYmlSchema implements YamlSchema {
public final YType t_any = f.yany("Object");
public final YType t_params = f.ymap(t_string, t_any);
public final YType t_string_params = f.ymap(t_string, t_string);
public final YType t_resource_version = f.ymap(t_string, t_string);
public final YType t_resource_version = f.yunion("ResourceVersion",
f.yenum("ResourceVersionString", "latest", "every"),
t_string_params
);
public final YType t_pos_integer = f.yatomic("Positive Integer")
.parseWith(ValueParsers.POS_INTEGER);
public final YType t_strictly_pos_integer = f.yatomic("Strictly Positive Integer")
Expand Down Expand Up @@ -346,7 +346,7 @@ public PipelineYmlSchema(ConcourseModel models) {
doStep,
tryStep
};
YBeanUnionType step = f.yunion("Step", stepTypes);
YBeanUnionType step = f.yBeanUnion("Step", stepTypes);
addProp(aggregateStep, "aggregate", f.yseq(step));
addProp(doStep, "do", f.yseq(step));
addProp(tryStep, "try", step);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4078,6 +4078,27 @@ public void gotoResourceTypeDefinition() throws Exception {
);
}

@Test public void getStepVersionShouldAcceptLatestAndEvery() throws Exception {
//See https://github.com/spring-projects/sts4/pull/24
Editor editor = harness.newEditor(
"jobs:\n" +
"- name: do-stuff\n" +
" plan:\n" +
" - get: cf-deployment-git\n" +
" version: latest\n" +
" - get: some-resource\n" +
" version: every\n" +
" - get: other-resource\n" +
" version: bogus"
);
editor.assertProblems(
"cf-deployment-git|resource does not exist",
"some-resource|resource does not exist",
"other-resource|resource does not exist",
"bogus|Valid values are: [every, latest]"
);
}

@Test public void getStepVersionShouldAcceptMap() throws Exception {
//See https://github.com/spring-projects/sts4/pull/24
Editor editor = harness.newEditor(
Expand All @@ -4090,6 +4111,36 @@ public void gotoResourceTypeDefinition() throws Exception {
editor.assertProblems("cf-deployment-git|resource does not exist");
}

@Test public void getStepVersionCompletionsSuggestLatestAndEvery() throws Exception {
//See https://github.com/spring-projects/sts4/pull/24
Editor editor = harness.newEditor(
"jobs:\n" +
"- name: do-stuff\n" +
" plan:\n" +
" - get: cf-deployment-git\n" +
" version: <*>"
);
editor.assertCompletionLabels("every", "latest");
}

@Test public void getStepVersionMapStringStringValidation() throws Exception {
//See https://github.com/spring-projects/sts4/pull/24
Editor editor = harness.newEditor(
"jobs:\n" +
"- name: do-stuff\n" +
" plan:\n" +
" - get: cf-deployment-git\n" +
" version: { ref: good}\n" +
" - get: other-rsrc\n" +
" version: { ref: [bad]}\n"
);
editor.assertProblems(
"cf-deployment-git|resource does not exist",
"other-rsrc|resource does not exist",
"[bad]|Expecting a 'String' but found a 'Sequence'"
);
}

//////////////////////////////////////////////////////////////////////////////

private void assertContextualCompletions(String conText, String textBefore, String... textAfter) throws Exception {
Expand Down

0 comments on commit 3658f87

Please sign in to comment.