Dynamic CA for github repo uris in concourse resource definitions

This commit is contained in:
Kris De Volder
2017-12-22 17:14:27 -08:00
parent 6c2a189712
commit 1fb0a6acc6
15 changed files with 442 additions and 26 deletions

View File

@@ -37,7 +37,7 @@ public abstract class ScoreableProposal implements ICompletionProposal {
if (p1 instanceof ScoreableProposal && p2 instanceof ScoreableProposal) {
double s1 = ((ScoreableProposal)p1).getScore();
double s2 = ((ScoreableProposal)p2).getScore();
if (Math.abs(s1-s2)<1E-5) {
if (s1==s2) {
String name1 = ((ScoreableProposal)p1).getLabel();
String name2 = ((ScoreableProposal)p2).getLabel();
return name1.compareTo(name2);
@@ -45,7 +45,13 @@ public abstract class ScoreableProposal implements ICompletionProposal {
return Double.compare(s2, s1);
}
}
return 0;
if (p1 instanceof ScoreableProposal) {
return -1;
}
if (p2 instanceof ScoreableProposal) {
return +1;
}
return p1.getLabel().compareTo(p2.getLabel());
}
};
public abstract double getBaseScore();

View File

@@ -8,11 +8,10 @@
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.handlers;
package org.springframework.ide.vscode.commons.languageserver.completion;
import org.eclipse.lsp4j.CompletionItemKind;
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
import org.springframework.ide.vscode.commons.util.Renderable;
import org.springframework.ide.vscode.commons.util.text.IDocument;
@@ -20,13 +19,13 @@ public class SimpleCompletionFactory {
public static class SimpleProposal implements ICompletionProposal{
private DocumentEdits edits;
private CompletionItemKind kind;
private Renderable info;
private String detail;
private String label;
public SimpleProposal(DocumentEdits edits, CompletionItemKind kind, Renderable info,
String detail, String label) {
this.edits = edits;
@@ -66,9 +65,17 @@ public class SimpleCompletionFactory {
return detail;
}
@Override
public String toString() {
return "SimpleProposal("+label+")";
}
}
public static SimpleProposal simpleProposal(DocumentRegion query, CompletionItemKind kind, String value, String detail, Renderable info) {
return simpleProposal(query.getDocument(), query.getEnd(), query.toString(), kind, value, detail, info);
}
public static SimpleProposal simpleProposal(IDocument doc, int offset, String query, CompletionItemKind kind, String value, String detail, Renderable info) {
DocumentEdits edits = new DocumentEdits(doc);
edits.replace(offset-query.length(), offset, value);

View File

@@ -181,6 +181,10 @@ public class DocumentRegion implements CharSequence, IRegion {
return -1;
}
public int indexOf(char c) {
return indexOf(c, 0);
}
public DocumentRegion[] split(char c) {
List<DocumentRegion> pieces = new ArrayList<>();
int start = 0;
@@ -338,5 +342,4 @@ public class DocumentRegion implements CharSequence, IRegion {
return getStart();
}
}

View File

@@ -24,7 +24,7 @@ public class FuzzyMatcher {
* 'score' when it does. The higher the score, the better the match is considered to
* be.
*/
public static double matchScore(String pattern, String data) {
public static double matchScore(CharSequence pattern, String data) {
int ppos = 0; //pos of next char in pattern to look for
int dpos = 0; //pos of next char in data not yet matched
int gaps = 0; //number of 'gaps' in the match. A gap is any non-empty run of consecutive characters in the data that are not used by the match
@@ -61,7 +61,7 @@ public class FuzzyMatcher {
return score(gaps, skips, pattern);
}
private static double score(int gaps, int skips, String pattern) {
private static double score(int gaps, int skips, CharSequence pattern) {
if (gaps==0) {
//gaps == 0 means a prefix match, ignore 'skips' at end of String and just sort
// alphabetic (see STS-4049)

View File

@@ -55,21 +55,25 @@ public abstract class AbstractYamlAssistContext implements YamlAssistContext {
if (keyNode.isInValue(offset)) {
int valueStart = keyNode.getColonOffset()+1;
int valueEnd = keyNode.getNodeEnd(); // assumes we only look at the current line, good enough for now
return new DocumentRegion(doc.getDocument(), valueStart, valueEnd);
DocumentRegion region = new DocumentRegion(doc.getDocument(), valueStart, valueEnd);
if (region.startsWith(" ")) {
region = region.subSequence(1);
}
return region;
}
}
return null; // TODO Reaching here might mean support for calling the custom assistant isn't
// implemented for this kind of context yet. It will have to be expanded upon
// as the need for it arises in real use-cases.
}
private static PrefixFinder prefixfinder = new PrefixFinder() {
@Override
protected boolean isPrefixChar(char c) {
return !Character.isWhitespace(c);
}
};
protected String getPrefix(YamlDocument doc, SNode node, int offset) {
//For value completions... in general we would like to determine the whole text
// corresponding to the value, so a simplistic backwards scan isn't good enough.

View File

@@ -37,7 +37,19 @@
<artifactId>commons-yaml</artifactId>
<version>${dependencies.version}</version>
</dependency>
<!-- github client -->
<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>github-api</artifactId>
<version>1.90</version>
</dependency>
<!-- Test harness -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>${mockito-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>language-server-test-harness</artifactId>

View File

@@ -40,6 +40,7 @@ import org.springframework.ide.vscode.commons.yaml.schema.YType;
import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
import org.springframework.ide.vscode.commons.yaml.snippet.SchemaBasedSnippetGenerator;
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider;
import org.springframework.ide.vscode.concourse.github.GithubInfoProvider;
import com.google.common.collect.ImmutableList;
@@ -90,10 +91,10 @@ public class ConcourseLanguageServer extends SimpleLanguageServer {
}
}
public ConcourseLanguageServer(YamlCompletionEngineOptions completionOptions) {
public ConcourseLanguageServer(YamlCompletionEngineOptions completionOptions, GithubInfoProvider github) {
super("vscode-concourse");
this.COMPLETION_OPTIONS = completionOptions;
PipelineYmlSchema pipelineSchema = new PipelineYmlSchema(models);
PipelineYmlSchema pipelineSchema = new PipelineYmlSchema(models, github);
enableSnippets(pipelineSchema, true);
this.yamlQuickfixes = new YamlQuickfixes(getQuickfixRegistry(), documents, structureProvider);

View File

@@ -16,13 +16,19 @@ import java.io.IOException;
import org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp;
import org.springframework.ide.vscode.commons.util.LogRedirect;
import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions;
import org.springframework.ide.vscode.concourse.github.DefaultGithubInfoProvider;
import org.springframework.ide.vscode.concourse.github.GithubInfoProvider;
import static org.springframework.ide.vscode.commons.languageserver.LaunguageServerApp.STANDALONE_STARTUP;
public class Main {
private static final YamlCompletionEngineOptions OPTIONS = YamlCompletionEngineOptions.DEFAULT;
public static void main(String[] args) throws IOException, InterruptedException {
String serverName = "concourse-language-server";
LogRedirect.redirectToFile(serverName);
LaunguageServerApp.start(serverName, () -> new ConcourseLanguageServer(OPTIONS));
public static void main(String[] args) throws IOException, InterruptedException {
String serverName = "concourse-language-server";
if (!Boolean.getBoolean(STANDALONE_STARTUP)) {
LogRedirect.redirectToFile(serverName);
}
LaunguageServerApp.start(serverName, () -> new ConcourseLanguageServer(OPTIONS, new DefaultGithubInfoProvider()));
}
}

View File

@@ -47,6 +47,8 @@ import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema;
import org.springframework.ide.vscode.commons.yaml.schema.constraints.Constraints;
import org.springframework.ide.vscode.concourse.ConcourseModel.ResourceModel;
import org.springframework.ide.vscode.concourse.ConcourseModel.StepModel;
import org.springframework.ide.vscode.concourse.github.GithubInfoProvider;
import org.springframework.ide.vscode.concourse.github.GithubRepoContentAssistant;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
@@ -160,7 +162,10 @@ public class PipelineYmlSchema implements YamlSchema {
private List<YType> definitionTypes = new ArrayList<>();
public PipelineYmlSchema(ConcourseModel models) {
private GithubInfoProvider github;
public PipelineYmlSchema(ConcourseModel models, GithubInfoProvider github) {
this.github = github;
this.models = models;
this.asts = models.getAstCache();
models.setResourceTypeRegistry(resourceTypes);
@@ -417,8 +422,11 @@ public class PipelineYmlSchema implements YamlSchema {
private void initializeDefaultResourceTypes() {
// git :
{
AbstractType t_git_repo_uri = f.yatomic("GitRepoUri");
t_git_repo_uri.setCustomContentAssistant(new GithubRepoContentAssistant(github));
AbstractType source = f.ybean("GitSource");
addProp(source, "uri", t_ne_string).isPrimary(true);
addProp(source, "uri", t_git_repo_uri).isPrimary(true);
addProp(source, "branch", t_ne_string); //It's more complicated than that! Its only required in 'put' step. So we'll check this as a contrain in put steps!
addProp(source, "private_key", t_ne_string);
addProp(source, "username", t_ne_string);

View File

@@ -0,0 +1,120 @@
/*******************************************************************************
* Copyright (c) 2017 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.github;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import org.kohsuke.github.GHPerson;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;
import org.springframework.ide.vscode.commons.util.CollectorUtil;
import org.springframework.ide.vscode.commons.util.Log;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import reactor.core.publisher.Flux;
public class DefaultGithubInfoProvider implements GithubInfoProvider {
//TODO: we only try to connect to github once and cache the connection.
//This means that, if creating the connection fails we won't try again.
//It would be nice to cache connection only for a limited amount of time
//especially when connecting fails. So that user may try to address the
//issue and try again.
private GitHub github;
private IOException connectionError;
private Collection<String> owners;
private Cache<String, Collection<String>> reposByOwner = CacheBuilder.newBuilder()
.expireAfterAccess(10, TimeUnit.MINUTES)
.build();
{
try {
checkConfiguration();
github = GitHub.connect();
} catch (IOException e) {
connectionError = e;
}
}
@Override
public Collection<String> getOwners() throws Exception {
if (connectionError!=null) {
throw connectionError;
}
if (github!=null) {
if (owners==null) {
ImmutableSet.Builder<String> owners = ImmutableSet.builder();
for (GHRepository repo : github.getMyself().listRepositories()) {
owners.add(repo.getOwnerName());
}
this.owners = owners.build();
}
return owners;
}
return ImmutableList.of();
}
private void checkConfiguration() throws IOException {
File configFile = new File(System.getProperty("user.home"));
configFile = new File(configFile, ".github");
if (!configFile.isFile()) {
throw new IOException("`~/.github` doesn't exist: You will get better content assist for github " +
"repos if you create a file at `~/.github` containing your github login and password:\n"+
"\n" +
" login=...username...\n" +
" password=...password...\n"+
"\n" +
"Note: Github connection data is cached indefinitely, so the editor will need to be restarted for " +
"this to take effect."
);
}
}
@Override
public Collection<String> getReposForOwner(String ownerName) throws Exception {
if (connectionError!=null) {
throw connectionError;
}
try {
if (github!=null) {
return reposByOwner.get(ownerName, () -> {
GHPerson owner = getOwner(ownerName);
return Flux.fromIterable(owner.listRepositories())
.filter(repo -> repo.getOwnerName().equals(ownerName))
.map(GHRepository::getName)
.collect(CollectorUtil.toImmutableSet())
.block();
});
}
} catch (Exception e) {
Log.log(e);
}
return ImmutableList.of();
}
private GHPerson getOwner(String ownerName) throws IOException {
try {
return github.getUser(ownerName);
} catch (IOException e) {
return github.getOrganization(ownerName);
}
}
}

View File

@@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright (c) 2017 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.github;
import java.util.Collection;
public interface GithubInfoProvider {
/**
* Retrieves a list of owners that can be suggested as hints in completions of github repo urls.
* <p>
* Note: since github has millions of users and fetching all of them isn't really an option, the owners
* are expected to be somehow limited based on the user credentials (i.e. returning a list that is
* deemed relevant to the current logged in user, rather than an exhaustive list of every org and user name
* on github.
*/
Collection<String> getOwners() throws Exception;
Collection<String> getReposForOwner(String owner) throws Exception;
}

View File

@@ -0,0 +1,108 @@
/*******************************************************************************
* Copyright (c) 2017 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.github;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.languageserver.completion.SimpleCompletionFactory;
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
import org.springframework.ide.vscode.commons.util.Assert;
import org.springframework.ide.vscode.commons.util.ExceptionUtil;
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
import org.springframework.ide.vscode.commons.yaml.completion.CompletionFactory;
import org.springframework.ide.vscode.commons.yaml.schema.ISubCompletionEngine;
import org.eclipse.lsp4j.CompletionItemKind;
import com.google.common.collect.ImmutableList;
public class GithubRepoContentAssistant implements ISubCompletionEngine {
private String[] uriPrefixes = {
"git@github.com:",
"https://github.com/"
};
private GithubInfoProvider github;
public GithubRepoContentAssistant(GithubInfoProvider github) {
this.github = github;
}
@Override
public List<ICompletionProposal> getCompletions(CompletionFactory f, DocumentRegion region, int offset) {
DocumentRegion query = region.subSequence(0, offset);
//If uri prefix is already there, we provide CA for owner / repo
for (String uriPrefix : uriPrefixes) {
if (query.startsWith(uriPrefix)) {
return getOwnerOrRepoCompletions(f, query.subSequence(uriPrefix.length()));
}
}
//If uri prefix is not yet there, maybe we can suggest it (if it matches the query)
List<ICompletionProposal> proposals = new ArrayList<>(uriPrefixes.length);
for (String uriPrefix : uriPrefixes) {
if (FuzzyMatcher.matchScore(query, uriPrefix)!=0.0) {
proposals.add(SimpleCompletionFactory.simpleProposal(query, CompletionItemKind.Text, uriPrefix, null, null));
}
}
return proposals;
}
private List<ICompletionProposal> getOwnerOrRepoCompletions(CompletionFactory f, DocumentRegion ownerAndRepoRegion) {
try {
int slash = ownerAndRepoRegion.indexOf('/');
if (slash>=0) {
DocumentRegion owner = ownerAndRepoRegion.subSequence(0, slash);
return getRepoCompletions(f, owner, ownerAndRepoRegion.subSequence(slash+1));
} else {
Collection<String> owners = github.getOwners();
DocumentRegion query = ownerAndRepoRegion;
if (!owners.isEmpty()) {
List<ICompletionProposal> proposals = new ArrayList<>(owners.size());
for (String owner : owners) {
if (FuzzyMatcher.matchScore(query, owner)!=0.0) {
proposals.add(SimpleCompletionFactory.simpleProposal(query, CompletionItemKind.Text, owner+"/", null, null));
}
}
return proposals;
} else {
return ImmutableList.of();
}
}
} catch (Exception e) {
return ImmutableList.of(f.errorMessage(ownerAndRepoRegion.toString(), ExceptionUtil.getMessageNoAppendedInformation(e)));
}
}
private List<ICompletionProposal> getRepoCompletions(CompletionFactory f, DocumentRegion owner, DocumentRegion query) {
try {
Collection<String> repos = github.getReposForOwner(owner.toString());
if (repos!=null && !repos.isEmpty()) {
List<ICompletionProposal> proposals = new ArrayList<>(repos.size());
for (String repo : repos) {
if (FuzzyMatcher.matchScore(query, repo)!=0.0) {
proposals.add(SimpleCompletionFactory.simpleProposal(query, CompletionItemKind.Text, repo, null, null));
}
}
return proposals;
} else {
return ImmutableList.of();
}
} catch (Exception e) {
return ImmutableList.of(f.errorMessage(query.toString(), ExceptionUtil.getMessageNoAppendedInformation(e)));
}
}
}

View File

@@ -12,8 +12,12 @@ package org.springframework.ide.vscode.concourse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import static org.springframework.ide.vscode.languageserver.testharness.Editor.INDENTED_COMPLETION;
import static org.springframework.ide.vscode.languageserver.testharness.Editor.PLAIN_COMPLETION;
import static org.springframework.ide.vscode.languageserver.testharness.TestAsserts.assertContains;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
@@ -31,12 +35,15 @@ import org.springframework.ide.vscode.commons.util.Unicodes;
import org.springframework.ide.vscode.commons.util.text.LanguageId;
import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions;
import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems;
import org.springframework.ide.vscode.concourse.github.GithubInfoProvider;
import org.springframework.ide.vscode.languageserver.testharness.CodeAction;
import org.springframework.ide.vscode.languageserver.testharness.Editor;
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
import org.springframework.ide.vscode.languageserver.testharness.SynchronizationPoint;
import static org.springframework.ide.vscode.languageserver.testharness.Editor.*;
import com.google.common.collect.ImmutableList;
import org.mockito.Mockito;
public class ConcourseEditorTest {
@@ -45,9 +52,11 @@ public class ConcourseEditorTest {
private static final String CURSOR = "<*>";
LanguageServerHarness harness;
private GithubInfoProvider github= Mockito.mock(GithubInfoProvider.class);
@Before public void setup() throws Exception {
harness = new LanguageServerHarness(() -> {
return new ConcourseLanguageServer(OPTIONS)
return new ConcourseLanguageServer(OPTIONS, github)
.setMaxCompletions(100);
},
LanguageId.CONCOURSE_PIPELINE
@@ -4373,7 +4382,107 @@ public class ConcourseEditorTest {
"publish-snapshot|'publish-snapshot' belongs to no group",
"publish-release|'publish-release' belongs to no group"
);
}
@Test public void githubCompletionsUriTypes() throws Exception {
Editor editor = harness.newEditor(
"resources:\n" +
"- name: my-repo\n" +
" type: git\n" +
" source:\n" +
" uri: <*>"
);
editor.assertContextualCompletions("<*>",
"git@github.com:<*>",
"https://github.com/<*>"
);
editor.assertContextualCompletions("@<*>",
"git@github.com:<*>"
);
}
@Test public void githubCompletionsOwners() throws Exception {
when(github.getOwners()).thenReturn(ImmutableList.of(
"kdvolder", "spring-projects", "spring-guides"
));
Editor editor = harness.newEditor(
"resources:\n" +
"- name: my-repo\n" +
" type: git\n" +
" source:\n" +
" uri: <*>"
);
editor.assertContextualCompletions("git@github.com:<*>",
"git@github.com:kdvolder/<*>",
"git@github.com:spring-guides/<*>",
"git@github.com:spring-projects/<*>"
);
editor.assertContextualCompletions("git@github.com:vol<*>",
"git@github.com:kdvolder/<*>"
);
editor.assertContextualCompletions("https://github.com/<*>",
"https://github.com/kdvolder/<*>",
"https://github.com/spring-guides/<*>",
"https://github.com/spring-projects/<*>"
);
}
@Test public void githubCompletionsRepos() throws Exception {
when(github.getReposForOwner("the-owner")).thenReturn(ImmutableList.of(
"nice-repo", "cool-project", "good-stuff"
));
Editor editor = harness.newEditor(
"resources:\n" +
"- name: my-repo\n" +
" type: git\n" +
" source:\n" +
" uri: <*>"
);
editor.assertContextualCompletions("https://github.com/the-owner/<*>",
"https://github.com/the-owner/cool-project<*>",
"https://github.com/the-owner/good-stuff<*>",
"https://github.com/the-owner/nice-repo<*>"
);
editor.assertContextualCompletions("https://github.com/the-owner/proj<*>",
"https://github.com/the-owner/cool-project<*>"
);
editor.assertContextualCompletions("git@github.com:the-owner/<*>",
"git@github.com:the-owner/cool-project<*>",
"git@github.com:the-owner/good-stuff<*>",
"git@github.com:the-owner/nice-repo<*>"
);
editor.assertContextualCompletions("git@github.com:the-owner/proj<*>",
"git@github.com:the-owner/cool-project<*>"
);
}
@Test public void githubCompletionErrors() throws Exception {
when(github.getReposForOwner("the-owner")).thenThrow(new IOException("Explain some stuff"));
when(github.getOwners()).thenThrow(new IOException("Explain some stuff"));
Editor editor = harness.newEditor(
"resources:\n" +
"- name: my-repo\n" +
" type: git\n" +
" source:\n" +
" uri: git@github.com:the-owner/<*>"
);
editor.assertCompletionLabels("Explain some stuff");
editor.setText(
"resources:\n" +
"- name: my-repo\n" +
" type: git\n" +
" source:\n" +
" uri: git@github.com:<*>"
);
editor.assertCompletionLabels("Explain some stuff");
}
//////////////////////////////////////////////////////////////////////////////

View File

@@ -20,7 +20,9 @@ import java.nio.file.Paths;
import org.eclipse.lsp4j.InitializeResult;
import org.eclipse.lsp4j.TextDocumentSyncKind;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.ide.vscode.concourse.ConcourseLanguageServer;
import org.springframework.ide.vscode.concourse.github.GithubInfoProvider;
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
import static org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngineOptions.*;
@@ -32,7 +34,8 @@ public class ConcourseLanguageServerTest {
@Test
public void createAndInitializeServerWithWorkspace() throws Exception {
LanguageServerHarness harness = new LanguageServerHarness(() -> new ConcourseLanguageServer(TEST_DEFAULT));
LanguageServerHarness harness = new LanguageServerHarness(() ->
new ConcourseLanguageServer(TEST_DEFAULT, Mockito.mock(GithubInfoProvider.class)));
File workspaceRoot = getTestResource("/workspace/");
assertExpectedInitResult(harness.intialize(workspaceRoot));
}
@@ -40,7 +43,8 @@ public class ConcourseLanguageServerTest {
@Test
public void createAndInitializeServerWithoutWorkspace() throws Exception {
File workspaceRoot = null;
LanguageServerHarness harness = new LanguageServerHarness(() -> new ConcourseLanguageServer(TEST_DEFAULT));
LanguageServerHarness harness = new LanguageServerHarness(() ->
new ConcourseLanguageServer(TEST_DEFAULT, Mockito.mock(GithubInfoProvider.class)));
assertExpectedInitResult(harness.intialize(workspaceRoot));
}

View File

@@ -32,7 +32,7 @@ function error(msg : string) {
export function activate(context: VSCode.ExtensionContext) {
let options : commons.ActivatorOptions = {
DEBUG : false,
CONNECT_TO_LS: false,
CONNECT_TO_LS: true,
extensionId: 'vscode-concourse',
launcher: (context: VSCode.ExtensionContext) => Path.resolve(context.extensionPath, 'jars/language-server.jar'),
jvmHeap: "48m",