Add basic support for resource-types attribute

Also some cleanups in test code etc.
This commit is contained in:
Kris De Volder
2016-12-14 09:09:41 -08:00
parent fece70fa8d
commit e09c6cb8cd
22 changed files with 348 additions and 601 deletions

View File

@@ -1,9 +1,5 @@
package org.springframework.ide.vscode.concourse;
import java.util.Collection;
import javax.inject.Provider;
import org.eclipse.lsp4j.CompletionOptions;
import org.eclipse.lsp4j.ServerCapabilities;
import org.eclipse.lsp4j.TextDocumentSyncKind;
@@ -23,19 +19,14 @@ import org.springframework.ide.vscode.commons.yaml.completion.YamlAssistContextP
import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngine;
import org.springframework.ide.vscode.commons.yaml.hover.YamlHoverInfoProvider;
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaBasedReconcileEngine;
import org.springframework.ide.vscode.commons.yaml.schema.YValueHint;
import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider;
import org.yaml.snakeyaml.Yaml;
import com.google.common.collect.ImmutableList;
public class ConcourseLanguageServer extends SimpleLanguageServer {
private static final Provider<Collection<YValueHint>> NO_BUILDPACKS = () -> ImmutableList.of();
private Yaml yaml = new Yaml();
private YamlSchema schema = new PipelineYmlSchema(NO_BUILDPACKS);
private YamlSchema schema = new PipelineYmlSchema();
public ConcourseLanguageServer() {

View File

@@ -10,10 +10,6 @@
*******************************************************************************/
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;
@@ -21,7 +17,6 @@ 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;
/**
@@ -34,7 +29,7 @@ public class PipelineYmlSchema implements YamlSchema {
private final YTypeFactory f = new YTypeFactory();
public PipelineYmlSchema(Provider<Collection<YValueHint>> buildpackProvider) {
public PipelineYmlSchema() {
TYPE_UTIL = f.TYPE_UTIL;
// define schema types
@@ -52,20 +47,22 @@ public class PipelineYmlSchema implements YamlSchema {
YAtomicType t_version = f.yatomic("Version");
t_version.addHints("latest", "every");
YAtomicType t_image_type = f.yatomic("ImageType");
t_image_type.addHints("docker_image");
YAtomicType t_resource_type = f.yatomic("ResourceType");
t_resource_type.addHints(
f.hint("archive", "archive - The 'archive' resource can fetch and extract .tar.gz archives."),
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.")
f.hint("semver", "semver - The 'semver' resource can set or bump version numbers."),
f.hint("time", "time - The 'time' resource can start jobs on a schedule or timestamp outputs."),
f.hint("docker-image", "docker-image - The 'docker-image' resource can fetch, build, and push Docker images")
//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
//
@@ -122,9 +119,16 @@ public class PipelineYmlSchema implements YamlSchema {
prop(job, "public", t_boolean);
prop(job, "disable_manual_trigger", t_boolean);
prop(job, "plan", f.yseq(step));
YType resource_type_def = f.ybean("ResourceTypeDef",
f.yprop("name", t_ne_string),
f.yprop("type", t_image_type),
f.yprop("source", t_any)
);
prop(TOPLEVEL_TYPE, "resources", f.yseq(resource));
prop(TOPLEVEL_TYPE, "jobs", f.yseq(job));
prop(TOPLEVEL_TYPE, "resource_types", f.yseq(resource_type_def));
}

View File

@@ -0,0 +1,52 @@
<h1>Additional resource types used by your pipeline</h1>
<p>Each resource in a pipeline has a <code>type</code>. The resource's type determines
what versions are detected, the bits that are fetched when used for a
<a href="get-step.html"><code>get</code></a> step, and the side effect that occurs when used for a
<a href="put-step.html"><code>put</code></a> step.</p><p>Out of the box, Concourse comes with a few resource types to cover common CI
use cases like dealing with Git repositories and S3 buckets.</p><p>Beyond these core types, each pipeline can configure its own custom types by
specifying <code>resource_types</code> at the top level. Each custom resource type is
itself defined as a resource that provides the container image for the custom
resource type (see <a href="implementing-resources.html">Implementing a Resource</a>). You will almost always
be using the
<a href="https://github.com/concourse/docker-image-resource"><code>docker-image</code>
resource type</a> when doing this.</p><p>The following example extends a Concourse pipeline to support use of the
<a href="https://github.com/jtarchie/pullrequest-resource"><code>pull-request</code>
resource type</a> and then uses it within the pipeline:</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">resource_types</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">pull-request</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">type</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</span><span class="t">
</span><span class="t"> </span><span class="py">source</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">jtarchie/pr</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">resources</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">atomy-pr</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">type</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">pull-request</span><span class="t">
</span><span class="t"> </span><span class="py">source</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">repo</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">vito/atomy</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">access_token</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="pi">{</span><span class="pi">{</span><span class="nv"></span><span class="nv">access-token</span><span class="t"></span><span class="pi">}</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="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">atomy-pr-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">atomy-pr</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">atomy-pr</span><span class="t">
</span><span class="t"> </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">path</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">atomy-pr</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">status</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">pending</span><span class="t">
</span><span class="t"> </span><span class="nv">-</span><span class="sp"> </span><span class="py">task</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">unit</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">atomy-pr/ci/unit.yml</span><span class="t">
</span><span class="t"> </span><span class="py">on_success</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">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">atomy-pr</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">path</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">atomy-pr</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">status</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">success</span><span class="t">
</span><span class="t"> </span><span class="py">on_failure</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">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">atomy-pr</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">path</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">atomy-pr</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">status</span><span class="t"></span><span class="pi">:</span><span class="t"></span><span class="t"> </span><span class="nv"></span><span class="nv">failure</span></pre></div><p>Custom resource types can override the core resource types, and can be defined
in terms of each other. Also, a custom resource type can use the core type that
it's overriding. This is useful if you want to e.g. provide your own custom
<code>docker-image</code> resource, by overriding the core one (and using it one last
time for the override itself), and then using it for all other custom resource
types.</p>

View File

@@ -12,10 +12,10 @@ import org.junit.Test;
import org.springframework.ide.vscode.concourse.ConcourseLanguageServer;
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
public class ManifestYamlLanguageServerTest {
public class ConcourseLanguageServerTest {
public static File getTestResource(String name) throws URISyntaxException {
return Paths.get(ManifestYamlLanguageServerTest.class.getResource(name).toURI()).toFile();
return Paths.get(ConcourseLanguageServerTest.class.getResource(name).toURI()).toFile();
}
@Test
@@ -32,34 +32,6 @@ public class ManifestYamlLanguageServerTest {
assertExpectedInitResult(harness.intialize(workspaceRoot));
}
// @Test public void completions() throws Exception {
// LanguageServerHarness harness = new LanguageServerHarness(ManifestYamlLanguageServer::new);
//
// File workspaceRoot = getTestResource("/workspace/");
// assertExpectedInitResult(harness.intialize(workspaceRoot));
//
// TextDocumentInfo doc = harness.openDocument(getTestResource("/workspace/testfile.yml"));
//
// CompletionList completions = harness.getCompletions(doc, doc.positionOf("foo"));
// assertThat(completions.isIncomplete()).isFalse();
// assertThat(completions.getItems())
// .extracting(CompletionItem::getLabel)
// .containsExactly("TypeScript", "JavaScript");
//
// List<CompletionItem> resolved = harness.resolveCompletions(completions);
// assertThat(resolved)
// .extracting(CompletionItem::getLabel)
// .containsExactly("TypeScript", "JavaScript");
//
// assertThat(resolved)
// .extracting(CompletionItem::getDetail)
// .containsExactly("TypeScript details", "JavaScript details");
//
// assertThat(resolved)
// .extracting(CompletionItem::getDocumentation)
// .containsExactly("TypeScript docs", "JavaScript docs");
// }
private void assertExpectedInitResult(InitializeResult initResult) {
assertThat(initResult.getCapabilities().getCompletionProvider().getResolveProvider()).isFalse();
assertThat(initResult.getCapabilities().getTextDocumentSync()).isEqualTo(TextDocumentSyncKind.Incremental);

View File

@@ -1,493 +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 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;
public class ManifestYamlEditorTest {
LanguageServerHarness harness;
@Before public void setup() throws Exception {
harness = new LanguageServerHarness(ConcourseLanguageServer::new);
harness.intialize(null);
}
@Test public void testReconcileCatchesParseError() throws Exception {
Editor editor = harness.newEditor(
"somemap: val\n"+
"- sequence"
);
editor.assertProblems(
"-|expected <block end>"
);
}
@Test public void reconcileRunsOnDocumentOpenAndChange() throws Exception {
LanguageServerHarness harness = new LanguageServerHarness(ConcourseLanguageServer::new);
harness.intialize(null);
Editor editor = harness.newEditor(
"somemap: val\n"+
"- sequence"
);
editor.assertProblems(
"-|expected <block end>"
);
editor.setText(
"- sequence\n" +
"zomemap: val"
);
editor.assertProblems(
"z|expected <block end>"
);
}
@Test
public void reconcileMisSpelledPropertyNames() throws Exception {
Editor editor;
editor = harness.newEditor(
"memory: 1G\n" +
"aplications:\n" +
" - buildpack: zbuildpack\n" +
" domain: zdomain\n" +
" name: foo"
);
editor.assertProblems("aplications|Unknown property");
//mispelled or not allowed at toplevel
editor = harness.newEditor(
"name: foo\n" +
"buildpeck: yahah\n" +
"memory: 1G\n" +
"memori: 1G\n"
);
editor.assertProblems(
"name|Unknown property",
"buildpeck|Unknown property",
"memori|Unknown property"
);
//mispelled or not allowed as nested
editor = harness.newEditor(
"applications:\n" +
"- name: fine\n" +
" buildpeck: yahah\n" +
" memory: 1G\n" +
" memori: 1G\n" +
" applications: bad\n"
);
editor.assertProblems(
"buildpeck|Unknown property",
"memori|Unknown property",
"applications|Unknown property"
);
}
@Test
public void reconcileStructuralProblems() throws Exception {
Editor editor;
//forgot the 'applications:' heading
editor = harness.newEditor(
"- name: foo"
);
editor.assertProblems(
"- name: foo|Expecting a 'Map' but found a 'Sequence'"
);
//forgot to make the '-' after applications
editor = harness.newEditor(
"applications:\n" +
" name: foo"
);
editor.assertProblems(
"name: foo|Expecting a 'Sequence' but found a 'Map'"
);
//Using a 'composite' element where a scalar type is expected
editor = harness.newEditor(
"memory:\n"+
"- bad sequence\n" +
"buildpack:\n" +
" bad: map\n"
);
editor.assertProblems(
"- bad sequence|Expecting a 'Memory' but found a 'Sequence'",
"bad: map|Expecting a 'Buildpack' but found a 'Map'"
);
}
@Test
public void reconcileSimpleTypes() throws Exception {
Editor editor;
//check for 'format' errors:
editor = harness.newEditor(
"applications:\n" +
"- name: foo\n" +
" instances: not a number\n" +
" no-route: notBool\n"+
" memory: 1024\n" +
" disk_quota: 2048\n" +
" health-check-type: unhealthy"
);
editor.assertProblems(
"not a number|Positive Integer",
"notBool|boolean",
"1024|Memory",
"2048|Memory",
"unhealthy|Health Check Type"
);
//check for 'range' errors:
editor = harness.newEditor(
"applications:\n" +
"- name: foo\n" +
" instances: -3\n" +
" memory: -1024M\n" +
" disk_quota: -2048M\n"
);
editor.assertProblems(
"-3|Positive Integer",
"-1024M|Memory",
"-2048M|Memory"
);
//check that correct values are indeed accepted
editor = harness.newEditor(
"applications:\n" +
"- name: foo\n" +
" instances: 2\n" +
" no-route: true\n"+
" memory: 1024M\n" +
" disk_quota: 2048MB\n"
);
editor.assertProblems(/*none*/);
//check that correct values are indeed accepted
editor = harness.newEditor(
"applications:\n" +
"- name: foo\n" +
" instances: 2\n" +
" no-route: false\n" +
" memory: 1024m\n" +
" disk_quota: 2048mb\n"
);
editor.assertProblems(/*none*/);
editor = harness.newEditor(
"applications:\n" +
"- name: foo\n" +
" instances: 2\n" +
" memory: 1G\n" +
" disk_quota: 2g\n"
);
editor.assertProblems(/*none*/);
}
@Test
public void noListIndent() throws Exception {
Editor editor;
editor = harness.newEditor("appl<*>");
editor.assertCompletions(
"applications:\n"+
"- <*>"
);
}
@Test
public void toplevelCompletions() throws Exception {
Editor editor;
editor = harness.newEditor("<*>");
editor.assertCompletions(
"applications:\n"+
"- <*>",
// ---------------
"buildpack: <*>",
// ---------------
"command: <*>",
// ---------------
"disk_quota: <*>",
// ---------------
"domain: <*>",
// ---------------
"domains:\n"+
"- <*>",
// ---------------
"env:\n"+
" <*>",
// ---------------
"health-check-type: <*>",
// ---------------
// "host: <*>",
// ---------------
// "hosts: \n"+
// " - <*>",
// ---------------
"inherit: <*>",
// ---------------
"instances: <*>",
// ---------------
"memory: <*>",
// ---------------
// "name: <*>",
// ---------------
"no-hostname: <*>",
// ---------------
"no-route: <*>",
// ---------------
"path: <*>",
// ---------------
"random-route: <*>",
// ---------------
"services:\n"+
"- <*>",
// ---------------
"stack: <*>",
// ---------------
"timeout: <*>"
);
editor = harness.newEditor("ranro<*>");
editor.assertCompletions(
"random-route: <*>"
);
}
@Test
public void nestedCompletions() throws Exception {
Editor editor;
editor = harness.newEditor(
"applications:\n" +
"- <*>"
);
editor.assertCompletions(
// ---------------
"applications:\n" +
"- buildpack: <*>",
// ---------------
"applications:\n" +
"- command: <*>",
// ---------------
"applications:\n" +
"- disk_quota: <*>",
// ---------------
"applications:\n" +
"- domain: <*>",
// ---------------
"applications:\n" +
"- domains:\n"+
" - <*>",
// ---------------
"applications:\n" +
"- env:\n"+
" <*>",
// ---------------
"applications:\n" +
"- health-check-type: <*>",
// ---------------
"applications:\n" +
"- host: <*>",
// ---------------
"applications:\n" +
"- hosts:\n"+
" - <*>",
// ---------------
"applications:\n" +
"- instances: <*>",
// ---------------
"applications:\n" +
"- memory: <*>",
// ---------------
"applications:\n" +
"- name: <*>",
// ---------------
"applications:\n" +
"- no-hostname: <*>",
// ---------------
"applications:\n" +
"- no-route: <*>",
// ---------------
"applications:\n" +
"- path: <*>",
// ---------------
"applications:\n" +
"- random-route: <*>",
// ---------------
"applications:\n" +
"- services:\n"+
" - <*>",
// ---------------
"applications:\n" +
"- stack: <*>",
// ---------------
"applications:\n" +
"- timeout: <*>"
);
}
@Test
public void completionDetailsAndDocs() throws Exception {
Editor editor = harness.newEditor(
"applications:\n" +
"- build<*>"
);
editor.assertCompletionDetails("buildpack", "Buildpack", "If your application requires a custom buildpack");
}
@Test
public void valueCompletions() throws Exception {
assertCompletions("disk_quota: <*>",
"disk_quota: 1024M<*>",
"disk_quota: 256M<*>",
"disk_quota: 512M<*>"
);
assertCompletions("memory: <*>",
"memory: 1024M<*>",
"memory: 256M<*>",
"memory: 512M<*>"
);
assertCompletions("no-hostname: <*>",
"no-hostname: false<*>",
"no-hostname: true<*>"
);
assertCompletions("no-route: <*>",
"no-route: false<*>",
"no-route: true<*>"
);
assertCompletions("random-route: <*>",
"random-route: false<*>",
"random-route: true<*>"
);
assertCompletions("health-check-type: <*>",
"health-check-type: none<*>",
"health-check-type: port<*>"
);
}
@Test
public void hoverInfos() throws Exception {
Editor editor = harness.newEditor(
"memory: 1G\n" +
"#comment\n" +
"inherit: base-manifest.yml\n"+
"applications:\n" +
"- buildpack: zbuildpack\n" +
" domain: zdomain\n" +
" name: foo\n" +
" command: java main.java\n" +
" disk_quota: 1024M\n" +
" domains:\n" +
" - pivotal.io\n" +
" - otherdomain.org\n" +
" env:\n" +
" RAILS_ENV: production\n" +
" RACK_ENV: production\n" +
" host: apppage\n" +
" hosts:\n" +
" - apppage2\n" +
" - appage3\n" +
" instances: 2\n" +
" no-hostname: true\n" +
" no-route: true\n" +
" path: somepath/app.jar\n" +
" random-route: true\n" +
" services:\n" +
" - instance_ABC\n" +
" - instance_XYZ\n" +
" stack: cflinuxfs2\n" +
" timeout: 80\n" +
" health-check-type: none\n"
);
editor.assertIsHoverRegion("memory");
editor.assertIsHoverRegion("inherit");
editor.assertIsHoverRegion("applications");
editor.assertIsHoverRegion("buildpack");
editor.assertIsHoverRegion("domain");
editor.assertIsHoverRegion("name");
editor.assertIsHoverRegion("command");
editor.assertIsHoverRegion("disk_quota");
editor.assertIsHoverRegion("domains");
editor.assertIsHoverRegion("env");
editor.assertIsHoverRegion("host");
editor.assertIsHoverRegion("hosts");
editor.assertIsHoverRegion("instances");
editor.assertIsHoverRegion("no-hostname");
editor.assertIsHoverRegion("no-route");
editor.assertIsHoverRegion("path");
editor.assertIsHoverRegion("random-route");
editor.assertIsHoverRegion("services");
editor.assertIsHoverRegion("stack");
editor.assertIsHoverRegion("timeout");
editor.assertIsHoverRegion("health-check-type");
editor.assertHoverContains("memory", "Use the `memory` attribute to specify the memory limit");
editor.assertHoverContains("1G", "Use the `memory` attribute to specify the memory limit");
editor.assertHoverContains("inherit", "For example, every child of a parent manifest called `base-manifest.yml` begins like this");
editor.assertHoverContains("buildpack", "use the `buildpack` attribute to specify its URL or name");
editor.assertHoverContains("name", "The `name` attribute is the only required attribute for an application in a manifest file");
editor.assertHoverContains("command", "On the command line, use the `-c` option to specify the custom start command as the following example shows");
editor.assertHoverContains("disk_quota", "Use the `disk_quota` attribute to allocate the disk space for your app instance");
editor.assertHoverContains("domain", "You can use the `domain` attribute when you want your application to be served");
editor.assertHoverContains("domains", "Use the `domains` attribute to provide multiple domains");
editor.assertHoverContains("env", "The `env` block consists of a heading, then one or more environment variable/value pairs");
editor.assertHoverContains("host", "Use the `host` attribute to provide a hostname, or subdomain, in the form of a string");
editor.assertHoverContains("hosts", "Use the `hosts` attribute to provide multiple hostnames, or subdomains");
editor.assertHoverContains("instances", "Use the `instances` attribute to specify the number of app instances that you want to start upon push");
editor.assertHoverContains("no-hostname", "By default, if you do not provide a hostname, the URL for the app takes the form of `APP-NAME.DOMAIN`");
editor.assertHoverContains("no-route", "You can use the `no-route` attribute with a value of `true` to prevent a route from being created for your application");
editor.assertHoverContains("path", "You can use the `path` attribute to tell Cloud Foundry where to find your application");
editor.assertHoverContains("random-route", "Use the `random-route` attribute to create a URL that includes the app name and random words");
editor.assertHoverContains("services", "The `services` block consists of a heading, then one or more service instance names");
editor.assertHoverContains("stack", "Use the `stack` attribute to specify which stack to deploy your application to.");
editor.assertHoverContains("timeout", "The `timeout` attribute defines the number of seconds Cloud Foundry allocates for starting your application");
editor.assertHoverContains("health-check-type", "Use the `health-check-type` attribute to");
}
@Test
public void noHoverInfos() throws Exception {
Editor editor = harness.newEditor(
"#comment\n" +
"applications:\n" +
"- buildpack: zbuildpack\n" +
" name: foo\n" +
" domains:\n" +
" - pivotal.io\n" +
" - otherdomain.org\n"
);
editor.assertNoHover("comment");
// May fail in the future if hover support is added, but if hover support is added in the future,
// it is expected that these should start to fail, as right now they have no hover
editor.assertNoHover("pivotal.io");
editor.assertNoHover("otherdomain.org");
}
//////////////////////////////////////////////////////////////////////////////
private void assertCompletions(String textBefore, String... textAfter) throws Exception {
Editor editor = harness.newEditor(textBefore);
editor.assertCompletions(textAfter);
}
}

