1) Turn errors for empty task.input|output.path into a warning

2) Add task.optional property to the schema
This commit is contained in:
Kris De Volder
2018-02-20 14:48:30 -08:00
parent 5ac6d4010e
commit 0d94dfef2b
7 changed files with 81 additions and 13 deletions

View File

@@ -24,7 +24,7 @@ public class ValueParsers {
throw new ValueParseException("String should not be empty");
}
};
public static final ValueParser POS_INTEGER = integerRange(0, null);
public static ValueParser integerAtLeast(final Integer lowerBound) {

View File

@@ -55,7 +55,7 @@ public class YamlSchemaProblems {
public static final ProblemType DEPRECATED_VALUE = problemType("DeprecatedValue", ProblemSeverity.WARNING);
public static final ProblemType MISSING_PROPERTY = problemType("MissingProperty", ProblemSeverity.ERROR);
public static final ProblemType EXTRA_PROPERTY = problemType("ExtraProperty", ProblemSeverity.ERROR);
public static final ProblemType EMPTY_OPTIONAL_STRING = problemType("EmptyOptionalString", ProblemSeverity.WARNING);
public static final Set<ProblemType> PROPERTY_CONSTRAINT = ImmutableSet.of(
MISSING_PROPERTY, EXTRA_PROPERTY

View File

@@ -0,0 +1,30 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.yaml.reconcile;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileException;
import org.springframework.ide.vscode.commons.util.StringUtil;
import org.springframework.ide.vscode.commons.util.ValueParser;
/**
* Reusable value parsers and helpers that are somewhat specific
* to yaml schema validation.
*/
public class YamlSchemaValueParsers {
public static final ValueParser OPT_STRING = (s) -> {
if (StringUtil.hasText(s)) {
return s;
} else {
throw new ReconcileException("Empty optional String attribute is useless and can be omitted.", YamlSchemaProblems.EMPTY_OPTIONAL_STRING);
}
};
}

View File

@@ -106,5 +106,4 @@ public class ConcourseValueParsers {
return time + pm + zone;
}
}

View File

@@ -31,6 +31,7 @@ import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST;
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.reconcile.YamlSchemaProblems;
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaValueParsers;
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;
@@ -88,6 +89,8 @@ public class PipelineYmlSchema implements YamlSchema {
public final YType t_string = f.yatomic("String");
public final YType t_ne_string = f.yatomic("String")
.parseWith(ValueParsers.NE_STRING);
public final YType t_opt_string = f.yatomic("String")
.parseWith(YamlSchemaValueParsers.OPT_STRING);
public final YType t_strings = f.yseq(t_string);
public final YType t_pair = f.ybean("NameValuePair",
@@ -248,11 +251,12 @@ public class PipelineYmlSchema implements YamlSchema {
AbstractType t_input = f.ybean("TaskInput");
addProp(t_input, "name", t_ne_string).isPrimary(true);
addProp(t_input, "path", t_ne_string);
addProp(t_input, "path", t_opt_string);
addProp(t_input, "optional", t_boolean);
AbstractType t_output = f.ybean("TaskOutput");
addProp(t_output, "name", t_ne_string).isPrimary(true);
addProp(t_output, "path", t_ne_string);
addProp(t_output, "path", t_opt_string);
AbstractType t_command = f.ybean("Command");
addProp(t_command, "path", t_ne_string).isRequired(true);

View File

@@ -0,0 +1,3 @@
*Optional*. If `true`, then the input is not required by the task. The task may run even if this input is missing.
An optional input that is missing will not appear in the current directory of the running task.

View File

@@ -12,7 +12,6 @@ package org.springframework.ide.vscode.concourse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.when;
import static org.springframework.ide.vscode.languageserver.testharness.Editor.INDENTED_COMPLETION;
import static org.springframework.ide.vscode.languageserver.testharness.Editor.PLAIN_COMPLETION;
@@ -31,7 +30,7 @@ import org.eclipse.lsp4j.DiagnosticSeverity;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity;
import org.mockito.Mockito;
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;
@@ -47,21 +46,20 @@ import org.springframework.ide.vscode.languageserver.testharness.Synchronization
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.mockito.Mockito;
public class ConcourseEditorTest {
private static final YamlCompletionEngineOptions OPTIONS = YamlCompletionEngineOptions.TEST_DEFAULT;
private static final String CURSOR = "<*>";
LanguageServerHarness harness;
LanguageServerHarness<ConcourseLanguageServer> harness;
private GithubInfoProvider github= Mockito.mock(GithubInfoProvider.class);
@Before public void setup() throws Exception {
harness = new LanguageServerHarness(() -> {
return new ConcourseLanguageServer(OPTIONS, github)
.setMaxCompletions(100);
harness = new LanguageServerHarness<>(() -> {
ConcourseLanguageServer s = new ConcourseLanguageServer(OPTIONS, github);
s.setMaxCompletions(100);
return s;
},
LanguageId.CONCOURSE_PIPELINE
);
@@ -4611,6 +4609,40 @@ public class ConcourseEditorTest {
}
}
@Test public void emptyInputPathWarning() throws Exception {
Editor editor = harness.newEditor(LanguageId.CONCOURSE_TASK,
"platform: linux\n" +
"run:\n" +
" path: blah\n" +
"inputs:\n" +
"- name: foo\n" +
" path: \"\"\n" +
"outputs:\n" +
"- name: bar\n" +
" path: \"\"\n"
);
List<Diagnostic> problems = editor.assertProblems(
"\"\"|Empty optional String attribute is useless and can be omitted",
"\"\"|Empty optional String attribute is useless and can be omitted"
);
for (Diagnostic problem : problems) {
assertEquals(DiagnosticSeverity.Warning, problem.getSeverity());
}
}
@Test public void taskInputOptionalAttribute() throws Exception {
Editor editor = harness.newEditor(LanguageId.CONCOURSE_TASK,
"platform: linux\n" +
"run:\n" +
" path: blah\n" +
"inputs:\n" +
"- name: foo\n" +
" optional: non-bool\n"
);
editor.assertProblems("non-bool|boolean");
editor.assertHoverContains("optional", "If `true`, then the input is not required by the task");
}
//////////////////////////////////////////////////////////////////////////////
private void assertContextualCompletions(String conText, String textBefore, String... textAfter) throws Exception {