Validate that concourse job groups assignment is complete
This commit is contained in:
@@ -22,6 +22,7 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
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.util.SimpleLanguageServer;
|
||||
@@ -32,30 +33,26 @@ import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.YamlASTProvider;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.YamlAstCache;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.YamlParser;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.ASTRootCursor;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.NodeCursor;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlPath;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlPathSegment;
|
||||
import org.springframework.ide.vscode.commons.yaml.path.YamlTraversal;
|
||||
import org.springframework.ide.vscode.commons.yaml.reconcile.ASTTypeCache;
|
||||
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems;
|
||||
import org.springframework.ide.vscode.commons.yaml.reconcile.ASTTypeCache.NodeTypes;
|
||||
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.YType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.AbstractType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YBeanUnionType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.constraints.Constraint;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YValueHint;
|
||||
import org.springframework.ide.vscode.commons.yaml.util.StaleFallbackCache;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.constraints.Constraint;
|
||||
import org.springframework.ide.vscode.commons.yaml.util.Streams;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
import org.yaml.snakeyaml.nodes.MappingNode;
|
||||
import org.yaml.snakeyaml.nodes.Node;
|
||||
@@ -131,6 +128,25 @@ public class ConcourseModel {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Verification of constraint: if at least one job is assigned to a group, then all jobs must be assigned to a group.
|
||||
*/
|
||||
public final void jobAssignmentIsComplete(DynamicSchemaContext dc, Node parent, Node node, YType type, IProblemCollector problems) {
|
||||
Multiset<String> assignedJobs = getStringsFromAst(dc.getDocument(), JOBS_ASSIGNED_TO_GROUPS);
|
||||
if (assignedJobs!=null && !assignedJobs.isEmpty()) {
|
||||
getJobNameNodes(dc).forEach(jobDefName -> {
|
||||
String name = NodeUtil.asScalar(jobDefName);
|
||||
if (StringUtil.hasText(name)) { //'not assigned to a group' errors for empty names are a bit silly, so avoid that
|
||||
if (!assignedJobs.contains(name)) {
|
||||
problems.accept(YamlSchemaProblems.schemaProblem("'"+name+"' belongs to no group", jobDefName));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the job with given name. If there is no such job, or if there is more than one, this will return null.
|
||||
*/
|
||||
@@ -238,6 +254,14 @@ public class ConcourseModel {
|
||||
anyChild()
|
||||
);
|
||||
|
||||
public static final YamlPath JOBS_ASSIGNED_TO_GROUPS = new YamlPath(
|
||||
anyChild(),
|
||||
valueAt("groups"),
|
||||
anyChild(),
|
||||
valueAt("jobs"),
|
||||
anyChild()
|
||||
);
|
||||
|
||||
public static final YamlPath JOB_NAMES_PATH = new YamlPath(
|
||||
anyChild(),
|
||||
valueAt("jobs"),
|
||||
@@ -333,6 +357,11 @@ public class ConcourseModel {
|
||||
return getStringsFromAst(dc.getDocument(), JOB_NAMES_PATH);
|
||||
}
|
||||
|
||||
public Stream<Node> getJobNameNodes(DynamicSchemaContext dc) {
|
||||
return getFromAst(dc.getDocument(), ast -> JOB_NAMES_PATH.traverseAmbiguously(ast));
|
||||
}
|
||||
|
||||
|
||||
private Multiset<String> getStringsFromAst(IDocument doc, YamlPath path) {
|
||||
return getFromAst(doc, (ast) -> {
|
||||
return path
|
||||
|
||||
@@ -399,7 +399,7 @@ public class PipelineYmlSchema implements YamlSchema {
|
||||
addProp(TOPLEVEL_TYPE, "resources", f.yseq(t_resource));
|
||||
addProp(TOPLEVEL_TYPE, "jobs", f.yseq(job));
|
||||
addProp(TOPLEVEL_TYPE, "resource_types", f.yseq(resourceType));
|
||||
addProp(TOPLEVEL_TYPE, "groups", f.yseq(group));
|
||||
addProp(TOPLEVEL_TYPE, "groups", f.yseq(group).require(models::jobAssignmentIsComplete));
|
||||
|
||||
definitionTypes = ImmutableList.of(
|
||||
jobNameDef,
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.ide.vscode.commons.util.IOUtil;
|
||||
import org.springframework.ide.vscode.commons.util.Unicodes;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions;
|
||||
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.CodeAction;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
|
||||
@@ -4313,6 +4314,68 @@ public class ConcourseEditorTest {
|
||||
editor.assertProblems("not-a-valid-version|Valid values are: [every, latest]");
|
||||
}
|
||||
|
||||
@Test public void jobGroupsCompletenessReconcile() throws Exception {
|
||||
//1) if all jobs are assigned to a group... don't complain:
|
||||
Editor editor = harness.newEditor(
|
||||
"jobs:\n" +
|
||||
"- name: build-snapshot\n" +
|
||||
"- name: build-release\n" +
|
||||
"- name: test-snapshot\n" +
|
||||
"- name: test-release\n" +
|
||||
"- name: publish-snapshot\n" +
|
||||
"- name: publish-release\n" +
|
||||
"groups:\n" +
|
||||
"- name: snapshot\n" +
|
||||
" jobs:\n" +
|
||||
" - build-snapshot\n" +
|
||||
" - test-snapshot\n" +
|
||||
" - publish-snapshot\n" +
|
||||
"- name: release\n" +
|
||||
" jobs:\n" +
|
||||
" - build-release\n" +
|
||||
" - test-release\n" +
|
||||
" - publish-release\n"
|
||||
);
|
||||
editor.ignoreProblem(YamlSchemaProblems.MISSING_PROPERTY);
|
||||
editor.assertProblems(/*NONE*/);
|
||||
|
||||
//If there are no groups then, don't complain about inconmplete jobs partitioning
|
||||
editor.setText(
|
||||
"jobs:\n" +
|
||||
"- name: build-snapshot\n" +
|
||||
"- name: build-release\n" +
|
||||
"- name: test-snapshot\n" +
|
||||
"- name: test-release\n" +
|
||||
"- name: publish-snapshot\n" +
|
||||
"- name: publish-release\n"
|
||||
);
|
||||
|
||||
//If at least one job is in a group, check that all jobs are in a group
|
||||
editor.setText(
|
||||
"jobs:\n" +
|
||||
"- name: build-snapshot\n" +
|
||||
"- name: build-release\n" +
|
||||
"- name: test-snapshot\n" +
|
||||
"- name: test-release\n" +
|
||||
"- name: publish-snapshot\n" +
|
||||
"- name: publish-release\n" +
|
||||
"groups:\n" +
|
||||
"- name: snapshot\n" +
|
||||
" jobs:\n" +
|
||||
" - build-snapshot\n" +
|
||||
"- name: release\n" +
|
||||
" jobs:\n" +
|
||||
" - build-release"
|
||||
);
|
||||
editor.assertProblems(
|
||||
"test-snapshot|'test-snapshot' belongs to no group",
|
||||
"test-release|'test-release' belongs to no group",
|
||||
"publish-snapshot|'publish-snapshot' belongs to no group",
|
||||
"publish-release|'publish-release' belongs to no group"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void assertContextualCompletions(String conText, String textBefore, String... textAfter) throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user