diff --git a/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshDeploymentManifestSchema.java b/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshDeploymentManifestSchema.java index 2199b7584..79d53c016 100644 --- a/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshDeploymentManifestSchema.java +++ b/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshDeploymentManifestSchema.java @@ -16,6 +16,7 @@ import java.util.UUID; import org.springframework.ide.vscode.commons.util.Assert; 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.util.ValueParsers; import org.springframework.ide.vscode.commons.yaml.schema.YType; import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory; @@ -27,6 +28,7 @@ import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YTypedPro import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil; import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty; import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema; +import org.springframework.ide.vscode.commons.yaml.schema.constraints.Constraints; import com.google.common.collect.ImmutableSet; @@ -102,6 +104,10 @@ public class BoshDeploymentManifestSchema implements YamlSchema { YAtomicType t_ip_address = f.yatomic("IPAddress"); //TODO: some kind of checking? t_ip_address.parseWith(ValueParsers.NE_STRING); + + YAtomicType t_url = f.yatomic("URL"); //TODO: some kind of checking? + t_url.parseWith(ValueParsers.NE_STRING); + YAtomicType t_network_name = f.yatomic("NetworkName"); //TODO: resolve from 'cloud config' https://www.pivotaltracker.com/story/show/148712155 t_network_name.parseWith(ValueParsers.NE_STRING); @@ -136,8 +142,15 @@ public class BoshDeploymentManifestSchema implements YamlSchema { YBeanType t_release = f.ybean("Release"); addProp(t_release, "name", t_ne_string).isPrimary(true); - addProp(t_release, "version", t_version).isRequired(true); + addProp(t_release, "version", t_version).isRequired(true); //TODO: Is it really required? Maybe not id we use url + sha + //See: https://github.com/cloudfoundry/docs-bosh/issues/330 + addProp(t_release, "url", t_url); + addProp(t_release, "sha1", t_ne_string); addProp(v2Schema, "releases", f.yseq(t_release)).isRequired(true); + //TODO: these extra checks disabled because we aren't sure they are valid + // See: https://github.com/cloudfoundry/docs-bosh/issues/330 + // t_release.require(Constraints.requireOneOf("url", "version")); + // t_release.require(Constraints.mutuallyExclusive("version", "sha1")); YBeanType t_stemcell = f.ybean("Stemcell"); addProp(t_stemcell, "alias", t_ne_string).isRequired(true); diff --git a/headless-services/bosh-language-server/src/main/resources/desc/Release/sha1.md b/headless-services/bosh-language-server/src/main/resources/desc/Release/sha1.md new file mode 100644 index 000000000..fb04fe343 --- /dev/null +++ b/headless-services/bosh-language-server/src/main/resources/desc/Release/sha1.md @@ -0,0 +1 @@ +The SHA1 of the release tarball. SHA1 is only required when using HTTP(s) URLs. \ No newline at end of file diff --git a/headless-services/bosh-language-server/src/main/resources/desc/Release/url.md b/headless-services/bosh-language-server/src/main/resources/desc/Release/url.md new file mode 100644 index 000000000..ee0df6ea5 --- /dev/null +++ b/headless-services/bosh-language-server/src/main/resources/desc/Release/url.md @@ -0,0 +1 @@ +URL of the release to use. URL may use the file protocol (`file://`) or HTTP(s) (`http(s)://`). File URLs can be absolute or relative to the current directory of `bosh-init` execution. \ No newline at end of file diff --git a/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/concourse/BoshEditorTest.java b/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/concourse/BoshEditorTest.java index 35c392eb2..f9e86bccf 100644 --- a/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/concourse/BoshEditorTest.java +++ b/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/concourse/BoshEditorTest.java @@ -115,7 +115,7 @@ public class BoshEditorTest { editor.assertHoverContains("tags", "Specifies key value pairs to be sent to the CPI for VM tagging"); } - @Ignore //For now... because not passing yet. + //@Ignore //For now... because not passing yet. @Test public void reconcileCfManifest() throws Exception { Editor editor = harness.newEditorFromClasspath("/workspace/cf-deployment-manifest.yml"); editor.assertProblems(/*NONE*/); @@ -219,6 +219,14 @@ public class BoshEditorTest { " <*>" ); editor.assertCompletions(PLAIN_COMPLETION, + "releases:\n" + + "- name: foo\n" + + " sha1: <*>" + , // ============ + "releases:\n" + + "- name: foo\n" + + " url: <*>" + , // ============ "releases:\n" + "- name: foo\n" + " version: <*>" @@ -230,6 +238,8 @@ public class BoshEditorTest { "releases:\n" + "- name: some-release\n" + " version: some-version\n" + + " url: https://my.releases.com/funky.tar.gz\n" + + " sha1: 440248a31253296b1626ad52886e58900730f32e\n" + " woot: dunno\n" ); editor.ignoreProblem(YamlSchemaProblems.MISSING_PROPERTY); @@ -239,6 +249,8 @@ public class BoshEditorTest { editor.assertHoverContains("name", "Name of a release used in the deployment"); editor.assertHoverContains("version", "The version of the release to use"); + editor.assertHoverContains("url", "URL of the release to use"); + editor.assertHoverContains("sha1", "The SHA1 of the release tarball"); editor = harness.newEditor( "releases:\n" + diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/YamlSchemaProblems.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/YamlSchemaProblems.java index e97ab8fde..c46c7f2cb 100644 --- a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/YamlSchemaProblems.java +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/YamlSchemaProblems.java @@ -114,7 +114,7 @@ public class YamlSchemaProblems { return new ReconcileProblemImpl(problemType, msg, start, end-start); } - public static ReconcileProblemImpl missingProperty(String msg, IDocument doc, Node parent, MappingNode map) { + public static ReconcileProblemImpl missingProperty(String msg, IDocument doc, Node parent, Node map) { DocumentRegion underline = NodeUtil.region(doc, map); if (parent instanceof MappingNode) { for (NodeTuple prop : ((MappingNode) parent).getValue()) { diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/constraints/Constraints.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/constraints/Constraints.java index 37b6b4674..71350b6e9 100644 --- a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/constraints/Constraints.java +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/constraints/Constraints.java @@ -11,10 +11,12 @@ package org.springframework.ide.vscode.commons.yaml.schema.constraints; import static org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems.EXTRA_PROPERTY; -import static org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems.missingProperty; +import static org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems.*; import static org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems.problem; +import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Function; @@ -39,7 +41,7 @@ import com.google.common.collect.ImmutableSet; * @author Kris De Volder */ public class Constraints { - + public static Constraint requireOneOf(String... properties) { return new RequireOneOf(properties); } @@ -122,4 +124,24 @@ public class Constraints { dispatcher.withContext(dc).verify(dc, parent, node, type, problems); }; } + + public static Constraint mutuallyExclusive(String p1, String p2) { + return (DynamicSchemaContext dc, Node parent, Node node, YType type, IProblemCollector problems) -> { + if (node instanceof MappingNode) { + MappingNode map = (MappingNode) node; + Set defined = dc.getDefinedProperties(); + if (defined.contains(p1) && defined.contains(p2)) { + for (NodeTuple tup : map.getValue()) { + Node keyNode = tup.getKeyNode(); + String key = NodeUtil.asScalar(keyNode); + if (p1.equals(key) || p1.equals(key)) { + problems.accept(problem(EXTRA_PROPERTY, + "Only one of '"+p1+"' and '"+p2+"' should be defined for '"+type+"'", keyNode + )); + } + } + } + } + }; + } } \ No newline at end of file