Skip to content

Commit

Permalink
Fixes Concourse issues for #41
Browse files Browse the repository at this point in the history
1) Turn errors for empty task.input|output.path into a warning

2) Add task.optional property to the schema
  • Loading branch information
kdvolder committed Feb 20, 2018
1 parent 5ac6d40 commit 0d94dfe
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,4 @@ private static String createTimeRegexp() {
return time + pm + zone;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
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;
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -248,11 +251,12 @@ public PipelineYmlSchema(ConcourseModel models, GithubInfoProvider github) {

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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

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;
Expand All @@ -31,7 +30,7 @@
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;
Expand All @@ -47,21 +46,20 @@
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
);
Expand Down Expand Up @@ -4611,6 +4609,40 @@ public void gotoResourceTypeDefinition() throws Exception {
}
}

@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 {
Expand Down

0 comments on commit 0d94dfe

Please sign in to comment.