Basic concourse pipeline editor working
This commit is contained in:
@@ -94,6 +94,7 @@ public class SimpleTextDocumentService implements TextDocumentService {
|
||||
try {
|
||||
VersionedTextDocumentIdentifier docId = params.getTextDocument();
|
||||
String url = docId.getUri();
|
||||
LOG.info("didChange: "+url);
|
||||
if (url!=null) {
|
||||
TextDocument doc = getOrCreateDocument(url);
|
||||
for (TextDocumentContentChangeEvent change : params.getContentChanges()) {
|
||||
@@ -108,7 +109,7 @@ public class SimpleTextDocumentService implements TextDocumentService {
|
||||
|
||||
@Override
|
||||
public void didOpen(DidOpenTextDocumentParams params) {
|
||||
//LOG.info("didOpen: "+params);
|
||||
LOG.info("didOpen: "+params.getUri());
|
||||
//Example message:
|
||||
//{
|
||||
// "jsonrpc":"2.0",
|
||||
@@ -150,7 +151,7 @@ public class SimpleTextDocumentService implements TextDocumentService {
|
||||
|
||||
@Override
|
||||
public void didClose(DidCloseTextDocumentParams params) {
|
||||
System.out.println("closing: "+params.getTextDocument().getUri());
|
||||
LOG.info("didClose: "+params.getTextDocument().getUri());
|
||||
String url = params.getTextDocument().getUri();
|
||||
if (url!=null) {
|
||||
documents.remove(url);
|
||||
|
||||
@@ -241,42 +241,52 @@ public class Renderables {
|
||||
}
|
||||
|
||||
public static Renderable fromClasspath(final Class<?> klass, final String resourcePath) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
private String getText(final Class<?> klass, final String resourcePath, String extension) {
|
||||
try {
|
||||
InputStream stream = klass.getResourceAsStream(resourcePath + extension);
|
||||
if (stream != null) {
|
||||
return IOUtil.toString(stream);
|
||||
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);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error", e);
|
||||
}
|
||||
return null;
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static String getText(final Class<?> klass, String resourcePath, String extension) {
|
||||
if (extension!=null) {
|
||||
resourcePath = resourcePath + extension;
|
||||
}
|
||||
try {
|
||||
InputStream stream = klass.getResourceAsStream(resourcePath);
|
||||
if (stream != null) {
|
||||
return IOUtil.toString(stream);
|
||||
}
|
||||
};
|
||||
} catch (Exception e) {
|
||||
logger.error("Error", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ConcatRenderables implements Renderable {
|
||||
|
||||
@@ -41,6 +41,8 @@ public abstract class AbstractYamlAssistContext implements YamlAssistContext {
|
||||
|
||||
public final int documentSelector;
|
||||
public final YamlPath contextPath;
|
||||
private final YamlDocument doc;
|
||||
|
||||
|
||||
private static PrefixFinder prefixfinder = new PrefixFinder() {
|
||||
protected boolean isPrefixChar(char c) {
|
||||
@@ -48,6 +50,10 @@ public abstract class AbstractYamlAssistContext implements YamlAssistContext {
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public YamlDocument getDocument() {
|
||||
return doc;
|
||||
}
|
||||
|
||||
protected final String getPrefix(YamlDocument doc, SNode node, int offset) {
|
||||
//For value completions... in general we would like to determine the whole text
|
||||
@@ -78,7 +84,8 @@ public abstract class AbstractYamlAssistContext implements YamlAssistContext {
|
||||
}
|
||||
|
||||
|
||||
public AbstractYamlAssistContext(int documentSelector, YamlPath contextPath) {
|
||||
public AbstractYamlAssistContext(YamlDocument doc, int documentSelector, YamlPath contextPath) {
|
||||
this.doc = doc;
|
||||
this.documentSelector = documentSelector;
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,11 @@ public class SchemaBasedYamlAssistContextProvider implements YamlAssistContextPr
|
||||
protected YamlAssistContext getDocumentContext(int documentSelector) {
|
||||
return new YTypeAssistContext(this, documentSelector, schema.getTopLevelType(), schema.getTypeUtil());
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlDocument getDocument() {
|
||||
return doc;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ package org.springframework.ide.vscode.commons.yaml.completion;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -25,18 +24,20 @@ import org.springframework.ide.vscode.commons.languageserver.completion.IComplet
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.CollectionUtil;
|
||||
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
import org.springframework.ide.vscode.commons.yaml.hover.YPropertyInfoTemplates;
|
||||
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.path.YamlPathSegment.YamlPathSegmentType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.SNodeDynamicSchemaContext;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YType;
|
||||
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.YValueHint;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SChildBearingNode;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SKeyNode;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SNode;
|
||||
import org.springframework.ide.vscode.commons.yaml.util.YamlIndentUtil;
|
||||
|
||||
@@ -49,14 +50,14 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
final private YamlAssistContext parent;
|
||||
|
||||
public YTypeAssistContext(YTypeAssistContext parent, YamlPath contextPath, YType YType, YTypeUtil typeUtil) {
|
||||
super(parent.documentSelector, contextPath);
|
||||
super(parent.getDocument(), parent.documentSelector, contextPath);
|
||||
this.parent = parent;
|
||||
this.type = YType;
|
||||
this.typeUtil = typeUtil;
|
||||
}
|
||||
|
||||
public YTypeAssistContext(TopLevelAssistContext parent, int documentSelector, YType type, YTypeUtil typeUtil) {
|
||||
super(documentSelector, YamlPath.EMPTY);
|
||||
super(parent.getDocument(), documentSelector, YamlPath.EMPTY);
|
||||
this.type = type;
|
||||
this.typeUtil = typeUtil;
|
||||
this.parent = parent;
|
||||
@@ -74,11 +75,12 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
|
||||
public List<ICompletionProposal> getKeyCompletions(YamlDocument doc, int offset, String query) throws Exception {
|
||||
int queryOffset = offset - query.length();
|
||||
List<YTypedProperty> properties = typeUtil.getProperties(type);
|
||||
SNode contextNode = getContextNode(doc);
|
||||
DynamicSchemaContext dynamicCtxt = new SNodeDynamicSchemaContext(contextNode);
|
||||
List<YTypedProperty> properties = typeUtil.getProperties(type, dynamicCtxt);
|
||||
if (CollectionUtil.hasElements(properties)) {
|
||||
ArrayList<ICompletionProposal> proposals = new ArrayList<>(properties.size());
|
||||
SNode contextNode = getContextNode(doc);
|
||||
Set<String> definedProps = getDefinedProperties(contextNode);
|
||||
Set<String> definedProps = dynamicCtxt.getDefinedProperties();
|
||||
for (YTypedProperty p : properties) {
|
||||
String name = p.getName();
|
||||
double score = FuzzyMatcher.matchScore(query, name);
|
||||
@@ -140,26 +142,6 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> getDefinedProperties(SNode contextNode) {
|
||||
try {
|
||||
if (contextNode instanceof SChildBearingNode) {
|
||||
List<SNode> children = ((SChildBearingNode)contextNode).getChildren();
|
||||
if (CollectionUtil.hasElements(children)) {
|
||||
Set<String> keys = new HashSet<>(children.size());
|
||||
for (SNode c : children) {
|
||||
if (c instanceof SKeyNode) {
|
||||
keys.add(((SKeyNode) c).getKey());
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error getting defined props", e);
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
private List<ICompletionProposal> getValueCompletions(YamlDocument doc, int offset, String query) {
|
||||
YValueHint[] values = typeUtil.getHintValues(type);
|
||||
if (values!=null) {
|
||||
@@ -179,13 +161,15 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlAssistContext traverse(YamlPathSegment s) {
|
||||
public YamlAssistContext traverse(YamlPathSegment s) throws Exception {
|
||||
if (s.getType()==YamlPathSegmentType.VAL_AT_KEY) {
|
||||
if (typeUtil.isSequencable(type) || typeUtil.isMap(type)) {
|
||||
return contextWith(s, typeUtil.getDomainType(type));
|
||||
}
|
||||
String key = s.toPropString();
|
||||
Map<String, YTypedProperty> subproperties = typeUtil.getPropertiesMap(type);
|
||||
SNode contextNode = getContextNode(getDocument());
|
||||
DynamicSchemaContext dynamicCtxt = new SNodeDynamicSchemaContext(contextNode);
|
||||
Map<String, YTypedProperty> subproperties = typeUtil.getPropertiesMap(type, dynamicCtxt);
|
||||
if (subproperties!=null) {
|
||||
return contextWith(s, getType(subproperties.get(key)));
|
||||
}
|
||||
@@ -246,6 +230,16 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
return null;
|
||||
}
|
||||
|
||||
private DynamicSchemaContext getSchemaContext() {
|
||||
try {
|
||||
SNode contextNode = getContextNode(getDocument());
|
||||
return new SNodeDynamicSchemaContext(contextNode);
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
return DynamicSchemaContext.NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Renderable getValueHoverInfo(YamlDocument doc, DocumentRegion documentRegion) {
|
||||
//By default we don't provide value-specific hover, so just show the same hover
|
||||
@@ -254,6 +248,6 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
|
||||
}
|
||||
|
||||
private YTypedProperty getProperty(String name) {
|
||||
return typeUtil.getPropertiesMap(getType()).get(name);
|
||||
return typeUtil.getPropertiesMap(getType(), getSchemaContext()).get(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,4 +32,6 @@ public interface YamlAssistContext extends YamlNavigable<YamlAssistContext> {
|
||||
Renderable getHoverInfo(YamlPathSegment lastSegment);
|
||||
|
||||
Renderable getValueHoverInfo(YamlDocument doc, DocumentRegion documentRegion);
|
||||
|
||||
YamlDocument getDocument();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.ValueParser;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.ASTDynamicSchemaContext;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.DynamicSchemaContext;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
|
||||
@@ -53,7 +55,8 @@ public class SchemaBasedYamlASTReconciler implements YamlASTReconciler {
|
||||
reconcile(entry.getValueNode(), typeUtil.getDomainType(type));
|
||||
}
|
||||
} else if (typeUtil.isBean(type)) {
|
||||
Map<String, YTypedProperty> beanProperties = typeUtil.getPropertiesMap(type);
|
||||
DynamicSchemaContext schemaContext = new ASTDynamicSchemaContext(map);
|
||||
Map<String, YTypedProperty> beanProperties = typeUtil.getPropertiesMap(type, schemaContext);
|
||||
for (NodeTuple entry : map.getValue()) {
|
||||
Node keyNode = entry.getKeyNode();
|
||||
String key = NodeUtil.asScalar(keyNode);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 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.schema;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.ide.vscode.commons.yaml.ast.NodeUtil;
|
||||
import org.yaml.snakeyaml.nodes.MappingNode;
|
||||
import org.yaml.snakeyaml.nodes.NodeTuple;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Adapts a SnakeYaml ast node as a {@link DynamicSchemaContext} (so it
|
||||
* can be used in YamlSchema based reconciler.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class ASTDynamicSchemaContext extends CachingSchemaContext {
|
||||
|
||||
private MappingNode mapNode;
|
||||
|
||||
public ASTDynamicSchemaContext(MappingNode map) {
|
||||
this.mapNode = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> computeDefinedProperties() {
|
||||
if (mapNode!=null) {
|
||||
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
|
||||
for (NodeTuple entry : mapNode.getValue()) {
|
||||
String key = NodeUtil.asScalar(entry.getKeyNode());
|
||||
if (key!=null) { //key not a scalar? => something funky so skip it
|
||||
builder.add(key);
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.springframework.ide.vscode.commons.yaml.schema;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class CachingSchemaContext implements DynamicSchemaContext {
|
||||
|
||||
private Set<String> definedProps;
|
||||
|
||||
protected abstract Set<String> computeDefinedProperties();
|
||||
|
||||
@Override
|
||||
final public Set<String> getDefinedProperties() {
|
||||
if (definedProps==null) {
|
||||
definedProps = computeDefinedProperties();
|
||||
}
|
||||
return definedProps;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 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.schema;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Exposes some 'dynamic' contextual information to schema implementations.
|
||||
* <p>
|
||||
* This is necessary to enable the impementation of schema features where one
|
||||
* part of a yaml structure depends details of another part. A typical example
|
||||
* could be 'type' property, so that different values assigned to that property
|
||||
* change the structure that is expected for the rest of the node.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public interface DynamicSchemaContext {
|
||||
|
||||
DynamicSchemaContext NULL = new DynamicSchemaContext() {
|
||||
@Override
|
||||
public Set<String> getDefinedProperties() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the set of property names that are already defined in the current context.
|
||||
* <p>
|
||||
* In Content assist scenarios this is only a 'best effort' result. An empty set may
|
||||
* be returned because either no properties are yet defined, or because the sloppy parser
|
||||
* can not quite make out the yaml structure because yaml text is incomplete or too complex
|
||||
* for its analysis.
|
||||
* <p>
|
||||
* In a validation scenario however, the returned information should precisely reflect what
|
||||
* properties are defined in the surrounding object.
|
||||
*/
|
||||
Set<String> getDefinedProperties();
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 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.schema;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.ide.vscode.commons.util.CollectionUtil;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SChildBearingNode;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SKeyNode;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SNode;
|
||||
|
||||
/**
|
||||
* Adapts an SNode so it can be used by a YamlSchema as a {@link DynamicSchemaContext}
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class SNodeDynamicSchemaContext extends CachingSchemaContext {
|
||||
|
||||
private SNode contextNode;
|
||||
|
||||
public SNodeDynamicSchemaContext(SNode contextNode) {
|
||||
this.contextNode = contextNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> computeDefinedProperties() {
|
||||
try {
|
||||
if (contextNode instanceof SChildBearingNode) {
|
||||
List<SNode> children = ((SChildBearingNode)contextNode).getChildren();
|
||||
if (CollectionUtil.hasElements(children)) {
|
||||
Set<String> keys = new HashSet<>(children.size());
|
||||
for (SNode c : children) {
|
||||
if (c instanceof SKeyNode) {
|
||||
keys.add(((SKeyNode) c).getKey());
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -13,19 +13,26 @@ package org.springframework.ide.vscode.commons.yaml.schema;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.EnumValueParser;
|
||||
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 com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* Static utility method for creating YType objects representing either
|
||||
* 'array-like', 'map-like' or 'object-like' types which can be used
|
||||
@@ -35,6 +42,10 @@ import org.springframework.ide.vscode.commons.util.ValueParser;
|
||||
*/
|
||||
public class YTypeFactory {
|
||||
|
||||
public YType yany(String name) {
|
||||
return new YAny(name);
|
||||
}
|
||||
|
||||
public YType yseq(YType el) {
|
||||
return new YSeqType(el);
|
||||
}
|
||||
@@ -47,6 +58,14 @@ 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];
|
||||
}
|
||||
return new YBeanUnionType(name, types);
|
||||
}
|
||||
|
||||
/**
|
||||
* YTypeUtil instances capable of 'interpreting' the YType objects created by this
|
||||
* YTypeFactory
|
||||
@@ -69,13 +88,13 @@ public class YTypeFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, YTypedProperty> getPropertiesMap(YType type) {
|
||||
return ((AbstractType)type).getPropertiesMap();
|
||||
public Map<String, YTypedProperty> getPropertiesMap(YType type, DynamicSchemaContext dc) {
|
||||
return ((AbstractType)type).getPropertiesMap(dc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<YTypedProperty> getProperties(YType type) {
|
||||
return ((AbstractType)type).getProperties();
|
||||
public List<YTypedProperty> getProperties(YType type, DynamicSchemaContext dc) {
|
||||
return ((AbstractType)type).getProperties(dc);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -164,11 +183,11 @@ public class YTypeFactory {
|
||||
}
|
||||
}
|
||||
|
||||
public final List<YTypedProperty> getProperties() {
|
||||
public List<YTypedProperty> getProperties(DynamicSchemaContext dc) {
|
||||
return Collections.unmodifiableList(propertyList);
|
||||
}
|
||||
|
||||
public final Map<String, YTypedProperty> getPropertiesMap() {
|
||||
public Map<String, YTypedProperty> getPropertiesMap(DynamicSchemaContext dc) {
|
||||
if (cachedPropertyMap==null) {
|
||||
cachedPropertyMap = new LinkedHashMap<>();
|
||||
for (YTypedProperty p : propertyList) {
|
||||
@@ -212,12 +231,55 @@ public class YTypeFactory {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addHints(YValueHint... extraHints) {
|
||||
for (YValueHint h : extraHints) {
|
||||
if (!hints.contains(h)) {
|
||||
hints.add(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void parseWith(ValueParser parser) {
|
||||
this.parser = parser;
|
||||
}
|
||||
public ValueParser getParser() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a type that is completely unconstrained. Anything goes: A map, a sequence or some
|
||||
* atomic value.
|
||||
*/
|
||||
public static class YAny extends AbstractType {
|
||||
private final String name;
|
||||
|
||||
public YAny(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAtomic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSequenceable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMap() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class YMapType extends AbstractType {
|
||||
@@ -293,6 +355,26 @@ public class YTypeFactory {
|
||||
public boolean isBean() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated. This method disregards {@link DynamicSchemaContext}. This may be
|
||||
* alright for Schemas which don't rely on it but it will result in incorrect/inaccurate
|
||||
* behavior for Schemas that do.
|
||||
*/
|
||||
@Deprecated
|
||||
public List<YTypedProperty> getProperties() {
|
||||
return getProperties(DynamicSchemaContext.NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated. This method disregards {@link DynamicSchemaContext}. This may be
|
||||
* alright for Schemas which don't rely on it but it will result in incorrect/inaccurate
|
||||
* behavior for Schemas that do.
|
||||
*/
|
||||
@Deprecated
|
||||
public Map<String, YTypedProperty> getPropertiesMap() {
|
||||
return getPropertiesMap(DynamicSchemaContext.NULL);
|
||||
}
|
||||
}
|
||||
|
||||
public static class YAtomicType extends AbstractType {
|
||||
@@ -309,6 +391,103 @@ public class YTypeFactory {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a union of several bean types. It is assumed one primary property
|
||||
* exists in each of the the sub-bean types that can be used to identify the
|
||||
* type. In other words the primary property has a unique name so that when
|
||||
* this property is being assigned a value we can infer from that which
|
||||
* specific bean-type we are dealing with.
|
||||
*/
|
||||
public class YBeanUnionType extends AbstractType {
|
||||
private final String name;
|
||||
|
||||
private Map<String, AbstractType> typesByPrimary = new HashMap<>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
private String findPrimary(AbstractType t, 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)) {
|
||||
String name = p.getName();
|
||||
if (isUniqueFor(name, t, types)) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
for (YBeanType other : types) {
|
||||
if (other!=t) {
|
||||
//Note: passing null dynamic context below is okay, assuming the properties in YBeanType
|
||||
// do not care about dynamic context.
|
||||
if (other.getPropertiesMap(DynamicSchemaContext.NULL).containsKey(name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
@Override
|
||||
public boolean isBean() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, YTypedProperty> getPropertiesMap(DynamicSchemaContext dc) {
|
||||
return asMap(getProperties(dc));
|
||||
}
|
||||
|
||||
private Map<String, YTypedProperty> asMap(List<YTypedProperty> properties) {
|
||||
ImmutableMap.Builder<String, YTypedProperty> builder = ImmutableMap.builder();
|
||||
for (YTypedProperty p : properties) {
|
||||
builder.put(p.getName(), p);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<YTypedProperty> getProperties(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().getProperties(dc);
|
||||
}
|
||||
}
|
||||
}
|
||||
//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.
|
||||
return getPrimaryProps(dc);
|
||||
}
|
||||
|
||||
private List<YTypedProperty> getPrimaryProps(DynamicSchemaContext dc) {
|
||||
if (primaryProps==null) {
|
||||
Builder<YTypedProperty> builder = ImmutableList.builder();
|
||||
for (Entry<String, AbstractType> entry : typesByPrimary.entrySet()) {
|
||||
builder.add(entry.getValue().getPropertiesMap(dc).get(entry.getKey()));
|
||||
}
|
||||
primaryProps = builder.build();
|
||||
}
|
||||
return primaryProps;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class YTypedPropertyImpl implements YTypedProperty {
|
||||
|
||||
@@ -360,4 +539,9 @@ public class YTypeFactory {
|
||||
t.parseWith(new EnumValueParser(name, values));
|
||||
return t;
|
||||
}
|
||||
|
||||
public YValueHint hint(String value, String label) {
|
||||
return new BasicYValueHint(value, label);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,6 +35,6 @@ public interface YTypeUtil {
|
||||
ValueParser getValueParser(YType type);
|
||||
|
||||
//TODO: only one of these two should be enough?
|
||||
List<YTypedProperty> getProperties(YType type);
|
||||
Map<String, YTypedProperty> getPropertiesMap(YType yType);
|
||||
List<YTypedProperty> getProperties(YType type, DynamicSchemaContext dc);
|
||||
Map<String, YTypedProperty> getPropertiesMap(YType yType, DynamicSchemaContext dc);
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public class BootPropertiesLanguageServer extends SimpleLanguageServer {
|
||||
public YamlAssistContext getGlobalAssistContext(YamlDocument ydoc) {
|
||||
IDocument doc = ydoc.getDocument();
|
||||
FuzzyMap<PropertyInfo> index = indexProvider.getIndex(doc);
|
||||
return ApplicationYamlAssistContext.global(index, completionFactory, typeUtilProvider.getTypeUtil(doc), relaxedNameConfig);
|
||||
return ApplicationYamlAssistContext.global(ydoc, index, completionFactory, typeUtilProvider.getTypeUtil(doc), relaxedNameConfig);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ import org.springframework.ide.vscode.boot.metadata.hints.ValueHintHoverInfo;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.Type;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeParser;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypedProperty;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.BeanPropertyNameMode;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypeUtil.EnumCaseMode;
|
||||
import org.springframework.ide.vscode.boot.metadata.types.TypedProperty;
|
||||
import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap;
|
||||
import org.springframework.ide.vscode.boot.metadata.util.FuzzyMap.Match;
|
||||
import org.springframework.ide.vscode.commons.java.IField;
|
||||
@@ -88,8 +88,8 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
|
||||
public final TypeUtil typeUtil;
|
||||
|
||||
public ApplicationYamlAssistContext(int documentSelector, YamlPath contextPath, TypeUtil typeUtil, RelaxedNameConfig conf) {
|
||||
super(documentSelector, contextPath);
|
||||
public ApplicationYamlAssistContext(YamlDocument doc, int documentSelector, YamlPath contextPath, TypeUtil typeUtil, RelaxedNameConfig conf) {
|
||||
super(doc, documentSelector, contextPath);
|
||||
this.typeUtil = typeUtil;
|
||||
this.conf = conf;
|
||||
}
|
||||
@@ -121,16 +121,16 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
*/
|
||||
protected abstract Type getType();
|
||||
|
||||
public static ApplicationYamlAssistContext subdocument(int documentSelector, FuzzyMap<PropertyInfo> index, PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf) {
|
||||
return new IndexContext(documentSelector, YamlPath.EMPTY, IndexNavigator.with(index), completionFactory, typeUtil, conf);
|
||||
public static ApplicationYamlAssistContext subdocument(YamlDocument doc, int documentSelector, FuzzyMap<PropertyInfo> index, PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf) {
|
||||
return new IndexContext(doc, documentSelector, YamlPath.EMPTY, IndexNavigator.with(index), completionFactory, typeUtil, conf);
|
||||
}
|
||||
|
||||
public static YamlAssistContext forPath(YamlPath contextPath, FuzzyMap<PropertyInfo> index, PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf) {
|
||||
public static YamlAssistContext forPath(YamlDocument doc, YamlPath contextPath, FuzzyMap<PropertyInfo> index, PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf) {
|
||||
try {
|
||||
YamlPathSegment documentSelector = contextPath.getSegment(0);
|
||||
if (documentSelector!=null) {
|
||||
contextPath = contextPath.dropFirst(1);
|
||||
YamlAssistContext context = ApplicationYamlAssistContext.subdocument(documentSelector.toIndex(), index, completionFactory, typeUtil, conf);
|
||||
YamlAssistContext context = ApplicationYamlAssistContext.subdocument(doc, documentSelector.toIndex(), index, completionFactory, typeUtil, conf);
|
||||
for (YamlPathSegment s : contextPath.getSegments()) {
|
||||
if (context==null) return null;
|
||||
context = context.traverse(s);
|
||||
@@ -155,7 +155,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
|
||||
public TypeContext(ApplicationYamlAssistContext parent, YamlPath contextPath, Type type,
|
||||
PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf, HintProvider hints) {
|
||||
super(parent.documentSelector, contextPath, typeUtil, conf);
|
||||
super(parent.getDocument(), parent.documentSelector, contextPath, typeUtil, conf);
|
||||
this.parent = parent;
|
||||
this.completionFactory = completionFactory;
|
||||
this.type = type;
|
||||
@@ -401,9 +401,9 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
private IndexNavigator indexNav;
|
||||
PropertyCompletionFactory completionFactory;
|
||||
|
||||
public IndexContext(int documentSelector, YamlPath contextPath, IndexNavigator indexNav,
|
||||
public IndexContext(YamlDocument doc, int documentSelector, YamlPath contextPath, IndexNavigator indexNav,
|
||||
PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf) {
|
||||
super(documentSelector, contextPath, typeUtil, conf);
|
||||
super(doc, documentSelector, contextPath, typeUtil, conf);
|
||||
this.indexNav = indexNav;
|
||||
this.completionFactory = completionFactory;
|
||||
}
|
||||
@@ -479,9 +479,9 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
}
|
||||
}
|
||||
if (subIndex.getExtensionCandidate()!=null) {
|
||||
return new IndexContext(documentSelector, contextPath.append(s), subIndex, completionFactory, typeUtil, conf);
|
||||
return new IndexContext(getDocument(), documentSelector, contextPath.append(s), subIndex, completionFactory, typeUtil, conf);
|
||||
} else if (subIndex.getExactMatch()!=null) {
|
||||
IndexContext asIndexContext = new IndexContext(documentSelector, contextPath.append(s), subIndex, completionFactory, typeUtil, conf);
|
||||
IndexContext asIndexContext = new IndexContext(getDocument(), documentSelector, contextPath.append(s), subIndex, completionFactory, typeUtil, conf);
|
||||
PropertyInfo prop = subIndex.getExactMatch();
|
||||
return new TypeContext(asIndexContext, contextPath.append(s), TypeParser.parse(prop.getType()), completionFactory, typeUtil, conf, prop.getHints(typeUtil, true));
|
||||
}
|
||||
@@ -532,11 +532,16 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
|
||||
return null;
|
||||
}
|
||||
|
||||
public static YamlAssistContext global(final FuzzyMap<PropertyInfo> index, final PropertyCompletionFactory completionFactory, final TypeUtil typeUtil, final RelaxedNameConfig conf) {
|
||||
public static YamlAssistContext global(YamlDocument doc, final FuzzyMap<PropertyInfo> index, final PropertyCompletionFactory completionFactory, final TypeUtil typeUtil, final RelaxedNameConfig conf) {
|
||||
return new TopLevelAssistContext() {
|
||||
@Override
|
||||
protected YamlAssistContext getDocumentContext(int documentSelector) {
|
||||
return subdocument(documentSelector, index, completionFactory, typeUtil, conf);
|
||||
return subdocument(doc, documentSelector, index, completionFactory, typeUtil, conf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlDocument getDocument() {
|
||||
return doc;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
36
vscode-extensions/vscode-concourse/.classpath
Normal file
36
vscode-extensions/vscode-concourse/.classpath
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
vscode-extensions/vscode-concourse/.project
Normal file
23
vscode-extensions/vscode-concourse/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>vscode-concourse</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,5 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
||||
@@ -0,0 +1,4 @@
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
||||
@@ -47,7 +47,7 @@ export function activate(context: VSCode.ExtensionContext) {
|
||||
synchronize: {
|
||||
// TODO: Remove textDocumentFilter property once https://github.com/Microsoft/vscode-languageserver-node/issues/9 is resolved
|
||||
textDocumentFilter: function(textDocument : TextDocument) : boolean {
|
||||
let result : boolean = /^(.*\/)?pipeline[^\s\\/]*.yml$/i.test(textDocument.fileName);
|
||||
let result : boolean = /^(.*)pipeline(.*)\.yml$/i.test(textDocument.fileName);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
set -e
|
||||
(cd ../commons-vscode ; npm install)
|
||||
npm install ../commons-vscode
|
||||
../mvnw -U -f ../pom.xml -pl vscode-concourse -am clean install
|
||||
../mvnw -DskipTests -U -f ../pom.xml -pl vscode-concourse -am clean install
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ide.vscode.manifest.yaml;
|
||||
package org.springframework.ide.vscode.concourse;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -30,15 +30,15 @@ import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public class ManifestYamlLanguageServer extends SimpleLanguageServer {
|
||||
public class ConcourseLanguageServer extends SimpleLanguageServer {
|
||||
|
||||
private static final Provider<Collection<YValueHint>> NO_BUILDPACKS = () -> ImmutableList.of();
|
||||
|
||||
private Yaml yaml = new Yaml();
|
||||
private YamlSchema schema = new ManifestYmlSchema(NO_BUILDPACKS);
|
||||
private YamlSchema schema = new PipelineYmlSchema(NO_BUILDPACKS);
|
||||
|
||||
|
||||
public ManifestYamlLanguageServer() {
|
||||
public ConcourseLanguageServer() {
|
||||
SimpleTextDocumentService documents = getTextDocumentService();
|
||||
|
||||
YamlASTProvider parser = new YamlParser(yaml);
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.springframework.ide.vscode.manifest.yaml;
|
||||
package org.springframework.ide.vscode.concourse;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -6,9 +6,9 @@ import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
|
||||
public class Main {
|
||||
SimpleLanguageServer server = new ManifestYamlLanguageServer();
|
||||
SimpleLanguageServer server = new ConcourseLanguageServer();
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
LaunguageServerApp.start(ManifestYamlLanguageServer::new);
|
||||
LaunguageServerApp.start(ConcourseLanguageServer::new);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016 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.concourse;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
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.YAtomicType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YBeanType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YValueHint;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
|
||||
|
||||
/**
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class PipelineYmlSchema implements YamlSchema {
|
||||
|
||||
private final YBeanType TOPLEVEL_TYPE;
|
||||
private final YTypeUtil TYPE_UTIL;
|
||||
|
||||
private final YTypeFactory f = new YTypeFactory();
|
||||
|
||||
public PipelineYmlSchema(Provider<Collection<YValueHint>> buildpackProvider) {
|
||||
TYPE_UTIL = f.TYPE_UTIL;
|
||||
|
||||
// define schema types
|
||||
TOPLEVEL_TYPE = f.ybean("Pipeline");
|
||||
|
||||
YType t_string = f.yatomic("String");
|
||||
YAtomicType t_ne_string = f.yatomic("String");
|
||||
t_ne_string.parseWith(ValueParsers.NE_STRING);
|
||||
YType t_strings = f.yseq(t_string);
|
||||
YAtomicType t_boolean = f.yenum("boolean", "true", "false");
|
||||
YAtomicType t_pos_integer = f.yatomic("Positive Integer");
|
||||
t_pos_integer.parseWith(ValueParsers.POS_INTEGER);
|
||||
YType t_any = f.yany("Object");
|
||||
YType t_params = f.ymap(t_string, t_any);
|
||||
|
||||
YAtomicType t_version = f.yatomic("Version");
|
||||
t_version.addHints("latest", "every");
|
||||
|
||||
YAtomicType t_resource_type = f.yatomic("ResourceType");
|
||||
t_resource_type.addHints(
|
||||
f.hint("git", "git - The 'git' resource can pull and push to git repositories"),
|
||||
f.hint("time", "time - The 'time' resource can start jobs on a schedule or timestamp outputs."),
|
||||
f.hint("s3", "s3 - The 's3' resource can fetch from and upload to S3 buckets."),
|
||||
f.hint("archive", "archive - The archive resource can fetch and extract .tar.gz archives.")
|
||||
//TODO: add more resource types and descriptions.
|
||||
//
|
||||
// The semver resource can set or bump version numbers.
|
||||
//
|
||||
// The github-release resource can fetch and publish versioned GitHub resources.
|
||||
//
|
||||
// The docker-image resource can fetch, build, and push Docker images
|
||||
//
|
||||
// The tracker resource can deliver stories and bugs on Pivotal Tracker
|
||||
//
|
||||
// The pool resource allows you to configure how to serialize use of an external system. This lets you prevent test interference or overwork on shared systems.
|
||||
//
|
||||
// The cf resource can deploy an application to Cloud Foundry.
|
||||
//
|
||||
// The bosh-io-release resource can track and fetch new BOSH releases from bosh.io.
|
||||
//
|
||||
// The bosh-io-stemcell resource can track and fetch new BOSH stemcells from bosh.io.
|
||||
//
|
||||
// The bosh-deployment resource can deploy BOSH stemcells and releases.
|
||||
//
|
||||
// The vagrant-cloud r
|
||||
);
|
||||
|
||||
YBeanType getStep = f.ybean("GetStep");
|
||||
prop(getStep, "get", t_ne_string);
|
||||
prop(getStep, "resource", t_string);
|
||||
prop(getStep, "version", t_version);
|
||||
prop(getStep, "passed", t_strings);
|
||||
prop(getStep, "params", t_params);
|
||||
prop(getStep, "trigger", t_boolean);
|
||||
|
||||
YBeanType putStep = f.ybean("PutStep");
|
||||
prop(putStep, "put", t_ne_string);
|
||||
prop(putStep, "resource", t_string);
|
||||
prop(putStep, "params", t_params);
|
||||
|
||||
YBeanType taskStep = f.ybean("TaskStep");
|
||||
prop(taskStep, "task", t_ne_string);
|
||||
prop(taskStep, "file", t_string);
|
||||
prop(taskStep, "config", t_any);
|
||||
prop(taskStep, "privileged", t_boolean);
|
||||
prop(taskStep, "params", t_params);
|
||||
|
||||
YType step = f.yunion("Step",
|
||||
getStep,
|
||||
putStep,
|
||||
taskStep
|
||||
);
|
||||
|
||||
YBeanType resource = f.ybean("Resource");
|
||||
prop(resource, "name", t_ne_string);
|
||||
prop(resource, "type", t_resource_type);
|
||||
prop(resource, "source", t_any);
|
||||
|
||||
YBeanType job = f.ybean("Job");
|
||||
prop(job, "name", t_ne_string);
|
||||
prop(job, "serial", t_boolean);
|
||||
prop(job, "build_logs_to_retain", t_pos_integer);
|
||||
prop(job, "serial_groups", t_strings);
|
||||
prop(job, "max_in_flight", t_pos_integer);
|
||||
prop(job, "public", t_boolean);
|
||||
prop(job, "disable_manual_trigger", t_boolean);
|
||||
prop(job, "plan", f.yseq(step));
|
||||
|
||||
prop(TOPLEVEL_TYPE, "resources", f.yseq(resource));
|
||||
prop(TOPLEVEL_TYPE, "jobs", f.yseq(job));
|
||||
|
||||
}
|
||||
|
||||
private void prop(YBeanType 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");
|
||||
}
|
||||
|
||||
@Override
|
||||
public YBeanType getTopLevelType() {
|
||||
return TOPLEVEL_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public YTypeUtil getTypeUtil() {
|
||||
return TYPE_UTIL;
|
||||
}
|
||||
}
|
||||
@@ -8,60 +8,30 @@
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.manifest.yaml;
|
||||
|
||||
import java.util.Set;
|
||||
package org.springframework.ide.vscode.concourse;
|
||||
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.ValueParser;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* Methods and constants to create/get parsers for some atomic types
|
||||
* used in manifest yml schema.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class ManifestYmlValueParsers {
|
||||
public class ValueParsers {
|
||||
|
||||
public static final ValueParser POS_INTEGER = integerRange(0, null);
|
||||
|
||||
public static final ValueParser MEMORY = new ValueParser() {
|
||||
|
||||
private final ImmutableSet<String> GIGABYTE = ImmutableSet.of("G", "GB");
|
||||
private final ImmutableSet<String> MEGABYTE = ImmutableSet.of("M", "MB");
|
||||
private final Set<String> UNITS = Sets.union(GIGABYTE, MEGABYTE);
|
||||
|
||||
@Override
|
||||
public Object parse(String str) {
|
||||
str = str.trim();
|
||||
String unit = getUnit(str.toUpperCase());
|
||||
if (unit==null) {
|
||||
throw new NumberFormatException(
|
||||
"'"+str+"' doesn't end with a valid unit of memory ('M', 'MB', 'G' or 'GB')"
|
||||
);
|
||||
}
|
||||
str = str.substring(0, str.length()-unit.length());
|
||||
int unitSize = GIGABYTE.contains(unit)?1024:1;
|
||||
int value = Integer.parseInt(str);
|
||||
if (value<0) {
|
||||
throw new NumberFormatException("Negative value is not allowed");
|
||||
}
|
||||
return value * unitSize;
|
||||
}
|
||||
|
||||
private String getUnit(String str) {
|
||||
for (String u : UNITS) {
|
||||
if (str.endsWith(u)) {
|
||||
return u;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
public static final ValueParser NE_STRING = (s) -> {
|
||||
if (StringUtil.hasText(s)) {
|
||||
return s;
|
||||
} else {
|
||||
throw new IllegalArgumentException("String should not be empty");
|
||||
}
|
||||
};
|
||||
|
||||
public static final ValueParser POS_INTEGER = integerRange(0, null);
|
||||
|
||||
public static ValueParser integerAtLeast(final Integer lowerBound) {
|
||||
return integerRange(lowerBound, null);
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016 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.manifest.yaml;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
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.YAtomicType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YBeanType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YTypedPropertyImpl;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypeUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YValueHint;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class ManifestYmlSchema implements YamlSchema {
|
||||
|
||||
private final YBeanType TOPLEVEL_TYPE;
|
||||
private final YTypeUtil TYPE_UTIL;
|
||||
private final Provider<Collection<YValueHint>> buildpackProvider;
|
||||
|
||||
private static final Set<String> TOPLEVEL_EXCLUDED = ImmutableSet.of(
|
||||
"name", "host", "hosts"
|
||||
);
|
||||
|
||||
public ManifestYmlSchema(Provider<Collection<YValueHint>> buildpackProvider) {
|
||||
this.buildpackProvider = buildpackProvider;
|
||||
YTypeFactory f = new YTypeFactory();
|
||||
TYPE_UTIL = f.TYPE_UTIL;
|
||||
|
||||
// define schema types
|
||||
TOPLEVEL_TYPE = f.ybean("manifest.yml schema");
|
||||
|
||||
YBeanType application = f.ybean("Application");
|
||||
YAtomicType t_path = f.yatomic("Path");
|
||||
|
||||
YAtomicType t_buildpack = f.yatomic("Buildpack");
|
||||
|
||||
t_buildpack.addHintProvider(this.buildpackProvider);
|
||||
|
||||
YAtomicType t_boolean = f.yenum("boolean", "true", "false");
|
||||
YType t_string = f.yatomic("String");
|
||||
YType t_strings = f.yseq(t_string);
|
||||
|
||||
YAtomicType t_memory = f.yatomic("Memory");
|
||||
t_memory.addHints("256M", "512M", "1024M");
|
||||
t_memory.parseWith(ManifestYmlValueParsers.MEMORY);
|
||||
|
||||
YAtomicType t_health_check_type = f.yenum("Health Check Type", "none", "port");
|
||||
|
||||
YAtomicType t_strictly_pos_integer = f.yatomic("Strictly Positive Integer");
|
||||
t_strictly_pos_integer.parseWith(ManifestYmlValueParsers.integerAtLeast(1));
|
||||
|
||||
YAtomicType t_pos_integer = f.yatomic("Positive Integer");
|
||||
t_pos_integer.parseWith(ManifestYmlValueParsers.POS_INTEGER);
|
||||
|
||||
YType t_env = f.ymap(t_string, t_string);
|
||||
|
||||
// define schema structure...
|
||||
TOPLEVEL_TYPE.addProperty("applications", f.yseq(application));
|
||||
TOPLEVEL_TYPE.addProperty("inherit", t_string, descriptionFor("inherit"));
|
||||
|
||||
YTypedPropertyImpl[] props = {
|
||||
f.yprop("buildpack", t_buildpack),
|
||||
f.yprop("command", t_string),
|
||||
f.yprop("disk_quota", t_memory),
|
||||
f.yprop("domain", t_string),
|
||||
f.yprop("domains", t_strings),
|
||||
f.yprop("env", t_env),
|
||||
f.yprop("host", t_string),
|
||||
f.yprop("hosts", t_strings),
|
||||
f.yprop("instances", t_strictly_pos_integer),
|
||||
f.yprop("memory", t_memory),
|
||||
f.yprop("name", t_string),
|
||||
f.yprop("no-hostname", t_boolean),
|
||||
f.yprop("no-route", t_boolean),
|
||||
f.yprop("path", t_path),
|
||||
f.yprop("random-route", t_boolean),
|
||||
f.yprop("services", t_strings),
|
||||
f.yprop("stack", t_string),
|
||||
f.yprop("timeout", t_pos_integer),
|
||||
f.yprop("health-check-type", t_health_check_type)
|
||||
};
|
||||
|
||||
for (YTypedPropertyImpl prop : props) {
|
||||
prop.setDescriptionProvider(descriptionFor(prop));
|
||||
if (!TOPLEVEL_EXCLUDED.contains(prop.getName())) {
|
||||
TOPLEVEL_TYPE.addProperty(prop);
|
||||
}
|
||||
application.addProperty(prop);
|
||||
}
|
||||
}
|
||||
|
||||
private Renderable descriptionFor(String propName) {
|
||||
return Renderables.fromClasspath(this.getClass(), "/description-by-prop-name/"+propName);
|
||||
}
|
||||
|
||||
private Renderable descriptionFor(YTypedPropertyImpl prop) {
|
||||
return descriptionFor(prop.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public YBeanType getTopLevelType() {
|
||||
return TOPLEVEL_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public YTypeUtil getTypeUtil() {
|
||||
return TYPE_UTIL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<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>
|
||||
@@ -0,0 +1,3 @@
|
||||
<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>
|
||||
@@ -0,0 +1,15 @@
|
||||
<p><em>Optional.</em> When specified, only the versions of the resource that
|
||||
made it through the given list of jobs will be considered when triggering
|
||||
and fetching.</p><p>Note that if multiple <code>get</code>s are configured with <code>passed</code>
|
||||
constraints, all of the mentioned jobs are correlated. That is, with the
|
||||
following set of inputs:</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">a</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">passed</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">a-unit</span><span class="t"></span><span class="pi">,</span><span class="t"> </span><span class="nv"></span><span class="nv">integration</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="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">b</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">passed</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">b-unit</span><span class="t"></span><span class="pi">,</span><span class="t"> </span><span class="nv"></span><span class="nv">integration</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="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">x</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">passed</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">integration</span><span class="t"></span><span class="pi">]</span></pre></div><p>This means "give me the versions of <code>a</code>, <code>b</code>, and <code>x</code> that
|
||||
have passed the <em>same build</em> of <code>integration</code>, with the same
|
||||
version of <code>a</code> passing <code>a-unit</code> and the same version of
|
||||
<code>b</code> passing <code>b-unit</code>."</p><p>This is crucial to being able to implement safe "fan-in" semantics as
|
||||
things progress through a pipeline.</p>
|
||||
@@ -0,0 +1,2 @@
|
||||
<p><em>Optional. Defaults to <code>name</code>.</em> The resource to fetch, as
|
||||
configured in <a href="configuring-resources.html"><code>resources</code></a>.</p>
|
||||
@@ -0,0 +1,4 @@
|
||||
<p><em>Optional. Default <code>false</code>.</em> Set to <code>true</code> to auto-trigger
|
||||
new builds of the plan's job whenever this step has new versions available,
|
||||
as specified by the <code>resource</code> and any <code>passed</code> constraints.</p><p>Otherwise, if no <code>get</code> steps set this to <code>true</code>, the job can only
|
||||
be manually triggered.</p>
|
||||
@@ -0,0 +1,11 @@
|
||||
<p><em>Optional. Defaults to <code>latest</code>.</em> The version of the resource to
|
||||
fetch.</p><p>If set to <code>latest</code>, scheduling will just find the latest available
|
||||
version of a resource and use it, allowing versions to be skipped. This is
|
||||
usually what you want, e.g. if someone pushes 100 git commits.</p><p>If set to <code>every</code>, builds will walk through all available versions of
|
||||
the resource. Note that if <code>passed</code> is also configured, it will only
|
||||
step through the versions satisfying the constraints.</p><p>If set to a specific version (e.g. <code>{ref: abcdef123}</code>), only that
|
||||
version will be used. Note that the version must be available and detected by
|
||||
the resource, otherwise the input will never be satisfied. You may want to
|
||||
use <a href="fly-check-resource.html"><code>check-resource</code></a> to force detection of resource versions,
|
||||
if you need to use an older one that was never detected (as all newly
|
||||
configured resources start from the latest version).</p>
|
||||
@@ -0,0 +1,10 @@
|
||||
<p><em>Optional.</em> If configured, only the last specified number of builds
|
||||
will have their build logs persisted. This is useful if you have a job that
|
||||
runs periodically but after some amount of time the logs aren't worth keeping
|
||||
around.</p><p>Example:</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">jobs</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">name</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">smoke-tests</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">build_logs_to_retain</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="mi">100</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">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="mi">10</span><span class="nv"></span><span class="nv">m</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">smoke-tests</span><span class="t">
|
||||
</span><span class="t"> </span><span class="nv">#</span><span class="sp"> </span><span class="nv">...</span></pre></div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<p><em>Optional. Default <code>false</code>.</em> If set to <code>true</code>, manual
|
||||
triggering of the job (via the web UI or <a href="fly-trigger-job.html"><code>trigger-job</code></a>) will be
|
||||
disabled.</p>
|
||||
@@ -0,0 +1,3 @@
|
||||
<p><em>Optional.</em> If set, specifies a maximum number of builds to run at a
|
||||
time. If <code>serial</code> or <code>serial_groups</code> are set, they take precedence
|
||||
and force this value to be <code>1</code>.</p>
|
||||
@@ -0,0 +1,2 @@
|
||||
<p><em>Required.</em> The name of the job. This should be short; it will show up
|
||||
in URLs.</p>
|
||||
@@ -0,0 +1,60 @@
|
||||
<p>Each <a href="concepts.html#jobs">Job</a> has a single build plan. When a build of a job is
|
||||
created, the plan determines what happens.</p><p>A build plan is a sequence of <em>steps</em> to execute. These steps may fetch
|
||||
down or update <a href="concepts.html#resources">Resources</a>, or execute
|
||||
<a href="concepts.html#tasks">Tasks</a>.</p><p>A new build of the job is scheduled whenever <a href="get-step.html"><code>get</code></a> steps with
|
||||
<code>trigger: true</code> have new versions available.</p><p>To visualize the job in the pipeline, resources that appear as <code>get</code>
|
||||
steps are drawn as inputs, and resources that appear in <code>put</code> steps
|
||||
appear as outputs.</p><p>A simple unit test job may look something like:</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">name</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">banana-unit</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">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">banana</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">trigger</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">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</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">banana/task.yml</span></pre></div><p>This job says: <a href="get-step.html"><code>get</code></a> the <code>banana</code> resource,
|
||||
and run a <a href="task-step.html"><code>task</code></a> step called <code>unit</code>, using
|
||||
the configuration from the <code>task.yml</code> file fetched from the <code>banana</code>
|
||||
step.</p><p>When new versions of <code>banana</code> are detected, a new build of
|
||||
<code>banana-unit</code> will be scheduled, because we've set <code>trigger: true</code>.</p><p>Jobs can depend on resources that are produced by or pass through upstream
|
||||
jobs, by configuring <code>passed: [job-a, job-b]</code> on the
|
||||
<a href="get-step.html"><code>get</code></a> step.</p><p>Putting these pieces together, if we were to propagate <code>banana</code> from
|
||||
the above example into an integration suite with another <code>apple</code>
|
||||
component (pretending we also defined its <code>apple-unit</code> job), the
|
||||
configuration for the integration job may look something like:</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">name</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">fruit-basket-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">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">banana</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">trigger</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="t"></span><span class="t"></span><span class="nv"></span><span class="py">passed</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">banana-unit</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="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">apple</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">trigger</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="t"></span><span class="t"></span><span class="nv"></span><span class="py">passed</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">apple-unit</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="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="t"></span><span class="t"></span><span class="nv"></span><span class="py">trigger</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">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><p>Note the use of the <a href="aggregate-step.html"><code>aggregate</code></a> step to
|
||||
collect multiple inputs at once.</p><p>With this example we've configured a tiny pipeline that will automatically
|
||||
run unit tests for two components, and continuously run integration tests
|
||||
against whichever versions pass both unit tests.</p><p>This can be further chained into later "stages" of your pipeline; for
|
||||
example, you may want to continuously deliver an artifact built from
|
||||
whichever components pass <code>fruit-basket-integration</code>.</p><p>To push artifacts, you would use a <a href="put-step.html"><code>put</code></a> step
|
||||
that targets the destination resource. For example:</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">name</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">deliver-food</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">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">banana</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">trigger</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="t"></span><span class="t"></span><span class="nv"></span><span class="py">passed</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">fruit-basket-integration</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="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">apple</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">trigger</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="t"></span><span class="t"></span><span class="nv"></span><span class="py">passed</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">fruit-basket-integration</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="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">baggy</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">trigger</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">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">shrink-wrap</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">baggy/shrink-wrap.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">bagged-food</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">bag</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">shrink-wrap/bagged.tgz</span></pre></div><p>This presumes that there's a <code>bagged-food</code>
|
||||
<a href="concepts.html#resources">resource</a> defined, which understands that the
|
||||
<code>bag</code> parameter points to a file to ship up to the resource's location.</p><p>Note that both <code>banana</code> and <code>apple</code> list the same job as an
|
||||
upstream dependency. This guarantees that <code>deliver-food</code> will only
|
||||
trigger when a version of both of these dependencies pass through the same
|
||||
build of the integration job (and transitively, their individual unit jobs).
|
||||
This prevents bad apples or bruised bananas from being delivered. (I'm sorry.)</p>
|
||||
@@ -0,0 +1,5 @@
|
||||
<p><em>Optional. Default <code>false</code>.</em> If set to <code>true</code>, the build log
|
||||
of this job will be viewable by unauthenticated users. Unauthenticated users
|
||||
will always be able to see the inputs, outputs, and build status history of a
|
||||
job. This is useful if you would like to expose your pipeline publicly without
|
||||
showing sensitive information in the build log.</p>
|
||||
@@ -0,0 +1,2 @@
|
||||
<p><em>Optional. Default <code>false</code>.</em> If set to <code>true</code>, builds will
|
||||
queue up and execute one-by-one, rather than executing in parallel.</p>
|
||||
@@ -0,0 +1,12 @@
|
||||
<p><em>Optional. Default <code>[]</code>.</em> When set to an array of arbitrary
|
||||
tag-like strings, builds of this job and other jobs referencing the same
|
||||
tags will be serialized.</p><p>This can be used to ensure that certain jobs do not run at the same time,
|
||||
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">jobs</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">name</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">job-a</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">serial_groups</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">some-tag</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="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">name</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">job-b</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">serial_groups</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">some-tag</span><span class="t"></span><span class="pi">,</span><span class="t"> </span><span class="nv"></span><span class="nv">some-other-tag</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="pi">-</span><span class="t"></span><span class="t"> </span><span class="t"></span><span class="nv"></span><span class="py">name</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">job-c</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">serial_groups</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">[</span><span class="nv"></span><span class="nv">some-other-tag</span><span class="t"></span><span class="pi">]</span></pre></div><p>In this example, <code>job-a</code> and <code>job-c</code> can run concurrently, but
|
||||
neither job can run builds at the same time as <code>job-b</code>.</p><p>The builds are executed in their order of creation, across all jobs with
|
||||
common tags.</p>
|
||||
@@ -0,0 +1,16 @@
|
||||
<p>At a high level, a job describes some actions to perform when dependent
|
||||
resources change (or when manually triggered). For example, you may define a
|
||||
job that runs your unit tests whenever new code is pushed to a repository.</p><p>Jobs can be thought of as functions with inputs and outputs, that
|
||||
automatically run when new inputs are available. A job can depend on the
|
||||
outputs of upstream jobs, which is the root of pipeline functionality.</p><p>The definition of actions to perform is done via a
|
||||
<a href="build-plans.html">Build Plan</a>, which is a very powerful
|
||||
composition-based DSL that can express anything from running simple unit
|
||||
tests to running a matrix of tasks and aggregating the result.</p><div class="section" id="section_job-builds"><h3><a name="job-builds"></a>Builds</h3><p>An instance of execution of a job's plan is called a <em>build</em>. A build
|
||||
can either succeed or fail, or error if something unrelated to your code
|
||||
goes wrong (i.e. if one of your workers falls off the face of the earth).</p><p>When a build runs, the job's plan is realized. Each step described by the
|
||||
job's plan is executed, and so long as all <a href="concepts.html#tasks">Tasks</a> succeed, the
|
||||
build succeeds. If a task fails, the build fails, and its resources do not
|
||||
propagate to the rest of the pipeline.</p><p>The containers running in a build can be accessed while they're running
|
||||
(and also shortly after they finish) via
|
||||
<a href="fly-intercept.html"><code>fly intercept</code></a>, which can greatly help in
|
||||
debugging.</p>
|
||||
@@ -0,0 +1,14 @@
|
||||
<p>A resource is any entity that can be checked for new versions, pulled down
|
||||
at a specific version, and/or pushed up to idempotently create new versions.
|
||||
A common example would be a git repository, but it can also represent more
|
||||
abstract things like
|
||||
<a href="https://github.com/concourse/time-resource">time itself</a>.</p><p>At its core, Concourse knows nothing about things like <code>git</code>. Instead,
|
||||
it consumes a generic interface implemented by <em>resource types</em>. This
|
||||
allows Concourse to be extended by configuring workers with resource type
|
||||
implementations.</p><p>This abstraction is immensely powerful, as it does not limit Concourse to
|
||||
whatever things its authors thought to integrate with. Instead, as a user of
|
||||
Concourse you can just reuse resource type implementations, or
|
||||
<a href="implementing-resources.html">implement your own</a>.</p><p>To use resources, configure them in your pipeline via the
|
||||
<a href="configuring-resources.html"><code>resources</code></a> section, and use them in
|
||||
your <a href="build-plans.html">Build Plans</a> via the <a href="get-step.html"><code>get</code></a> and
|
||||
<a href="put-step.html"><code>put</code></a> steps.</p>
|
||||
@@ -0,0 +1,3 @@
|
||||
<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>
|
||||
@@ -0,0 +1,20 @@
|
||||
<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>
|
||||
@@ -0,0 +1,2 @@
|
||||
<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>
|
||||
@@ -0,0 +1,6 @@
|
||||
<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>
|
||||
@@ -0,0 +1,8 @@
|
||||
<span class="py">privileged</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">boolean</span></a></pre></div><p><em>Optional. Default <code>false</code>.</em> If set to <code>true</code>, the task will
|
||||
run with full capabilities, as determined by the Garden backend the task runs
|
||||
on. For Linux-based backends it typically determines whether or not the
|
||||
container will run in a separate user namespace, and whether the <code>root</code>
|
||||
user is "actual" <code>root</code> (if set to <code>true</code>) or a user namespaced
|
||||
<code>root</code> (if set to <code>false</code>, the default).</p><p>This is a gaping security hole; use wisely and only if necessary. This is not
|
||||
part of the task configuration to prevent privilege escalation via pull
|
||||
requests.</p>
|
||||
@@ -0,0 +1,23 @@
|
||||
<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>
|
||||
@@ -1,11 +0,0 @@
|
||||
<p>If your application requires a custom buildpack, you can use the <code>buildpack</code> attribute to specify its URL or name:</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
buildpack: buildpack_URL
|
||||
</pre>
|
||||
|
||||
<p class="note"><strong>Note</strong>: The <code>cf buildpacks</code> command lists the buildpacks that you can refer to by name in a manifest or a command line option.</p>
|
||||
|
||||
<p>The command line option that overrides this attribute is <code>-b</code>.</p>
|
||||
@@ -1,11 +0,0 @@
|
||||
If your application requires a custom buildpack, you can use the `buildpack` attribute to specify its URL or name:
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
buildpack: buildpack_URL
|
||||
```
|
||||
|
||||
**Note**: The `cf buildpacks` command lists the buildpacks that you can refer to by name in a manifest or a command line option.
|
||||
|
||||
The command line option that overrides this attribute is `-b`.
|
||||
@@ -1,34 +0,0 @@
|
||||
<p>Some languages and frameworks require that you provide a custom command to start an application. Refer to the <a href="/buildpacks/">buildpack</a> documentation to determine if you need to provide a custom start command.</p>
|
||||
|
||||
<p>You can provide the custom start command in your application manifest or on the command line.</p>
|
||||
|
||||
<p>To specify the custom start command in your application manifest, add it in the <code>command: START-COMMAND</code> format as the following example shows:</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
command: bundle exec rake VERBOSE=true
|
||||
</pre>
|
||||
|
||||
<p>On the command line, use the <code>-c</code> option to specify the custom start command as the following example shows:</p>
|
||||
|
||||
<pre class="terminal">
|
||||
$ cf push my-app -c "bundle exec rake VERBOSE=true"
|
||||
</pre>
|
||||
|
||||
<p class="note"><strong>Note</strong>: The <code>-c</code> option with a value of ‘null’ forces <code>cf push</code> to use the buildpack start command. See <a href="./app-startup.html">About Starting Applications</a> for more information.</p>
|
||||
|
||||
<p>If you override the start command for a Buildpack application, Linux uses
|
||||
<code>bash -c YOUR-COMMAND</code> to invoke your application.
|
||||
If you override the start command for a Docker application, Linux uses <code>sh -c YOUR-COMMAND</code> to invoke your application.
|
||||
Because of this, if you override a start command, you should prefix <code>exec</code> to the final command in your custom composite start command.</p>
|
||||
|
||||
<p><code>exec</code> causes the last command to become the root process of your application. The <a href="./prepare-to-deploy.html#moving-apps">Cloud Foundry Updates and Your Application</a> section of the <em>Considerations for Designing and Running an Application in the Cloud</em> topic explains why your application should handle a <code>termination signal</code> during Cloud Foundry updates.
|
||||
Without an <code>exec</code> statement, the parent process remains as the implied bash process, and does not propagate signals to your application process.</p>
|
||||
|
||||
<p>For example, both of the following composite start commands run database migrations when the first instance of the app starts, then start the app to serve requests, but they behave differently on graceful shutdown. </p>
|
||||
|
||||
<ul>
|
||||
<li><p><code>bin/rake cf:on_first_instance db:migrate && bin/rails server -p $PORT -e $RAILS_ENV</code>: The process tree is <code>bash -> ruby</code>, so on graceful shutdown only the <code>bash</code> process receives the TERM signal, and not the <code>ruby</code> process.</p></li>
|
||||
<li><p><code>bin/rake cf:on_first_instance db:migrate && exec bin/rails server -p $PORT -e $RAILS_ENV</code>: Because of the <code>exec</code> prefix on the final command, the <code>ruby</code> process invoked by <code>rails</code> takes over the <code>bash</code> process managing the execution of the composite command. The process tree is only <code>ruby</code>, so the ruby web server receives the TERM signal can shutdown gracefully for 10 seconds.</p></li>
|
||||
</ul>
|
||||
@@ -1,30 +0,0 @@
|
||||
Some languages and frameworks require that you provide a custom command to start an application. Refer to the [buildpack](/buildpacks/) documentation to determine if you need to provide a custom start command.
|
||||
|
||||
You can provide the custom start command in your application manifest or on the command line.
|
||||
|
||||
To specify the custom start command in your application manifest, add it in the `command: START-COMMAND` format as the following example shows:
|
||||
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
command: bundle exec rake VERBOSE=true
|
||||
```
|
||||
|
||||
On the command line, use the `-c` option to specify the custom start command as the following example shows:
|
||||
|
||||
```
|
||||
$ cf push my-app -c "bundle exec rake VERBOSE=true"
|
||||
```
|
||||
|
||||
**Note**: The `-c` option with a value of ‘null’ forces `cf push` to use the buildpack start command. See [About Starting Applications](./app-startup.html) for more information.
|
||||
|
||||
If you override the start command for a Buildpack application, Linux uses `bash -c YOUR-COMMAND` to invoke your application. If you override the start command for a Docker application, Linux uses `sh -c YOUR-COMMAND` to invoke your application. Because of this, if you override a start command, you should prefix `exec` to the final command in your custom composite start command.
|
||||
|
||||
`exec` causes the last command to become the root process of your application. The [Cloud Foundry Updates and Your Application](./prepare-to-deploy.html#moving-apps) section of the _Considerations for Designing and Running an Application in the Cloud_ topic explains why your application should handle a `termination signal` during Cloud Foundry updates. Without an `exec` statement, the parent process remains as the implied bash process, and does not propagate signals to your application process.
|
||||
|
||||
For example, both of the following composite start commands run database migrations when the first instance of the app starts, then start the app to serve requests, but they behave differently on graceful shutdown.
|
||||
|
||||
* `bin/rake cf:on_first_instance db:migrate && bin/rails server -p $PORT -e $RAILS_ENV`: The process tree is `bash -> ruby`, so on graceful shutdown only the `bash` process receives the TERM signal, and not the `ruby` process.
|
||||
|
||||
* `bin/rake cf:on_first_instance db:migrate && exec bin/rails server -p $PORT -e $RAILS_ENV`: Because of the `exec` prefix on the final command, the `ruby` process invoked by `rails` takes over the `bash` process managing the execution of the composite command. The process tree is only `ruby`, so the ruby web server receives the TERM signal can shutdown gracefully for 10 seconds.
|
||||
@@ -1,9 +0,0 @@
|
||||
<p>Use the <code>disk_quota</code> attribute to allocate the disk space for your app instance. This attribute requires a unit of measurement: <code>M</code>, <code>MB</code>, <code>G</code>, or <code>GB</code>, in upper case or lower case.</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
disk_quota: 1024M
|
||||
</pre>
|
||||
|
||||
<p>The command line option that overrides this attribute is <code>-k</code>.</p>
|
||||
@@ -1,9 +0,0 @@
|
||||
Use the `disk_quota` attribute to allocate the disk space for your app instance. This attribute requires a unit of measurement: `M`, `MB`, `G`, or `GB`, in upper case or lower case.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
disk_quota: 1024M
|
||||
```
|
||||
|
||||
The command line option that overrides this attribute is `-k`.
|
||||
@@ -1,27 +0,0 @@
|
||||
<p>Every <code>cf push</code> deploys applications to one particular Cloud Foundry instance.
|
||||
Every Cloud Foundry instance may have a shared domain set by an admin.
|
||||
Unless you specify a domain, Cloud Foundry incorporates that shared domain in the route to your application.</p>
|
||||
|
||||
<p>You can use the <code>domain</code> attribute when you want your application to be served from a domain other than the default shared domain.</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
domain: unique-example.com
|
||||
</pre>
|
||||
|
||||
<p>The command line option that overrides this attribute is <code>-d</code>.</p>
|
||||
|
||||
<h3><a id='domains'></a>The domains attribute</h3>
|
||||
|
||||
<p>Use the <code>domains</code> attribute to provide multiple domains. If you define both <code>domain</code> and <code>domains</code> attributes, Cloud Foundry creates routes for domains defined in both of these fields.</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
domains:
|
||||
- domain-example1.com
|
||||
- domain-example2.org
|
||||
</pre>
|
||||
|
||||
<p>The command line option that overrides this attribute is <code>-d</code>.</p>
|
||||
@@ -1,25 +0,0 @@
|
||||
Every `cf push` deploys applications to one particular Cloud Foundry instance. Every Cloud Foundry instance may have a shared domain set by an admin. Unless you specify a domain, Cloud Foundry incorporates that shared domain in the route to your application.
|
||||
|
||||
You can use the `domain` attribute when you want your application to be served from a domain other than the default shared domain.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
domain: unique-example.com
|
||||
```
|
||||
|
||||
The command line option that overrides this attribute is `-d`.
|
||||
|
||||
### The domains attribute
|
||||
|
||||
Use the `domains` attribute to provide multiple domains. If you define both `domain` and `domains` attributes, Cloud Foundry creates routes for domains defined in both of these fields.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
domains:
|
||||
- domain-example1.com
|
||||
- domain-example2.org
|
||||
```
|
||||
|
||||
The command line option that overrides this attribute is `-d`.
|
||||
@@ -1,10 +0,0 @@
|
||||
<p>Use the <code>domains</code> attribute to provide multiple domains. If you define both <code>domain</code> and <code>domains</code> attributes, Cloud Foundry creates routes for domains defined in both of these fields.</p>
|
||||
|
||||
<pre>---
|
||||
...
|
||||
domains:
|
||||
- domain-example1.com
|
||||
- domain-example2.org
|
||||
</pre>
|
||||
|
||||
<p>The command line option that overrides this attribute is <code>-d</code>.</p>
|
||||
@@ -1,11 +0,0 @@
|
||||
Use the `domains` attribute to provide multiple domains. If you define both `domain` and `domains` attributes, Cloud Foundry creates routes for domains defined in both of these fields.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
domains:
|
||||
- domain-example1.com
|
||||
- domain-example2.org
|
||||
```
|
||||
|
||||
The command line option that overrides this attribute is `-d`.
|
||||
@@ -1,28 +0,0 @@
|
||||
<p>The <code>env</code> block consists of a heading, then one or more environment variable/value pairs.</p>
|
||||
|
||||
<p>For example:</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
env:
|
||||
RAILS_ENV: production
|
||||
RACK_ENV: production
|
||||
</pre>
|
||||
|
||||
<p><code>cf push</code> deploys the application to a container on the server. The variables belong to the container environment.</p>
|
||||
|
||||
<p>While the application is running, Cloud Foundry allows you to operate on environment variables.</p>
|
||||
|
||||
<ul>
|
||||
<li>View all variables: <code>cf env my-app</code></li>
|
||||
<li>Set an individual variable: <code>cf set-env my-app my-variable_name my-variable_value</code></li>
|
||||
<li>Unset an individual variable: <code>cf unset-env my-app my-variable_name my-variable_value</code></li>
|
||||
</ul>
|
||||
|
||||
<p>Environment variables interact with manifests in the following ways:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>When you deploy an application for the first time, Cloud Foundry reads the variables described in the environment block of the manifest, and adds them to the environment of the container where the application is deployed.</p></li>
|
||||
<li><p>When you stop and then restart an application, its environment variables persist.</p></li>
|
||||
</ul>
|
||||
@@ -1,24 +0,0 @@
|
||||
The `env` block consists of a heading, then one or more environment variable/value pairs.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
env:
|
||||
RAILS_ENV: production
|
||||
RACK_ENV: production
|
||||
```
|
||||
|
||||
`cf push` deploys the application to a container on the server. The variables belong to the container environment.
|
||||
|
||||
While the application is running, Cloud Foundry allows you to operate on environment variables.
|
||||
|
||||
* View all variables: `cf env my-app`
|
||||
* Set an individual variable: `cf set-env my-app my-variable_name my-variable_value`
|
||||
* Unset an individual variable: `cf unset-env my-app my-variable_name my-variable_value`
|
||||
|
||||
Environment variables interact with manifests in the following ways:
|
||||
|
||||
* When you deploy an application for the first time, Cloud Foundry reads the variables described in the environment block of the manifest, and adds them to the environment of the container where the application is deployed.
|
||||
* When you stop and then restart an application, its environment variables persist.
|
||||
@@ -1,9 +0,0 @@
|
||||
<p>Use the <code>health-check-type</code> attribute to set the <code>health_check_type</code>
|
||||
flag to either <code>port</code> or <code>none</code>. If you do not provide
|
||||
a <code>health-check-type</code> attribute, it defaults to <code>port</code>.</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
health-check-type: none
|
||||
</pre>
|
||||
@@ -1,9 +0,0 @@
|
||||
Use the `health-check-type` attribute to set the `health_check_type`
|
||||
flag to either `port` or `none`. If you do not provide a `health-check-type`
|
||||
attribute, it defaults to `port`.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
health-check-type: none
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
<p>Use the <code>host</code> attribute to provide a hostname, or subdomain, in the form of a string. This segment of a route helps to ensure that the route is unique. If you do not provide a hostname, the URL for the app takes the form of <code>APP-NAME.DOMAIN</code>.</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
host: my-app
|
||||
</pre>
|
||||
|
||||
<p>The command line option that overrides this attribute is <code>-n</code>.</p>
|
||||
@@ -1,9 +0,0 @@
|
||||
Use the `host` attribute to provide a hostname, or subdomain, in the form of a string. This segment of a route helps to ensure that the route is unique. If you do not provide a hostname, the URL for the app takes the form of `APP-NAME.DOMAIN`.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
host: my-app
|
||||
```
|
||||
|
||||
The command line option that overrides this attribute is `-n`.
|
||||
@@ -1,11 +0,0 @@
|
||||
<p>Use the <code>hosts</code> attribute to provide multiple hostnames, or subdomains. Each hostname generates a unique route for the app. <code>hosts</code> can be used in conjunction with <code>host</code>. If you define both attributes, Cloud Foundry creates routes for hostnames defined in both <code>host</code> and <code>hosts</code>.</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
hosts:
|
||||
- app_host1
|
||||
- app_host2
|
||||
</pre>
|
||||
|
||||
<p>The command line option that overrides this attribute is <code>-n</code>.</p>
|
||||
@@ -1,11 +0,0 @@
|
||||
Use the `hosts` attribute to provide multiple hostnames, or subdomains. Each hostname generates a unique route for the app. `hosts` can be used in conjunction with `host`. If you define both attributes, Cloud Foundry creates routes for hostnames defined in both `host` and `hosts`.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
hosts:
|
||||
- app_host1
|
||||
- app_host2
|
||||
```
|
||||
|
||||
The command line option that overrides this attribute is `-n`.
|
||||
@@ -1,62 +0,0 @@
|
||||
<p>A single manifest can describe multiple applications. Another powerful technique is to create multiple manifests with inheritance. Here, manifests have parent-child relationships such that children inherit descriptions from a parent. Children can use inherited descriptions as-is, extend them, or override them.</p>
|
||||
|
||||
<p>Content in the child manifest overrides content in the parent manifest, if the two conflict.</p>
|
||||
|
||||
<p>This technique helps in these and other scenarios:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>An application has a set of different deployment modes, such as debug, local, and public. Each deployment mode is described in child manifests that extend the settings in a base parent manifest.</p></li>
|
||||
<li><p>An application is packaged with a basic configuration described by a parent manifest. Users can extend the basic configuration by creating child manifests that add new properties or override those in the parent manifest.</p></li>
|
||||
</ul>
|
||||
|
||||
<p>The benefits of multiple manifests with inheritance are similar to those of minimizing duplicated content within single manifests. With inheritance, though, we “promote” content by placing it in the parent manifest.</p>
|
||||
|
||||
<p>Every child manifest must contain an “inherit” line that points to the parent manifest. Place the inherit line immediately after the three dashes at the top of the child manifest. For example, every child of a parent manifest called <code>base-manifest.yml</code> begins like this:</p>
|
||||
|
||||
<pre>---
|
||||
...
|
||||
inherit: base-manifest.yml
|
||||
</pre>
|
||||
|
||||
<p>You do not need to add anything to the parent manifest.</p>
|
||||
|
||||
<p>In the simple example below, a parent manifest gives each application minimal resources, while a production child manifest scales them up.</p>
|
||||
|
||||
<p><strong>simple-base-manifest.yml</strong></p>
|
||||
|
||||
<pre>---
|
||||
path: .
|
||||
domain: shared-domain.com
|
||||
memory: 256M
|
||||
instances: 1
|
||||
services:
|
||||
- singular-backend
|
||||
|
||||
# app-specific configuration
|
||||
applications:
|
||||
- name: springtock
|
||||
host: 765shower
|
||||
path: ./april/build/libs/april-weather.war
|
||||
- name: wintertick
|
||||
host: 321flurry
|
||||
path: ./december/target/december-weather.war
|
||||
</pre>
|
||||
|
||||
<p><strong>simple-prod-manifest.yml</strong></p>
|
||||
|
||||
<pre>---
|
||||
inherit: simple-base-manifest.yml
|
||||
applications:
|
||||
- name:springstorm
|
||||
memory: 512M
|
||||
instances: 1
|
||||
host: 765deluge
|
||||
path: ./april/build/libs/april-weather.war
|
||||
- name: winterblast
|
||||
memory: 1G
|
||||
instances: 2
|
||||
host: 321blizzard
|
||||
path: ./december/target/december-weather.war
|
||||
</pre>
|
||||
|
||||
<p><class='note'><strong>Note</strong>: Inheritance can add an additional level of complexity to manifest creation and maintenance. Comments that precisely explain how the child manifest extends or overrides the descriptions in the parent manifest can alleviate this complexity.</class='note'>
|
||||
@@ -1,63 +0,0 @@
|
||||
A single manifest can describe multiple applications. Another powerful technique is to create multiple manifests with inheritance. Here, manifests have parent-child relationships such that children inherit descriptions from a parent. Children can use inherited descriptions as-is, extend them, or override them.
|
||||
|
||||
Content in the child manifest overrides content in the parent manifest, if the two conflict.
|
||||
|
||||
This technique helps in these and other scenarios:
|
||||
|
||||
* An application has a set of different deployment modes, such as debug, local, and public. Each deployment mode is described in child manifests that extend the settings in a base parent manifest.
|
||||
|
||||
* An application is packaged with a basic configuration described by a parent manifest. Users can extend the basic configuration by creating child manifests that add new properties or override those in the parent manifest.
|
||||
|
||||
The benefits of multiple manifests with inheritance are similar to those of minimizing duplicated content within single manifests. With inheritance, though, we “promote” content by placing it in the parent manifest.
|
||||
|
||||
Every child manifest must contain an “inherit” line that points to the parent manifest. Place the inherit line immediately after the three dashes at the top of the child manifest. For example, every child of a parent manifest called `base-manifest.yml` begins like this:
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
inherit: base-manifest.yml
|
||||
```
|
||||
You do not need to add anything to the parent manifest.
|
||||
|
||||
In the simple example below, a parent manifest gives each application minimal resources, while a production child manifest scales them up.
|
||||
|
||||
**simple-base-manifest.yml**
|
||||
|
||||
```
|
||||
---
|
||||
path: .
|
||||
domain: shared-domain.com
|
||||
memory: 256M
|
||||
instances: 1
|
||||
services:
|
||||
- singular-backend
|
||||
|
||||
# app-specific configuration
|
||||
applications:
|
||||
- name: springtock
|
||||
host: 765shower
|
||||
path: ./april/build/libs/april-weather.war
|
||||
- name: wintertick
|
||||
host: 321flurry
|
||||
path: ./december/target/december-weather.war
|
||||
```
|
||||
|
||||
**simple-prod-manifest.yml**
|
||||
|
||||
```
|
||||
---
|
||||
inherit: simple-base-manifest.yml
|
||||
applications:
|
||||
- name:springstorm
|
||||
memory: 512M
|
||||
instances: 1
|
||||
host: 765deluge
|
||||
path: ./april/build/libs/april-weather.war
|
||||
- name: winterblast
|
||||
memory: 1G
|
||||
instances: 2
|
||||
host: 321blizzard
|
||||
path: ./december/target/december-weather.war
|
||||
```
|
||||
|
||||
**Note**: Inheritance can add an additional level of complexity to manifest creation and maintenance. Comments that precisely explain how the child manifest extends or overrides the descriptions in the parent manifest can alleviate this complexity.
|
||||
@@ -1,11 +0,0 @@
|
||||
<p>Use the <code>instances</code> attribute to specify the number of app instances that you want to start upon push:</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
instances: 2
|
||||
</pre>
|
||||
|
||||
<p>We recommend that you run at least two instances of any apps for which fault tolerance matters.</p>
|
||||
|
||||
<p>The command line option that overrides this attribute is <code>-i</code>.</p>
|
||||
@@ -1,11 +0,0 @@
|
||||
Use the `instances` attribute to specify the number of app instances that you want to start upon push:
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
instances: 2
|
||||
```
|
||||
|
||||
We recommend that you run at least two instances of any apps for which fault tolerance matters.
|
||||
|
||||
The command line option that overrides this attribute is `-i`.
|
||||
@@ -1,11 +0,0 @@
|
||||
<p>Use the <code>memory</code> attribute to specify the memory limit for all instances of an app. This attribute requires a unit of measurement: <code>M</code>, <code>MB</code>, <code>G</code>, or <code>GB</code>, in upper case or lower case. For example:</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
memory: 1024M
|
||||
</pre>
|
||||
|
||||
<p>The default memory limit is 1G. You might want to specify a smaller limit to conserve quota space if you know that your app instances do not require 1G of memory.</p>
|
||||
|
||||
<p>The command line option that overrides this attribute is <code>-m</code>.</p>
|
||||
@@ -1,11 +0,0 @@
|
||||
Use the `memory` attribute to specify the memory limit for all instances of an app. This attribute requires a unit of measurement: `M`, `MB`, `G`, or `GB`, in upper case or lower case. For example:
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
memory: 1024M
|
||||
```
|
||||
|
||||
The default memory limit is 1G. You might want to specify a smaller limit to conserve quota space if you know that your app instances do not require 1G of memory.
|
||||
|
||||
The command line option that overrides this attribute is `-m`.
|
||||
@@ -1,10 +0,0 @@
|
||||
<p>The <code>name</code> attribute is the only required attribute
|
||||
for an application in a manifest file. </p>
|
||||
|
||||
<p>This is an example of a minimal manifest:</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
applications:
|
||||
- name: nifty-gui
|
||||
</pre>
|
||||
@@ -1,9 +0,0 @@
|
||||
The `name` attribute is the only required attribute for an application in a manifest file.
|
||||
|
||||
This is an example of a minimal manifest:
|
||||
|
||||
```
|
||||
---
|
||||
applications:
|
||||
- name: nifty-gui
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
<p>By default, if you do not provide a hostname, the URL for the app takes the form of <code>APP-NAME.DOMAIN</code>. If you want to override this and map the root domain to this app then you can set no-hostname as true.</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
no-hostname: true
|
||||
</pre>
|
||||
|
||||
<p>The command line option that corresponds to this attribute is <code>--no-hostname</code>.</p>
|
||||
@@ -1,9 +0,0 @@
|
||||
By default, if you do not provide a hostname, the URL for the app takes the form of `APP-NAME.DOMAIN`. If you want to override this and map the root domain to this app then you can set no-hostname as true.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
no-hostname: true
|
||||
```
|
||||
|
||||
The command line option that corresponds to this attribute is `--no-hostname`.
|
||||
@@ -1,18 +0,0 @@
|
||||
<p>By default, <code>cf push</code> assigns a route to every application. But some applications process data while running in the background, and should not be assigned routes.</p>
|
||||
|
||||
<p>You can use the <code>no-route</code> attribute with a value of <code>true</code> to prevent a route from being created for your application.</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
no-route: true
|
||||
</pre>
|
||||
|
||||
<p>The command line option that corresponds to this attribute is <code>--no-route</code>.</p>
|
||||
|
||||
<p>If you find that an application which should not have a route does have one:</p>
|
||||
|
||||
<ol>
|
||||
<li>Remove the route using the <code>cf unmap-route</code> command.</li>
|
||||
<li>Push the app again with the <code>no-route: true</code> attribute in the manifest or the <code>--no-route</code> command line option.</li>
|
||||
</ol>
|
||||
@@ -1,16 +0,0 @@
|
||||
By default, `cf push` assigns a route to every application. But some applications process data while running in the background, and should not be assigned routes.
|
||||
|
||||
You can use the `no-route` attribute with a value of `true` to prevent a route from being created for your application.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
no-route: true
|
||||
```
|
||||
|
||||
The command line option that corresponds to this attribute is `--no-route`.
|
||||
|
||||
If you find that an application which should not have a route does have one:
|
||||
|
||||
1. Remove the route using the `cf unmap-route` command.
|
||||
2. Push the app again with the `no-route: true` attribute in the manifest or the `--no-route` command line option.
|
||||
@@ -1,9 +0,0 @@
|
||||
<p>You can use the <code>path</code> attribute to tell Cloud Foundry where to find your application. This is generally not necessary when you run <code>cf push</code> from the directory where an application is located.</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
path: path_to_application_bits
|
||||
</pre>
|
||||
|
||||
<p>The command line option that overrides this attribute is <code>-p</code>.</p>
|
||||
@@ -1,9 +0,0 @@
|
||||
You can use the `path` attribute to tell Cloud Foundry where to find your application. This is generally not necessary when you run `cf push` from the directory where an application is located.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
path: path_to_application_bits
|
||||
```
|
||||
|
||||
The command line option that overrides this attribute is `-p`.
|
||||
@@ -1,11 +0,0 @@
|
||||
<p>Use the <code>random-route</code> attribute to create a URL that includes the app name and
|
||||
random words.
|
||||
Use this attribute to avoid URL collision when pushing the same app to multiple spaces, or to avoid managing app URLs.</p>
|
||||
|
||||
<p>The command line option that corresponds to this attribute is <code>--random-route</code>.</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
random-route: true
|
||||
</pre>
|
||||
@@ -1,9 +0,0 @@
|
||||
Use the `random-route` attribute to create a URL that includes the app name and random words. Use this attribute to avoid URL collision when pushing the same app to multiple spaces, or to avoid managing app URLs.
|
||||
|
||||
The command line option that corresponds to this attribute is `--random-route`.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
random-route: true
|
||||
```
|
||||
@@ -1,18 +0,0 @@
|
||||
<p>Applications can bind to services such as databases, messaging, and key-value stores.</p>
|
||||
|
||||
<p>Applications are deployed into App Spaces. An application can only bind to services instances that exist in the target App Space before the application is deployed.</p>
|
||||
|
||||
<p>The <code>services</code> block consists of a heading, then one or more service instance names.</p>
|
||||
|
||||
<p>Whoever creates the service chooses the service instance names. These names can convey logical information, as in <code>backend_queue</code>, describe the nature of the service, as in <code>mysql_5.x</code>, or do neither, as in the example below.</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
services:
|
||||
- instance_ABC
|
||||
- instance_XYZ
|
||||
</pre>
|
||||
|
||||
<p>Binding to a service instance is a special case of setting an environment
|
||||
variable, namely <code>VCAP_SERVICES</code>.
|
||||
@@ -1,17 +0,0 @@
|
||||
Applications can bind to services such as databases, messaging, and key-value stores.
|
||||
|
||||
Applications are deployed into App Spaces. An application can only bind to services instances that exist in the target App Space before the application is deployed.
|
||||
|
||||
The `services` block consists of a heading, then one or more service instance names.
|
||||
|
||||
Whoever creates the service chooses the service instance names. These names can convey logical information, as in `backend_queue`, describe the nature of the service, as in `mysql_5.x`, or do neither, as in the example below.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
services:
|
||||
- instance_ABC
|
||||
- instance_XYZ
|
||||
```
|
||||
|
||||
Binding to a service instance is a special case of setting an environment variable, namely `VCAP_SERVICES`.
|
||||
@@ -1,11 +0,0 @@
|
||||
<p>Use the <code>stack</code> attribute to specify which stack to deploy your application to.</p>
|
||||
|
||||
<p>To see a list of available stacks, run <code>cf stacks</code> from the cf cli.</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
stack: cflinuxfs2
|
||||
</pre>
|
||||
|
||||
<p>The command line option that overrides this attribute is <code>-s</code>.</p>
|
||||
@@ -1,11 +0,0 @@
|
||||
Use the `stack` attribute to specify which stack to deploy your application to.
|
||||
|
||||
To see a list of available stacks, run `cf stacks` from the cf cli.
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
stack: cflinuxfs2
|
||||
```
|
||||
|
||||
The command line option that overrides this attribute is `-s`.
|
||||
@@ -1,14 +0,0 @@
|
||||
<p>The <code>timeout</code> attribute defines the number of seconds Cloud Foundry allocates for starting your application. </p>
|
||||
|
||||
<p>For example:</p>
|
||||
|
||||
<pre>
|
||||
---
|
||||
...
|
||||
timeout: 80
|
||||
</pre>
|
||||
|
||||
<p>You can increase the timeout length for very large apps that require more time to start. The default timeout is 60 seconds with an upper bound of 180 seconds.</p>
|
||||
<p class="note"><strong>Note</strong>: Administrators can set the upper bound of the <code>maximum_health_check_timeout</code> property to any value. Any changes to Cloud Controller properties in the deployment manifest require running <code>bosh deploy</code>.</p>
|
||||
|
||||
<p>The command line option that overrides the timeout attribute for the shell is <code>-t</code>. Manifest values still apply to applications pushed to the deployment.</p>
|
||||
@@ -1,15 +0,0 @@
|
||||
The `timeout` attribute defines the number of seconds Cloud Foundry allocates for starting your application.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
---
|
||||
...
|
||||
timeout: 80
|
||||
```
|
||||
|
||||
You can increase the timeout length for very large apps that require more time to start. The default timeout is 60 seconds with an upper bound of 180 seconds.
|
||||
|
||||
**Note**: Administrators can set the upper bound of the `maximum_health_check_timeout` property to any value. Any changes to Cloud Controller properties in the deployment manifest require running `bosh deploy`.
|
||||
|
||||
The command line option that overrides the timeout attribute for the shell is `-t`. Manifest values still apply to applications pushed to the deployment.
|
||||
@@ -12,6 +12,7 @@ package org.springframework.ide.vscode.manifest.yaml;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.concourse.ConcourseLanguageServer;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
|
||||
|
||||
@@ -20,7 +21,7 @@ public class ManifestYamlEditorTest {
|
||||
LanguageServerHarness harness;
|
||||
|
||||
@Before public void setup() throws Exception {
|
||||
harness = new LanguageServerHarness(ManifestYamlLanguageServer::new);
|
||||
harness = new LanguageServerHarness(ConcourseLanguageServer::new);
|
||||
harness.intialize(null);
|
||||
}
|
||||
|
||||
@@ -36,7 +37,7 @@ public class ManifestYamlEditorTest {
|
||||
}
|
||||
|
||||
@Test public void reconcileRunsOnDocumentOpenAndChange() throws Exception {
|
||||
LanguageServerHarness harness = new LanguageServerHarness(ManifestYamlLanguageServer::new);
|
||||
LanguageServerHarness harness = new LanguageServerHarness(ConcourseLanguageServer::new);
|
||||
harness.intialize(null);
|
||||
|
||||
Editor editor = harness.newEditor(
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.nio.file.Paths;
|
||||
import org.eclipse.lsp4j.InitializeResult;
|
||||
import org.eclipse.lsp4j.TextDocumentSyncKind;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.concourse.ConcourseLanguageServer;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
|
||||
|
||||
public class ManifestYamlLanguageServerTest {
|
||||
@@ -19,7 +20,7 @@ public class ManifestYamlLanguageServerTest {
|
||||
|
||||
@Test
|
||||
public void createAndInitializeServerWithWorkspace() throws Exception {
|
||||
LanguageServerHarness harness = new LanguageServerHarness(ManifestYamlLanguageServer::new);
|
||||
LanguageServerHarness harness = new LanguageServerHarness(ConcourseLanguageServer::new);
|
||||
File workspaceRoot = getTestResource("/workspace/");
|
||||
assertExpectedInitResult(harness.intialize(workspaceRoot));
|
||||
}
|
||||
@@ -27,7 +28,7 @@ public class ManifestYamlLanguageServerTest {
|
||||
@Test
|
||||
public void createAndInitializeServerWithoutWorkspace() throws Exception {
|
||||
File workspaceRoot = null;
|
||||
LanguageServerHarness harness = new LanguageServerHarness(ManifestYamlLanguageServer::new);
|
||||
LanguageServerHarness harness = new LanguageServerHarness(ConcourseLanguageServer::new);
|
||||
assertExpectedInitResult(harness.intialize(workspaceRoot));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
package org.springframework.ide.vscode.manifest.yaml;
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2015, 2016 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
@@ -9,147 +8,138 @@ package org.springframework.ide.vscode.manifest.yaml;
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.manifest.yaml;
|
||||
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.commons.util.Renderables;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypedProperty;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YBeanType;
|
||||
import org.springframework.ide.vscode.commons.yaml.schema.YTypeFactory.YSeqType;
|
||||
import org.springframework.ide.vscode.manifest.yaml.ManifestYmlSchema;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSet.Builder;
|
||||
|
||||
/**
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class ManifestYmlSchemaTest {
|
||||
|
||||
private static final String[] NESTED_PROP_NAMES = {
|
||||
// "applications",
|
||||
"buildpack",
|
||||
"command",
|
||||
"disk_quota",
|
||||
"domain",
|
||||
"domains",
|
||||
"env",
|
||||
"health-check-type",
|
||||
"host",
|
||||
"hosts",
|
||||
// "inherit",
|
||||
"instances",
|
||||
"memory",
|
||||
"name",
|
||||
"no-hostname",
|
||||
"no-route",
|
||||
"path",
|
||||
"random-route",
|
||||
"services",
|
||||
"stack",
|
||||
"timeout"
|
||||
};
|
||||
|
||||
private static final String[] TOPLEVEL_PROP_NAMES = {
|
||||
"applications",
|
||||
"buildpack",
|
||||
"command",
|
||||
"disk_quota",
|
||||
"domain",
|
||||
"domains",
|
||||
"env",
|
||||
"health-check-type",
|
||||
@Test
|
||||
public void shouldMakeSomeTests() {
|
||||
fail("We should make some tests for this");
|
||||
}
|
||||
//
|
||||
// private static final String[] NESTED_PROP_NAMES = {
|
||||
//// "applications",
|
||||
// "buildpack",
|
||||
// "command",
|
||||
// "disk_quota",
|
||||
// "domain",
|
||||
// "domains",
|
||||
// "env",
|
||||
// "health-check-type",
|
||||
// "host",
|
||||
// "hosts",
|
||||
"inherit",
|
||||
"instances",
|
||||
"memory",
|
||||
//// "inherit",
|
||||
// "instances",
|
||||
// "memory",
|
||||
// "name",
|
||||
"no-hostname",
|
||||
"no-route",
|
||||
"path",
|
||||
"random-route",
|
||||
"services",
|
||||
"stack",
|
||||
"timeout"
|
||||
};
|
||||
|
||||
ManifestYmlSchema schema = new ManifestYmlSchema(null);
|
||||
|
||||
@Test
|
||||
public void toplevelProperties() throws Exception {
|
||||
assertPropNames(schema.getTopLevelType().getProperties(), TOPLEVEL_PROP_NAMES);
|
||||
assertPropNames(schema.getTopLevelType().getPropertiesMap(), TOPLEVEL_PROP_NAMES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedProperties() throws Exception {
|
||||
assertPropNames(getNestedProps(), NESTED_PROP_NAMES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toplevelPropertiesHaveDescriptions() {
|
||||
for (YTypedProperty p : schema.getTopLevelType().getProperties()) {
|
||||
if (!p.getName().equals("applications")) {
|
||||
assertHasRealDescription(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedPropertiesHaveDescriptions() {
|
||||
for (YTypedProperty p : getNestedProps()) {
|
||||
assertHasRealDescription(p);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void assertHasRealDescription(YTypedProperty p) {
|
||||
{
|
||||
String noDescriptionText = Renderables.NO_DESCRIPTION.toHtml();
|
||||
String actual = p.getDescription().toHtml();
|
||||
String msg = "Description missing for '"+p.getName()+"'";
|
||||
assertTrue(msg, StringUtil.hasText(actual));
|
||||
assertFalse(msg, noDescriptionText.equals(actual));
|
||||
}
|
||||
{
|
||||
String noDescriptionText = Renderables.NO_DESCRIPTION.toMarkdown();
|
||||
String actual = p.getDescription().toMarkdown();
|
||||
String msg = "Description missing for '"+p.getName()+"'";
|
||||
assertTrue(msg, StringUtil.hasText(actual));
|
||||
assertFalse(msg, noDescriptionText.equals(actual));
|
||||
}
|
||||
}
|
||||
|
||||
private List<YTypedProperty> getNestedProps() {
|
||||
YSeqType applications = (YSeqType) schema.getTopLevelType().getPropertiesMap().get("applications").getType();
|
||||
YBeanType application = (YBeanType) applications.getDomainType();
|
||||
return application.getProperties();
|
||||
}
|
||||
|
||||
private void assertPropNames(List<YTypedProperty> properties, String... expectedNames) {
|
||||
assertEquals(ImmutableSet.copyOf(expectedNames), getNames(properties));
|
||||
}
|
||||
|
||||
private void assertPropNames(Map<String, YTypedProperty> propertiesMap, String[] toplevelPropNames) {
|
||||
assertEquals(ImmutableSet.copyOf(toplevelPropNames), ImmutableSet.copyOf(propertiesMap.keySet()));
|
||||
}
|
||||
|
||||
private ImmutableSet<String> getNames(Iterable<YTypedProperty> properties) {
|
||||
Builder<String> builder = ImmutableSet.builder();
|
||||
for (YTypedProperty p : properties) {
|
||||
builder.add(p.getName());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
// "no-hostname",
|
||||
// "no-route",
|
||||
// "path",
|
||||
// "random-route",
|
||||
// "services",
|
||||
// "stack",
|
||||
// "timeout"
|
||||
// };
|
||||
//
|
||||
// private static final String[] TOPLEVEL_PROP_NAMES = {
|
||||
// "applications",
|
||||
// "buildpack",
|
||||
// "command",
|
||||
// "disk_quota",
|
||||
// "domain",
|
||||
// "domains",
|
||||
// "env",
|
||||
// "health-check-type",
|
||||
//// "host",
|
||||
//// "hosts",
|
||||
// "inherit",
|
||||
// "instances",
|
||||
// "memory",
|
||||
//// "name",
|
||||
// "no-hostname",
|
||||
// "no-route",
|
||||
// "path",
|
||||
// "random-route",
|
||||
// "services",
|
||||
// "stack",
|
||||
// "timeout"
|
||||
// };
|
||||
//
|
||||
// PipelineYmlSchema schema = new PipelineYmlSchema(null);
|
||||
//
|
||||
// @Test
|
||||
// public void toplevelProperties() throws Exception {
|
||||
// assertPropNames(schema.getTopLevelType().getProperties(DynamicSchemaContext.NULL), TOPLEVEL_PROP_NAMES);
|
||||
// assertPropNames(schema.getTopLevelType().getPropertiesMap(DynamicSchemaContext.NULL), TOPLEVEL_PROP_NAMES);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void nestedProperties() throws Exception {
|
||||
// assertPropNames(getNestedProps(), NESTED_PROP_NAMES);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void toplevelPropertiesHaveDescriptions() {
|
||||
// for (YTypedProperty p : schema.getTopLevelType().getProperties(DynamicSchemaContext.NULL)) {
|
||||
// if (!p.getName().equals("applications")) {
|
||||
// assertHasRealDescription(p);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void nestedPropertiesHaveDescriptions() {
|
||||
// for (YTypedProperty p : getNestedProps()) {
|
||||
// assertHasRealDescription(p);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// private void assertHasRealDescription(YTypedProperty p) {
|
||||
// {
|
||||
// String noDescriptionText = Renderables.NO_DESCRIPTION.toHtml();
|
||||
// String actual = p.getDescription().toHtml();
|
||||
// String msg = "Description missing for '"+p.getName()+"'";
|
||||
// assertTrue(msg, StringUtil.hasText(actual));
|
||||
// assertFalse(msg, noDescriptionText.equals(actual));
|
||||
// }
|
||||
// {
|
||||
// String noDescriptionText = Renderables.NO_DESCRIPTION.toMarkdown();
|
||||
// String actual = p.getDescription().toMarkdown();
|
||||
// String msg = "Description missing for '"+p.getName()+"'";
|
||||
// assertTrue(msg, StringUtil.hasText(actual));
|
||||
// assertFalse(msg, noDescriptionText.equals(actual));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private List<YTypedProperty> getNestedProps() {
|
||||
// YSeqType applications = (YSeqType) schema.getTopLevelType().getPropertiesMap().get("applications").getType();
|
||||
// YBeanType application = (YBeanType) applications.getDomainType();
|
||||
// return application.getProperties();
|
||||
// }
|
||||
//
|
||||
// private void assertPropNames(List<YTypedProperty> properties, String... expectedNames) {
|
||||
// assertEquals(ImmutableSet.copyOf(expectedNames), getNames(properties));
|
||||
// }
|
||||
//
|
||||
// private void assertPropNames(Map<String, YTypedProperty> propertiesMap, String[] toplevelPropNames) {
|
||||
// assertEquals(ImmutableSet.copyOf(toplevelPropNames), ImmutableSet.copyOf(propertiesMap.keySet()));
|
||||
// }
|
||||
//
|
||||
// private ImmutableSet<String> getNames(Iterable<YTypedProperty> properties) {
|
||||
// Builder<String> builder = ImmutableSet.builder();
|
||||
// for (YTypedProperty p : properties) {
|
||||
// builder.add(p.getName());
|
||||
// }
|
||||
// return builder.build();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user