View File

@@ -0,0 +1,258 @@
/*******************************************************************************
* 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.io.InputStream;
import org.junit.Before;
import org.junit.Test;
import org.springframework.ide.vscode.commons.util.IOUtil;
import org.springframework.ide.vscode.concourse.ConcourseLanguageServer;
import org.springframework.ide.vscode.languageserver.testharness.Editor;
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
public class PipelineYamlEditorTest {
LanguageServerHarness harness;
@Before public void setup() throws Exception {
harness = new LanguageServerHarness(ConcourseLanguageServer::new);
harness.intialize(null);
}
@Test public void testReconcileCatchesParseError() throws Exception {
Editor editor = harness.newEditor(
"somemap: val\n"+
"- sequence"
);
editor.assertProblems(
"-|expected <block end>"
);
}
@Test public void reconcileRunsOnDocumentOpenAndChange() throws Exception {
LanguageServerHarness harness = new LanguageServerHarness(ConcourseLanguageServer::new);
harness.intialize(null);
Editor editor = harness.newEditor(
"somemap: val\n"+
"- sequence"
);
editor.assertProblems(
"-|expected <block end>"
);
editor.setText(
"- sequence\n" +
"zomemap: val"
);
editor.assertProblems(
"z|expected <block end>"
);
}
@Test
public void reconcileMisSpelledPropertyNames() throws Exception {
Editor editor;
editor = harness.newEditor(
"resorces:\n" +
"- name: git\n" +
" type: git\n"
);
editor.assertProblems("resorces|Unknown property");
}
@Test
public void reconcileAcceptsSensiblePipelineFile() throws Exception {
Editor editor;
editor = harness.newEditor(
getClasspathResourceText("workspace/pipeline.yml")
);
editor.assertProblems(/*NONE*/);;
}
private String getClasspathResourceText(String resourceName) throws Exception {
InputStream stream = PipelineYamlEditorTest.class.getClassLoader().getResourceAsStream(resourceName);
return IOUtil.toString(stream);
}
@Test
public void reconcileStructuralProblems() throws Exception {
Editor editor;
//resources should be a sequence not a map, even if there's only one entry
editor = harness.newEditor(
"resources:\n" +
" name: git\n" +
" type: git\n"
);
editor.assertProblems(
"name: git\n type: git|Expecting a 'Sequence' but found a 'Map'"
);
//TODO: Add more test cases for structural problem?
}
@Test
public void reconcileSimpleTypes() throws Exception {
Editor editor;
//check for 'format' errors:
editor = harness.newEditor(
"jobs:\n" +
"- name: foo\n" +
" serial: boohoo\n" +
" max_in_flight: 0\n" +
" plan:\n" +
" - get: git\n" +
" trigger: yohoho"
);
editor.assertProblems(
"boohoo|boolean",
"0|Positive Integer",
"yohoho|boolean"
);
//check that correct values are indeed accepted
editor = harness.newEditor(
"jobs:\n" +
"- name: foo\n" +
" serial: true\n" +
" max_in_flight: 2\n" +
" plan:\n" +
" - get: git\n" +
" trigger: true"
);
editor.assertProblems(/*none*/);
}
@Test
public void noListIndent() throws Exception {
Editor editor;
editor = harness.newEditor("jo<*>");
editor.assertCompletions(
"jobs:\n"+
"- <*>"
);
}
@Test
public void toplevelCompletions() throws Exception {
Editor editor;
editor = harness.newEditor("<*>");
editor.assertCompletions(
"resources:\n"+
"- <*>",
// ---------------
"resource-types:\n" +
"- <*>",
// ---------------
"jobs:\n" +
"- <*>"
);
editor = harness.newEditor("ranro<*>");
editor.assertCompletions(
"random-route: <*>"
);
}
@Test
public void completionDetailsAndDocs() throws Exception {
Editor editor = harness.newEditor(
"applications:\n" +
"- build<*>"
);
editor.assertCompletionDetails("buildpack", "Buildpack", "If your application requires a custom buildpack");
}
@Test
public void valueCompletions() throws Exception {
assertCompletions(
"resources:\n" +
"- type: <*>"
, //=>
"resources:\n" +
"- type: archive<*>",
"resources:\n" +
"- type: docker-image<*>",
"resources:\n" +
"- type: git<*>",
"resources:\n" +
"- type: s3<*>",
"resources:\n" +
"- type: semver<*>",
"resources:\n" +
"- type: time<*>"
);
assertCompletions(
"jobs:\n" +
"- name: foo\n" +
" serial: <*>"
, // =>
"jobs:\n" +
"- name: foo\n" +
" serial: false<*>"
, // --
"jobs:\n" +
"- name: foo\n" +
" serial: true<*>"
);
}
@Test
public void topLevelHoverInfos() throws Exception {
Editor editor = harness.newEditor(
"resource_types:\n" +
"- name: s3-multi\n" +
" type: docker-image\n" +
" source:\n" +
" repository: kdvolder/s3-resource-simple\n" +
"resources:\n" +
"- name: docker-git\n" +
" type: git\n" +
" source:\n" +
" uri: git@github.com:spring-projects/sts4.git\n" +
" branch: {{branch}}\n" +
" username: kdvolder\n" +
" private_key: {{rsa_id}}\n" +
" paths:\n" +
" - concourse/docker\n" +
"jobs:\n" +
"- name: build-docker-image\n" +
" serial: true\n" +
" plan:\n" +
" - get: docker-git\n" +
" trigger: true\n" +
" - put: docker-image\n" +
" params:\n" +
" build: docker-git/concourse/docker\n" +
" get_params: \n" +
" skip_download: true\n"
);
editor.assertHoverContains("resource_types", "each pipeline can configure its own custom types by specifying `resource_types` at the top level.");
editor.assertHoverContains("resources", "A resource is any entity that can be checked for new versions");
editor.assertHoverContains("jobs", "At a high level, a job describes some actions to perform");
}
//////////////////////////////////////////////////////////////////////////////
private void assertCompletions(String textBefore, String... textAfter) throws Exception {
Editor editor = harness.newEditor(textBefore);
editor.assertCompletions(textAfter);
}
}

