Skip to content

Commit

Permalink
Merge pull request #49996 from dibarbet/local_lsp
Browse files Browse the repository at this point in the history
Add feature flag to allow VS to use the LSP based editor
  • Loading branch information
dibarbet authored Mar 3, 2021
2 parents 4eee999 + bdb3aa5 commit ae76121
Show file tree
Hide file tree
Showing 30 changed files with 344 additions and 118 deletions.
31 changes: 31 additions & 0 deletions azure-pipelines-integration-lsp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Separate pipeline from normal integration CI to allow branches to change legs

# Branches that trigger a build on commit
trigger:
- master
- master-vs-deps
- release/*
- features/*
- demos/*

# Branches that trigger builds on PR
pr:
- master
- master-vs-deps
- release/*
- features/*
- demos/*

jobs:
- job: VS_Integration_LSP
pool:
name: NetCorePublic-Pool
queue: $(queueName)
timeoutInMinutes: 135

steps:
- template: eng/pipelines/test-integration-job.yml
parameters:
configuration: Debug
oop64bit: true
lspEditor: true
39 changes: 5 additions & 34 deletions azure-pipelines-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,37 +37,8 @@ jobs:
timeoutInMinutes: 135

steps:
- template: eng/pipelines/checkout-windows-task.yml

- task: PowerShell@2
displayName: Build and Test
inputs:
filePath: eng/build.ps1
arguments: -ci -restore -build -pack -sign -publish -binaryLog -configuration $(_configuration) -prepareMachine -testVsi -oop64bit:$$(_oop64bit) -collectDumps

- task: PublishTestResults@2
displayName: Publish xUnit Test Results
inputs:
testRunner: XUnit
testResultsFiles: $(Build.SourcesDirectory)\artifacts\TestResults\$(_configuration)\*.xml
mergeTestResults: true
testRunTitle: '$(System.JobAttempt)-Integration $(_configuration) OOP64_$(_oop64bit)'
condition: always()

- task: PublishBuildArtifacts@1
displayName: Publish Logs
inputs:
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\log\$(_configuration)'
ArtifactName: '$(System.JobAttempt)-Logs $(_configuration) OOP64_$(_oop64bit) $(Build.BuildNumber)'
publishLocation: Container
continueOnError: true
condition: not(succeeded())

- task: PublishBuildArtifacts@1
displayName: Publish Screenshots
inputs:
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\bin\Microsoft.VisualStudio.LanguageServices.IntegrationTests\$(_configuration)\net472\xUnitResults'
ArtifactName: '$(System.JobAttempt)-Screenshots $(_configuration) OOP64_$(_oop64bit) $(Build.BuildNumber)'
publishLocation: Container
continueOnError: true
condition: not(succeeded())
- template: eng/pipelines/test-integration-job.yml
parameters:
configuration: $(_configuration)
oop64bit: $(_oop64bit)
lspEditor: false
27 changes: 27 additions & 0 deletions eng/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ param (
[switch]$warnAsError = $false,
[switch]$sourceBuild = $false,
[switch]$oop64bit = $true,
[switch]$lspEditor = $false,

# official build settings
[string]$officialBuildId = "",
Expand Down Expand Up @@ -414,6 +415,13 @@ function TestUsingRunTests() {
$args += " --sequential"
$args += " --include '\.IntegrationTests'"
$args += " --include 'Microsoft.CodeAnalysis.Workspaces.MSBuild.UnitTests'"

if ($lspEditor) {
$args += " --testfilter FullyQualifiedName~Roslyn.VisualStudio.IntegrationTests.LanguageServerProtocol|Editor=LanguageServerProtocol"
}
else {
$args += " --testfilter FullyQualifiedName!~Roslyn.VisualStudio.IntegrationTests.LanguageServerProtocol"
}
}

if (-not $ci -and -not $testVsi) {
Expand Down Expand Up @@ -466,6 +474,24 @@ function TestUsingRunTests() {
} else {
Write-Host "No ServiceHub logs found to copy"
}

if ($lspEditor) {
$lspLogs = Join-Path $TempDir "VisualStudio\LSP"
$telemetryLog = Join-Path $TempDir "VSTelemetryLog"
if (Test-Path $lspLogs) {
Write-Host "Copying LSP logs to $LogDir"
Copy-Item -Path $lspLogs -Destination (Join-Path $LogDir "LSP") -Recurse
} else {
Write-Host "No LSP logs found to copy"
}

if (Test-Path $telemetryLog) {
Write-Host "Copying telemetry logs to $LogDir"
Copy-Item -Path $telemetryLog -Destination (Join-Path $LogDir "Telemetry") -Recurse
} else {
Write-Host "No telemetry logs found to copy"
}
}
}
}
}
Expand Down Expand Up @@ -604,6 +630,7 @@ function Setup-IntegrationTestRun() {
}

$env:ROSLYN_OOP64BIT = "$oop64bit"
$env:ROSLYN_LSPEDITOR = "$lspEditor"
}

function Prepare-TempDir() {
Expand Down
49 changes: 49 additions & 0 deletions eng/pipelines/test-integration-job.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
parameters:
- name: configuration
type: string
default: 'Debug'
- name: oop64bit
# This is actually a boolean but must be defined as string.
# Parameters are evaluated at compile time, but all variables are strings at compile time.
# So in order to pass a parameter that comes from a variable these must be typed as string.
type: string
default: true
- name: lspEditor
type: string
default: false

steps:
- template: checkout-windows-task.yml

- task: PowerShell@2
displayName: Build and Test
inputs:
filePath: eng/build.ps1
arguments: -ci -restore -build -pack -sign -publish -binaryLog -configuration ${{ parameters.configuration }} -prepareMachine -testVsi -oop64bit:$${{ parameters.oop64bit }} -collectDumps -lspEditor:$${{ parameters.lspEditor }}

- task: PublishTestResults@2
displayName: Publish xUnit Test Results
inputs:
testRunner: XUnit
testResultsFiles: $(Build.SourcesDirectory)\artifacts\TestResults\${{ parameters.configuration }}\*.xml
mergeTestResults: true
testRunTitle: '$(System.JobAttempt)-Integration ${{ parameters.configuration }} OOP64_${{ parameters.oop64bit }}'
condition: always()

- task: PublishBuildArtifacts@1
displayName: Publish Logs
inputs:
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\log\${{ parameters.configuration }}'
ArtifactName: '$(System.JobAttempt)-Logs ${{ parameters.configuration }} OOP64_${{ parameters.oop64bit }} LspEditor_${{ parameters.lspEditor }} $(Build.BuildNumber)'
publishLocation: Container
continueOnError: true
condition: not(succeeded())

- task: PublishBuildArtifacts@1
displayName: Publish Screenshots
inputs:
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\bin\Microsoft.VisualStudio.LanguageServices.IntegrationTests\${{ parameters.configuration }}\net472\xUnitResults'
ArtifactName: '$(System.JobAttempt)-Screenshots ${{ parameters.configuration }} OOP64_${{ parameters.oop64bit }} LspEditor_${{ parameters.lspEditor }} $(Build.BuildNumber)'
publishLocation: Container
continueOnError: true
condition: not(succeeded())
1 change: 1 addition & 0 deletions src/Compilers/Test/Core/Traits/Traits.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public static class Editors
public const string KeyProcessors = nameof(KeyProcessors);
public const string KeyProcessorProviders = nameof(KeyProcessorProviders);
public const string Preview = nameof(Preview);
public const string LanguageServerProtocol = nameof(LanguageServerProtocol);
}

public const string Feature = nameof(Feature);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Editor.Tags;
using Microsoft.CodeAnalysis.Host.Mef;
Expand Down Expand Up @@ -76,11 +77,18 @@ public SuggestedActionsSourceProvider(
ImageMonikerServices = ExtensionOrderer.Order(imageMonikerServices).ToImmutableArray();
}

public ISuggestedActionsSource CreateSuggestedActionsSource(ITextView textView, ITextBuffer textBuffer)
public ISuggestedActionsSource? CreateSuggestedActionsSource(ITextView textView, ITextBuffer textBuffer)
{
Contract.ThrowIfNull(textView);
Contract.ThrowIfNull(textBuffer);

// Disable lightbulb points when running under the LSP editor.
// The LSP client will interface with the editor to display our code actions.
if (textBuffer.IsInLspEditorContext())
{
return null;
}

return new SuggestedActionsSource(_threadingContext, this, textView, textBuffer, _suggestedActionCategoryRegistry);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable disable

using System.ComponentModel.Composition;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Shared.TestHooks;
Expand Down Expand Up @@ -47,13 +46,21 @@ public SemanticClassificationBufferTaggerProvider(
_asyncListener = listenerProvider.GetListener(FeatureAttribute.Classification);
}

public IAccurateTagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
public IAccurateTagger<T>? CreateTagger<T>(ITextBuffer buffer) where T : ITag
{
this.AssertIsForeground();

// The LSP client will handle producing tags when running under the LSP editor.
// Our tagger implementation should return nothing to prevent conflicts.
if (buffer.IsInLspEditorContext())
{
return null;
}

return new Tagger(this, buffer, _asyncListener) as IAccurateTagger<T>;
}

ITagger<T> ITaggerProvider.CreateTagger<T>(ITextBuffer buffer)
ITagger<T>? ITaggerProvider.CreateTagger<T>(ITextBuffer buffer)
=> CreateTagger<T>(buffer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ protected override Task ProduceTagsAsync(TaggerContext<IClassificationTag> conte
return Task.CompletedTask;
}

// The LSP client will handle producing tags when running under the LSP editor.
// Our tagger implementation should return nothing to prevent conflicts.
var workspaceContextService = document?.Project.Solution.Workspace.Services.GetRequiredService<IWorkspaceContextService>();
if (workspaceContextService?.IsInLspEditorContext() == true)
{
return Task.CompletedTask;
}

return SemanticClassificationUtilities.ProduceTagsAsync(context, spanToTag, classificationService, _typeMap);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ private static bool CanRename(RenameCommandArgs args)
{
return args.SubjectBuffer.TryGetWorkspace(out var workspace) &&
workspace.CanApplyChange(ApplyChangesKind.ChangeDocument) &&
args.SubjectBuffer.SupportsRename();
args.SubjectBuffer.SupportsRename() && !args.SubjectBuffer.IsInLspEditorContext();
}

private static void ShowErrorDialog(Workspace workspace, string message)
Expand Down
8 changes: 3 additions & 5 deletions src/Tools/Source/RunTests/ITestExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,16 @@ internal readonly struct TestExecutionOptions
internal string DotnetFilePath { get; }
internal ProcDumpInfo? ProcDumpInfo { get; }
internal string TestResultsDirectory { get; }
internal string? Trait { get; }
internal string? NoTrait { get; }
internal string? TestFilter { get; }
internal bool IncludeHtml { get; }
internal bool Retry { get; }

internal TestExecutionOptions(string dotnetFilePath, ProcDumpInfo? procDumpInfo, string testResultsDirectory, string? trait, string? noTrait, bool includeHtml, bool retry)
internal TestExecutionOptions(string dotnetFilePath, ProcDumpInfo? procDumpInfo, string testResultsDirectory, string? testFilter, bool includeHtml, bool retry)
{
DotnetFilePath = dotnetFilePath;
ProcDumpInfo = procDumpInfo;
TestResultsDirectory = testResultsDirectory;
Trait = trait;
NoTrait = noTrait;
TestFilter = testFilter;
IncludeHtml = includeHtml;
Retry = retry;
}
Expand Down
18 changes: 5 additions & 13 deletions src/Tools/Source/RunTests/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,9 @@ internal class Options
public Display Display { get; set; }

/// <summary>
/// Trait string to pass to xunit.
/// Filter string to pass to xunit.
/// </summary>
public string? Trait { get; set; }

/// <summary>
/// The no-trait string to pass to xunit.
/// </summary>
public string? NoTrait { get; set; }
public string? TestFilter { get; set; }

public string Configuration { get; set; }

Expand Down Expand Up @@ -137,8 +132,7 @@ public Options(
var helix = false;
var helixQueueName = "Windows.10.Amd64.Open";
var retry = false;
string? traits = null;
string? noTraits = null;
string? testFilter = null;
int? timeout = null;
string? resultFileDirectory = null;
string? logFileDirectory = null;
Expand All @@ -158,8 +152,7 @@ public Options(
{ "sequential", "Run tests sequentially", o => sequential = o is object },
{ "helix", "Run tests on Helix", o => helix = o is object },
{ "helixQueueName=", "Name of the Helix queue to run tests on", (string s) => helixQueueName = s },
{ "traits=", "xUnit traits to include (semicolon delimited)", (string s) => traits = s },
{ "notraits=", "xUnit traits to exclude (semicolon delimited)", (string s) => noTraits = s },
{ "testfilter=", "xUnit string to pass to --filter, e.g. FullyQualifiedName~TestClass1|Category=CategoryA", (string s) => testFilter = s },
{ "timeout=", "Minute timeout to limit the tests to", (int i) => timeout = i },
{ "out=", "Test result file directory (when running on Helix, this is relative to the Helix work item directory)", (string s) => resultFileDirectory = s },
{ "logs=", "Log file directory (when running on Helix, this is relative to the Helix work item directory)", (string s) => logFileDirectory = s },
Expand Down Expand Up @@ -241,8 +234,7 @@ public Options(
UseHelix = helix,
HelixQueueName = helixQueueName,
IncludeHtml = includeHtml,
Trait = traits,
NoTrait = noTraits,
TestFilter = testFilter,
Timeout = timeout is { } t ? TimeSpan.FromMinutes(t) : null,
Retry = retry,
};
Expand Down
20 changes: 4 additions & 16 deletions src/Tools/Source/RunTests/ProcessTestExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public string GetCommandLineArguments(AssemblyInfo assemblyInfo, bool useSingleQ
builder.Append($@"test");
builder.Append($@" {sep}{assemblyInfo.AssemblyName}{sep}");
var typeInfoList = assemblyInfo.PartitionInfo.TypeInfoList;
if (typeInfoList.Length > 0 || !string.IsNullOrWhiteSpace(Options.Trait) || !string.IsNullOrWhiteSpace(Options.NoTrait))
if (typeInfoList.Length > 0 || !string.IsNullOrWhiteSpace(Options.TestFilter))
{
builder.Append($@" --filter {sep}");
var any = false;
Expand All @@ -50,22 +50,10 @@ public string GetCommandLineArguments(AssemblyInfo assemblyInfo, bool useSingleQ
}
builder.Append(sep);

if (Options.Trait is object)
if (Options.TestFilter is object)
{
foreach (var trait in Options.Trait.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
MaybeAddSeparator();
builder.Append($"Trait={trait}");
}
}

if (Options.NoTrait is object)
{
foreach (var trait in Options.NoTrait.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
MaybeAddSeparator('&');
builder.Append($"Trait!~{trait}");
}
MaybeAddSeparator();
builder.Append(Options.TestFilter);
}

void MaybeAddSeparator(char separator = '|')
Expand Down
4 changes: 1 addition & 3 deletions src/Tools/Source/RunTests/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ internal static async Task<int> Main(string[] args)
{
Logger.Log("RunTest command line");
Logger.Log(string.Join(" ", args));

var options = Options.Parse(args);
if (options == null)
{
Expand Down Expand Up @@ -372,8 +371,7 @@ private static ProcessTestExecutor CreateTestExecutor(Options options)
dotnetFilePath: options.DotnetFilePath,
procDumpInfo: options.CollectDumps ? GetProcDumpInfo(options) : null,
testResultsDirectory: options.TestResultsDirectory,
trait: options.Trait,
noTrait: options.NoTrait,
testFilter: options.TestFilter,
includeHtml: options.IncludeHtml,
retry: options.Retry);
return new ProcessTestExecutor(testExecutionOptions);
Expand Down
Loading

0 comments on commit ae76121

Please sign in to comment.