diff --git a/TestAssets/TestProjects/MSBuildAppWithMultipleFrameworks/MSBuildAppWithMultipleFrameworks.csproj b/TestAssets/TestProjects/MSBuildAppWithMultipleFrameworks/MSBuildAppWithMultipleFrameworks.csproj index 0df7ccb42..255d7f570 100644 --- a/TestAssets/TestProjects/MSBuildAppWithMultipleFrameworks/MSBuildAppWithMultipleFrameworks.csproj +++ b/TestAssets/TestProjects/MSBuildAppWithMultipleFrameworks/MSBuildAppWithMultipleFrameworks.csproj @@ -1,13 +1,10 @@ - + Exe net451;netcoreapp2.0 + $(CLI_SharedFrameworkVersion) - - - - \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-run/LocalizableStrings.cs b/src/dotnet/commands/dotnet-run/LocalizableStrings.cs index b1143338f..b27c6426b 100644 --- a/src/dotnet/commands/dotnet-run/LocalizableStrings.cs +++ b/src/dotnet/commands/dotnet-run/LocalizableStrings.cs @@ -9,27 +9,23 @@ namespace Microsoft.DotNet.Tools.Run public const string AppDescription = "Command used to run .NET apps"; - public const string CommandOptionProjectDescription = "The path to the project file to run (defaults to the current directory if there is only one project)."; - public const string CommandOptionNoBuildDescription = "Skip building the project prior to running. By default, the project will be built."; + public const string CommandOptionFrameworkDescription = "Build and run the app using the specified framework. The framework has to be specified in the project file. "; + + public const string CommandOptionNoBuild = "Do not build the project before running."; + + public const string CommandOptionProjectDescription = "The path to the project file to run (defaults to the current directory if there is only one project)."; + public const string RunCommandException = "The build failed. Please fix the build errors and run again."; + public const string RunCommandExceptionUnableToRunSpecifyFramework = "Unable to run your project\nYour project targets multiple frameworks. Please specify which framework to run using '{0}'."; + public const string RunCommandExceptionUnableToRun = "Unable to run your project\nPlease ensure you have a runnable project type and ensure '{0}' supports this project.\nThe current {1} is '{2}'"; - public const string RunCommandExceptionUnableToRun1 = "Unable to run your project."; + public const string RunCommandExceptionNoProjects = "Couldn't find a project to run. Ensure a project exists in {0}, or pass the path to the project using {1}."; - public const string RunCommandExceptionUnableToRun2 = "Please ensure you have a runnable project type and ensure 'dotnet run' supports this project."; - - public const string RunCommandExceptionUnableToRun3 = "The current OutputType is "; - - public const string RunCommandInvalidOperationException1 = "Couldn't find a project to run. Ensure a project exists in "; - - public const string RunCommandInvalidOperationException2 = "Or pass the path to the project using --project"; - - public const string RunCommandInvalidOperationException3 = "Specify which project file to use because this "; - - public const string RunCommandInvalidOperationException4 = "contains more than one project file."; + public const string RunCommandExceptionMultipleProjects = "Specify which project file to use because {0} contains more than one project file."; public const string RunCommandAdditionalArgsHelpText = "Arguments passed to the application that is being run."; } diff --git a/src/dotnet/commands/dotnet-run/RunCommand.cs b/src/dotnet/commands/dotnet-run/RunCommand.cs index 225757c50..c285a72ca 100644 --- a/src/dotnet/commands/dotnet-run/RunCommand.cs +++ b/src/dotnet/commands/dotnet-run/RunCommand.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using Microsoft.Build.Execution; +using Microsoft.Build.Evaluation; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Tools.MSBuild; @@ -15,16 +15,21 @@ namespace Microsoft.DotNet.Tools.Run { public string Configuration { get; set; } public string Framework { get; set; } + public bool NoBuild { get; set; } public string Project { get; set; } public IReadOnlyCollection Args { get; set; } private List _args; + private bool ShouldBuild => !NoBuild; public int Start() { Initialize(); - EnsureProjectIsBuilt(); + if (ShouldBuild) + { + EnsureProjectIsBuilt(); + } ICommand runCommand = GetRunCommand(); @@ -36,9 +41,9 @@ namespace Microsoft.DotNet.Tools.Run private void EnsureProjectIsBuilt() { List buildArgs = new List(); - - buildArgs.Add(Project); - + + buildArgs.Add(Project); + buildArgs.Add("/nologo"); buildArgs.Add("/verbosity:quiet"); @@ -78,23 +83,16 @@ namespace Microsoft.DotNet.Tools.Run globalProperties.Add("TargetFramework", Framework); } - ProjectInstance projectInstance = new ProjectInstance(Project, globalProperties, null); + Project project = new Project(Project, globalProperties, null); - string runProgram = projectInstance.GetPropertyValue("RunCommand"); + string runProgram = project.GetPropertyValue("RunCommand"); if (string.IsNullOrEmpty(runProgram)) { - string outputType = projectInstance.GetPropertyValue("OutputType"); - - throw new GracefulException( - string.Format( - LocalizableStrings.RunCommandExceptionUnableToRun, - "dotnet run", - "OutputType", - outputType)); + ThrowUnableToRunError(project); } - string runArguments = projectInstance.GetPropertyValue("RunArguments"); - string runWorkingDirectory = projectInstance.GetPropertyValue("RunWorkingDirectory"); + string runArguments = project.GetPropertyValue("RunArguments"); + string runWorkingDirectory = project.GetPropertyValue("RunWorkingDirectory"); string fullArguments = runArguments; if (_args.Any()) @@ -108,6 +106,30 @@ namespace Microsoft.DotNet.Tools.Run .WorkingDirectory(runWorkingDirectory); } + private void ThrowUnableToRunError(Project project) + { + string targetFrameworks = project.GetPropertyValue("TargetFrameworks"); + if (!string.IsNullOrEmpty(targetFrameworks)) + { + string targetFramework = project.GetPropertyValue("TargetFramework"); + if (string.IsNullOrEmpty(targetFramework)) + { + var framework = "--framework"; + + throw new GracefulException(LocalizableStrings.RunCommandExceptionUnableToRunSpecifyFramework, framework); + } + } + + string outputType = project.GetPropertyValue("OutputType"); + + throw new GracefulException( + string.Format( + LocalizableStrings.RunCommandExceptionUnableToRun, + "dotnet run", + "OutputType", + outputType)); + } + private void Initialize() { if (string.IsNullOrWhiteSpace(Project)) @@ -119,13 +141,11 @@ namespace Microsoft.DotNet.Tools.Run { var project = "--project"; - throw new InvalidOperationException( - $"Couldn't find a project to run. Ensure a project exists in {directory}, or pass the path to the project using {project}"); + throw new GracefulException(LocalizableStrings.RunCommandExceptionNoProjects, directory, project); } else if (projectFiles.Length > 1) { - throw new InvalidOperationException( - $"Specify which project file to use because {directory} contains more than one project file."); + throw new GracefulException(LocalizableStrings.RunCommandExceptionMultipleProjects, directory); } Project = projectFiles[0]; diff --git a/src/dotnet/commands/dotnet-run/RunCommandParser.cs b/src/dotnet/commands/dotnet-run/RunCommandParser.cs index 1dc22c122..aaadd8aa9 100644 --- a/src/dotnet/commands/dotnet-run/RunCommandParser.cs +++ b/src/dotnet/commands/dotnet-run/RunCommandParser.cs @@ -19,6 +19,7 @@ namespace Microsoft.DotNet.Cli { Configuration = o.SingleArgumentOrDefault("--configuration"), Framework = o.SingleArgumentOrDefault("--framework"), + NoBuild = o.HasOption("--no-build"), Project = o.SingleArgumentOrDefault("--project"), Args = o.Arguments }), diff --git a/test/dotnet-run.Tests/GivenDotnetRunRunsCsProj.cs b/test/dotnet-run.Tests/GivenDotnetRunRunsCsProj.cs index f4e3913c9..466d0c650 100644 --- a/test/dotnet-run.Tests/GivenDotnetRunRunsCsProj.cs +++ b/test/dotnet-run.Tests/GivenDotnetRunRunsCsProj.cs @@ -145,5 +145,23 @@ namespace Microsoft.DotNet.Cli.Run.Tests .Should().Pass() .And.HaveStdOutContaining("Hello World"); } + + [Fact] + public void ItReportsAGoodErrorWhenProjectHasMultipleFrameworks() + { + var testAppName = "MSBuildAppWithMultipleFrameworks"; + var testInstance = TestAssets.Get(testAppName) + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles(); + + // use --no-build so this test can run on all platforms. + // the test app targets net451, which can't be built on non-Windows + new RunCommand() + .WithWorkingDirectory(testInstance.Root) + .ExecuteWithCapturedOutput("--no-build") + .Should().Fail() + .And.HaveStdErrContaining("--framework"); + } } }