concourse editor basics working, tests passing

This commit is contained in:
Kris De Volder
2016-12-14 16:32:02 -08:00
parent e09c6cb8cd
commit d199bb260f
31 changed files with 539 additions and 143 deletions

View File

@@ -241,37 +241,39 @@ public class Renderables {
}
public static Renderable fromClasspath(final Class<?> klass, final String resourcePath) {
if (resourcePath.endsWith(".html")) {
return htmlBlob((HtmlBuffer html) -> {
html.raw(getText(klass, resourcePath, null));
});
} else {
return new Renderable() {
@Override
public void renderAsMarkdown(StringBuilder buffer) {
String extension = ".md";
String value = getText(klass, resourcePath, extension);
if (value != null) {
buffer.append(value);
} else {
NO_DESCRIPTION.renderAsMarkdown(buffer);
return Renderables.lazy(() -> {
String html = getText(klass, resourcePath, ".html");
String markdown = getText(klass, resourcePath, ".md");
if (html==null && markdown==null) {
return NO_DESCRIPTION;
} else {
return new Renderable() {
@Override
public void renderAsMarkdown(StringBuilder buffer) {
if (markdown!=null) {
buffer.append(markdown);
} else {
buffer.append(getHtmlToMarkdownConverter().convert(html));
}
}
}
@Override
public void renderAsHtml(HtmlBuffer buffer) {
String extension = ".html";
String value = getText(klass, resourcePath, extension);
if (value != null) {
buffer.raw(value);
} else {
NO_DESCRIPTION.renderAsHtml(buffer);
@Override
public void renderAsHtml(HtmlBuffer buffer) {
if (html!=null) {
buffer.raw(html);
} else {
//TODO: proper conversion to html
buffer.raw("<pre>");
buffer.raw(markdown);
buffer.raw("</pre>");
}
}
}
};
}
};
}
});
}
private static String getText(final Class<?> klass, String resourcePath, String extension) {

View File

@@ -65,6 +65,7 @@ public class SchemaBasedYamlASTReconciler implements YamlASTReconciler {
} else {
YTypedProperty prop = beanProperties.get(key);
if (prop==null) {
type = typeUtil.inferMoreSpecificType(type, schemaContext);
unknownBeanProperty(keyNode, type, key);
} else {
reconcile(entry.getValueNode(), prop.getType());

View File

@@ -11,6 +11,7 @@
package org.springframework.ide.vscode.commons.yaml.schema;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -58,11 +59,8 @@ public class YTypeFactory {
return new YBeanType(name, properties);
}
public YType yunion(String name, YBeanType... types) {
Assert.isLegal(types.length>0);
if (types.length==1) {
return types[0];
}
public YBeanUnionType yunion(String name, YBeanType... types) {
Assert.isLegal(types.length>1);
return new YBeanUnionType(name, types);
}
@@ -126,6 +124,11 @@ public class YTypeFactory {
public ValueParser getValueParser(YType type) {
return ((AbstractType)type).getParser();
}
@Override
public YType inferMoreSpecificType(YType type, DynamicSchemaContext schemaContext) {
return ((AbstractType)type).inferMoreSpecificType(schemaContext);
}
};
/////////////////////////////////////////////////////////////////////////////////////
@@ -145,6 +148,10 @@ public class YTypeFactory {
return false;
}
public YType inferMoreSpecificType(DynamicSchemaContext dc) {
return this;
}
public boolean isBean() {
return false;
}
@@ -401,19 +408,21 @@ public class YTypeFactory {
*/
public class YBeanUnionType extends AbstractType {
private final String name;
private List<YBeanType> types;
private Map<String, AbstractType> typesByPrimary = new HashMap<>();
private Map<String, AbstractType> typesByPrimary;
private ImmutableList<YTypedProperty> primaryProps;
public YBeanUnionType(String name, YBeanType... types) {
this.name = name;
for (YType _t : types) {
AbstractType t = (AbstractType)_t;
typesByPrimary.put(findPrimary(t, types), t);
}
this.types = new ArrayList<>(Arrays.asList(types));
}
private String findPrimary(AbstractType t, YBeanType[] types) {
public synchronized void addUnionMember(YBeanType type) {
types.add(type);
}
private String findPrimary(AbstractType t, List<YBeanType> types) {
//Note: passing null dynamic context below is okay, assuming the properties in YBeanType
// do not care about dynamic context.
for (YTypedProperty p : t.getProperties(DynamicSchemaContext.NULL)) {
@@ -425,7 +434,7 @@ public class YTypeFactory {
Assert.isLegal(false, "Couldn't find a unique property key for "+t);
return null; //unreachable, but compiler doesn't know.
}
private boolean isUniqueFor(String name, AbstractType t, YBeanType[] types) {
private boolean isUniqueFor(String name, AbstractType t, List<YBeanType> types) {
for (YBeanType other : types) {
if (other!=t) {
//Note: passing null dynamic context below is okay, assuming the properties in YBeanType
@@ -463,29 +472,65 @@ public class YTypeFactory {
public List<YTypedProperty> getProperties(DynamicSchemaContext dc) {
Set<String> existingProps = dc.getDefinedProperties();
if (!existingProps.isEmpty()) {
for (Entry<String, AbstractType> entry : typesByPrimary.entrySet()) {
Builder<YTypedProperty> builder = ImmutableList.builder();
for (Entry<String, AbstractType> entry : typesByPrimary().entrySet()) {
String primaryName = entry.getKey();
if (existingProps.contains(primaryName)) {
return entry.getValue().getProperties(dc);
builder.addAll(entry.getValue().getProperties(dc));
break;
}
}
//Add 'shared' properties too:
builder.addAll(super.getProperties(dc));
return builder.build();
}
//Reaching here means we couldn't guess the type from existing props.
//We'll just return the primary properties, these are good to give as hints
//then, since at least one of them should typically be added.
//then, since at least one of them should be added.
return getPrimaryProps(dc);
}
private synchronized Map<String, AbstractType> typesByPrimary() {
if (typesByPrimary==null) {
//To ensure that the map of 'typesByPrimary' is never stale, make the list of
// types immutable at this point. The assumption here is that union can be
// built up flexibly using mutation ops during initialization, but once it
// starts being used it becomes immutable.
types = ImmutableList.copyOf(types);
ImmutableMap.Builder<String, AbstractType> builder = ImmutableMap.builder();
for (YType _t : types) {
AbstractType t = (AbstractType)_t;
builder.put(findPrimary(t, types), t);
}
typesByPrimary = builder.build();
}
return typesByPrimary;
}
private List<YTypedProperty> getPrimaryProps(DynamicSchemaContext dc) {
if (primaryProps==null) {
Builder<YTypedProperty> builder = ImmutableList.builder();
for (Entry<String, AbstractType> entry : typesByPrimary.entrySet()) {
for (Entry<String, AbstractType> entry : typesByPrimary().entrySet()) {
builder.add(entry.getValue().getPropertiesMap(dc).get(entry.getKey()));
}
primaryProps = builder.build();
}
return primaryProps;
}
@Override
public YType inferMoreSpecificType(DynamicSchemaContext dc) {
Set<String> existingProps = dc.getDefinedProperties();
if (!existingProps.isEmpty()) {
for (Entry<String, AbstractType> entry : typesByPrimary().entrySet()) {
String primaryName = entry.getKey();
if (existingProps.contains(primaryName)) {
return entry.getValue();
}
}
}
return super.inferMoreSpecificType(dc);
}
}

View File

@@ -37,4 +37,12 @@ public interface YTypeUtil {
//TODO: only one of these two should be enough?
List<YTypedProperty> getProperties(YType type, DynamicSchemaContext dc);
Map<String, YTypedProperty> getPropertiesMap(YType yType, DynamicSchemaContext dc);
/**
* Given a {@link DynamicSchemaContext} attempt to get a more specific type, as
* may be inferred by stuff present in the context. If not enough information is
* present in the context to narrow the type, then the type itself
* should be returned.
*/
YType inferMoreSpecificType(YType type, DynamicSchemaContext schemaContext);
}

View File

@@ -43,7 +43,9 @@ export function activate(context: VSCode.ExtensionContext) {
// events pass on to Language Server only for documents for which function passed via textDocumentFilter property return true
// TODO: Remove <any> cast ones https://github.com/Microsoft/vscode-languageserver-node/issues/9 is resolved
documentSelector: [ <any> {language: 'yaml', pattern: '**/*pipeline*.yml'}],
documentSelector: [
<any> {language: 'yaml', pattern: '**/*pipeline*.yml'}
],
synchronize: {
// TODO: Remove textDocumentFilter property once https://github.com/Microsoft/vscode-languageserver-node/issues/9 is resolved
textDocumentFilter: function(textDocument : TextDocument) : boolean {

View File

@@ -2,4 +2,4 @@
set -e
(cd ../commons-vscode ; npm install)
npm install ../commons-vscode
../mvnw -DskipTests -U -f ../pom.xml -pl vscode-concourse -am clean install
../mvnw -U -f ../pom.xml -pl vscode-concourse -am clean install

View File

@@ -14,8 +14,10 @@ import org.springframework.ide.vscode.commons.util.Renderable;
import org.springframework.ide.vscode.commons.util.Renderables;
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.YAtomicType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YBeanType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YBeanUnionType;
import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
@@ -44,6 +46,7 @@ public class PipelineYmlSchema implements YamlSchema {
t_pos_integer.parseWith(ValueParsers.POS_INTEGER);
YType t_any = f.yany("Object");
YType t_params = f.ymap(t_string, t_any);
YType t_string_params = f.ymap(t_string, t_string);
YAtomicType t_version = f.yatomic("Version");
t_version.addHints("latest", "every");
@@ -91,6 +94,7 @@ public class PipelineYmlSchema implements YamlSchema {
prop(putStep, "put", t_ne_string);
prop(putStep, "resource", t_string);
prop(putStep, "params", t_params);
prop(putStep, "get_params", t_params);
YBeanType taskStep = f.ybean("TaskStep");
prop(taskStep, "task", t_ne_string);
@@ -98,13 +102,25 @@ public class PipelineYmlSchema implements YamlSchema {
prop(taskStep, "config", t_any);
prop(taskStep, "privileged", t_boolean);
prop(taskStep, "params", t_params);
prop(taskStep, "image", t_ne_string);
prop(taskStep, "input_mapping", t_string_params);
prop(taskStep, "output_mapping", t_string_params);
YType step = f.yunion("Step",
YBeanType aggregateStep = f.ybean("AggregateStep");
YBeanType[] stepTypes = {
getStep,
putStep,
taskStep
);
taskStep,
aggregateStep
};
YBeanUnionType step = f.yunion("Step", stepTypes);
prop(aggregateStep, "aggregate", f.yseq(step));
// shared properties applicable for any type of Step:
prop(step, "on_success", step);
prop(step, "on_failure", step);
YBeanType resource = f.ybean("Resource");
prop(resource, "name", t_ne_string);
prop(resource, "type", t_resource_type);
@@ -132,13 +148,13 @@ public class PipelineYmlSchema implements YamlSchema {
}
private void prop(YBeanType bean, String name, YType type) {
private void prop(AbstractType bean, String name, YType type) {
bean.addProperty(name, type, descriptionFor(bean, name));
}
private Renderable descriptionFor(YType owner, String propName) {
String typeName = owner.toString();
return Renderables.fromClasspath(this.getClass(), "/desc/"+typeName+"/"+propName+".html");
return Renderables.fromClasspath(this.getClass(), "/desc/"+typeName+"/"+propName);
}
@Override

View File

@@ -0,0 +1,19 @@
<p>Performs the given steps in parallel.</p><p>If any sub-steps in an aggregate result in an error, the aggregate step as a
whole is considered to have errored.</p><p>Similarly, when aggregating <a href="task-step.html"><code>task</code></a> steps, if any
<em>fail</em>, the aggregate step will fail. This is useful for build matrixes:</p><div class="highlight"><pre class="verbatim"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">plan</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">some-repo</span><span class="t">
</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">aggregate</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"> </span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">task</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">unit-windows</span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">file</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">some-repo/ci/windows.yml</span><span class="t">
</span><span class="t"> </span><span class="nv">-</span><span class="sp"> </span><span class="py">task</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">unit-linux</span><span class="t">
</span><span class="t"> </span><span class="py">file</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">some-repo/ci/linux.yml</span><span class="t">
</span><span class="t"> </span><span class="nv">-</span><span class="sp"> </span><span class="py">task</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">unit-darwin</span><span class="t">
</span><span class="t"> </span><span class="py">file</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">some-repo/ci/darwin.yml</span></pre></div><p>The <code>aggregate</code> step is also useful for performing arbitrary steps in
parallel, for the sake of speeding up the build. It is often used to fetch
all dependent resources together:</p><div class="highlight"><pre class="verbatim"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">plan</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">aggregate</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"> </span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">component-a</span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">component-b</span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">integration-suite</span><span class="t">
</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">task</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">integration</span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">file</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">integration-suite/task.yml</span></pre></div>

View File

@@ -1,11 +0,0 @@
<p>Fetches a resource, making it available to subsequent steps via the given
name.</p><p>For example, the following plan fetches a version number via the
<code>semver</code> resource, bumps it to the next release candidate, and
<a href="put-step.html"><code>put</code></a>s it back.</p><div class="highlight"><pre class="verbatim"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">plan</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">version</span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">params</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">bump</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">minor</span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">rc</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="kc">true</span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">put</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">version</span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">params</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">version</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">version/number</span></pre></div><div class="definition"><div class="thumb"><pre><a name="get"></a><a href="get-step.html#get"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span>

View File

@@ -0,0 +1,21 @@
Fetches a resource, making it available to subsequent steps via the given name.
For example, the following plan fetches a version number via the `semver` resource, bumps it to the next release candidate, and `put`s it back.
```
plan:
- get: version
params:
bump: minor
rc: true
- put: version
params:
version: version/number
```
```
get: string
```
*Required.* The logical name of the resource being fetched. This name satisfies logical inputs to a [Task](https://concourse.ci/concepts.html#tasks), and may be referenced within the plan itself (e.g. in the `file` attribute of a `task` step).

View File

@@ -1,4 +1,4 @@
<h1>Additional resource types used by your pipeline</h1>
<p>Additional resource types used by your pipeline.</p>
<p>Each resource in a pipeline has a <code>type</code>. The resource's type determines
what versions are detected, the bits that are fetched when used for a

View File

@@ -0,0 +1 @@
*Optional.* A map of arbitrary configuration to forward to the resource that will be utilized during the implicit `get` step. Refer to the resource type's documentation to see what it supports.

View File

@@ -1,3 +0,0 @@
<p><em>Optional.</em> A map of arbitrary configuration to forward to the
resource. Refer to the resource type's documentation to see what it
supports.</p>

View File

@@ -0,0 +1,3 @@
*Optional.* A map of arbitrary configuration to forward to the resource.
Refer to the resource type's documentation to see what it supports.

View File

@@ -1,20 +0,0 @@
<pre>put: resource-name</pre>
<p>Pushes to the given <a href="concepts.html#resources">Resource</a>. All artifacts collected
during the plan's execution will be available in the working directory.</p><p>For example, the following plan fetches a repo using
<a href="get-step.html"><code>get</code></a> and pushes it to another repo (assuming
<code>repo-develop</code> and <code>repo-master</code> are defined as <code>git</code> resources):</p><div class="highlight"><pre class="verbatim"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">plan</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">repo-develop</span><span class="t">
</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">put</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">repo-master</span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">params</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">repository</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">repo-develop</span></pre></div><p>When the <code>put</code> succeeds, the produced version of the resource will be
immediately fetched via an implicit <a href="get-step.html"><code>get</code></a> step. This is so that
later steps in your plan can use the artifact that was produced. The source
will be available under whatever name <code>put</code> specifies, just like as with
<code>get</code>.</p><p>So, if the logical name (whatever <code>put</code> specifies) differs from the
concrete resource, you would specify <code>resource</code> as well, like so:</p><div class="highlight"><pre class="verbatim"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">plan</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">put</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">resource-image</span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">resource</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">docker-image-resource</span></pre></div><div class="definition"><div class="thumb"><pre><a name="put"></a><a href="put-step.html#put"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">put</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">string</span></a></pre></div><p><em>Required.</em> The logical name of the resource being pushed. The pushed
resource will be available under this name after the push succeeds.</p></div><div class="definition"><div class="thumb"><pre><a name="resource"></a><a href="put-step.html#resource"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">resource</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">string</span></a></pre></div><p><em>Optional. Defaults to <code>name</code>.</em> The resource to update,
as configured in <a href="configuring-resources.html"><code>resources</code></a>.</p></div><div class="definition"><div class="thumb"><pre><a name="put-params"></a><a href="put-step.html#put-params"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">params</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">object</span></a></pre></div><p><em>Optional.</em> A map of arbitrary configuration to forward to the
resource. Refer to the resource type's documentation to see what it
supports.</p>

View File

@@ -0,0 +1,37 @@
Pushes to the given [Resource](https://concourse.ci/concepts.html#resources).
All artifacts collected during the plan's execution will be available in the working directory.
For example, the following plan fetches a repo using [get](https://concourse.ci/get-step.html) and pushes it to another repo (assuming `repo-develop` and `repo-master` are defined as `git` resources):
```
plan:
- get: repo-develop
- put: repo-master
params:
repository: repo-develop
```
When the `put` succeeds, the produced version of the resource will be immediately fetched via an implicit `get` step. This is so that later steps in your plan can use the artifact that was produced. The source will be available under whatever name `put` specifies, just like as with `get`.
So, if the logical name (whatever put specifies) differs from the concrete resource, you would specify resource as well, like so:
```
plan:
- put: resource-image
resource: docker-image-resource
```
Additionally, you can control the settings of the implicit `get` step by setting get_params. For example, if you did not want a put step utilizing the `docker-image` resource type to download the image, you would implement your `put` step as such:
```
plan:
- put: docker-build
params: build: git-resource
get_params: skip_download: true
```
```
put: string
```
Required. The logical name of the resource being pushed. The pushed resource will be available under this name after the push succeeds.

View File

@@ -1,2 +0,0 @@
<p><em>Optional. Defaults to <code>name</code>.</em> The resource to update, as
configured in <a href="configuring-resources.html"><code>resources</code></a>.</p>

View File

@@ -0,0 +1,3 @@
*Optional.* Defaults to `name`.
The resource to update, as configured in [resources](https://concourse.ci/configuring-resources.html).

View File

@@ -0,0 +1,15 @@
Any step can have `on_failure` tacked onto it, whose value is a second step to execute only if the parent step fails.
on_failure: step
The step to execute when the parent step fails. If the attached step succeeds, the entire step is still failed.
The following will perform the attached task only if the first one fails:
plan:
- get: foo
- task: unit
file: foo/unit.yml
on_failure:
task: alert
file: foo/alert.yml

View File

@@ -0,0 +1,26 @@
Any step can have `on_success` tacked onto it, whose value is a second step to execute only if the parent step succeeds.
on_success: step
The step to execute when the parent step succeeds. If the attached step fails, the outer step is considered to have failed.
The following will perform the second task only if the first one succeeds:
plan:
- get: foo
- task: unit
file: foo/unit.yml
on_success:
task: alert
file: foo/alert.yml
Note that this is semantically equivalent to the following:
plan:
- get: foo
- task: unit
file: foo/unit.yml
- task: alert
file: foo/alert.yml
...however it is provided mainly for cases where there is an equivalent `on_failure`, and having them next to each other is more clear.

View File

@@ -1,6 +0,0 @@
<span class="py">config</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">object</span></a></pre></div><p><em>One required.</em> The configuration for the task's running environment.</p><p><code>file</code> points at a <code>.yml</code> file containing the
<a href="single-page.html#configuring-tasks">task config</a>, which allows this to be tracked
with your resources.</p><p>The first segment in the path should refer to another source from the plan,
and the rest of the path is relative to that source.</p><p>For example, if in your plan you have the following
<a href="single-page.html#get-step"><code>get</code></a> step:</p><div class="highlight"><pre class="verbatim"><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">something</span></pre></div><p>And the <code>something</code> resource provided a <code>unit.yml</code> file, you
would set <code>file: something/unit.yml</code>.</p><p><code>config</code> can be defined to inline the task config statically.</p>

View File

@@ -0,0 +1,3 @@
*One of `config` or `file` attributes is required.*
Use `config` to inline the task config statically.

View File

@@ -0,0 +1,13 @@
*One of `config` or `file` attributes is required.*
`file` points at a `.yml` file containing the task config, which allows this to be tracked with your resources.
The first segment in the path should refer to another source from the plan, and the rest of the path is relative to that source.
For example, if in your plan you have the following `get` step:
- get: something
And the `something` resource provided a `unit.yml` file, you would set
file: something/unit.yml.

View File

@@ -0,0 +1,33 @@
*Optional.* Names an artifact source within the plan containing an image to use for the task. This overrides any `image` or `image_resource` configuration present in the task configuration.
This is very useful when part of your pipeline involves building an image, possibly with dependencies pre-baked. You can then propagate that image through the rest of your pipeline, guaranteeing that the correct version (and thus a consistent set of dependencies) is used throughout your pipeline.
For example, here's a pipeline building an image in one job and propagating it to the next:
resources:
- name: my-project
type: git
source: {uri: https://github.com/my-user/my-project}
- name: my-task-image
type: docker-image
source: {repository: my-user/my-repo}
jobs:
- name: build-task-image
plan:
- get: my-project
- put: my-task-image
params: {build: my-project/ci/images/my-task}
- name: use-task-image
plan:
- get: my-task-image
passed: [build-task-image]
- get: my-project
passed: [build-task-image]
- task: use-task-image
image: my-task-image
file: my-project/ci/tasks/my-task.yml
This can also be used in the simpler case of explicitly keeping track of dependent images, in which case you just wouldn't have a job building it (`build-task-image` in the above example).

View File

@@ -0,0 +1,14 @@
*Optional.* A map from task input names to concrete names in the build plan. This allows a task with generic input names to be used multiple times in the same plan, mapping its inputs to specific resources within the plan.
For example:
plan:
- get: diego-release
- get: cf-release
- get: ci-scripts
- task: audit-diego-release
file: ci-scripts/audit-release.yml
input_mapping: {release-repo: diego-release}
- task: audit-cf-release
file: ci-scripts/audit-release.yml
input_mapping: {release-repo: cf-release}

View File

@@ -0,0 +1,16 @@
*Optional.* A map from task output names to concrete names to register in the build plan. This allows a task with generic output names to be used multiple times in the same plan.
This is often used together with input_mapping. For example:
plan:
- get: diego-release
- get: cf-release
- get: ci-scripts
- task: create-diego-release
file: ci-scripts/create-release.yml
input_mapping: {release-repo: diego-release}
output_mapping: {release-tarball: diego-release-tarball}
- task: create-cf-release
file: ci-scripts/create-release.yml
input_mapping: {release-repo: cf-release}
output_mapping: {release-tarball: cf-release-tarball}

View File

@@ -0,0 +1,14 @@
*Optional.* A map of task parameters to set, overriding those configured in `config` or `file`. This is useful for passing in credentials or other configuration to the task from the pipeline.
For example:
plan:
- get: my-repo
- task: integration
file: my-repo/ci/integration.yml
params:
REMOTE_SERVER: 10.20.30.40:8080
USERNAME: my-user
PASSWORD: my-pass
This is often used in combination with `{{parameters}}` in the pipeline.

View File

@@ -1,23 +0,0 @@
<p>Executes a <a href="single-page.html#tasks">Task</a>, either from a file fetched via the
preceding steps, or with inlined configuration.</p><p>If any task in the build plan fails, the build will complete with failure. By
default, any subsequent steps will not be performed. You can perform additional
steps after failure by adding a <a href="single-page.html#on-failure-step"><code>on_failure</code></a>
or <a href="single-page.html#ensure-step"><code>ensure</code></a> step.</p><p>For example, the following plan fetches a single repository and executes
multiple tasks, using the <a href="single-page.html#aggregate-step"><code>aggregate</code></a> step,
in a build matrix style configuration:</p><div class="highlight"><pre class="verbatim"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">plan</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">my-repo</span><span class="t">
</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">aggregate</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"> </span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">task</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">go-1.3</span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">file</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">my-repo/go-1.3.yml</span><span class="t">
</span><span class="t"> </span><span class="nv">-</span><span class="sp"> </span><span class="py">task</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">go-1.4</span><span class="t">
</span><span class="t"> </span><span class="py">file</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">my-repo/ci/go-1.4.yml</span></pre></div><p>Only if both tasks succeed will the build go green.</p><p>When a task completes, the files in its declared outputs will be made avaliable
to subsequent steps. This allows those subsequent steps to process the result
of a task. For example, the following plan pulls down a repo, makes a commit to
it, and pushes the commit to another repo (the task must have an output called
<code>repo-with-commit</code>):</p><div class="highlight"><pre class="verbatim"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">plan</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">get</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">my-repo</span><span class="t">
</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">task</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">commit</span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">file</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">my-repo/commit.yml</span><span class="t">
</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">put</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">other-repo</span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">params</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"></span><span class="t"></span><span class="t">
</span><span class="t"> </span><span class="t"></span><span class="t"></span><span class="nv"></span><span class="py">repository</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">repo-with-commit</span></pre></div><div class="definition"><div class="thumb"><pre><a name="task"></a><a href="single-page.html#task"><span class="t"></span><span class="t"></span><span class="t"></span><span class="nv"></span>

View File

@@ -0,0 +1,30 @@
Executes a [Task](https://concourse.ci/concepts.html#tasks), either from a file fetched via the preceding steps, or with inlined configuration.
task: string
Required. A freeform name for the task that's being executed. Common examples would be `unit` or `integration`.
If any task in the build plan fails, the build will complete with failure. By default, any subsequent steps will not be performed. You can perform additional steps after failure by adding a `on_failure` or `ensure` step.
For example, the following plan fetches a single repository and executes multiple tasks, using the `aggregate` step, in a build matrix style configuration:
plan:
- get: my-repo
- aggregate:
- task: go-1.3
file: my-repo/go-1.3.yml
- task: go-1.4
file: my-repo/ci/go-1.4.yml
Only if both tasks succeed will the build go green.
When a task completes, the files in its declared outputs will be made available to subsequent steps. This allows those subsequent steps to process the result of a task. For example, the following plan pulls down a repo, makes a commit to it, and pushes the commit to another repo (the task must have an output called `repo-with-commit`):
plan:
- get: my-repo
- task: commit
file: my-repo/commit.yml
- put: other-repo
params:
repository: repo-with-commit

View File

@@ -10,7 +10,11 @@
*******************************************************************************/
package org.springframework.ide.vscode.manifest.yaml;
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.assertContains;
import java.io.InputStream;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Test;
@@ -21,6 +25,7 @@ import org.springframework.ide.vscode.languageserver.testharness.LanguageServerH
public class PipelineYamlEditorTest {
private static final String CURSOR = "<*>";
LanguageServerHarness harness;
@Before public void setup() throws Exception {
@@ -105,6 +110,139 @@ public class PipelineYamlEditorTest {
//TODO: Add more test cases for structural problem?
}
@Test
public void primaryStepCompletions() throws Exception {
assertContextualCompletions(
// Context:
"jobs:\n" +
"- name: some-job\n" +
" plan:\n" +
" - <*>"
, // ==============
"<*>"
, // =>
"aggregate:\n" +
" - <*>"
, // ==============
"get: <*>"
, // ==============
"put: <*>"
, // ==============
"task: <*>"
);
}
@Test
public void primaryStepHovers() throws Exception {
Editor editor = harness.newEditor(
"jobs:\n" +
"- name: some-job\n" +
" plan:\n" +
" - get: something\n" +
" - put: something\n" +
" - aggregate:\n" +
" - task: do-something\n"
);
editor.assertHoverContains("get", "Fetches a resource");
editor.assertHoverContains("put", "Pushes to the given [Resource]");
editor.assertHoverContains("aggregate", "Performs the given steps in parallel");
editor.assertHoverContains("task", "Executes a [Task]");
}
@Test
public void putStepHovers() throws Exception {
Editor editor = harness.newEditor(
"jobs:\n" +
"- name: some-job\n" +
" plan:\n" +
" - put: something\n" +
" resource: something\n" +
" params:\n" +
" some_param: some_value\n" +
" get_params:\n" +
" skip_download: true\n"
);
editor.assertHoverContains("resource", "The resource to update");
editor.assertHoverContains("params", "A map of arbitrary configuration");
editor.assertHoverContains("get_params", "A map of arbitrary configuration to forward to the resource that will be utilized during the implicit `get` step");
}
@Test
public void getStepHovers() throws Exception {
Editor editor = harness.newEditor(
"jobs:\n" +
"- name: some-job\n" +
" plan:\n" +
" - get: something\n" +
" resource: something\n" +
" version: latest\n" +
" passed: [other-job]\n" +
" params:\n" +
" some_param: some_value\n" +
" trigger: true\n" +
" on_failure:\n" +
" - bogus: bad\n" +
" on_success:\n" +
" - bogus: bad\n"
);
editor.assertHoverContains("resource", "The resource to fetch");
editor.assertHoverContains("version", "The version of the resource to fetch");
editor.assertHoverContains("params", "A map of arbitrary configuration");
editor.assertHoverContains("trigger", "Set to `true` to auto-trigger");
editor.assertHoverContains("on_failure", "Any step can have `on_failure` tacked onto it");
editor.assertHoverContains("on_success", "Any step can have `on_success` tacked onto it");
}
@Test
public void taskStepHovers() throws Exception {
Editor editor = harness.newEditor(
"jobs:\n" +
"- name: some-job\n" +
" plan:\n" +
" - task: do-something\n" +
" file: some-file.yml\n" +
" privileged: true\n" +
" image: some-image\n" +
" params:\n" +
" map: of-stuff\n" +
" input_mapping:\n" +
" map: of-stuff\n" +
" output_mapping:\n" +
" map: of-stuff\n" +
" config: some-config\n" +
" ensure:\n" +
" bogus: bad\n" +
" on_failure:\n" +
" bogus: bad\n" +
" on_success:\n" +
" bogus: bad\n"
);
editor.assertHoverContains("file", "`file` points at a `.yml` file containing the task config");
editor.assertHoverContains("privileged", "If set to `true`, the task will run with full capabilities");
editor.assertHoverContains("image", "Names an artifact source within the plan");
editor.assertHoverContains("params", "A map of task parameters to set, overriding those configured in `config` or `file`");
editor.assertHoverContains("input_mapping", "A map from task input names to concrete names in the build plan");
editor.assertHoverContains("output_mapping", "A map from task output names to concrete names");
editor.assertHoverContains("config", "Use `config` to inline the task config");
}
@Test
public void aggregateStepHovers() throws Exception {
Editor editor;
editor = harness.newEditor(
"jobs:\n" +
"- name: some-job\n" +
" plan:\n" +
" - aggregate:\n" +
" - get: some-resource\n"
);
editor.assertHoverContains("aggregate", "Performs the given steps in parallel");
}
@Test
public void reconcileSimpleTypes() throws Exception {
Editor editor;
@@ -114,14 +252,14 @@ public class PipelineYamlEditorTest {
"jobs:\n" +
"- name: foo\n" +
" serial: boohoo\n" +
" max_in_flight: 0\n" +
" max_in_flight: -1\n" +
" plan:\n" +
" - get: git\n" +
" trigger: yohoho"
);
editor.assertProblems(
"boohoo|boolean",
"0|Positive Integer",
"-1|Positive Integer",
"yohoho|boolean"
);
@@ -152,33 +290,25 @@ public class PipelineYamlEditorTest {
@Test
public void toplevelCompletions() throws Exception {
Editor editor;
editor = harness.newEditor("<*>");
editor = harness.newEditor(CURSOR);
editor.assertCompletions(
"resources:\n"+
"- <*>",
// ---------------
"resource-types:\n" +
"- <*>",
// ---------------
"jobs:\n" +
"- <*>"
, // ---------------
"resource_types:\n" +
"- <*>"
, // ---------------
"resources:\n"+
"- <*>"
);
editor = harness.newEditor("ranro<*>");
editor = harness.newEditor("rety<*>");
editor.assertCompletions(
"random-route: <*>"
"resource_types:\n" +
"- <*>"
);
}
@Test
public void completionDetailsAndDocs() throws Exception {
Editor editor = harness.newEditor(
"applications:\n" +
"- build<*>"
);
editor.assertCompletionDetails("buildpack", "Buildpack", "If your application requires a custom buildpack");
}
@Test
public void valueCompletions() throws Exception {
assertCompletions(
@@ -251,6 +381,15 @@ public class PipelineYamlEditorTest {
//////////////////////////////////////////////////////////////////////////////
private void assertContextualCompletions(String conText, String textBefore, String... textAfter) throws Exception {
assertContains(CURSOR, conText);
textBefore = conText.replace(CURSOR, textBefore);
textAfter = Arrays.stream(textAfter)
.map((String t) -> conText.replace(CURSOR, t))
.collect(Collectors.toList()).toArray(new String[0]);
assertCompletions(textBefore, textAfter);
}
private void assertCompletions(String textBefore, String... textAfter) throws Exception {
Editor editor = harness.newEditor(textBefore);
editor.assertCompletions(textAfter);

View File

@@ -20,10 +20,10 @@ import org.springframework.ide.vscode.concourse.PipelineYmlSchema;
*/
public class PipelineYmlSchemaTest {
@Test
public void shouldMakeSomeTests() {
fail("We should make some tests for this");
}
// @Test
// public void shouldMakeSomeTests() {
// fail("We should make some tests for this");
// }
//
// private static final String[] NESTED_PROP_NAMES = {
//// "applications",