View File

@@ -13,11 +13,12 @@ package org.springframework.ide.vscode.manifest.yaml;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.springframework.ide.vscode.concourse.PipelineYmlSchema;
/**
* @author Kris De Volder
*/
public class ManifestYmlSchemaTest {
public class PipelineYmlSchemaTest {
@Test
public void shouldMakeSomeTests() {
@@ -48,31 +49,14 @@ public class ManifestYmlSchemaTest {
// "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);
private static final String[] TOPLEVEL_PROP_NAMES = {
"resources",
"jobs",
"resource-types"
//groups
};
PipelineYmlSchema schema = new PipelineYmlSchema();
//
// @Test
// public void toplevelProperties() throws Exception {

View File

@@ -1,5 +0,0 @@
#Comment
applications:
- name: foo
buildpack: something

View File

@@ -0,0 +1,116 @@
##########################################################
resource_types:
- name: s3-multi
type: docker-image
source:
repository: kdvolder/s3-resource-simple
- name: slack-notification
type: docker-image
source:
repository: cfcommunity/slack-notification-resource
tag: latest
#########################################################
resources:
- name: docker-git
type: git
source:
uri: git@github.com:spring-projects/sts4.git
branch: {{branch}}
username: kdvolder
private_key: {{rsa_id}}
paths:
- concourse/docker
- name: sts4
type: git
source:
uri: git@github.com:spring-projects/sts4.git
branch: {{branch}}
private_key: {{rsa_id}}
- name: s3-boot-properties-vsix
type: s3
source:
bucket: {{s3_bucket}}
access_key_id: {{s3_accesskey}}
secret_access_key: {{s3_secretkey}}
region_name: {{s3_region}}
regexp: sts4/vscode-extensions/vscode-boot-properties-(.*).vsix
- name: s3-manifest-yaml-vsix
type: s3
source:
bucket: {{s3_bucket}}
access_key_id: {{s3_accesskey}}
secret_access_key: {{s3_secretkey}}
region_name: {{s3_region}}
regexp: sts4/vscode-extensions/vscode-manifest-yaml-(.*).vsix
- name: website
type: s3-multi
source:
bucket: {{s3_prod_bucket}}
access_key_id: {{s3_prod_accesskey}}
secret_access_key: {{s3_prod_secretkey}}
region_name: {{s3_region}}
path: snapshot/STS4/vscode-extensions
options:
- "--acl public-read"
- name: slack-notification
type: slack-notification
source:
url: https://hooks.slack.com/services/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
- name: docker-image
type: docker-image
source:
username: {{docker_hub_username}}
email: {{docker_hub_email}}
password: {{docker_hub_password}}
repository: kdvolder/sts4-build-env
########################################################################################
jobs:
- name: build-docker-image
serial: true
plan:
- get: docker-git
trigger: true
- put: docker-image
params:
build: docker-git/concourse/docker
get_params:
skip_download: true
- name: build-vsix
plan:
- get: sts4
trigger: true
- task: build-vscode-extensions
file: sts4/concourse/tasks/build-vscode-extensions.yml
on_success:
aggregate:
- put: s3-manifest-yaml-vsix
params:
file: vsix-files/vscode-manifest-yaml-*.vsix
acl: public-read
- put: s3-boot-properties-vsix
params:
file: vsix-files/vscode-boot-properties-*.vsix
acl: public-read
on_failure:
put: slack-notification
params:
channel: "@kdvolder"
text: |
Concourse ${BUILD_PIPELINE_NAME}/${BUILD_JOB_NAME}/${BUILD_NAME} has failed!
- name: build-website
plan:
- aggregate:
- get: sts4
- get: s3-manifest-yaml-vsix
passed:
- build-vsix
trigger: true
- get: s3-boot-properties-vsix
passed:
- build-vsix
trigger: true
- task: build-website
file: sts4/concourse/tasks/build-website.yml
- put: website
params:
path: website

View File

@@ -0,0 +1,10 @@
#!/bin/bash
set -e
workdir=`pwd`
cd sts4/vscode-extensions
./build-all.sh
cd $workdir
cp `find sts4/vscode-extensions -name "*.vsix"` vsix-files

View File

@@ -0,0 +1,11 @@
inputs:
- name: sts4
outputs:
- name: vsix-files
platform: linux
image_resource:
type: docker-image
source:
repository: kdvolder/sts4-build-env
run:
path: "sts4/concourse/tasks/build-vscode-extensions.sh"

View File

@@ -0,0 +1,43 @@
#!/bin/bash
set -e
workdir=`pwd`
sources=$workdir/sts4/eclipse-distribution/common/html
target=$workdir/website
#cp -r "${sources}/stylesheet.css" "$target"
#cp -r ${sources}/*.js "$target"
#cp s3-manifest-yaml-vsix/*.vsix "$target"
#cp s3-boot-properties-vsix/*.vsix "$target"
export vscode_manifest_yaml=$(basename s3-manifest-yaml-vsix/*.vsix)
echo "vscode_manifest_yaml=$vscode_manifest_yaml"
export vscode_boot_properties=$(basename s3-boot-properties-vsix/*.vsix)
echo "vscode_boot_properties=$vscode_boot_properties"
envsubst > "$target/vscode-extensions-snippet.html" << XXXXXX
<ul>
<li>Spring Boot Property Language Server:
<a href="http://s3-test.spring.io/sts4/vscode-extensions/${vscode_boot_properties}">${vscode_boot_properties}</a>
</li>
<li>Cloud Foundry Manifest Language Server:
<a href="http://s3-test.spring.io/sts4/vscode-extensions/${vscode_manifest_yaml}">${vscode_manifest_yaml}</a>
</li>
</ul>
XXXXXX
export vscode_snippet=`cat "$target/vscode-extensions-snippet.html"`
envsubst > "$target/vscode-extensions.html" << XXXXXX
<!DOCTYPE html>
<html>
<body>
<h1>STS4 Vscode Extensions</h1>
$vscode_snippet
</body>
</html>
XXXXXX
cat $target/vscode-extensions.html

View File

@@ -0,0 +1,13 @@
inputs:
- name: sts4
- name: s3-manifest-yaml-vsix
- name: s3-boot-properties-vsix
outputs:
- name: website
platform: linux
image_resource:
type: docker-image
source:
repository: kdvolder/sts4-build-env
run:
path: "sts4/concourse/tasks/build-website.sh"