diff --git a/src/dotnet-ef/Project.cs b/src/dotnet-ef/Project.cs index dc890dd55f0..060434ce8c0 100644 --- a/src/dotnet-ef/Project.cs +++ b/src/dotnet-ef/Project.cs @@ -51,7 +51,7 @@ public static Project FromFile( { Debug.Assert(!string.IsNullOrEmpty(file), "file is null or empty."); - var args = new List { "msbuild", }; + var args = new List { "build", "--no-restore", }; if (framework != null) { @@ -148,7 +148,7 @@ private record class ProjectMetadata private static bool HasMultipleTargetFrameworks(string file) { - var args = new List { "msbuild", "/getProperty:TargetFrameworks", file }; + var args = new List { "build", "--no-restore", "/getProperty:TargetFrameworks", file }; var output = new StringBuilder(); var exitCode = Exe.Run("dotnet", args, handleOutput: line => output.AppendLine(line)); diff --git a/src/dotnet-ef/Properties/Resources.Designer.cs b/src/dotnet-ef/Properties/Resources.Designer.cs index d4071969249..e8714245063 100644 --- a/src/dotnet-ef/Properties/Resources.Designer.cs +++ b/src/dotnet-ef/Properties/Resources.Designer.cs @@ -522,7 +522,7 @@ public static string PrefixDescription => GetString("PrefixDescription"); /// - /// The project to use. Defaults to the current working directory. + /// The project or file-based app to use. Defaults to the current working directory. /// public static string ProjectDescription => GetString("ProjectDescription"); @@ -566,7 +566,7 @@ public static string SelfContainedDescription => GetString("SelfContainedDescription"); /// - /// The startup project to use. Defaults to the current working directory. + /// The startup project or file-based app to use. Defaults to the current working directory. /// public static string StartupProjectDescription => GetString("StartupProjectDescription"); diff --git a/src/dotnet-ef/Properties/Resources.resx b/src/dotnet-ef/Properties/Resources.resx index b2af87b0376..9a68c50fee2 100644 --- a/src/dotnet-ef/Properties/Resources.resx +++ b/src/dotnet-ef/Properties/Resources.resx @@ -355,7 +355,7 @@ Prefix output with level. - The project to use. Defaults to the current working directory. + The project or file-based app to use. Defaults to the current working directory. Obsolete @@ -376,7 +376,7 @@ Also bundle the .NET runtime so it doesn't need to be installed on the machine. - The startup project to use. Defaults to the current working directory. + The startup project or file-based app to use. Defaults to the current working directory. The suffix to attach to the name of all the generated files diff --git a/test/dotnet-ef.Tests/DotNetEfConfigTest.cs b/test/dotnet-ef.Tests/DotNetEfConfigTest.cs index c194190a2bd..46685d2f18c 100644 --- a/test/dotnet-ef.Tests/DotNetEfConfigTest.cs +++ b/test/dotnet-ef.Tests/DotNetEfConfigTest.cs @@ -264,25 +264,9 @@ private static string CreateConfig(string directory, string contents) return configFile; } - private sealed class TestDirectory : IDisposable + private sealed class TestDirectory : TempDirectory { - public TestDirectory() - { - Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()); - Directory.CreateDirectory(Path); - } - - public string Path { get; } - public string CreateConfig(string contents) => DotNetEfConfigTest.CreateConfig(Path, contents); - - public void Dispose() - { - if (Directory.Exists(Path)) - { - Directory.Delete(Path, recursive: true); - } - } } } diff --git a/test/dotnet-ef.Tests/ProjectTest.cs b/test/dotnet-ef.Tests/ProjectTest.cs new file mode 100644 index 00000000000..87685e56767 --- /dev/null +++ b/test/dotnet-ef.Tests/ProjectTest.cs @@ -0,0 +1,95 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Tools; + +public sealed class ProjectTest(ITestOutputHelper output) +{ + private const string TargetFramework = "net10.0"; + + [Fact] + public void Csproj_metadata_can_be_extracted() + { + using var directory = new TempDirectory(); + var csprojFile = Path.Combine(directory.Path, "MyApp.csproj"); + File.WriteAllText(csprojFile, $""" + + + {TargetFramework} + + + """); + + Exe.Run("dotnet", ["restore", csprojFile], handleOutput: _ => { }); + + var project = Project.FromFile(csprojFile); + + Assert.Equal("C#", project.Language); + Assert.Equal("MyApp", project.AssemblyName); + Assert.Equal(TargetFramework, project.TargetFramework); + Assert.NotNull(project.OutputPath); + Assert.NotNull(project.ProjectDir); + Assert.Equal("MyApp.dll", project.TargetFileName); + } + + [Fact] + public void File_based_app_can_be_built() + { + WithVerboseOutput(() => + { + using var directory = new TempDirectory(); + var csFile = Path.Combine(directory.Path, "MyApp.cs"); + File.WriteAllText(csFile, $""" + #:property TargetFramework={TargetFramework} + Console.WriteLine("Hello"); + """); + + Exe.Run("dotnet", ["restore", csFile], handleOutput: Reporter.WriteVerbose); + + var project = Project.FromFile(csFile); + + Assert.Equal("C#", project.Language); + Assert.Equal("MyApp", project.AssemblyName); + Assert.Equal(TargetFramework, project.TargetFramework); + Assert.NotNull(project.OutputPath); + Assert.NotNull(project.ProjectDir); + Assert.NotNull(project.TargetFileName); + + project.Build(additionalArgs: null); + + var targetDir = Path.GetFullPath(Path.Combine(project.ProjectDir!, project.OutputPath!)); + var targetPath = Path.Combine(targetDir, project.TargetFileName!); + Assert.True(File.Exists(targetPath), $"Expected build output at {targetPath}"); + }); + } + + private void WithVerboseOutput(Action action) + { + var previousIsVerbose = Reporter.IsVerbose; + var previousPrefixOutput = Reporter.PrefixOutput; + Reporter.IsVerbose = true; + Reporter.PrefixOutput = true; + Reporter.SetStdOut(new TestOutputWriter(output)); + try + { + action(); + } + finally + { + Reporter.IsVerbose = previousIsVerbose; + Reporter.PrefixOutput = previousPrefixOutput; + Reporter.SetStdOut(Console.Out); + } + } + + private sealed class TestOutputWriter(ITestOutputHelper output) : StringWriter + { + public override void WriteLine(string? value) + { + if (value != null) + { + output.WriteLine(value); + } + } + } +} diff --git a/test/dotnet-ef.Tests/TempDirectory.cs b/test/dotnet-ef.Tests/TempDirectory.cs new file mode 100644 index 00000000000..ca92aeee97f --- /dev/null +++ b/test/dotnet-ef.Tests/TempDirectory.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Tools; + +internal class TempDirectory : IDisposable +{ + public TempDirectory() + { + Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()); + Directory.CreateDirectory(Path); + } + + public string Path { get; } + + public void Dispose() + { + if (Directory.Exists(Path)) + { + Directory.Delete(Path, recursive: true); + } + } +}