From e481df3d49f5185faaf12be098dd6b0f4d64d698 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Fri, 13 Jan 2017 09:52:32 -0800 Subject: [PATCH] Add better errors, fix help output text, and add 'dotnet watch --list' to help us diagnose issues Fixes #252 - help output shown twice in dotnet-watch Fixes #250 - add dotnet-watch --list. Prints a list of all files discovered Fixes #249 - better error message when GenerateWatchList fails --- .editorconfig | 28 ++++++++++ DotNetTools.sln | 13 +++-- .../CommandLineOptions.cs | 13 ++++- .../DotNetWatcher.cs | 9 ++- .../Internal/MsBuildFileSetFactory.cs | 41 +++++++++----- src/Microsoft.DotNet.Watcher.Tools/Program.cs | 55 +++++++++++++++++-- .../Internal/ProjectIdResolver.cs | 6 +- .../AppWithDepsTests.cs | 2 +- .../AwaitableProcess.cs | 20 ++++++- .../GlobbingAppTests.cs | 30 ++++++++-- .../NoDepsAppTests.cs | 4 +- .../Scenario/ProjectToolScenario.cs | 18 +++--- .../Scenario/WatchableApp.cs | 25 ++++++--- .../MsBuildFileSetFactoryTest.cs | 4 +- 14 files changed, 207 insertions(+), 61 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..98fd05f5b3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,28 @@ +; EditorConfig to support per-solution formatting. +; Use the EditorConfig VS add-in to make this work. +; http://editorconfig.org/ + +; This is the default for the codeline. +root = true + +[*] +indent_style = space +charset = utf-8 +trim_trailing_whitespace = true + +[*.{cs}] +indent_size = 4 +insert_final_newline = true + +; All XML-based file formats +[*.{config,csproj,nuspec,props,resx,targets,xml}] +indent_size = 2 + +[*.{json}] +indent_size = 2 + +[*.{ps1}] +indent_size = 4 + +[*.{sh}] +indent_size = 4 \ No newline at end of file diff --git a/DotNetTools.sln b/DotNetTools.sln index a03be635f6..f39e982eb5 100644 --- a/DotNetTools.sln +++ b/DotNetTools.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.25807.0 +VisualStudioVersion = 15.0.26020.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{66517987-2A5A-4330-B130-207039378FD4}" EndProject @@ -8,6 +8,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.Watcher.To EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8321E0D1-9A47-4D2F-AED8-3AE636D44E35}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig NuGet.Config = NuGet.Config EndProjectSection EndProject @@ -43,10 +44,6 @@ Global {8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Debug|Any CPU.Build.0 = Debug|Any CPU {8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Release|Any CPU.ActiveCfg = Debug|Any CPU {8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E}.Release|Any CPU.Build.0 = Debug|Any CPU - {9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Release|Any CPU.ActiveCfg = Debug|Any CPU - {9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Release|Any CPU.Build.0 = Debug|Any CPU {7B331122-83B1-4F08-A119-DC846959844C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7B331122-83B1-4F08-A119-DC846959844C}.Debug|Any CPU.Build.0 = Debug|Any CPU {7B331122-83B1-4F08-A119-DC846959844C}.Release|Any CPU.ActiveCfg = Debug|Any CPU @@ -59,6 +56,10 @@ Global {53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Debug|Any CPU.Build.0 = Debug|Any CPU {53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Release|Any CPU.ActiveCfg = Debug|Any CPU {53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Release|Any CPU.Build.0 = Debug|Any CPU + {9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD}.Release|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -67,9 +68,9 @@ Global {8A8CEABC-AC47-43FF-A5DF-69224F7E1F46} = {66517987-2A5A-4330-B130-207039378FD4} {16BADE2F-1184-4518-8A70-B68A19D0805B} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134} {8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E} = {66517987-2A5A-4330-B130-207039378FD4} - {9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134} {7B331122-83B1-4F08-A119-DC846959844C} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134} {8A2E6961-6B12-4A8E-8215-3E7301D52EAC} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134} {53F3B53D-303A-4DAA-9C38-4F55195FA5B9} = {66517987-2A5A-4330-B130-207039378FD4} + {9295E811-FF0F-E40A-2F9A-0B2C4EBC22AD} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134} EndGlobalSection EndGlobal diff --git a/src/Microsoft.DotNet.Watcher.Tools/CommandLineOptions.cs b/src/Microsoft.DotNet.Watcher.Tools/CommandLineOptions.cs index c602659f11..8056dff67e 100644 --- a/src/Microsoft.DotNet.Watcher.Tools/CommandLineOptions.cs +++ b/src/Microsoft.DotNet.Watcher.Tools/CommandLineOptions.cs @@ -16,6 +16,7 @@ namespace Microsoft.DotNet.Watcher public bool IsQuiet { get; private set; } public bool IsVerbose { get; private set; } public IList RemainingArguments { get; private set; } + public bool ListFiles { get; private set; } public static CommandLineOptions Parse(string[] args, IConsole console) { @@ -63,6 +64,9 @@ Examples: CommandOptionType.NoValue); var optVerbose = app.VerboseOption(); + var optList = app.Option("--list", "Lists all discovered files without starting the watcher", + CommandOptionType.NoValue); + app.VersionOptionFromAssemblyAttributes(typeof(Program).GetTypeInfo().Assembly); if (app.Execute(args) != 0) @@ -75,7 +79,9 @@ Examples: throw new CommandParsingException(app, Resources.Error_QuietAndVerboseSpecified); } - if (app.RemainingArguments.Count == 0) + if (app.RemainingArguments.Count == 0 + && !app.IsShowingInformation + && !optList.HasValue()) { app.ShowHelp(); } @@ -86,8 +92,9 @@ Examples: IsQuiet = optQuiet.HasValue(), IsVerbose = optVerbose.HasValue(), RemainingArguments = app.RemainingArguments, - IsHelp = app.IsShowingInformation + IsHelp = app.IsShowingInformation, + ListFiles = optList.HasValue(), }; } } -} \ No newline at end of file +} diff --git a/src/Microsoft.DotNet.Watcher.Tools/DotNetWatcher.cs b/src/Microsoft.DotNet.Watcher.Tools/DotNetWatcher.cs index e326d83ae2..fb324de797 100644 --- a/src/Microsoft.DotNet.Watcher.Tools/DotNetWatcher.cs +++ b/src/Microsoft.DotNet.Watcher.Tools/DotNetWatcher.cs @@ -34,6 +34,13 @@ namespace Microsoft.DotNet.Watcher while (true) { var fileSet = await fileSetFactory.CreateAsync(cancellationToken); + + if (fileSet == null) + { + _reporter.Error("Failed to find a list of files to watch"); + return; + } + if (cancellationToken.IsCancellationRequested) { return; @@ -91,4 +98,4 @@ namespace Microsoft.DotNet.Watcher } } } -} \ No newline at end of file +} diff --git a/src/Microsoft.DotNet.Watcher.Tools/Internal/MsBuildFileSetFactory.cs b/src/Microsoft.DotNet.Watcher.Tools/Internal/MsBuildFileSetFactory.cs index 5aded8f772..1a7e900845 100644 --- a/src/Microsoft.DotNet.Watcher.Tools/Internal/MsBuildFileSetFactory.cs +++ b/src/Microsoft.DotNet.Watcher.Tools/Internal/MsBuildFileSetFactory.cs @@ -16,17 +16,19 @@ namespace Microsoft.DotNet.Watcher.Internal public class MsBuildFileSetFactory : IFileSetFactory { private const string TargetName = "GenerateWatchList"; - private const string ProjectExtensionFileExtension = ".dotnetwatch.targets"; + private const string ProjectExtensionFileExtension = ".dotnetwatch.g.targets"; private const string WatchTargetsFileName = "DotNetWatchCommon.targets"; private readonly IReporter _reporter; private readonly string _projectFile; private readonly string _watchTargetsDir; private readonly OutputSink _outputSink; private readonly ProcessRunner _processRunner; + private readonly bool _waitOnError; - public MsBuildFileSetFactory(IReporter reporter, string projectFile) + public MsBuildFileSetFactory(IReporter reporter, string projectFile, bool waitOnError) : this(reporter, projectFile, new OutputSink()) { + _waitOnError = waitOnError; } // output sink is for testing @@ -86,7 +88,7 @@ namespace Microsoft.DotNet.Watcher.Internal var exitCode = await _processRunner.RunAsync(processSpec, cancellationToken); - if (exitCode == 0) + if (exitCode == 0 && File.Exists(watchList)) { var fileset = new FileSet( File.ReadAllLines(watchList) @@ -109,28 +111,41 @@ namespace Microsoft.DotNet.Watcher.Internal _reporter.Error($"Error(s) finding watch items project file '{Path.GetFileName(_projectFile)}'"); - _reporter.Output($"MSBuild output from target '{TargetName}'"); + _reporter.Output($"MSBuild output from target '{TargetName}':"); + _reporter.Output(string.Empty); foreach (var line in capture.Lines) { - _reporter.Output($" [MSBUILD] : {line}"); + _reporter.Output($" {line}"); } - _reporter.Warn("Fix the error to continue or press Ctrl+C to exit."); + _reporter.Output(string.Empty); - var fileSet = new FileSet(new[] {_projectFile}); - - using (var watcher = new FileSetWatcher(fileSet)) + if (!_waitOnError) { - await watcher.GetChangedFileAsync(cancellationToken); + return null; + } + else + { + _reporter.Warn("Fix the error to continue or press Ctrl+C to exit."); - _reporter.Output($"File changed: {_projectFile}"); + var fileSet = new FileSet(new[] { _projectFile }); + + using (var watcher = new FileSetWatcher(fileSet)) + { + await watcher.GetChangedFileAsync(cancellationToken); + + _reporter.Output($"File changed: {_projectFile}"); + } } } } finally { - File.Delete(watchList); + if (File.Exists(watchList)) + { + File.Delete(watchList); + } } } @@ -173,4 +188,4 @@ namespace Microsoft.DotNet.Watcher.Internal return Path.GetDirectoryName(targetPath); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.DotNet.Watcher.Tools/Program.cs b/src/Microsoft.DotNet.Watcher.Tools/Program.cs index 9c488ff283..9d18757d3c 100644 --- a/src/Microsoft.DotNet.Watcher.Tools/Program.cs +++ b/src/Microsoft.DotNet.Watcher.Tools/Program.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -80,7 +80,20 @@ namespace Microsoft.DotNet.Watcher try { - return await MainInternalAsync(reporter, options.Project, options.RemainingArguments, ctrlCTokenSource.Token); + if (options.ListFiles) + { + return await ListFilesAsync(reporter, + options.Project, + ctrlCTokenSource.Token); + } + else + { + + return await MainInternalAsync(reporter, + options.Project, + options.RemainingArguments, + ctrlCTokenSource.Token); + } } catch (Exception ex) { @@ -115,8 +128,7 @@ namespace Microsoft.DotNet.Watcher return 1; } - var fileSetFactory = new MsBuildFileSetFactory(reporter, projectFile); - + var fileSetFactory = new MsBuildFileSetFactory(reporter, projectFile, waitOnError: true); var processInfo = new ProcessSpec { Executable = DotNetMuxer.MuxerPathOrDefault(), @@ -130,6 +142,39 @@ namespace Microsoft.DotNet.Watcher return 0; } + private async Task ListFilesAsync( + IReporter reporter, + string project, + CancellationToken cancellationToken) + { + // TODO multiple projects should be easy enough to add here + string projectFile; + try + { + projectFile = MsBuildProjectFinder.FindMsBuildProject(_workingDir, project); + } + catch (FileNotFoundException ex) + { + reporter.Error(ex.Message); + return 1; + } + + var fileSetFactory = new MsBuildFileSetFactory(reporter, projectFile, waitOnError: false); + var files = await fileSetFactory.CreateAsync(cancellationToken); + + if (files == null) + { + return 1; + } + + foreach (var file in files) + { + _console.Out.WriteLine(file); + } + + return 0; + } + private static IReporter CreateReporter(bool verbose, bool quiet, IConsole console) { const string prefix = "watch : "; @@ -178,4 +223,4 @@ namespace Microsoft.DotNet.Watcher .Build(); } } -} \ No newline at end of file +} diff --git a/src/Microsoft.Extensions.SecretManager.Tools/Internal/ProjectIdResolver.cs b/src/Microsoft.Extensions.SecretManager.Tools/Internal/ProjectIdResolver.cs index a2d86da7ae..afea6d7a58 100644 --- a/src/Microsoft.Extensions.SecretManager.Tools/Internal/ProjectIdResolver.cs +++ b/src/Microsoft.Extensions.SecretManager.Tools/Internal/ProjectIdResolver.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -98,9 +98,7 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal // running tool using (var resource = GetType().GetTypeInfo().Assembly.GetManifestResourceStream("ProjectIdResolverTargets.xml")) using (var stream = new FileStream(projectExtensionsPath, FileMode.Create)) - using (var writer = new StreamWriter(stream)) { - writer.WriteLine(""); resource.CopyTo(stream); } } @@ -120,4 +118,4 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal } } } -} \ No newline at end of file +} diff --git a/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/AppWithDepsTests.cs b/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/AppWithDepsTests.cs index 253f3643d1..37bfd618d1 100644 --- a/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/AppWithDepsTests.cs +++ b/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/AppWithDepsTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Fact] public async Task ChangeFileInDependency() { - await _app.StartWatcher().OrTimeout(); + await _app.StartWatcherAsync().OrTimeout(); var fileToChange = Path.Combine(_app.DependencyFolder, "Foo.cs"); var programCs = File.ReadAllText(fileToChange); diff --git a/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/AwaitableProcess.cs b/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/AwaitableProcess.cs index 2abbdf9068..11583832d0 100644 --- a/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/AwaitableProcess.cs +++ b/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/AwaitableProcess.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; @@ -9,8 +10,8 @@ using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Dataflow; using Microsoft.Extensions.Internal; -using Xunit.Abstractions; using Microsoft.Extensions.Tools.Internal; +using Xunit.Abstractions; namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests { @@ -71,6 +72,21 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests return null; } + public async Task> GetAllOutputLines() + { + var lines = new List(); + while (!_source.Completion.IsCompleted) + { + while (await _source.OutputAvailableAsync()) + { + var next = await _source.ReceiveAsync(); + _logger.WriteLine($"{DateTime.Now}: recv: '{next}'"); + lines.Add(next); + } + } + return lines; + } + private void StartProcessingOutput(StreamReader streamReader) { _source = _source ?? new BufferBlock(); @@ -80,7 +96,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests string line; while ((line = streamReader.ReadLine()) != null) { - _logger.WriteLine($"{DateTime.Now} post: {line}"); + _logger.WriteLine($"{DateTime.Now}: post: '{line}'"); _source.Post(line); } diff --git a/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/GlobbingAppTests.cs b/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/GlobbingAppTests.cs index cb67bfec9e..f2c37077d5 100644 --- a/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/GlobbingAppTests.cs +++ b/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/GlobbingAppTests.cs @@ -5,6 +5,7 @@ using System; using System.IO; using System.Linq; using System.Threading.Tasks; +using Microsoft.DotNet.Watcher.Tools.Tests; using Xunit; using Xunit.Abstractions; @@ -24,7 +25,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [InlineData(false)] public async Task ChangeCompiledFile(bool usePollingWatcher) { - await _app.StartWatcher().OrTimeout(); + await _app.StartWatcherAsync().OrTimeout(); var types = await _app.GetCompiledAppDefinedTypes().OrTimeout(); Assert.Equal(2, types); @@ -41,7 +42,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Fact(Skip = "Broken. See https://github.com/aspnet/DotNetTools/issues/212")] public async Task AddCompiledFile() { - await _app.StartWatcher().OrTimeout(); + await _app.StartWatcherAsync().OrTimeout(); var types = await _app.GetCompiledAppDefinedTypes().OrTimeout(); Assert.Equal(2, types); @@ -57,7 +58,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Fact] public async Task DeleteCompiledFile() { - await _app.StartWatcher().OrTimeout(); + await _app.StartWatcherAsync().OrTimeout(); var types = await _app.GetCompiledAppDefinedTypes().OrTimeout(); Assert.Equal(2, types); @@ -73,7 +74,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Fact] public async Task DeleteSourceFolder() { - await _app.StartWatcher().OrTimeout(); + await _app.StartWatcherAsync().OrTimeout(); var types = await _app.GetCompiledAppDefinedTypes().OrTimeout(); Assert.Equal(2, types); @@ -89,7 +90,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Fact] public async Task RenameCompiledFile() { - await _app.StartWatcher().OrTimeout(); + await _app.StartWatcherAsync().OrTimeout(); var oldFile = Path.Combine(_app.SourceDirectory, "include", "Foo.cs"); var newFile = Path.Combine(_app.SourceDirectory, "include", "Foo_new.cs"); @@ -101,7 +102,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Fact] public async Task ChangeExcludedFile() { - await _app.StartWatcher().OrTimeout(); + await _app.StartWatcherAsync().OrTimeout(); var changedFile = Path.Combine(_app.SourceDirectory, "exclude", "Baz.cs"); File.WriteAllText(changedFile, ""); @@ -111,6 +112,23 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests Assert.NotSame(restart, finished); } + [Fact] + public async Task ListsFiles() + { + _app.Start(new [] { "--list" }); + var lines = await _app.Process.GetAllOutputLines(); + + AssertEx.EqualFileList( + _app.Scenario.WorkFolder, + new[] + { + "GlobbingApp/Program.cs", + "GlobbingApp/include/Foo.cs", + "GlobbingApp/GlobbingApp.csproj", + }, + lines); + } + public void Dispose() { _app.Dispose(); diff --git a/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/NoDepsAppTests.cs b/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/NoDepsAppTests.cs index 73d5ecd982..6e22a55436 100644 --- a/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/NoDepsAppTests.cs +++ b/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/NoDepsAppTests.cs @@ -23,7 +23,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Fact] public async Task RestartProcessOnFileChange() { - await _app.StartWatcher(new[] { "--no-exit" }).OrTimeout(); + await _app.StartWatcherAsync(new[] { "--no-exit" }).OrTimeout(); var pid = await _app.GetProcessId().OrTimeout(); // Then wait for it to restart when we change a file @@ -42,7 +42,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests [Fact] public async Task RestartProcessThatTerminatesAfterFileChange() { - await _app.StartWatcher().OrTimeout(); + await _app.StartWatcherAsync().OrTimeout(); var pid = await _app.GetProcessId().OrTimeout(); await _app.HasExited().OrTimeout(); // process should exit after run diff --git a/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/Scenario/ProjectToolScenario.cs b/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/Scenario/ProjectToolScenario.cs index 2b62d17db9..1b0f62c7de 100644 --- a/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/Scenario/ProjectToolScenario.cs +++ b/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/Scenario/ProjectToolScenario.cs @@ -118,17 +118,17 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests // this launches a new .NET Core process using the runtime of the current test app // and the version of dotnet-watch that this test app is compiled against var thisAssembly = Path.GetFileNameWithoutExtension(GetType().GetTypeInfo().Assembly.Location); - var args = new List(); - args.Add("exec"); - args.Add("--depsfile"); - args.Add(Path.Combine(AppContext.BaseDirectory, thisAssembly + ".deps.json")); + var args = new List + { + "exec", + "--depsfile", + Path.Combine(AppContext.BaseDirectory, thisAssembly + ".deps.json"), + "--runtimeconfig", + Path.Combine(AppContext.BaseDirectory, thisAssembly + ".runtimeconfig.json") + }; - args.Add("--runtimeconfig"); - args.Add(Path.Combine(AppContext.BaseDirectory, thisAssembly + ".runtimeconfig.json")); - - var currentFxVersion = AppContext.GetData("FX_DEPS_FILE") as string; - if (currentFxVersion != null) + if (AppContext.GetData("FX_DEPS_FILE") is string currentFxVersion) { // This overrides the version of shared fx in the runtimeconfig.json file. // Tests do this to ensure dotnet-watch is executing on the version of Microsoft.NETCore.App diff --git a/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/Scenario/WatchableApp.cs b/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/Scenario/WatchableApp.cs index 797e17f640..6e4d6cc883 100644 --- a/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/Scenario/WatchableApp.cs +++ b/test/Microsoft.DotNet.Watcher.Tools.FunctionalTests/Scenario/WatchableApp.cs @@ -1,12 +1,13 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.Extensions.Tools.Internal; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Threading.Tasks; +using Microsoft.Extensions.Tools.Internal; using Xunit.Abstractions; namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests @@ -16,12 +17,11 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests private const string StartedMessage = "Started"; private const string ExitingMessage = "Exiting"; - protected ProjectToolScenario Scenario { get; } private readonly ITestOutputHelper _logger; - protected AwaitableProcess Process { get; set; } private string _appName; private bool _prepared; + public WatchableApp(string appName, ITestOutputHelper logger) { _logger = logger; @@ -31,6 +31,10 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests SourceDirectory = Path.Combine(Scenario.WorkFolder, appName); } + public ProjectToolScenario Scenario { get; } + + public AwaitableProcess Process { get; protected set; } + public string SourceDirectory { get; } public Task HasRestarted() @@ -41,9 +45,6 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests public bool UsePollingWatcher { get; set; } - public Task StartWatcher([CallerMemberName] string name = null) - => StartWatcher(Array.Empty(), name); - public async Task GetProcessId() { var line = await Process.GetOutputLineAsync(l => l.StartsWith("PID =")); @@ -58,7 +59,7 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests _prepared = true; } - public async Task StartWatcher(string[] arguments, [CallerMemberName] string name = null) + public void Start(IEnumerable arguments, [CallerMemberName] string name = null) { if (!_prepared) { @@ -67,7 +68,6 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests var args = Scenario .GetDotnetWatchArguments() - .Concat(new[] { "run", "--" }) .Concat(arguments); var spec = new ProcessSpec @@ -79,6 +79,15 @@ namespace Microsoft.DotNet.Watcher.Tools.FunctionalTests Process = new AwaitableProcess(spec, _logger); Process.Start(); + } + + public Task StartWatcherAsync([CallerMemberName] string name = null) + => StartWatcherAsync(Array.Empty(), name); + + public async Task StartWatcherAsync(string[] arguments, [CallerMemberName] string name = null) + { + var args = new[] { "run", "--" }.Concat(arguments); + Start(args, name); await Process.GetOutputLineAsync(StartedMessage); } diff --git a/test/Microsoft.DotNet.Watcher.Tools.Tests/MsBuildFileSetFactoryTest.cs b/test/Microsoft.DotNet.Watcher.Tools.Tests/MsBuildFileSetFactoryTest.cs index 39c69ce4cc..9b46f04c1d 100644 --- a/test/Microsoft.DotNet.Watcher.Tools.Tests/MsBuildFileSetFactoryTest.cs +++ b/test/Microsoft.DotNet.Watcher.Tools.Tests/MsBuildFileSetFactoryTest.cs @@ -297,7 +297,8 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests } private Task GetFileSet(TemporaryCSharpProject target) - => GetFileSet(new MsBuildFileSetFactory(_reporter, target.Path)); + => GetFileSet(new MsBuildFileSetFactory(_reporter, target.Path, waitOnError: false)); + private async Task GetFileSet(MsBuildFileSetFactory filesetFactory) { _tempDir.Create(); @@ -305,6 +306,7 @@ namespace Microsoft.DotNet.Watcher.Tools.Tests var finished = await Task.WhenAny(createTask, Task.Delay(TimeSpan.FromSeconds(10))); Assert.Same(createTask, finished); + Assert.NotNull(createTask.Result); return createTask.Result; }