From b5244a253cfab9b0627ff440b886dbea7de7f007 Mon Sep 17 00:00:00 2001 From: Kris De Volder Date: Mon, 15 May 2017 18:56:57 -0700 Subject: [PATCH] Support for rootfs_uri property with deprecation warning for `image` property --- concourse/pipeline.yml | 6 -- .../yaml/completion/YTypeAssistContext.java | 12 ++-- .../SchemaBasedYamlASTReconciler.java | 7 ++- .../commons/yaml/schema/YTypeFactory.java | 11 ++++ .../commons/yaml/schema/YTypedProperty.java | 1 + .../vscode/concourse/PipelineYmlSchema.java | 9 +-- .../main/resources/desc/TaskConfig/image.md | 4 +- .../resources/desc/TaskConfig/rootfs_uri.md | 7 +++ .../vscode/concourse/ConcourseEditorTest.java | 59 +++++++++++++------ 9 files changed, 81 insertions(+), 35 deletions(-) create mode 100644 headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/rootfs_uri.md diff --git a/concourse/pipeline.yml b/concourse/pipeline.yml index 6473275b3..71076e778 100644 --- a/concourse/pipeline.yml +++ b/concourse/pipeline.yml @@ -39,12 +39,6 @@ resources: uri: git@github.com:spring-projects/sts4.git branch: {{branch}} private_key: {{rsa_id}} -# - name: sts4-out-TEST -# type: git -# source: -# uri: git@github.com:spring-projects/sts4.git -# branch: kdvolder-temp -# private_key: {{rsa_id}} - name: s3-boot-properties-vsix-snapshot type: s3 source: diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YTypeAssistContext.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YTypeAssistContext.java index 46eb40643..d77b9d87b 100644 --- a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YTypeAssistContext.java +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YTypeAssistContext.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.commons.yaml.completion; -import static org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal.DEEMP_DASH_PROPOSAL; +import static org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal.*; import java.util.ArrayList; import java.util.Collection; @@ -24,6 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal; import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion; import org.springframework.ide.vscode.commons.util.CollectionUtil; import org.springframework.ide.vscode.commons.util.ExceptionUtil; @@ -131,10 +132,13 @@ public class YTypeAssistContext extends AbstractYamlAssistContext { edits.insert(queryOffset, " "); } edits.createPathInPlace(contextNode, relativePath, queryOffset, appendTextFor(YType)); - proposals.add(completionFactory().beanProperty(doc.getDocument(), + ICompletionProposal completion = completionFactory().beanProperty(doc.getDocument(), contextPath.toPropString(), getType(), - query, p, score, edits, typeUtil) - ); + query, p, score, edits, typeUtil); + if (p.isDeprecated() && completion instanceof ScoreableProposal) { + completion.deemphasize(DEEMP_DEPRECATION); + } + proposals.add(completion); } } } diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/SchemaBasedYamlASTReconciler.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/SchemaBasedYamlASTReconciler.java index 73d0a039f..114328423 100644 --- a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/SchemaBasedYamlASTReconciler.java +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/SchemaBasedYamlASTReconciler.java @@ -162,7 +162,12 @@ public class SchemaBasedYamlASTReconciler implements YamlASTReconciler { unknownBeanProperty(keyNode, type, key); } else { if (prop.isDeprecated()) { - problems.accept(YamlSchemaProblems.deprecatedProperty(keyNode, type, prop)); + String msg = prop.getDeprecationMessage(); + if (StringUtil.hasText(msg)) { + problems.accept(YamlSchemaProblems.deprecatedProperty(msg, keyNode)); + } else { + problems.accept(YamlSchemaProblems.deprecatedProperty(keyNode, type, prop)); + } } reconcile(ast, valueAt(path, key), map, entry.getValueNode(), prop.getType()); } diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java index 3d0e3e06b..e00c634ae 100644 --- a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java @@ -734,6 +734,7 @@ public class YTypeFactory { private boolean isRequired; private boolean isDeprecated; private boolean isPrimary; + private String deprecationMessage; private YTypedPropertyImpl(String name, YType type) { this.name = name; @@ -778,6 +779,15 @@ public class YTypeFactory { public void isDeprecated(boolean isDeprecated) { this.isDeprecated = isDeprecated; } + public void isDeprecated(String deprecationMessage) { + this.isDeprecated = deprecationMessage!=null; + this.deprecationMessage = deprecationMessage; + } + + @Override + public String getDeprecationMessage() { + return this.deprecationMessage; + } @Override public boolean isDeprecated() { @@ -801,6 +811,7 @@ public class YTypeFactory { public boolean isPrimary() { return isPrimary; } + } public YAtomicType yatomic(String name) { diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypedProperty.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypedProperty.java index ddfc941a3..69d49f6c9 100644 --- a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypedProperty.java +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypedProperty.java @@ -21,5 +21,6 @@ public interface YTypedProperty { Renderable getDescription(); default boolean isRequired() { return false; } default boolean isDeprecated() { return false; } + default String getDeprecationMessage() { return null; } default boolean isPrimary() { return false; } } diff --git a/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/PipelineYmlSchema.java b/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/PipelineYmlSchema.java index 25d652c3a..e2ae2e2e2 100644 --- a/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/PipelineYmlSchema.java +++ b/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/PipelineYmlSchema.java @@ -248,7 +248,8 @@ public class PipelineYmlSchema implements YamlSchema { task = f.ybean("TaskConfig"); addProp(task, "platform", t_platform).isRequired(true); addProp(task, "image_resource", t_image_resource); - addProp(task, "image", t_ne_string); + addProp(task, "rootfs_uri", t_ne_string); + addProp(task, "image", t_ne_string).isDeprecated("The 'image' property in 'TaskConfig' is renamed to 'rootfs_uri' in Concourse 3.0"); addProp(task, "inputs", f.yseq(t_input)); addProp(task, "outputs", f.yseq(t_output)); addProp(task, "run", t_command).isRequired(true); @@ -258,16 +259,16 @@ public class PipelineYmlSchema implements YamlSchema { if (LanguageId.CONCOURSE_PIPELINE.equals(languageId)) { Node parentImageDef = models.getParentPropertyNode("image", dc); if (parentImageDef==null) { - return Constraints.requireOneOf("image_resource", "image"); + return Constraints.requireOneOf("image_resource", "rootfs_uri", "image"); } else { return Constraints.deprecated((name) -> "Deprecated: This attribute in the task config will be ignored! "+ "The 'image' attribute on the task itself takes precedence.", - "image_resource", "image" + "image_resource", "rootfs_uri", "image" ); } } else { - return Constraints.requireAtMostOneOf("image_resource", "image"); + return Constraints.requireAtMostOneOf("image_resource", "rootfs_uri", "image"); } })); diff --git a/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/image.md b/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/image.md index ade815381..8ed654518 100644 --- a/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/image.md +++ b/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/image.md @@ -2,4 +2,6 @@ by your worker's Garden backend. You should only use this if you cannot use `image_resource` for some reason, -and you know what you're doing. \ No newline at end of file +and you know what you're doing. + +WARNING: This property has been renamed to `rootfs_uri` in Concourse 3.0. \ No newline at end of file diff --git a/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/rootfs_uri.md b/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/rootfs_uri.md new file mode 100644 index 000000000..e40eca352 --- /dev/null +++ b/headless-services/concourse-language-server/src/main/resources/desc/TaskConfig/rootfs_uri.md @@ -0,0 +1,7 @@ +*Optional.* A string specifying the rootfs of the container, as interpreted +by your worker's Garden backend. + +You should only use this if you cannot use `image_resource` for some reason, +and you know what you're doing. + +Note: Prior to Concourse 3.0 this property was called `image`. \ No newline at end of file diff --git a/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java b/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java index ffdaae38d..a18ebe78e 100644 --- a/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java +++ b/headless-services/concourse-language-server/src/test/java/org/springframework/ide/vscode/concourse/ConcourseEditorTest.java @@ -350,6 +350,26 @@ public class ConcourseEditorTest { editor.assertHoverContains("jobs", " A list of jobs that should appear in this group"); } + @Test + public void concourse_3_0_rootfs_uri_prop() throws Exception { + Editor editor = harness.newEditor(LanguageId.CONCOURSE_TASK, + "platform: linux\n" + + "image: blah\n" + + "run:\n" + + " path: demo-repo/ci/tasks/run-tests.sh" + ); + Diagnostic p = editor.assertProblems("image|renamed to 'rootfs_uri'").get(0); + assertEquals(DiagnosticSeverity.Warning, p.getSeverity()); + + editor = harness.newEditor(LanguageId.CONCOURSE_TASK, + "platform: linux\n" + + "image: blah\n" + + "run:\n" + + " path: demo-repo/ci/tasks/run-tests.sh" + ); + editor.assertHoverContains("image", "renamed to `rootfs_uri`"); + } + @Test public void taskStepHovers() throws Exception { Editor editor = harness.newEditor( @@ -664,7 +684,7 @@ public class ConcourseEditorTest { List problems = editor.assertProblems( "config|[platform, run] are required", "config|Only one of [config, file]", - "config|One of [image_resource, image]", + "config|One of [image_resource, rootfs_uri, image]", "file|Only one of [config, file]" ); //All of the problems in this example are property contraint violations! So all should be warnings. @@ -2718,9 +2738,9 @@ public class ConcourseEditorTest { Editor editor; editor = harness.newEditor(LanguageId.CONCOURSE_TASK, - "image: some-image" + "rootfs_uri: some-image" ); - editor.assertProblems("image: some-imag^e^|[platform, run] are required"); + editor.assertProblems("rootfs_uri: some-imag^e^|[platform, run] are required"); editor = harness.newEditor(LanguageId.CONCOURSE_TASK, "platform: a-platform\n" + @@ -2731,7 +2751,7 @@ public class ConcourseEditorTest { " bogus-source-prop: bad\n" + " repository: ruby\n" + " tag: '2.1'\n" + - "image: some-image\n" + + "rootfs_uri: some-image\n" + "inputs:\n" + "- path: path/to/input\n" + "outputs:\n" + @@ -2741,10 +2761,10 @@ public class ConcourseEditorTest { "params: the-params\n" ); editor.assertProblems( - "image_resource|Only one of [image_resource, image] should be defined", + "image_resource|Only one of [image_resource, rootfs_uri, image] should be defined", "name|Unknown property", "bogus-source-prop|Unknown property", - "image|Only one of [image_resource, image] should be defined", + "rootfs_uri|Only one of [image_resource, rootfs_uri, image] should be defined", "-^ path: path/to/input|'name' is required", "-^ path: path/to/output|'name' is required", "the-params|Expecting a 'Map'" @@ -2755,16 +2775,15 @@ public class ConcourseEditorTest { Editor editor; editor = harness.newEditor(LanguageId.CONCOURSE_TASK, - "image: some-image" + "rootfs_uri: some-image" ); - editor.assertProblems("image: some-imag^e^|[platform, run] are required"); + editor.assertProblems("rootfs_uri: some-imag^e^|[platform, run] are required"); editor = harness.newEditor(LanguageId.CONCOURSE_TASK, - "image: some-image\n" + - "\n" + + "rootfs_uri: some-image\n" + " \n" ); - editor.assertProblems("image: some-imag^e^|[platform, run] are required"); + editor.assertProblems("rootfs_uri: some-imag^e^|[platform, run] are required"); } @@ -2785,8 +2804,6 @@ public class ConcourseEditorTest { , "<*>" , // ==> - "image: <*>" - , "image_resource:\n" + " <*>" , @@ -2798,6 +2815,10 @@ public class ConcourseEditorTest { , "params:\n" + " <*>" + , + "rootfs_uri: <*>" + , + "image: <*>" ); assertTaskCompletions( @@ -2851,7 +2872,7 @@ public class ConcourseEditorTest { " bogus-source-prop: bad\n" + " repository: ruby\n" + " tag: '2.1'\n" + - " image: some-image\n" + + " rootfs_uri: some-image\n" + " inputs:\n" + " - path: path/to/input\n" + " outputs:\n" + @@ -2861,10 +2882,10 @@ public class ConcourseEditorTest { " params: the-params" ); editor.assertProblems( - "image_resource|Only one of [image_resource, image] should be defined", + "image_resource|Only one of [image_resource, rootfs_uri, image] should be defined", "name|Unknown property", "bogus-source-prop|Unknown property", - "image|Only one of [image_resource, image] should be defined", + "rootfs_uri|Only one of [image_resource, rootfs_uri, image] should be defined", "-^ path: path/to/input|'name' is required", "-^ path: path/to/output|'name' is required", "the-params|Expecting a 'Map'" @@ -3044,7 +3065,7 @@ public class ConcourseEditorTest { editor.assertProblems( "docker-image|Unused", - "config|One of [image_resource, image] is required" + "config|One of [image_resource, rootfs_uri, image] is required" ); } @@ -3076,7 +3097,7 @@ public class ConcourseEditorTest { " - task: hello-world\n" + " image: my-docker-image\n" + " config:\n" + - " image: blah\n" + + " rootfs_uri: blah\n" + " image_resource:\n" + " type: docker-image\n" + " inputs:\n" + @@ -3088,7 +3109,7 @@ public class ConcourseEditorTest { " - mvn" ); List problems = editor.assertProblems( - "image|Deprecated", + "rootfs_uri|Deprecated", "image_resource|Deprecated" ); for (Diagnostic d : problems) {