From 9755628485ca31ff75b91ac04a7160bf92c6155f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 13:24:58 +0000 Subject: [PATCH 1/5] Initial plan From 4db2295fb4df55e518f814d98e1ded34c9db5592 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 13:36:45 +0000 Subject: [PATCH 2/5] Route diagnostic output (error, warning, info, verbose) to stderr; fix ShouldHelp for exit codes Co-authored-by: roji <1862641+roji@users.noreply.github.com> --- src/dotnet-ef/RootCommand.cs | 8 ++++---- src/ef/AnsiConsole.cs | 1 + src/ef/Reporter.cs | 28 +++++++++++++++++++++++----- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/dotnet-ef/RootCommand.cs b/src/dotnet-ef/RootCommand.cs index 73802a1d391..a567f7a8a31 100644 --- a/src/dotnet-ef/RootCommand.cs +++ b/src/dotnet-ef/RootCommand.cs @@ -54,7 +54,7 @@ protected override int Execute(string[] _) { var commands = _args!.TakeWhile(a => a[0] != '-').ToList(); if (_help!.HasValue() - || ShouldHelp(commands)) + || ShouldHelp(commands, _args!)) { return ShowHelp(_help.HasValue(), commands); } @@ -333,9 +333,9 @@ private static string GetVersion() => typeof(RootCommand).Assembly.GetCustomAttribute()! .InformationalVersion; - private static bool ShouldHelp(IReadOnlyList commands) - => commands.Count == 0 - || (commands.Count == 1 + private static bool ShouldHelp(IReadOnlyList commands, IList args) + => args.Count == 0 + || (args.Count == 1 && (commands[0] == "database" || commands[0] == "dbcontext" || commands[0] == "migrations")); diff --git a/src/ef/AnsiConsole.cs b/src/ef/AnsiConsole.cs index 8403a40f19c..e8f7827a943 100644 --- a/src/ef/AnsiConsole.cs +++ b/src/ef/AnsiConsole.cs @@ -6,6 +6,7 @@ namespace Microsoft.EntityFrameworkCore.Tools; internal static class AnsiConsole { public static readonly AnsiTextWriter Out = new(Console.Out); + public static readonly AnsiTextWriter Error = new(Console.Error); public static void WriteLine(string? text) => Out.WriteLine(text); diff --git a/src/ef/Reporter.cs b/src/ef/Reporter.cs index f19e447e299..2d1fba51f8a 100644 --- a/src/ef/Reporter.cs +++ b/src/ef/Reporter.cs @@ -23,13 +23,13 @@ internal static class Reporter => NoColor ? value : colorizeFunc(value); public static void WriteError(string? message) - => WriteLine(Prefix(ErrorPrefix, Colorize(message, x => Bold + Red + x + Reset))); + => WriteStdErr(Prefix(ErrorPrefix, Colorize(message, x => Bold + Red + x + Reset))); public static void WriteWarning(string? message) - => WriteLine(Prefix(WarningPrefix, Colorize(message, x => Bold + Yellow + x + Reset))); + => WriteStdErr(Prefix(WarningPrefix, Colorize(message, x => Bold + Yellow + x + Reset))); public static void WriteInformation(string? message) - => WriteLine(Prefix(InfoPrefix, message)); + => WriteStdErr(Prefix(InfoPrefix, message)); public static void WriteData(string? message) => WriteLine(Prefix(DataPrefix, Colorize(message, x => Bold + Gray + x + Reset))); @@ -38,7 +38,7 @@ public static void WriteVerbose(string? message) { if (IsVerbose) { - WriteLine(Prefix(VerbosePrefix, Colorize(message, x => Bold + Black + x + Reset))); + WriteStdErr(Prefix(VerbosePrefix, Colorize(message, x => Bold + Black + x + Reset))); } } @@ -59,7 +59,25 @@ private static void WriteLine(string? value) } else { - AnsiConsole.WriteLine(value); + AnsiConsole.Out.WriteLine(value); + } + } + + private static void WriteStdErr(string? value) + { + if (PrefixOutput) + { + WriteLine(value); + return; + } + + if (NoColor) + { + Console.Error.WriteLine(value); + } + else + { + AnsiConsole.Error.WriteLine(value); } } } From 262e4abf1c798f75919173312428889edf3f3c28 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 13:39:23 +0000 Subject: [PATCH 3/5] Fix edge case in ShouldHelp when args start with dash Co-authored-by: roji <1862641+roji@users.noreply.github.com> --- src/dotnet-ef/RootCommand.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dotnet-ef/RootCommand.cs b/src/dotnet-ef/RootCommand.cs index a567f7a8a31..d019cf8c068 100644 --- a/src/dotnet-ef/RootCommand.cs +++ b/src/dotnet-ef/RootCommand.cs @@ -335,7 +335,9 @@ private static string GetVersion() private static bool ShouldHelp(IReadOnlyList commands, IList args) => args.Count == 0 + || commands.Count == 0 || (args.Count == 1 + && commands.Count == 1 && (commands[0] == "database" || commands[0] == "dbcontext" || commands[0] == "migrations")); From 8163931edb7bef4f73090d2ca028bfebeaacb5eb Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Fri, 20 Feb 2026 08:07:43 +0100 Subject: [PATCH 4/5] Address review comments --- src/ef/Reporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ef/Reporter.cs b/src/ef/Reporter.cs index 2d1fba51f8a..e9ec7b59bca 100644 --- a/src/ef/Reporter.cs +++ b/src/ef/Reporter.cs @@ -55,7 +55,7 @@ private static void WriteLine(string? value) { if (NoColor) { - Console.WriteLine(value); + Console.Out.WriteLine(value); } else { From 9ad653ff1a0b89f8e9ecdf6ab54899758ce69b93 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Fri, 20 Feb 2026 08:39:48 +0100 Subject: [PATCH 5/5] Redirect EF logging to stderr as well --- src/dotnet-ef/Program.cs | 5 +++++ src/ef/Program.cs | 6 ++++++ src/ef/Reporter.cs | 13 +++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/dotnet-ef/Program.cs b/src/dotnet-ef/Program.cs index 0ad0cbb64e4..83e678a5021 100644 --- a/src/dotnet-ef/Program.cs +++ b/src/dotnet-ef/Program.cs @@ -9,6 +9,11 @@ internal static class Program { private static int Main(string[] args) { + // Redirect Console.Out to stderr so that help text and diagnostics + // don't pollute stdout. Actual data output uses the original stdout saved by Reporter. + Reporter.SetStdOut(Console.Out); + Console.SetOut(Console.Error); + var app = new CommandLineApplication(throwOnUnexpectedArg: false) { Name = "dotnet ef" }; new RootCommand().Configure(app); diff --git a/src/ef/Program.cs b/src/ef/Program.cs index dc5a5deda48..ea7314042c0 100644 --- a/src/ef/Program.cs +++ b/src/ef/Program.cs @@ -16,6 +16,12 @@ private static int Main(string[] args) Console.OutputEncoding = Encoding.UTF8; } + // Redirect Console.Out to stderr so that any user-configured logging providers + // (e.g. ConsoleLogger) don't pollute stdout with diagnostic messages. + // Actual data output uses the original stdout saved by Reporter. + Reporter.SetStdOut(Console.Out); + Console.SetOut(Console.Error); + var app = new CommandLineApplication { Name = "ef" }; new RootCommand().Configure(app); diff --git a/src/ef/Reporter.cs b/src/ef/Reporter.cs index e9ec7b59bca..20efe64bebe 100644 --- a/src/ef/Reporter.cs +++ b/src/ef/Reporter.cs @@ -14,10 +14,19 @@ internal static class Reporter public const string DataPrefix = "data: "; public const string VerbosePrefix = "verbose: "; + private static TextWriter _stdOut = Console.Out; + private static AnsiTextWriter _stdOutAnsi = new(Console.Out); + public static bool IsVerbose { get; set; } public static bool NoColor { get; set; } public static bool PrefixOutput { get; set; } + public static void SetStdOut(TextWriter writer) + { + _stdOut = writer; + _stdOutAnsi = new AnsiTextWriter(writer); + } + [return: NotNullIfNotNull(nameof(value))] public static string? Colorize(string? value, Func colorizeFunc) => NoColor ? value : colorizeFunc(value); @@ -55,11 +64,11 @@ private static void WriteLine(string? value) { if (NoColor) { - Console.Out.WriteLine(value); + _stdOut.WriteLine(value); } else { - AnsiConsole.Out.WriteLine(value); + _stdOutAnsi.WriteLine(value); } }