From 392da4bf6bc4dba8ed18ce416eba3f1dd093f474 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Thu, 5 Feb 2026 21:16:14 -0800 Subject: [PATCH] Add FileLoggerProvider for CLI log persistence and clean error messages - Add Channel-based async FileLoggerProvider writing to ~/.aspire/logs/ - Add --debug-level (-v) option for console log verbosity - Show 'See logs at {path}' instead of raw stack traces on console - Centralize child process option forwarding via RootCommand.GetChildProcessArgs() - Suppress Microsoft.Hosting.Lifetime logs from file logger - Log backchannel socket errors at Debug level when AppHost has exited - Add log cleanup to 'aspire cache clear' - Make CliExecutionContext.LogFilePath a required constructor parameter Fixes #13787 --- src/Aspire.Cli/CliExecutionContext.cs | 14 +- src/Aspire.Cli/Commands/AddCommand.cs | 2 +- src/Aspire.Cli/Commands/CacheCommand.cs | 39 +++ src/Aspire.Cli/Commands/ExecCommand.cs | 6 +- src/Aspire.Cli/Commands/RootCommand.cs | 44 +++ src/Aspire.Cli/Commands/RunCommand.cs | 84 +++--- .../Diagnostics/FileLoggerProvider.cs | 256 ++++++++++++++++++ src/Aspire.Cli/DotNet/DotNetCliRunner.cs | 5 +- src/Aspire.Cli/Program.cs | 82 +++++- .../Projects/DotNetAppHostProject.cs | 16 +- .../Resources/AddCommandStrings.resx | 3 +- src/Aspire.Cli/Resources/ErrorStrings.resx | 2 +- .../InteractionServiceStrings.Designer.cs | 11 +- .../Resources/InteractionServiceStrings.resx | 6 +- .../Resources/RootCommandStrings.Designer.cs | 9 + .../Resources/RootCommandStrings.resx | 3 + .../Resources/RunCommandStrings.resx | 2 +- .../Resources/TemplatingStrings.Designer.cs | 4 +- .../Resources/TemplatingStrings.resx | 8 +- .../Resources/xlf/AddCommandStrings.cs.xlf | 6 +- .../Resources/xlf/AddCommandStrings.de.xlf | 6 +- .../Resources/xlf/AddCommandStrings.es.xlf | 6 +- .../Resources/xlf/AddCommandStrings.fr.xlf | 6 +- .../Resources/xlf/AddCommandStrings.it.xlf | 6 +- .../Resources/xlf/AddCommandStrings.ja.xlf | 6 +- .../Resources/xlf/AddCommandStrings.ko.xlf | 6 +- .../Resources/xlf/AddCommandStrings.pl.xlf | 6 +- .../Resources/xlf/AddCommandStrings.pt-BR.xlf | 6 +- .../Resources/xlf/AddCommandStrings.ru.xlf | 6 +- .../Resources/xlf/AddCommandStrings.tr.xlf | 6 +- .../xlf/AddCommandStrings.zh-Hans.xlf | 6 +- .../xlf/AddCommandStrings.zh-Hant.xlf | 6 +- .../Resources/xlf/ErrorStrings.cs.xlf | 4 +- .../Resources/xlf/ErrorStrings.de.xlf | 4 +- .../Resources/xlf/ErrorStrings.es.xlf | 4 +- .../Resources/xlf/ErrorStrings.fr.xlf | 4 +- .../Resources/xlf/ErrorStrings.it.xlf | 4 +- .../Resources/xlf/ErrorStrings.ja.xlf | 4 +- .../Resources/xlf/ErrorStrings.ko.xlf | 4 +- .../Resources/xlf/ErrorStrings.pl.xlf | 4 +- .../Resources/xlf/ErrorStrings.pt-BR.xlf | 4 +- .../Resources/xlf/ErrorStrings.ru.xlf | 4 +- .../Resources/xlf/ErrorStrings.tr.xlf | 4 +- .../Resources/xlf/ErrorStrings.zh-Hans.xlf | 4 +- .../Resources/xlf/ErrorStrings.zh-Hant.xlf | 4 +- .../xlf/InteractionServiceStrings.cs.xlf | 9 +- .../xlf/InteractionServiceStrings.de.xlf | 9 +- .../xlf/InteractionServiceStrings.es.xlf | 9 +- .../xlf/InteractionServiceStrings.fr.xlf | 9 +- .../xlf/InteractionServiceStrings.it.xlf | 9 +- .../xlf/InteractionServiceStrings.ja.xlf | 9 +- .../xlf/InteractionServiceStrings.ko.xlf | 9 +- .../xlf/InteractionServiceStrings.pl.xlf | 9 +- .../xlf/InteractionServiceStrings.pt-BR.xlf | 9 +- .../xlf/InteractionServiceStrings.ru.xlf | 9 +- .../xlf/InteractionServiceStrings.tr.xlf | 9 +- .../xlf/InteractionServiceStrings.zh-Hans.xlf | 9 +- .../xlf/InteractionServiceStrings.zh-Hant.xlf | 9 +- .../Resources/xlf/RootCommandStrings.cs.xlf | 5 + .../Resources/xlf/RootCommandStrings.de.xlf | 5 + .../Resources/xlf/RootCommandStrings.es.xlf | 5 + .../Resources/xlf/RootCommandStrings.fr.xlf | 5 + .../Resources/xlf/RootCommandStrings.it.xlf | 5 + .../Resources/xlf/RootCommandStrings.ja.xlf | 5 + .../Resources/xlf/RootCommandStrings.ko.xlf | 5 + .../Resources/xlf/RootCommandStrings.pl.xlf | 5 + .../xlf/RootCommandStrings.pt-BR.xlf | 5 + .../Resources/xlf/RootCommandStrings.ru.xlf | 5 + .../Resources/xlf/RootCommandStrings.tr.xlf | 5 + .../xlf/RootCommandStrings.zh-Hans.xlf | 5 + .../xlf/RootCommandStrings.zh-Hant.xlf | 5 + .../Resources/xlf/RunCommandStrings.cs.xlf | 4 +- .../Resources/xlf/RunCommandStrings.de.xlf | 4 +- .../Resources/xlf/RunCommandStrings.es.xlf | 4 +- .../Resources/xlf/RunCommandStrings.fr.xlf | 4 +- .../Resources/xlf/RunCommandStrings.it.xlf | 4 +- .../Resources/xlf/RunCommandStrings.ja.xlf | 4 +- .../Resources/xlf/RunCommandStrings.ko.xlf | 4 +- .../Resources/xlf/RunCommandStrings.pl.xlf | 4 +- .../Resources/xlf/RunCommandStrings.pt-BR.xlf | 4 +- .../Resources/xlf/RunCommandStrings.ru.xlf | 4 +- .../Resources/xlf/RunCommandStrings.tr.xlf | 4 +- .../xlf/RunCommandStrings.zh-Hans.xlf | 4 +- .../xlf/RunCommandStrings.zh-Hant.xlf | 4 +- .../Resources/xlf/TemplatingStrings.cs.xlf | 12 +- .../Resources/xlf/TemplatingStrings.de.xlf | 12 +- .../Resources/xlf/TemplatingStrings.es.xlf | 12 +- .../Resources/xlf/TemplatingStrings.fr.xlf | 12 +- .../Resources/xlf/TemplatingStrings.it.xlf | 12 +- .../Resources/xlf/TemplatingStrings.ja.xlf | 12 +- .../Resources/xlf/TemplatingStrings.ko.xlf | 12 +- .../Resources/xlf/TemplatingStrings.pl.xlf | 12 +- .../Resources/xlf/TemplatingStrings.pt-BR.xlf | 12 +- .../Resources/xlf/TemplatingStrings.ru.xlf | 12 +- .../Resources/xlf/TemplatingStrings.tr.xlf | 12 +- .../xlf/TemplatingStrings.zh-Hans.xlf | 12 +- .../xlf/TemplatingStrings.zh-Hant.xlf | 12 +- .../Templating/DotNetTemplateFactory.cs | 4 +- src/Aspire.Cli/Utils/AppHostHelper.cs | 18 +- src/Aspire.Cli/Utils/OutputCollector.cs | 31 +++ .../CopilotCliAgentEnvironmentScannerTests.cs | 4 + .../VsCodeAgentEnvironmentScannerTests.cs | 2 + .../Caching/DiskCacheTests.cs | 2 +- .../Commands/RunCommandTests.cs | 14 +- .../DotNet/DotNetCliRunnerTests.cs | 2 +- .../DotNetSdkInstallerTests.cs | 3 +- .../ConsoleInteractionServiceTests.cs | 30 +- .../Mcp/ListAppHostsToolTests.cs | 2 +- .../Mcp/MockPackagingService.cs | 4 +- .../NuGet/NuGetPackagePrefetcherTests.cs | 2 +- .../NuGetConfigMergerSnapshotTests.cs | 10 +- .../Packaging/PackagingServiceTests.cs | 24 +- .../Projects/ProjectLocatorTests.cs | 2 +- .../Projects/ProjectUpdaterTests.cs | 2 +- .../Templating/DotNetTemplateFactoryTests.cs | 2 +- tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs | 10 +- 116 files changed, 938 insertions(+), 346 deletions(-) create mode 100644 src/Aspire.Cli/Diagnostics/FileLoggerProvider.cs diff --git a/src/Aspire.Cli/CliExecutionContext.cs b/src/Aspire.Cli/CliExecutionContext.cs index 7f68c238fbf..062c2b6c35c 100644 --- a/src/Aspire.Cli/CliExecutionContext.cs +++ b/src/Aspire.Cli/CliExecutionContext.cs @@ -5,12 +5,24 @@ namespace Aspire.Cli; -internal sealed class CliExecutionContext(DirectoryInfo workingDirectory, DirectoryInfo hivesDirectory, DirectoryInfo cacheDirectory, DirectoryInfo sdksDirectory, bool debugMode = false, IReadOnlyDictionary? environmentVariables = null, DirectoryInfo? homeDirectory = null) +internal sealed class CliExecutionContext(DirectoryInfo workingDirectory, DirectoryInfo hivesDirectory, DirectoryInfo cacheDirectory, DirectoryInfo sdksDirectory, DirectoryInfo logsDirectory, string logFilePath, bool debugMode = false, IReadOnlyDictionary? environmentVariables = null, DirectoryInfo? homeDirectory = null) { public DirectoryInfo WorkingDirectory { get; } = workingDirectory; public DirectoryInfo HivesDirectory { get; } = hivesDirectory; public DirectoryInfo CacheDirectory { get; } = cacheDirectory; public DirectoryInfo SdksDirectory { get; } = sdksDirectory; + + /// + /// Gets the directory where CLI log files are stored. + /// Used by cache clear command to clean up old log files. + /// + public DirectoryInfo LogsDirectory { get; } = logsDirectory; + + /// + /// Gets the path to the current session's log file. + /// + public string LogFilePath { get; } = logFilePath; + public DirectoryInfo HomeDirectory { get; } = homeDirectory ?? new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); public bool DebugMode { get; } = debugMode; diff --git a/src/Aspire.Cli/Commands/AddCommand.cs b/src/Aspire.Cli/Commands/AddCommand.cs index c0c1053185f..c075bc02953 100644 --- a/src/Aspire.Cli/Commands/AddCommand.cs +++ b/src/Aspire.Cli/Commands/AddCommand.cs @@ -213,7 +213,7 @@ await Parallel.ForEachAsync(channels, cancellationToken, async (channel, ct) => { InteractionService.DisplayLines(outputCollector.GetLines()); } - InteractionService.DisplayError(string.Format(CultureInfo.CurrentCulture, AddCommandStrings.PackageInstallationFailed, ExitCodeConstants.FailedToAddPackage)); + InteractionService.DisplayError(string.Format(CultureInfo.CurrentCulture, AddCommandStrings.PackageInstallationFailed, ExitCodeConstants.FailedToAddPackage, ExecutionContext.LogFilePath)); return ExitCodeConstants.FailedToAddPackage; } diff --git a/src/Aspire.Cli/Commands/CacheCommand.cs b/src/Aspire.Cli/Commands/CacheCommand.cs index 13043cb3f57..eef3d1501b7 100644 --- a/src/Aspire.Cli/Commands/CacheCommand.cs +++ b/src/Aspire.Cli/Commands/CacheCommand.cs @@ -108,6 +108,45 @@ protected override Task ExecuteAsync(ParseResult parseResult, CancellationT } } + // Also clear the logs directory (skip current process's log file) + var logsDirectory = ExecutionContext.LogsDirectory; + // Log files are named cli-{timestamp}-{pid}.log, so we need to check the suffix + var currentLogFileSuffix = $"-{Environment.ProcessId}.log"; + if (logsDirectory.Exists) + { + foreach (var file in logsDirectory.GetFiles("*", SearchOption.AllDirectories)) + { + // Skip the current process's log file to avoid deleting it while in use + if (file.Name.EndsWith(currentLogFileSuffix, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + try + { + file.Delete(); + filesDeleted++; + } + catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or System.Security.SecurityException) + { + // Continue deleting other files even if some fail + } + } + + // Delete subdirectories + foreach (var directory in logsDirectory.GetDirectories()) + { + try + { + directory.Delete(recursive: true); + } + catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or System.Security.SecurityException) + { + // Continue deleting other directories even if some fail + } + } + } + if (filesDeleted == 0) { InteractionService.DisplayMessage("information", CacheCommandStrings.CacheAlreadyEmpty); diff --git a/src/Aspire.Cli/Commands/ExecCommand.cs b/src/Aspire.Cli/Commands/ExecCommand.cs index 29707d34844..225266239b8 100644 --- a/src/Aspire.Cli/Commands/ExecCommand.cs +++ b/src/Aspire.Cli/Commands/ExecCommand.cs @@ -152,7 +152,7 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell env[KnownConfigNames.WaitForDebugger] = "true"; } - appHostCompatibilityCheck = await AppHostHelper.CheckAppHostCompatibilityAsync(_runner, InteractionService, effectiveAppHostProjectFile, Telemetry, ExecutionContext.WorkingDirectory, cancellationToken); + appHostCompatibilityCheck = await AppHostHelper.CheckAppHostCompatibilityAsync(_runner, InteractionService, effectiveAppHostProjectFile, Telemetry, ExecutionContext.WorkingDirectory, ExecutionContext.LogFilePath, cancellationToken); if (!appHostCompatibilityCheck?.IsCompatibleAppHost ?? throw new InvalidOperationException(RunCommandStrings.IsCompatibleAppHostIsNull)) { return ExitCodeConstants.FailedToDotnetRunAppHost; @@ -253,7 +253,7 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell if (result != 0) { InteractionService.DisplayLines(runOutputCollector.GetLines()); - InteractionService.DisplayError(RunCommandStrings.ProjectCouldNotBeRun); + InteractionService.DisplayError(string.Format(CultureInfo.CurrentCulture, RunCommandStrings.ProjectCouldNotBeRun, ExecutionContext.LogFilePath)); return result; } else @@ -264,7 +264,7 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell else { InteractionService.DisplayLines(runOutputCollector.GetLines()); - InteractionService.DisplayError(RunCommandStrings.ProjectCouldNotBeRun); + InteractionService.DisplayError(string.Format(CultureInfo.CurrentCulture, RunCommandStrings.ProjectCouldNotBeRun, ExecutionContext.LogFilePath)); return ExitCodeConstants.FailedToDotnetRunAppHost; } } diff --git a/src/Aspire.Cli/Commands/RootCommand.cs b/src/Aspire.Cli/Commands/RootCommand.cs index bc16361315b..64da8930f04 100644 --- a/src/Aspire.Cli/Commands/RootCommand.cs +++ b/src/Aspire.Cli/Commands/RootCommand.cs @@ -3,6 +3,7 @@ using System.CommandLine; using System.CommandLine.Help; +using Microsoft.Extensions.Logging; #if DEBUG using System.Globalization; @@ -22,6 +23,13 @@ internal sealed class RootCommand : BaseRootCommand public static readonly Option DebugOption = new(CommonOptionNames.Debug, CommonOptionNames.DebugShort) { Description = RootCommandStrings.DebugArgumentDescription, + Recursive = true, + Hidden = true // Hidden for backward compatibility, use --debug-level instead + }; + + public static readonly Option DebugLevelOption = new("--debug-level", "-v") + { + Description = RootCommandStrings.DebugLevelArgumentDescription, Recursive = true }; @@ -58,6 +66,41 @@ internal sealed class RootCommand : BaseRootCommand DefaultValueFactory = _ => false }; + /// + /// Global options that should be passed through to child CLI processes when spawning. + /// Add new global options here to ensure they are forwarded during detached mode execution. + /// + private static readonly (Option Option, Func GetArgs)[] s_childProcessOptions = + [ + (DebugOption, pr => pr.GetValue(DebugOption) ? ["--debug"] : null), + (DebugLevelOption, pr => + { + var level = pr.GetValue(DebugLevelOption); + return level.HasValue ? ["--debug-level", level.Value.ToString()] : null; + }), + (WaitForDebuggerOption, pr => pr.GetValue(WaitForDebuggerOption) ? ["--wait-for-debugger"] : null), + ]; + + /// + /// Gets the command-line arguments for global options that should be passed to a child CLI process. + /// + /// The parse result from the current command invocation. + /// Arguments to pass to the child process. + public static IEnumerable GetChildProcessArgs(ParseResult parseResult) + { + foreach (var (_, getArgs) in s_childProcessOptions) + { + var args = getArgs(parseResult); + if (args is not null) + { + foreach (var arg in args) + { + yield return arg; + } + } + } + } + private readonly IInteractionService _interactionService; public RootCommand( @@ -116,6 +159,7 @@ public RootCommand( #endif Options.Add(DebugOption); + Options.Add(DebugLevelOption); Options.Add(NonInteractiveOption); Options.Add(NoLogoOption); Options.Add(BannerOption); diff --git a/src/Aspire.Cli/Commands/RunCommand.cs b/src/Aspire.Cli/Commands/RunCommand.cs index 954965a0eb6..ba6384a4269 100644 --- a/src/Aspire.Cli/Commands/RunCommand.cs +++ b/src/Aspire.Cli/Commands/RunCommand.cs @@ -66,6 +66,7 @@ internal sealed class RunCommand : BaseCommand private readonly ILogger _logger; private readonly IAppHostProjectFactory _projectFactory; private readonly IAuxiliaryBackchannelMonitor _backchannelMonitor; + private readonly Diagnostics.FileLoggerProvider _fileLoggerProvider; private static readonly Option s_projectOption = new("--project") { @@ -102,6 +103,7 @@ public RunCommand( ILogger logger, IAppHostProjectFactory projectFactory, IAuxiliaryBackchannelMonitor backchannelMonitor, + Diagnostics.FileLoggerProvider fileLoggerProvider, TimeProvider? timeProvider) : base("run", RunCommandStrings.Description, features, updateNotifier, executionContext, interactionService, telemetry) { @@ -118,6 +120,7 @@ public RunCommand( _logger = logger; _projectFactory = projectFactory; _backchannelMonitor = backchannelMonitor; + _fileLoggerProvider = fileLoggerProvider; _timeProvider = timeProvider ?? TimeProvider.System; Options.Add(s_projectOption); @@ -252,7 +255,7 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell { InteractionService.DisplayLines(outputCollector.GetLines()); } - InteractionService.DisplayError(InteractionServiceStrings.ProjectCouldNotBeBuilt); + InteractionService.DisplayError(string.Format(CultureInfo.CurrentCulture, InteractionServiceStrings.ProjectCouldNotBeBuilt, ExecutionContext.LogFilePath)); return await pendingRun; } @@ -261,12 +264,8 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell isExtensionHost ? InteractionServiceStrings.BuildingAppHost : RunCommandStrings.ConnectingToAppHost, async () => await backchannelCompletionSource.Task.WaitAsync(cancellationToken)); - // Set up log capture - var logFile = AppHostHelper.GetLogFilePath( - Environment.ProcessId, - ExecutionContext.HomeDirectory.FullName, - _timeProvider); - var pendingLogCapture = CaptureAppHostLogsAsync(logFile, backchannel, _interactionService, cancellationToken); + // Set up log capture - writes to unified CLI log file + var pendingLogCapture = CaptureAppHostLogsAsync(_fileLoggerProvider, backchannel, _interactionService, cancellationToken); // Get dashboard URLs var dashboardUrls = await InteractionService.ShowStatusAsync( @@ -286,7 +285,7 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell appHostRelativePath, dashboardUrls.BaseUrlWithLoginToken, dashboardUrls.CodespacesUrlWithLoginToken, - logFile.FullName, + _fileLoggerProvider.LogFilePath, isExtensionHost); // Handle remote environments (Codespaces, Remote Containers, SSH) @@ -375,10 +374,8 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell var errorMessage = string.Format(CultureInfo.CurrentCulture, InteractionServiceStrings.ErrorConnectingToAppHost, ex.Message.EscapeMarkup()); Telemetry.RecordError(errorMessage, ex); InteractionService.DisplayError(errorMessage); - if (context?.OutputCollector is { } outputCollector) - { - InteractionService.DisplayLines(outputCollector.GetLines()); - } + // Don't display raw output - it's already in the log file + InteractionService.DisplayMessage("page_facing_up", string.Format(CultureInfo.CurrentCulture, InteractionServiceStrings.SeeLogsAt, ExecutionContext.LogFilePath)); return ExitCodeConstants.FailedToDotnetRunAppHost; } catch (Exception ex) @@ -386,10 +383,8 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell var errorMessage = string.Format(CultureInfo.CurrentCulture, InteractionServiceStrings.UnexpectedErrorOccurred, ex.Message.EscapeMarkup()); Telemetry.RecordError(errorMessage, ex); InteractionService.DisplayError(errorMessage); - if (context?.OutputCollector is { } outputCollector) - { - InteractionService.DisplayLines(outputCollector.GetLines()); - } + // Don't display raw output - it's already in the log file + InteractionService.DisplayMessage("page_facing_up", string.Format(CultureInfo.CurrentCulture, InteractionServiceStrings.SeeLogsAt, ExecutionContext.LogFilePath)); return ExitCodeConstants.FailedToDotnetRunAppHost; } } @@ -516,22 +511,12 @@ internal static int RenderAppHostSummary( return longestLabelLength; } - private static async Task CaptureAppHostLogsAsync(FileInfo logFile, IAppHostCliBackchannel backchannel, IInteractionService interactionService, CancellationToken cancellationToken) + private static async Task CaptureAppHostLogsAsync(Diagnostics.FileLoggerProvider fileLoggerProvider, IAppHostCliBackchannel backchannel, IInteractionService interactionService, CancellationToken cancellationToken) { try { await Task.Yield(); - if (!logFile.Directory!.Exists) - { - logFile.Directory.Create(); - } - - using var streamWriter = new StreamWriter(logFile.FullName, append: true) - { - AutoFlush = true - }; - var logEntries = backchannel.GetAppHostLogEntriesAsync(cancellationToken); await foreach (var entry in logEntries.WithCancellation(cancellationToken)) @@ -545,7 +530,19 @@ private static async Task CaptureAppHostLogsAsync(FileInfo logFile, IAppHostCliB } } - await streamWriter.WriteLineAsync($"{entry.Timestamp:HH:mm:ss} [{entry.LogLevel}] {entry.CategoryName}: {entry.Message}"); + // Write to the unified log file via FileLoggerProvider + var timestamp = entry.Timestamp.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); + var level = entry.LogLevel switch + { + LogLevel.Trace => "TRCE", + LogLevel.Debug => "DBUG", + LogLevel.Information => "INFO", + LogLevel.Warning => "WARN", + LogLevel.Error => "FAIL", + LogLevel.Critical => "CRIT", + _ => entry.LogLevel.ToString().ToUpperInvariant() + }; + fileLoggerProvider.WriteLog($"[{timestamp}] [{level}] [AppHost/{entry.CategoryName}] {entry.Message}"); } } catch (OperationCanceledException) @@ -668,15 +665,10 @@ private async Task ExecuteDetachedAsync(ParseResult parseResult, FileInfo? effectiveAppHostFile.FullName }; - // Pass through global options that were matched at the root level - if (parseResult.GetValue(RootCommand.DebugOption)) - { - args.Add("--debug"); - } - if (parseResult.GetValue(RootCommand.WaitForDebuggerOption)) - { - args.Add("--wait-for-debugger"); - } + // Pass through global options that should be forwarded to child CLI + args.AddRange(RootCommand.GetChildProcessArgs(parseResult)); + + // Pass through run-specific options if (parseResult.GetValue(s_isolatedOption)) { args.Add("--isolated"); @@ -841,12 +833,6 @@ private async Task ExecuteDetachedAsync(ParseResult parseResult, FileInfo? return ExitCodeConstants.FailedToDotnetRunAppHost; } - // Compute the expected log file path for error message - var expectedLogFile = AppHostHelper.GetLogFilePath( - childProcess.Id, - ExecutionContext.HomeDirectory.FullName, - _timeProvider); - if (childExitedEarly) { _interactionService.DisplayError(string.Format( @@ -876,7 +862,7 @@ private async Task ExecuteDetachedAsync(ParseResult parseResult, FileInfo? _interactionService.DisplayMessage("magnifying_glass_tilted_right", string.Format( CultureInfo.CurrentCulture, RunCommandStrings.CheckLogsForDetails, - expectedLogFile.FullName)); + _fileLoggerProvider.LogFilePath)); return ExitCodeConstants.FailedToDotnetRunAppHost; } @@ -886,12 +872,6 @@ private async Task ExecuteDetachedAsync(ParseResult parseResult, FileInfo? // Get the dashboard URLs var dashboardUrls = await backchannel.GetDashboardUrlsAsync(cancellationToken).ConfigureAwait(false); - // Get the log file path - var logFile = AppHostHelper.GetLogFilePath( - appHostInfo?.ProcessId ?? childProcess.Id, - ExecutionContext.HomeDirectory.FullName, - _timeProvider); - var pid = appHostInfo?.ProcessId ?? childProcess.Id; if (format == OutputFormat.Json) @@ -902,7 +882,7 @@ private async Task ExecuteDetachedAsync(ParseResult parseResult, FileInfo? pid, childProcess.Id, dashboardUrls?.BaseUrlWithLoginToken, - logFile.FullName); + _fileLoggerProvider.LogFilePath); var json = JsonSerializer.Serialize(result, RunCommandJsonContext.RelaxedEscaping.DetachOutputInfo); _interactionService.DisplayRawText(json); } @@ -915,7 +895,7 @@ private async Task ExecuteDetachedAsync(ParseResult parseResult, FileInfo? appHostRelativePath, dashboardUrls?.BaseUrlWithLoginToken, codespacesUrl: null, - logFile.FullName, + _fileLoggerProvider.LogFilePath, isExtensionHost, pid); _ansiConsole.WriteLine(); diff --git a/src/Aspire.Cli/Diagnostics/FileLoggerProvider.cs b/src/Aspire.Cli/Diagnostics/FileLoggerProvider.cs new file mode 100644 index 00000000000..4035352669d --- /dev/null +++ b/src/Aspire.Cli/Diagnostics/FileLoggerProvider.cs @@ -0,0 +1,256 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; +using System.Text; +using System.Threading.Channels; +using Microsoft.Extensions.Logging; +using Spectre.Console; + +namespace Aspire.Cli.Diagnostics; + +/// +/// A logger provider that writes all log messages to a file on disk. +/// This provider captures logs at all levels (Trace through Critical) for diagnostics, +/// independent of console verbosity settings. +/// +internal sealed class FileLoggerProvider : ILoggerProvider +{ + private const int MaxQueuedMessages = 1024; + + private readonly string _logFilePath; + private readonly StreamWriter? _writer; + private readonly Channel? _channel; + private readonly Task? _writerTask; + private bool _disposed; + + /// + /// Gets the path to the log file. + /// + public string LogFilePath => _logFilePath; + + /// + /// Creates a new FileLoggerProvider that writes to the specified directory. + /// + /// The directory where log files will be written. + /// The time provider for timestamp generation. + /// Optional console for error messages. Defaults to stderr. + public FileLoggerProvider(string logsDirectory, TimeProvider timeProvider, IAnsiConsole? errorConsole = null) + { + var pid = Environment.ProcessId; + var timestamp = timeProvider.GetUtcNow().ToString("yyyy-MM-dd-HH-mm-ss", CultureInfo.InvariantCulture); + // Timestamp first so files sort chronologically by name + _logFilePath = Path.Combine(logsDirectory, $"cli-{timestamp}-{pid}.log"); + + try + { + Directory.CreateDirectory(logsDirectory); + _writer = new StreamWriter(_logFilePath, append: false, Encoding.UTF8) + { + AutoFlush = true + }; + + _channel = CreateChannel(); + _writerTask = Task.Run(ProcessLogQueueAsync); + } + catch (IOException ex) + { + WriteWarning(errorConsole, _logFilePath, ex.Message); + _writer = null; + _channel = null; + } + } + + /// + /// Creates a new FileLoggerProvider with a specific log file path (for testing). + /// + /// The full path to the log file. + /// Optional console for error messages. Defaults to stderr. + internal FileLoggerProvider(string logFilePath, IAnsiConsole? errorConsole = null) + { + _logFilePath = logFilePath; + + try + { + var directory = Path.GetDirectoryName(logFilePath); + if (!string.IsNullOrEmpty(directory)) + { + Directory.CreateDirectory(directory); + } + + _writer = new StreamWriter(logFilePath, append: false, Encoding.UTF8) + { + AutoFlush = true + }; + + _channel = CreateChannel(); + _writerTask = Task.Run(ProcessLogQueueAsync); + } + catch (IOException ex) + { + WriteWarning(errorConsole, logFilePath, ex.Message); + _writer = null; + _channel = null; + } + } + + private static Channel CreateChannel() => + Channel.CreateBounded(new BoundedChannelOptions(MaxQueuedMessages) + { + FullMode = BoundedChannelFullMode.Wait, + SingleReader = true, + SingleWriter = false + }); + + private static void WriteWarning(IAnsiConsole? console, string path, string message) + { + // Use provided console or create a minimal one for stderr + var errorConsole = console ?? AnsiConsole.Create(new AnsiConsoleSettings + { + Out = new AnsiConsoleOutput(Console.Error) + }); + errorConsole.MarkupLine($"[yellow]⚠️ Warning:[/] Could not create log file at [blue]{path.EscapeMarkup()}[/]: {message.EscapeMarkup()}"); + } + + private async Task ProcessLogQueueAsync() + { + if (_channel is null || _writer is null) + { + return; + } + + try + { + await foreach (var message in _channel.Reader.ReadAllAsync()) + { + await _writer.WriteLineAsync(message).ConfigureAwait(false); + } + } + catch (ChannelClosedException) + { + // Expected when channel is completed during disposal + } + catch (ObjectDisposedException) + { + // Writer was disposed while writing - expected during shutdown + } + } + + public ILogger CreateLogger(string categoryName) + { + return new FileLogger(this, categoryName); + } + + internal void WriteLog(string message) + { + if (_channel is null || _disposed) + { + return; + } + + // Try to write to the channel - this will succeed as long as there's space + // and the channel hasn't been completed yet + if (_channel.Writer.TryWrite(message)) + { + return; + } + + // TryWrite failed - either channel is full (need backpressure) or completed (disposal) + if (_disposed) + { + return; + } + + // Try async write which will wait for space or throw if completed + try + { + // WaitToWriteAsync returns false if the channel is completed + // This is cheaper than catching ChannelClosedException from WriteAsync + if (!_channel.Writer.WaitToWriteAsync().AsTask().GetAwaiter().GetResult()) + { + return; + } + + // Space is available, write the message + _channel.Writer.TryWrite(message); + } + catch (ChannelClosedException) + { + // Channel was completed between WaitToWriteAsync and TryWrite - rare race + } + } + + public void Dispose() + { + if (_disposed) + { + return; + } + + _disposed = true; + + // Complete the channel to signal the writer task to finish + // Any messages already in the channel will be drained by the writer task + _channel?.Writer.TryComplete(); + + // Wait for the writer task to finish processing ALL remaining messages + _writerTask?.GetAwaiter().GetResult(); + + _writer?.Dispose(); + } +} + +/// +/// A logger that writes to a file via the FileLoggerProvider. +/// +internal sealed class FileLogger(FileLoggerProvider provider, string categoryName) : ILogger +{ + // Suppress Microsoft.Hosting.Lifetime logs - these are CLI host lifecycle noise + private static readonly string[] s_suppressedCategories = ["Microsoft.Hosting.Lifetime"]; + + // Always enabled for file logging, except suppressed categories + public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None && !s_suppressedCategories.Contains(categoryName); + + public IDisposable? BeginScope(TState state) where TState : notnull => null; + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) + { + if (!IsEnabled(logLevel)) + { + return; + } + + var message = formatter(state, exception); + if (string.IsNullOrEmpty(message) && exception is null) + { + return; + } + + var timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); + var level = GetLogLevelString(logLevel); + var shortCategory = GetShortCategoryName(categoryName); + + var logMessage = exception is not null + ? $"[{timestamp}] [{level}] [{shortCategory}] {message}{Environment.NewLine}{exception}" + : $"[{timestamp}] [{level}] [{shortCategory}] {message}"; + + provider.WriteLog(logMessage); + } + + private static string GetLogLevelString(LogLevel logLevel) => logLevel switch + { + LogLevel.Trace => "TRCE", + LogLevel.Debug => "DBUG", + LogLevel.Information => "INFO", + LogLevel.Warning => "WARN", + LogLevel.Error => "FAIL", + LogLevel.Critical => "CRIT", + _ => logLevel.ToString().ToUpperInvariant() + }; + + private static string GetShortCategoryName(string categoryName) + { + var lastDotIndex = categoryName.LastIndexOf('.'); + return lastDotIndex >= 0 ? categoryName.Substring(lastDotIndex + 1) : categoryName; + } +} diff --git a/src/Aspire.Cli/DotNet/DotNetCliRunner.cs b/src/Aspire.Cli/DotNet/DotNetCliRunner.cs index b3247b6c6c5..f8b9156fcd8 100644 --- a/src/Aspire.Cli/DotNet/DotNetCliRunner.cs +++ b/src/Aspire.Cli/DotNet/DotNetCliRunner.cs @@ -176,8 +176,9 @@ private async Task StartBackchannelAsync(IDotNetCliExecution? execution, string } catch (SocketException ex) when (execution is not null && execution.HasExited && execution.ExitCode != 0) { - logger.LogError(ex, "AppHost process has exited. Unable to connect to backchannel at {SocketPath}", socketPath); - var backchannelException = new FailedToConnectBackchannelConnection($"AppHost process has exited unexpectedly. Use --debug to see more details.", ex); + // Log at Debug level - this is expected when AppHost crashes, the real error is in AppHost output + logger.LogDebug(ex, "AppHost process has exited. Unable to connect to backchannel at {SocketPath}", socketPath); + var backchannelException = new FailedToConnectBackchannelConnection("AppHost process has exited unexpectedly.", ex); backchannelCompletionSource.SetException(backchannelException); return; } diff --git a/src/Aspire.Cli/Program.cs b/src/Aspire.Cli/Program.cs index 124e8587cc8..052182ecd5f 100644 --- a/src/Aspire.Cli/Program.cs +++ b/src/Aspire.Cli/Program.cs @@ -17,6 +17,7 @@ using Aspire.Cli.Commands; using Aspire.Cli.Commands.Sdk; using Aspire.Cli.Configuration; +using Aspire.Cli.Diagnostics; using Aspire.Cli.DotNet; using Aspire.Cli.Git; using Aspire.Cli.Interaction; @@ -52,6 +53,43 @@ private static string GetUsersAspirePath() return aspirePath; } + /// + /// Parses logging options from command-line arguments. + /// Returns the console log level (if specified) and whether debug mode is enabled. + /// + private static (LogLevel? ConsoleLogLevel, bool DebugMode) ParseLoggingOptions(string[]? args) + { + if (args is null || args.Length == 0) + { + return (null, false); + } + + // Check for --debug or -d (backward compatibility) + var debugMode = args.Any(a => a == "--debug" || a == "-d"); + + // Check for --debug-level or -v + LogLevel? logLevel = null; + for (var i = 0; i < args.Length; i++) + { + if ((args[i] == "--debug-level" || args[i] == "-v") && i + 1 < args.Length) + { + if (Enum.TryParse(args[i + 1], ignoreCase: true, out var parsedLevel)) + { + logLevel = parsedLevel; + } + break; + } + } + + // --debug implies Debug log level if --verbosity not specified + if (debugMode && logLevel is null) + { + logLevel = LogLevel.Debug; + } + + return (logLevel, debugMode); + } + private static string GetGlobalSettingsPath() { var usersAspirePath = GetUsersAspirePath(); @@ -112,12 +150,21 @@ internal static async Task BuildApplicationAsync(string[] args, Dictionar // - Diagnostic provider for OTLP/console exporters (exports all activities, DEBUG only) builder.Services.AddSingleton(new TelemetryManager(builder.Configuration, args)); - var debugMode = args?.Any(a => a == CommonOptionNames.Debug || a == CommonOptionNames.DebugShort) ?? false; + // Parse logging options from args + var (consoleLogLevel, debugMode) = ParseLoggingOptions(args); var extensionEndpoint = builder.Configuration[KnownConfigNames.ExtensionEndpoint]; - if (debugMode && !isMcpStartCommand && extensionEndpoint is null) + // Always register FileLoggerProvider to capture logs to disk + // This captures complete CLI session details for diagnostics + var logsDirectory = Path.Combine(GetUsersAspirePath(), "logs"); + var fileLoggerProvider = new FileLoggerProvider(logsDirectory, TimeProvider.System); + builder.Services.AddSingleton(fileLoggerProvider); // Register for direct access to LogFilePath + builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton(fileLoggerProvider)); + + // Configure console logging based on --verbosity or --debug + if (consoleLogLevel is not null && !isMcpStartCommand && extensionEndpoint is null) { - builder.Logging.AddFilter("Aspire.Cli", LogLevel.Debug); + builder.Logging.AddFilter("Aspire.Cli", consoleLogLevel.Value); builder.Logging.AddFilter("Microsoft.Hosting.Lifetime", LogLevel.Warning); // Reduce noise from hosting lifecycle // Use custom Spectre Console logger for clean debug output to stderr builder.Services.AddSingleton(sp => @@ -128,9 +175,9 @@ internal static async Task BuildApplicationAsync(string[] args, Dictionar // This keeps stdout clean for MCP protocol JSON-RPC messages if (isMcpStartCommand) { - if (debugMode) + if (consoleLogLevel is not null) { - builder.Logging.AddFilter("Aspire.Cli", LogLevel.Debug); + builder.Logging.AddFilter("Aspire.Cli", consoleLogLevel.Value); builder.Logging.AddFilter("Microsoft.Hosting.Lifetime", LogLevel.Warning); // Reduce noise from hosting lifecycle } @@ -142,7 +189,11 @@ internal static async Task BuildApplicationAsync(string[] args, Dictionar } // Shared services. - builder.Services.AddSingleton(_ => BuildCliExecutionContext(debugMode)); + builder.Services.AddSingleton(sp => + { + var logFilePath = sp.GetRequiredService().LogFilePath; + return BuildCliExecutionContext(debugMode, logsDirectory, logFilePath); + }); builder.Services.AddSingleton(s => new ConsoleEnvironment( BuildAnsiConsole(s, Console.Out), BuildAnsiConsole(s, Console.Error))); @@ -302,13 +353,13 @@ private static DirectoryInfo GetSdksDirectory() return new DirectoryInfo(sdksPath); } - private static CliExecutionContext BuildCliExecutionContext(bool debugMode) + private static CliExecutionContext BuildCliExecutionContext(bool debugMode, string logsDirectory, string logFilePath) { var workingDirectory = new DirectoryInfo(Environment.CurrentDirectory); var hivesDirectory = GetHivesDirectory(); var cacheDirectory = GetCacheDirectory(); var sdksDirectory = GetSdksDirectory(); - return new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, sdksDirectory, debugMode); + return new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, sdksDirectory, new DirectoryInfo(logsDirectory), logFilePath, debugMode); } private static DirectoryInfo GetCacheDirectory() @@ -475,8 +526,17 @@ public static async Task Main(string[] args) mainActivity.AddTag(TelemetryConstants.Tags.ProcessExecutableName, "aspire"); } + // Create a dedicated logger for CLI session info + var cliLogger = app.Services.GetRequiredService().CreateLogger(); + try { + // Log command invocation details for debugging + var commandLine = args.Length > 0 ? $"aspire {string.Join(" ", args)}" : "aspire"; + var workingDir = Environment.CurrentDirectory; + cliLogger.LogInformation("Command: {CommandLine}", commandLine); + cliLogger.LogInformation("Working directory: {WorkingDirectory}", workingDir); + logger.LogDebug("Parsing arguments: {Args}", string.Join(" ", args)); var parseResult = rootCommand.Parse(args); @@ -487,6 +547,9 @@ public static async Task Main(string[] args) var exitCode = await parseResult.InvokeAsync(invokeConfig, cts.Token); + // Log exit code for debugging + cliLogger.LogInformation("Exit code: {ExitCode}", exitCode); + mainActivity?.SetTag(TelemetryConstants.Tags.ProcessExitCode, exitCode); mainActivity?.Stop(); @@ -509,6 +572,9 @@ public static async Task Main(string[] args) interactionService.DisplayError(string.Format(CultureInfo.CurrentCulture, InteractionServiceStrings.UnexpectedErrorOccurred, ex.Message)); } + // Log exit code for debugging + cliLogger.LogError("Exit code: {ExitCode} (exception)", unknownErrorExitCode); + mainActivity?.SetTag(TelemetryConstants.Tags.ProcessExitCode, unknownErrorExitCode); mainActivity?.Stop(); diff --git a/src/Aspire.Cli/Projects/DotNetAppHostProject.cs b/src/Aspire.Cli/Projects/DotNetAppHostProject.cs index 8b8e0c400e1..0877339bdec 100644 --- a/src/Aspire.Cli/Projects/DotNetAppHostProject.cs +++ b/src/Aspire.Cli/Projects/DotNetAppHostProject.cs @@ -29,6 +29,7 @@ internal sealed class DotNetAppHostProject : IAppHostProject private readonly TimeProvider _timeProvider; private readonly IProjectUpdater _projectUpdater; private readonly RunningInstanceManager _runningInstanceManager; + private readonly Diagnostics.FileLoggerProvider _fileLoggerProvider; private static readonly string[] s_detectionPatterns = ["*.csproj", "*.fsproj", "*.vbproj", "apphost.cs"]; private static readonly string[] s_projectExtensions = [".csproj", ".fsproj", ".vbproj"]; @@ -41,6 +42,7 @@ public DotNetAppHostProject( IFeatures features, IProjectUpdater projectUpdater, ILogger logger, + Diagnostics.FileLoggerProvider fileLoggerProvider, TimeProvider? timeProvider = null) { _runner = runner; @@ -50,6 +52,7 @@ public DotNetAppHostProject( _features = features; _projectUpdater = projectUpdater; _logger = logger; + _fileLoggerProvider = fileLoggerProvider; _timeProvider = timeProvider ?? TimeProvider.System; _runningInstanceManager = new RunningInstanceManager(_logger, _interactionService, _timeProvider); } @@ -180,7 +183,7 @@ public async Task RunAsync(AppHostProjectContext context, CancellationToken var effectiveAppHostFile = context.AppHostFile; var isExtensionHost = ExtensionHelper.IsExtensionHost(_interactionService, out _, out var extensionBackchannel); - var buildOutputCollector = new OutputCollector(); + var buildOutputCollector = new OutputCollector(_fileLoggerProvider, "Build"); (bool IsCompatibleAppHost, bool SupportsBackchannel, string? AspireHostingVersion)? appHostCompatibilityCheck = null; @@ -255,7 +258,7 @@ public async Task RunAsync(AppHostProjectContext context, CancellationToken } else { - appHostCompatibilityCheck = await AppHostHelper.CheckAppHostCompatibilityAsync(_runner, _interactionService, effectiveAppHostFile, _telemetry, context.WorkingDirectory, cancellationToken); + appHostCompatibilityCheck = await AppHostHelper.CheckAppHostCompatibilityAsync(_runner, _interactionService, effectiveAppHostFile, _telemetry, context.WorkingDirectory, _fileLoggerProvider.LogFilePath, cancellationToken); } } catch @@ -273,7 +276,7 @@ public async Task RunAsync(AppHostProjectContext context, CancellationToken // Create collector and store in context for exception handling // This must be set BEFORE signaling build completion to avoid a race condition - var runOutputCollector = new OutputCollector(); + var runOutputCollector = new OutputCollector(_fileLoggerProvider, "AppHost"); context.OutputCollector = runOutputCollector; // Signal that build/preparation is complete @@ -349,6 +352,7 @@ public async Task PublishAsync(PublishContext context, CancellationToken ca effectiveAppHostFile, _telemetry, context.WorkingDirectory, + _fileLoggerProvider.LogFilePath, cancellationToken); if (!compatibilityCheck.IsCompatibleAppHost) @@ -362,7 +366,7 @@ public async Task PublishAsync(PublishContext context, CancellationToken ca } // Build the apphost - var buildOutputCollector = new OutputCollector(); + var buildOutputCollector = new OutputCollector(_fileLoggerProvider, "Build"); var buildOptions = new DotNetCliRunnerInvocationOptions { StandardOutputCallback = buildOutputCollector.AppendOutput, @@ -389,7 +393,7 @@ public async Task PublishAsync(PublishContext context, CancellationToken ca } // Create collector and store in context for exception handling - var runOutputCollector = new OutputCollector(); + var runOutputCollector = new OutputCollector(_fileLoggerProvider, "AppHost"); context.OutputCollector = runOutputCollector; var runOptions = new DotNetCliRunnerInvocationOptions @@ -419,7 +423,7 @@ public async Task PublishAsync(PublishContext context, CancellationToken ca /// public async Task AddPackageAsync(AddPackageContext context, CancellationToken cancellationToken) { - var outputCollector = new OutputCollector(); + var outputCollector = new OutputCollector(_fileLoggerProvider, "Package"); context.OutputCollector = outputCollector; var options = new DotNetCliRunnerInvocationOptions diff --git a/src/Aspire.Cli/Resources/AddCommandStrings.resx b/src/Aspire.Cli/Resources/AddCommandStrings.resx index 8ddde3635fa..be4dc72e55e 100644 --- a/src/Aspire.Cli/Resources/AddCommandStrings.resx +++ b/src/Aspire.Cli/Resources/AddCommandStrings.resx @@ -148,7 +148,8 @@ Adding Aspire hosting integration... - The package installation failed with exit code {0}. For more information run with --debug switch. + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The package {0}::{1} was added successfully. diff --git a/src/Aspire.Cli/Resources/ErrorStrings.resx b/src/Aspire.Cli/Resources/ErrorStrings.resx index 850f83815ce..79670fc65cc 100644 --- a/src/Aspire.Cli/Resources/ErrorStrings.resx +++ b/src/Aspire.Cli/Resources/ErrorStrings.resx @@ -157,7 +157,7 @@ Project file does not exist. - The project could not be analyzed due to a build error. For more information run with --debug switch. + The project could not be analyzed due to a build error. See logs at {0} The project does not contain an Aspire apphost. diff --git a/src/Aspire.Cli/Resources/InteractionServiceStrings.Designer.cs b/src/Aspire.Cli/Resources/InteractionServiceStrings.Designer.cs index 8bd51e6bcfa..593a48d7798 100644 --- a/src/Aspire.Cli/Resources/InteractionServiceStrings.Designer.cs +++ b/src/Aspire.Cli/Resources/InteractionServiceStrings.Designer.cs @@ -232,7 +232,7 @@ public static string OperationCancelled { } /// - /// Looks up a localized string similar to The project could not be built. For more information run with --debug switch.. + /// Looks up a localized string similar to The project could not be built. See logs at {0}. /// public static string ProjectCouldNotBeBuilt { get { @@ -339,6 +339,15 @@ public static string UnexpectedErrorOccurred { } } + /// + /// Looks up a localized string similar to See logs at {0}. + /// + public static string SeeLogsAt { + get { + return ResourceManager.GetString("SeeLogsAt", resourceCulture); + } + } + /// /// Looks up a localized string similar to Waiting for debugger to attach to app host process. /// diff --git a/src/Aspire.Cli/Resources/InteractionServiceStrings.resx b/src/Aspire.Cli/Resources/InteractionServiceStrings.resx index e93b26b6294..2f833c980a8 100644 --- a/src/Aspire.Cli/Resources/InteractionServiceStrings.resx +++ b/src/Aspire.Cli/Resources/InteractionServiceStrings.resx @@ -182,7 +182,7 @@ The project argument was not specified and no app host project files were detected. - The project could not be built. For more information run with --debug switch. + The project could not be built. See logs at {0} The operation was canceled. @@ -200,6 +200,10 @@ An unexpected error occurred: {0} {0} is the exception message + + See logs at {0} + {0} is the log file path + Waiting for debugger to attach to app host process diff --git a/src/Aspire.Cli/Resources/RootCommandStrings.Designer.cs b/src/Aspire.Cli/Resources/RootCommandStrings.Designer.cs index d90521752fe..79b40d5a3d1 100644 --- a/src/Aspire.Cli/Resources/RootCommandStrings.Designer.cs +++ b/src/Aspire.Cli/Resources/RootCommandStrings.Designer.cs @@ -114,6 +114,15 @@ public static string Description { } } + /// + /// Looks up a localized string similar to Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical).. + /// + public static string DebugLevelArgumentDescription { + get { + return ResourceManager.GetString("DebugLevelArgumentDescription", resourceCulture); + } + } + /// /// Looks up a localized string similar to Telemetry ///--------- diff --git a/src/Aspire.Cli/Resources/RootCommandStrings.resx b/src/Aspire.Cli/Resources/RootCommandStrings.resx index 3b69afad727..0e812a74fe1 100644 --- a/src/Aspire.Cli/Resources/RootCommandStrings.resx +++ b/src/Aspire.Cli/Resources/RootCommandStrings.resx @@ -132,6 +132,9 @@ Enable debug logging to the console. + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Suppress the startup banner and telemetry notice. diff --git a/src/Aspire.Cli/Resources/RunCommandStrings.resx b/src/Aspire.Cli/Resources/RunCommandStrings.resx index 1bd4964f296..10f852c8d69 100644 --- a/src/Aspire.Cli/Resources/RunCommandStrings.resx +++ b/src/Aspire.Cli/Resources/RunCommandStrings.resx @@ -170,7 +170,7 @@ [bold] should not be localized - The project could not be run. For more information run with --debug switch. + The project could not be run. See logs at {0} Dashboard diff --git a/src/Aspire.Cli/Resources/TemplatingStrings.Designer.cs b/src/Aspire.Cli/Resources/TemplatingStrings.Designer.cs index 144bae8c918..b430807749d 100644 --- a/src/Aspire.Cli/Resources/TemplatingStrings.Designer.cs +++ b/src/Aspire.Cli/Resources/TemplatingStrings.Designer.cs @@ -277,7 +277,7 @@ public static string ProjectCreatedSuccessfully { } /// - /// Looks up a localized string similar to Project creation failed with exit code {0}. For more information run with --debug switch.. + /// Looks up a localized string similar to Project creation failed with exit code {0}. See logs at {1}. /// public static string ProjectCreationFailed { get { @@ -331,7 +331,7 @@ public static string SearchingForAvailableTemplateVersions { } /// - /// Looks up a localized string similar to The template installation failed with exit code {0}. For more information run with --debug switch.. + /// Looks up a localized string similar to The template installation failed with exit code {0}. See logs at {1}. /// public static string TemplateInstallationFailed { get { diff --git a/src/Aspire.Cli/Resources/TemplatingStrings.resx b/src/Aspire.Cli/Resources/TemplatingStrings.resx index 84aa0165ffd..ce29acb971e 100644 --- a/src/Aspire.Cli/Resources/TemplatingStrings.resx +++ b/src/Aspire.Cli/Resources/TemplatingStrings.resx @@ -199,8 +199,8 @@ Getting templates... - The template installation failed with exit code {0}. For more information run with --debug switch. - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Using project templates version: {0} @@ -209,8 +209,8 @@ Creating new Aspire project... - Project creation failed with exit code {0}. For more information run with --debug switch. - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Project created successfully in {0}. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.cs.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.cs.xlf index ec681a32b19..a04ad12acff 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.cs.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.cs.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - Instalace balíčku se nezdařila s ukončovacím kódem {0}. Další informace získáte spuštěním s přepínačem --debug. - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.de.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.de.xlf index 5868e4ffcee..1f261ba44d4 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.de.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.de.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - Fehler bei der Paketinstallation. Exitcode: {0}. Weitere Informationen erhalten Sie, wenn Sie mit dem Schalter „--debug“ ausführen. - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.es.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.es.xlf index f316f98ff38..750beed2d51 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.es.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.es.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - La instalación del paquete falló con el código de salida {0}. Para obtener más información, ejecute con el modificador --debug. - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.fr.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.fr.xlf index 8cec457c39f..8ea37530273 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.fr.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.fr.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - L’installation du package a échoué avec le code de sortie {0}. Pour plus d’informations, exécutez avec le commutateur --debug. - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.it.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.it.xlf index e5638e01035..5fddb87f242 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.it.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.it.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - L'installazione del pacchetto non è riuscita con codice di uscita {0}. Per altre informazioni, eseguire con l'opzione --debug. - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.ja.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.ja.xlf index 251555913b0..16f473080e3 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.ja.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.ja.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - パッケージのインストールが終了コード {0} で失敗しました。詳細情報については、--debug スイッチを使用し実行してください。 - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.ko.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.ko.xlf index b0857012e37..85e30c2b5e7 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.ko.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.ko.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - 패키지 설치에 실패했습니다(종료 코드: {0}). 자세한 내용을 보려면 --debug 스위치를 이용하여 실행하세요. - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.pl.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.pl.xlf index bd283968b24..8e4c9649b77 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.pl.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.pl.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - Instalacja pakietu nie powiodła się z kodem zakończenia {0}. Aby uzyskać więcej informacji, uruchom polecenie przełącznika --debug. - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.pt-BR.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.pt-BR.xlf index aa57479a35f..dc788080830 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.pt-BR.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.pt-BR.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - A instalação do pacote falhou com o código de saída {0}. Para mais informações, execute com a opção --debug. - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.ru.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.ru.xlf index fc2d7cf9466..e7dc36b31d3 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.ru.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.ru.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - Не удалось установить пакет. Код завершения: {0}. Для получения дополнительных сведений запустите команду с параметром --debug. - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.tr.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.tr.xlf index dda03b6154d..ddac3946d36 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.tr.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.tr.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - Paket yüklemesi {0} çıkış koduyla başarısız oldu. Daha fazla bilgi için --debug anahtarıyla çalıştırın. - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.zh-Hans.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.zh-Hans.xlf index 5e356f7d606..17833c3a399 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.zh-Hans.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.zh-Hans.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - 包安装失败,退出代码为 {0}。有关详细信息,请使用 --debug 开关运行。 - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.zh-Hant.xlf b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.zh-Hant.xlf index a1cb8883245..04f4af8fd21 100644 --- a/src/Aspire.Cli/Resources/xlf/AddCommandStrings.zh-Hant.xlf +++ b/src/Aspire.Cli/Resources/xlf/AddCommandStrings.zh-Hant.xlf @@ -43,9 +43,9 @@ {0} is the package name, {1} is the version. - The package installation failed with exit code {0}. For more information run with --debug switch. - 套件安裝失敗,結束代碼為 {0}。如需詳細資訊,請使用 --debug 切換執行。 - + The package installation failed with exit code {0}. See logs at {1} + The package installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path The path to the project file to add the integration to. diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.cs.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.cs.xlf index 25b1e139c5e..66a1b5720b2 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.cs.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.cs.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - Projekt se nepodařilo analyzovat kvůli chybě sestavení. Další informace získáte spuštěním s přepínačem --debug. + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.de.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.de.xlf index ca0cd28cdcd..c445e70b9dd 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.de.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.de.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - Das Projekt konnte aufgrund eines Buildfehlers nicht analysiert werden. Weitere Informationen erhalten Sie, wenn Sie mit dem Schalter „--debug“ ausführen. + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.es.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.es.xlf index 0fb8f7835d0..86cd1b62e59 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.es.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.es.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - No se pudo analizar el proyecto debido a un error de compilación. Para obtener más información, ejecute con el modificador --debug. + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.fr.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.fr.xlf index 5a70a0503f5..2fc7e539ded 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.fr.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.fr.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - Impossible d’analyser le projet en raison d’une erreur de build. Pour plus d’informations, exécutez avec le commutateur --debug. + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.it.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.it.xlf index 16b425f34af..23fd89ae32d 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.it.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.it.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - Non è possibile analizzare il progetto a causa di un errore di compilazione. Per altre informazioni, eseguire con l'opzione --debug. + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.ja.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.ja.xlf index 4ab6d4cfdf1..e18e3ec2b63 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.ja.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.ja.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - ビルド エラーのため、プロジェクトを分析できませんでした。詳細情報については、--debug スイッチを使用し実行してください。 + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.ko.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.ko.xlf index 497584e2ae1..fdb73c82eb4 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.ko.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.ko.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - 빌드 오류로 인해 프로젝트를 분석할 수 없습니다. 자세한 내용을 보려면 --debug 스위치를 이용하여 실행하세요. + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.pl.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.pl.xlf index 7553e6ac2b0..da0ea70bdf4 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.pl.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.pl.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - Nie można przeanalizować projektu z powodu błędu kompilacji. Aby uzyskać więcej informacji, uruchom polecenie przełącznika --debug. + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.pt-BR.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.pt-BR.xlf index e5688a91ec4..9a961e33059 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.pt-BR.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.pt-BR.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - Não foi possível analisar o projeto devido a um erro de compilação. Para obter mais informações, execute com a opção --debug. + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.ru.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.ru.xlf index 9ee74d67365..f908976db4e 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.ru.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.ru.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - Не удалось проанализировать проект из-за ошибки сборки. Для получения дополнительных сведений запустите команду с параметром --debug. + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.tr.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.tr.xlf index 4ca21336f1d..90da22b7612 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.tr.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.tr.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - Proje bir derleme hatası nedeniyle analiz edilemedi. Daha fazla bilgi için --debug anahtarıyla çalıştırın. + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.zh-Hans.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.zh-Hans.xlf index e951aee7547..8d4b17e1288 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.zh-Hans.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.zh-Hans.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - 由于生成错误,无法分析项目。有关详细信息,请使用 --debug 开关运行。 + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/ErrorStrings.zh-Hant.xlf b/src/Aspire.Cli/Resources/xlf/ErrorStrings.zh-Hant.xlf index d624098ecb9..c238b0c9f83 100644 --- a/src/Aspire.Cli/Resources/xlf/ErrorStrings.zh-Hant.xlf +++ b/src/Aspire.Cli/Resources/xlf/ErrorStrings.zh-Hant.xlf @@ -138,8 +138,8 @@ - The project could not be analyzed due to a build error. For more information run with --debug switch. - 因為組建錯誤,無法分析專案。如需詳細資訊,請使用 --debug 切換執行。 + The project could not be analyzed due to a build error. See logs at {0} + The project could not be analyzed due to a build error. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.cs.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.cs.xlf index 0b59530b00c..ebf45f31ed4 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.cs.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.cs.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - Projekt se nepovedlo sestavit. Další informace získáte spuštěním s přepínačem --debug. + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ Vyhledávání… + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: Vyberte hostitele aplikací, kterého chcete použít: diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.de.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.de.xlf index b551201c693..7e6f11bf662 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.de.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.de.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - Das Projekt konnte nicht erstellt werden. Weitere Informationen erhalten Sie, wenn Sie mit dem Schalter „--debug“ ausführen. + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ Suche wird ausgeführt... + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: AppHost zur Verwendung auswählen: diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.es.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.es.xlf index 99725c51e8a..f1ee5ed6723 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.es.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.es.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - No se pudo compilar el proyecto. Para obtener más información, ejecute con el modificador --debug. + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ Buscando... + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: Seleccione un apphost para usar: diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.fr.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.fr.xlf index 005fa1014e6..e3bcea2458b 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.fr.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.fr.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - Le projet n’a pas pu être généré. Pour plus d’informations, exécutez avec le commutateur --debug. + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ Recherche en cours... + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: Sélectionnez un AppHost à utiliser : diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.it.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.it.xlf index a83161430f6..fae126e4717 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.it.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.it.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - Non è possibile compilare il progetto. Per altre informazioni, eseguire con l'opzione --debug. + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ Ricerca in corso... + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: Selezionare un AppHost da usare: diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ja.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ja.xlf index e40d36a28b5..c686fa44f84 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ja.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ja.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - プロジェクトをビルドできませんでした。詳細については、--debug スイッチを使用し実行してください。 + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ 検索しています... + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: 使用する Apphost を選択してください: diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ko.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ko.xlf index 2c7d6c1ad6b..eaa8780e51b 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ko.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ko.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - 프로젝트를 빌드할 수 없습니다. 자세한 내용을 보려면 --debug 스위치를 이용하여 실행하세요. + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ 검색 중... + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: 사용할 apphost를 선택하세요: diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.pl.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.pl.xlf index 805670556a3..09e7a99c688 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.pl.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.pl.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - Nie można skompilować projektu. Aby uzyskać więcej informacji, uruchom polecenie przełącznika --debug. + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ Trwa wyszukiwanie... + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: Wybierz hosta AppHost do użycia: diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.pt-BR.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.pt-BR.xlf index a133546987c..fd1ad3bf382 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.pt-BR.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.pt-BR.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - O projeto não pôde ser compilado. Para obter mais informações, execute com a opção --debug. + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ Pesquisando... + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: Selecione um apphost a ser usado: diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ru.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ru.xlf index a13c58c576a..906adc491ff 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ru.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ru.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - Не удалось выполнить сборку проекта. Для получения дополнительных сведений запустите команду с параметром --debug. + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ Выполняется поиск... + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: Выберите хост приложений для использования: diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.tr.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.tr.xlf index 072e897945d..ed31c07b031 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.tr.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.tr.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - Proje oluşturulamadı. Daha fazla bilgi için --debug anahtarıyla çalıştırın. + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ Aranıyor... + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: Kullanılacak AppHost seçeneğini belirtin: diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.zh-Hans.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.zh-Hans.xlf index f70042eb4ab..f8ebdddcf8d 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.zh-Hans.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.zh-Hans.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - 无法生成项目。有关详细信息,请使用 --debug 开关运行。 + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ 正在搜索... + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: 选择要使用的应用主机: diff --git a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.zh-Hant.xlf b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.zh-Hant.xlf index 574c51fbe8d..ec10422b7dd 100644 --- a/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.zh-Hant.xlf +++ b/src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.zh-Hant.xlf @@ -98,8 +98,8 @@ - The project could not be built. For more information run with --debug switch. - 無法建置專案。如需詳細資訊,請使用 --debug 切換執行。 + The project could not be built. See logs at {0} + The project could not be built. See logs at {0} @@ -127,6 +127,11 @@ 正在搜尋... + + See logs at {0} + See logs at {0} + {0} is the log file path + Select an apphost to use: 選擇要使用的應用程式主機: diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.cs.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.cs.xlf index d66eaa8362b..b6e8d1ffbcc 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.cs.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.cs.xlf @@ -27,6 +27,11 @@ Povolte protokolování ladění do konzoly. + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. Aspire CLI lze použít k vytváření, spouštění a publikování aplikací založených na Aspire. diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.de.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.de.xlf index a84792aa3c9..83ff154d2b5 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.de.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.de.xlf @@ -27,6 +27,11 @@ Aktivieren Sie die Debugprotokollierung in der Konsole. + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. Die Aspire CLI kann zum Erstellen, Ausführen und Veröffentlichen von Aspire-basierten Anwendungen verwendet werden. diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.es.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.es.xlf index 89bf02fc9db..4ee1b74a866 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.es.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.es.xlf @@ -27,6 +27,11 @@ Habilite el registro de depuración en la consola. + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. La CLI de Aspire puede utilizarse para crear, ejecutar y publicar aplicaciones basadas en Aspire. diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.fr.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.fr.xlf index e1ca384b128..5dbb5778707 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.fr.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.fr.xlf @@ -27,6 +27,11 @@ Activez la journalisation de débogage dans la console. + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. L’interface CLI Aspire peut être utilisée pour créer, exécuter et publier des applications basées sur Aspire. diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.it.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.it.xlf index 6e12f19d4fd..20703b1fdab 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.it.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.it.xlf @@ -27,6 +27,11 @@ Abilita la registrazione di debug nella console. + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. L'interfaccia della riga di comando Aspire può essere usata per creare, eseguire e pubblicare applicazioni basate su Aspire. diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.ja.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.ja.xlf index 8dc9f4cfde0..9b3075e8c66 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.ja.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.ja.xlf @@ -27,6 +27,11 @@ コンソールへのデバッグ ログを有効にします。 + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. Aspire CLI を使用して、Aspire ベースのアプリケーションを作成、実行、発行できます。 diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.ko.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.ko.xlf index b6e49aec70e..d79f1b67143 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.ko.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.ko.xlf @@ -27,6 +27,11 @@ 콘솔에 디버그 로깅을 활성화하세요. + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. Aspire CLI를 사용하여 Aspire 기반 애플리케이션을 만들고, 실행하고, 게시할 수 있습니다. diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.pl.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.pl.xlf index 7d9b077c9c6..6be567691f1 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.pl.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.pl.xlf @@ -27,6 +27,11 @@ Włącz rejestrowanie debugowania w konsoli. + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. Interfejs wiersza polecenia platformy Aspire może służyć do tworzenia, uruchamiania i publikowania aplikacji opartych na platformie Aspire. diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.pt-BR.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.pt-BR.xlf index f6c37412418..87dac35c7ef 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.pt-BR.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.pt-BR.xlf @@ -27,6 +27,11 @@ Habilitar o log de depuração no console. + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. A CLI do Aspire pode ser usada para criar, executar e publicar aplicações baseadas em Aspire. diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.ru.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.ru.xlf index 7a78e841298..4c1e6e179bb 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.ru.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.ru.xlf @@ -27,6 +27,11 @@ Включает журналирование отладки в консоли. + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. CLI Aspire можно использовать для создания, запуска и публикации приложений на основе Aspire. diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.tr.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.tr.xlf index e4b8e3eca1f..b73a9067f61 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.tr.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.tr.xlf @@ -27,6 +27,11 @@ Konsolda hata ayıklama kaydını etkinleştirin. + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. Aspire CLI, Aspire tabanlı uygulamalar oluşturmak, çalıştırmak ve yayımlamak için kullanılabilir. diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.zh-Hans.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.zh-Hans.xlf index f11e90f294e..8161a5ebcbc 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.zh-Hans.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.zh-Hans.xlf @@ -27,6 +27,11 @@ 启用控制台的调试日志记录。 + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. Aspire CLI 可用于创建、运行和发布基于 Aspire 的应用程序。 diff --git a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.zh-Hant.xlf b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.zh-Hant.xlf index dde0092131d..fb18139e269 100644 --- a/src/Aspire.Cli/Resources/xlf/RootCommandStrings.zh-Hant.xlf +++ b/src/Aspire.Cli/Resources/xlf/RootCommandStrings.zh-Hant.xlf @@ -27,6 +27,11 @@ 啟用控制台的偵錯記錄。 + + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + Set the minimum log level for console output (Trace, Debug, Information, Warning, Error, Critical). + + The Aspire CLI can be used to create, run, and publish Aspire-based applications. Aspire CLI 可用來建立、執行及發佈以 Aspire 為基礎的應用程式。 diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.cs.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.cs.xlf index 32c62a9d23c..0f0cec9a525 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.cs.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.cs.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - Projekt nelze spustit. Další informace získáte spuštěním s přepínačem --debug. + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.de.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.de.xlf index 615ff2db354..b871e5ddc75 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.de.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.de.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - Das Projekt konnte nicht ausgeführt werden. Weitere Informationen erhalten Sie, wenn Sie mit dem Schalter „--debug“ ausführen. + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.es.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.es.xlf index b7fa0eb6c59..5311149418b 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.es.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.es.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - No se pudo ejecutar el proyecto. Para obtener más información, ejecute con el conmutador --debug. + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.fr.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.fr.xlf index 96e854bda49..35f1597ed11 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.fr.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.fr.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - Le projet n’a pas pu être exécuté. Pour plus d’informations, exécutez avec le commutateur --debug. + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.it.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.it.xlf index 264b03995c4..8ad9e2f6fc0 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.it.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.it.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - Non è possibile eseguire il progetto. Per altre informazioni, eseguire con l'opzione --debug. + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.ja.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.ja.xlf index d7e7353efb1..456e326c43e 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.ja.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.ja.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - プロジェクトを実行できませんでした。詳細情報については、--debug スイッチを使用し実行してください。 + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.ko.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.ko.xlf index eb1c9d676b1..2b77fb08792 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.ko.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.ko.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - 프로젝트를 실행할 수 없습니다. 자세한 내용을 보려면 --debug 스위치를 이용하여 실행하세요. + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.pl.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.pl.xlf index b9213a49188..32e5ee5335e 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.pl.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.pl.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - Nie można uruchomić projektu. Aby uzyskać więcej informacji, uruchom polecenie przełącznika --debug. + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.pt-BR.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.pt-BR.xlf index ce5daa4faaa..51e822915e0 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.pt-BR.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.pt-BR.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - Não foi possível executar o projeto. Para obter mais informações, execute com a opção --debug. + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.ru.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.ru.xlf index ddb4a96a5c9..308dfdc0a1c 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.ru.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.ru.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - Не удалось запустить проект. Для получения дополнительных сведений запустите команду с параметром --debug. + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.tr.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.tr.xlf index adf4a40b82a..52fbacb96f3 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.tr.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.tr.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - Proje çalıştırılamadı. Daha fazla bilgi için --debug anahtarıyla çalıştırın. + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.zh-Hans.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.zh-Hans.xlf index abbd08d1c33..6aa572623b6 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.zh-Hans.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.zh-Hans.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - 无法运行该项目。有关详细信息,请使用 --debug 开关运行。 + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.zh-Hant.xlf b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.zh-Hant.xlf index e38e4104b48..097f37c223a 100644 --- a/src/Aspire.Cli/Resources/xlf/RunCommandStrings.zh-Hant.xlf +++ b/src/Aspire.Cli/Resources/xlf/RunCommandStrings.zh-Hant.xlf @@ -148,8 +148,8 @@ - The project could not be run. For more information run with --debug switch. - 無法執行專案。如需詳細資訊,請使用 --debug 切換執行。 + The project could not be run. See logs at {0} + The project could not be run. See logs at {0} diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.cs.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.cs.xlf index fe9fe4ef3b9..63b9c92b172 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.cs.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.cs.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - Vytvoření projektu se nezdařilo s ukončovacím kódem {0}. Další informace získáte spuštěním s přepínačem --debug. - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - Instalace balíčku se nezdařila s ukončovacím kódem {0}. Další informace získáte spuštěním s přepínačem --debug. - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.de.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.de.xlf index a1e832ffd02..9a013a57b9d 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.de.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.de.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - Fehler bei der Projekterstellung. Exitcode {0}: Weitere Informationen erhalten Sie, wenn Sie mit dem Schalter „--debug“ ausführen. - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - Fehler bei der Vorlageninstallation. Exitcode {0}: Weitere Informationen erhalten Sie, wenn Sie mit dem Schalter „--debug“ ausführen. - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.es.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.es.xlf index b607d5c69ad..93c8a62fe9b 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.es.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.es.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - Error al crear el proyecto con el código de salida {0}. Para obtener más información, ejecute con el modificador --debug. - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - La instalación de la plantilla falló con el código de salida {0}. Para obtener más información, ejecute con el modificador --debug. - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.fr.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.fr.xlf index def11edc4c8..73033b28e94 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.fr.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.fr.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - Échec de la création du projet avec le code de sortie {0}. Pour plus d’informations, exécutez avec le commutateur --debug. - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - L’installation du modèle a échoué avec le code de sortie {0}. Pour plus d’informations, exécutez avec le commutateur --debug. - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.it.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.it.xlf index 820c33ce2c9..e89a0dd45af 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.it.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.it.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - Creazione del progetto non riuscita con codice di uscita {0}. Per altre informazioni, eseguire con l'opzione --debug. - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - L'installazione del modello non è riuscita con codice di uscita {0}. Per altre informazioni, eseguire con l'opzione --debug. - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.ja.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.ja.xlf index fbe1a2ec522..26d80eda038 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.ja.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.ja.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - プロジェクトの作成が、次の終了コードで失敗しました: {0}。詳細情報については、--debug スイッチを使用し実行してください。 - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - テンプレートのインストールが、次の終了コードで失敗しました: {0}。詳細情報については、--debug スイッチを使用し実行してください。 - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.ko.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.ko.xlf index 9967b7bf526..7ff2546ec35 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.ko.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.ko.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - {0} 종료 코드를 이용하여 프로젝트 만들기에 실패했습니다. 자세한 내용을 보려면 --debug 스위치를 이용하여 실행하세요. - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - {0} 종료 코드를 이용한 템플릿 설치에 실패했습니다. 자세한 내용을 보려면 --debug 스위치를 이용하여 실행하세요. - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.pl.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.pl.xlf index b8e53fcf5b1..a8919998e7d 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.pl.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.pl.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - Tworzenie projektu nie powiodło się z kodem zakończenia {0}. Aby uzyskać więcej informacji, uruchom polecenie przełącznika --debug. - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - Instalacja szablonu nie powiodła się z kodem zakończenia {0}. Aby uzyskać więcej informacji, uruchom polecenie przełącznika --debug. - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.pt-BR.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.pt-BR.xlf index b267f8d0620..58553fa8d29 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.pt-BR.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.pt-BR.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - Falha na criação do projeto com código de saída {0}. Para mais informações, execute com a opção --debug. - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - A instalação do modelo falhou com o código de saída {0}. Para mais informações, execute com a opção --debug. - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.ru.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.ru.xlf index d7a11bd8ce5..07e0994760b 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.ru.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.ru.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - Не удалось создать проект. Код завершения: {0}. Для получения дополнительных сведений запустите команду с параметром --debug. - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - Не удалось установить шаблон. Код завершения: {0}. Для получения дополнительных сведений запустите команду с параметром --debug. - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.tr.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.tr.xlf index 7404e65a5fc..4156c1e8fea 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.tr.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.tr.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - Proje oluşturma başarısız oldu, çıkış kodu {0}. Daha fazla bilgi için --debug anahtarıyla çalıştırın. - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - Şablon yüklemesi, {0} çıkış koduyla başarısız oldu. Daha fazla bilgi için --debug anahtarıyla çalıştırın. - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.zh-Hans.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.zh-Hans.xlf index 83d654bbcd9..79915981c23 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.zh-Hans.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.zh-Hans.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - 项目创建失败,退出代码为 {0}。有关详细信息,请使用 --debug 开关运行。 - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - 模板安装失败,退出代码为 {0}。有关详细信息,请使用 --debug 开关运行。 - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.zh-Hant.xlf b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.zh-Hant.xlf index faa102f5ec7..3f4e735246a 100644 --- a/src/Aspire.Cli/Resources/xlf/TemplatingStrings.zh-Hant.xlf +++ b/src/Aspire.Cli/Resources/xlf/TemplatingStrings.zh-Hant.xlf @@ -123,9 +123,9 @@ {0} is a path - Project creation failed with exit code {0}. For more information run with --debug switch. - 專案建立失敗,結束代碼為 {0}。如需詳細資訊,請使用 --debug 切換執行。 - {0} is a number, --debug should not be localized + Project creation failed with exit code {0}. See logs at {1} + Project creation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Configures whether to create a project for integration tests using MSTest, NUnit, or xUnit.net. @@ -153,9 +153,9 @@ - The template installation failed with exit code {0}. For more information run with --debug switch. - 範本安裝失敗,結束代碼為 {0}。如需詳細資訊,請使用 --debug 切換執行。 - {0} is a number, --debug should not be localized + The template installation failed with exit code {0}. See logs at {1} + The template installation failed with exit code {0}. See logs at {1} + {0} is a number, {1} is the log file path Unknown diff --git a/src/Aspire.Cli/Templating/DotNetTemplateFactory.cs b/src/Aspire.Cli/Templating/DotNetTemplateFactory.cs index b5f4a59259f..cbb90cbd393 100644 --- a/src/Aspire.Cli/Templating/DotNetTemplateFactory.cs +++ b/src/Aspire.Cli/Templating/DotNetTemplateFactory.cs @@ -440,7 +440,7 @@ private async Task ApplyTemplateAsync(CallbackTemplate template, if (templateInstallResult.ExitCode != 0) { interactionService.DisplayLines(templateInstallCollector.GetLines()); - interactionService.DisplayError(string.Format(CultureInfo.CurrentCulture, TemplatingStrings.TemplateInstallationFailed, templateInstallResult.ExitCode)); + interactionService.DisplayError(string.Format(CultureInfo.CurrentCulture, TemplatingStrings.TemplateInstallationFailed, templateInstallResult.ExitCode, executionContext.LogFilePath)); return new TemplateResult(ExitCodeConstants.FailedToInstallTemplates); } @@ -479,7 +479,7 @@ private async Task ApplyTemplateAsync(CallbackTemplate template, } interactionService.DisplayLines(newProjectCollector.GetLines()); - interactionService.DisplayError(string.Format(CultureInfo.CurrentCulture, TemplatingStrings.ProjectCreationFailed, newProjectExitCode)); + interactionService.DisplayError(string.Format(CultureInfo.CurrentCulture, TemplatingStrings.ProjectCreationFailed, newProjectExitCode, executionContext.LogFilePath)); return new TemplateResult(ExitCodeConstants.FailedToCreateNewProject); } diff --git a/src/Aspire.Cli/Utils/AppHostHelper.cs b/src/Aspire.Cli/Utils/AppHostHelper.cs index 3bde0f9fee2..26cb04098d8 100644 --- a/src/Aspire.Cli/Utils/AppHostHelper.cs +++ b/src/Aspire.Cli/Utils/AppHostHelper.cs @@ -14,13 +14,13 @@ namespace Aspire.Cli.Utils; internal static class AppHostHelper { - internal static async Task<(bool IsCompatibleAppHost, bool SupportsBackchannel, string? AspireHostingVersion)> CheckAppHostCompatibilityAsync(IDotNetCliRunner runner, IInteractionService interactionService, FileInfo projectFile, AspireCliTelemetry telemetry, DirectoryInfo workingDirectory, CancellationToken cancellationToken) + internal static async Task<(bool IsCompatibleAppHost, bool SupportsBackchannel, string? AspireHostingVersion)> CheckAppHostCompatibilityAsync(IDotNetCliRunner runner, IInteractionService interactionService, FileInfo projectFile, AspireCliTelemetry telemetry, DirectoryInfo workingDirectory, string logFilePath, CancellationToken cancellationToken) { var appHostInformation = await GetAppHostInformationAsync(runner, interactionService, projectFile, telemetry, workingDirectory, cancellationToken); if (appHostInformation.ExitCode != 0) { - interactionService.DisplayError(ErrorStrings.ProjectCouldNotBeAnalyzed); + interactionService.DisplayError(string.Format(CultureInfo.CurrentCulture, ErrorStrings.ProjectCouldNotBeAnalyzed, logFilePath)); return (false, false, null); } @@ -135,18 +135,4 @@ internal static bool ProcessExists(int pid) /// The number of orphaned sockets deleted. internal static int CleanupOrphanedSockets(string backchannelsDirectory, string hash, int currentPid) => BackchannelConstants.CleanupOrphanedSockets(backchannelsDirectory, hash, currentPid); - - /// - /// Gets the log file path for an AppHost process. - /// - /// The process ID of the AppHost. - /// The user's home directory. - /// The time provider for timestamp generation. - /// The log file path. - internal static FileInfo GetLogFilePath(int pid, string homeDirectory, TimeProvider timeProvider) - { - var logsPath = Path.Combine(homeDirectory, ".aspire", "cli", "logs"); - var logFilePath = Path.Combine(logsPath, $"apphost-{pid}-{timeProvider.GetUtcNow():yyyy-MM-dd-HH-mm-ss}.log"); - return new FileInfo(logFilePath); - } } diff --git a/src/Aspire.Cli/Utils/OutputCollector.cs b/src/Aspire.Cli/Utils/OutputCollector.cs index 2efc5c167bb..c7b6a59c0bc 100644 --- a/src/Aspire.Cli/Utils/OutputCollector.cs +++ b/src/Aspire.Cli/Utils/OutputCollector.cs @@ -1,18 +1,41 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Aspire.Cli.Diagnostics; + namespace Aspire.Cli.Utils; internal sealed class OutputCollector { private readonly CircularBuffer<(string Stream, string Line)> _lines = new(10000); // 10k lines. private readonly object _lock = new object(); + private readonly FileLoggerProvider? _fileLogger; + private readonly string _category; + + /// + /// Creates an OutputCollector that only buffers output in memory. + /// + public OutputCollector() : this(null, "AppHost") + { + } + + /// + /// Creates an OutputCollector that buffers output and optionally logs to disk. + /// + /// Optional file logger for writing output to disk. + /// Category for log entries (e.g., "Build", "AppHost"). + public OutputCollector(FileLoggerProvider? fileLogger, string category = "AppHost") + { + _fileLogger = fileLogger; + _category = category; + } public void AppendOutput(string line) { lock (_lock) { _lines.Add(("stdout", line)); + _fileLogger?.WriteLog(FormatLogLine("stdout", line)); } } @@ -21,6 +44,7 @@ public void AppendError(string line) lock (_lock) { _lines.Add(("stderr", line)); + _fileLogger?.WriteLog(FormatLogLine("stderr", line)); } } @@ -31,4 +55,11 @@ public void AppendError(string line) return _lines.ToArray(); } } + + private string FormatLogLine(string stream, string line) + { + var timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", System.Globalization.CultureInfo.InvariantCulture); + var level = stream == "stderr" ? "FAIL" : "INFO"; + return $"[{timestamp}] [{level}] [{_category}] {line}"; + } } \ No newline at end of file diff --git a/tests/Aspire.Cli.Tests/Agents/CopilotCliAgentEnvironmentScannerTests.cs b/tests/Aspire.Cli.Tests/Agents/CopilotCliAgentEnvironmentScannerTests.cs index e4489ecc2fc..ee693cebaa6 100644 --- a/tests/Aspire.Cli.Tests/Agents/CopilotCliAgentEnvironmentScannerTests.cs +++ b/tests/Aspire.Cli.Tests/Agents/CopilotCliAgentEnvironmentScannerTests.cs @@ -201,6 +201,8 @@ private static CliExecutionContext CreateExecutionContext(DirectoryInfo workingD hivesDirectory: workingDirectory, cacheDirectory: workingDirectory, sdksDirectory: workingDirectory, + logsDirectory: workingDirectory, + logFilePath: "test.log", debugMode: false, environmentVariables: new Dictionary(), homeDirectory: workingDirectory); @@ -218,6 +220,8 @@ private static CliExecutionContext CreateExecutionContextWithVSCode(DirectoryInf hivesDirectory: workingDirectory, cacheDirectory: workingDirectory, sdksDirectory: workingDirectory, + logsDirectory: workingDirectory, + logFilePath: "test.log", debugMode: false, environmentVariables: environmentVariables, homeDirectory: workingDirectory); diff --git a/tests/Aspire.Cli.Tests/Agents/VsCodeAgentEnvironmentScannerTests.cs b/tests/Aspire.Cli.Tests/Agents/VsCodeAgentEnvironmentScannerTests.cs index bdb0b30a43e..bcb247ae7f8 100644 --- a/tests/Aspire.Cli.Tests/Agents/VsCodeAgentEnvironmentScannerTests.cs +++ b/tests/Aspire.Cli.Tests/Agents/VsCodeAgentEnvironmentScannerTests.cs @@ -323,6 +323,8 @@ private static CliExecutionContext CreateExecutionContext(DirectoryInfo workingD hivesDirectory: workingDirectory, cacheDirectory: workingDirectory, sdksDirectory: workingDirectory, + logsDirectory: workingDirectory, + logFilePath: "test.log", debugMode: false, environmentVariables: environmentVariables, homeDirectory: homeDirectory); diff --git a/tests/Aspire.Cli.Tests/Caching/DiskCacheTests.cs b/tests/Aspire.Cli.Tests/Caching/DiskCacheTests.cs index 365384ccfa4..9604548dc7b 100644 --- a/tests/Aspire.Cli.Tests/Caching/DiskCacheTests.cs +++ b/tests/Aspire.Cli.Tests/Caching/DiskCacheTests.cs @@ -19,7 +19,7 @@ private static DiskCache CreateCache(TemporaryWorkspace workspace, Action(); return new DiskCache(logger, ctx, configuration); diff --git a/tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs b/tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs index ed971058056..2be8fa710a4 100644 --- a/tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs +++ b/tests/Aspire.Cli.Tests/Commands/RunCommandTests.cs @@ -865,7 +865,7 @@ public async Task DotNetCliRunner_RunAsync_WhenWatchIsTrue_IncludesNonInteractiv var options = new DotNetCliRunnerInvocationOptions(); var executionContext = new CliExecutionContext( - workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")) + workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")), logsDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), logFilePath: "test.log" ); var runner = DotNetCliRunnerTestHelper.Create( @@ -914,7 +914,7 @@ public async Task DotNetCliRunner_RunAsync_WhenWatchIsFalse_DoesNotIncludeNonInt var options = new DotNetCliRunnerInvocationOptions(); var executionContext = new CliExecutionContext( - workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")) + workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")), logsDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), logFilePath: "test.log" ); var runner = DotNetCliRunnerTestHelper.Create( @@ -959,7 +959,7 @@ public async Task DotNetCliRunner_RunAsync_WhenWatchIsTrueAndDebugIsTrue_Include var options = new DotNetCliRunnerInvocationOptions { Debug = true }; var executionContext = new CliExecutionContext( - workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")) + workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")), logsDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), logFilePath: "test.log" ); var runner = DotNetCliRunnerTestHelper.Create( @@ -1008,7 +1008,7 @@ public async Task DotNetCliRunner_RunAsync_WhenWatchIsTrueAndDebugIsFalse_DoesNo var options = new DotNetCliRunnerInvocationOptions { Debug = false }; var executionContext = new CliExecutionContext( - workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")) + workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")), logsDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), logFilePath: "test.log" ); var runner = DotNetCliRunnerTestHelper.Create( @@ -1052,7 +1052,7 @@ public async Task DotNetCliRunner_RunAsync_WhenWatchIsFalseAndDebugIsTrue_DoesNo var options = new DotNetCliRunnerInvocationOptions { Debug = true }; var executionContext = new CliExecutionContext( - workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")) + workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")), logsDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), logFilePath: "test.log" ); var runner = DotNetCliRunnerTestHelper.Create( @@ -1097,7 +1097,7 @@ public async Task DotNetCliRunner_RunAsync_WhenWatchIsTrue_SetsSuppressLaunchBro var options = new DotNetCliRunnerInvocationOptions(); var executionContext = new CliExecutionContext( - workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")) + workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")), logsDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), logFilePath: "test.log" ); var runner = DotNetCliRunnerTestHelper.Create( @@ -1142,7 +1142,7 @@ public async Task DotNetCliRunner_RunAsync_WhenWatchIsFalse_DoesNotSetSuppressLa var options = new DotNetCliRunnerInvocationOptions(); var executionContext = new CliExecutionContext( - workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")) + workingDirectory: workspace.WorkspaceRoot, hivesDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("hives"), cacheDirectory: workspace.WorkspaceRoot.CreateSubdirectory(".aspire").CreateSubdirectory("cache"), sdksDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")), logsDirectory: new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), logFilePath: "test.log" ); var runner = DotNetCliRunnerTestHelper.Create( diff --git a/tests/Aspire.Cli.Tests/DotNet/DotNetCliRunnerTests.cs b/tests/Aspire.Cli.Tests/DotNet/DotNetCliRunnerTests.cs index dd27c7c5041..997dc6ab6ae 100644 --- a/tests/Aspire.Cli.Tests/DotNet/DotNetCliRunnerTests.cs +++ b/tests/Aspire.Cli.Tests/DotNet/DotNetCliRunnerTests.cs @@ -22,7 +22,7 @@ private static Aspire.Cli.CliExecutionContext CreateExecutionContext(DirectoryIn var settingsDirectory = workingDirectory.CreateSubdirectory(".aspire"); var hivesDirectory = settingsDirectory.CreateSubdirectory("hives"); var cacheDirectory = new DirectoryInfo(Path.Combine(workingDirectory.FullName, ".aspire", "cache")); - return new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + return new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); } [Fact] diff --git a/tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs b/tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs index d56ed37a41a..5df502be45e 100644 --- a/tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs +++ b/tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs @@ -23,8 +23,9 @@ private static CliExecutionContext CreateTestExecutionContext() var hivesDirectory = new DirectoryInfo(Path.Combine(tempPath, "hives")); var cacheDirectory = new DirectoryInfo(Path.Combine(tempPath, "cache")); var sdksDirectory = new DirectoryInfo(Path.Combine(tempPath, "sdks")); + var logsDirectory = new DirectoryInfo(Path.Combine(tempPath, "logs")); - return new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, sdksDirectory, debugMode: false); + return new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, sdksDirectory, logsDirectory, "test.log", debugMode: false); } private static ILogger CreateTestLogger() diff --git a/tests/Aspire.Cli.Tests/Interaction/ConsoleInteractionServiceTests.cs b/tests/Aspire.Cli.Tests/Interaction/ConsoleInteractionServiceTests.cs index 88c4c9a1658..3ee92c32353 100644 --- a/tests/Aspire.Cli.Tests/Interaction/ConsoleInteractionServiceTests.cs +++ b/tests/Aspire.Cli.Tests/Interaction/ConsoleInteractionServiceTests.cs @@ -22,7 +22,7 @@ private static ConsoleInteractionService CreateInteractionService(IAnsiConsole c public async Task PromptForSelectionAsync_EmptyChoices_ThrowsEmptyChoicesException() { // Arrange - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var interactionService = CreateInteractionService(AnsiConsole.Console, executionContext); var choices = Array.Empty(); @@ -35,7 +35,7 @@ await Assert.ThrowsAsync(() => public async Task PromptForSelectionsAsync_EmptyChoices_ThrowsEmptyChoicesException() { // Arrange - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var interactionService = CreateInteractionService(AnsiConsole.Console, executionContext); var choices = Array.Empty(); @@ -56,7 +56,7 @@ public void DisplayError_WithMarkupCharacters_DoesNotCauseMarkupParsingError() Out = new AnsiConsoleOutput(new StringWriter(output)) }); - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var interactionService = CreateInteractionService(console, executionContext); var errorMessage = "The JSON value could not be converted to . Path: $.values[0].Type | LineNumber: 0 | BytePositionInLine: 121."; @@ -81,7 +81,7 @@ public void DisplaySubtleMessage_WithMarkupCharacters_DoesNotCauseMarkupParsingE Out = new AnsiConsoleOutput(new StringWriter(output)) }); - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var interactionService = CreateInteractionService(console, executionContext); var message = "Path with and [markup] characters"; @@ -106,7 +106,7 @@ public void DisplayLines_WithMarkupCharacters_DoesNotCauseMarkupParsingError() Out = new AnsiConsoleOutput(new StringWriter(output)) }); - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var interactionService = CreateInteractionService(console, executionContext); var lines = new[] { @@ -137,7 +137,7 @@ public void DisplayMarkdown_WithBasicMarkdown_ConvertsToSpectreMarkup() Out = new AnsiConsoleOutput(new StringWriter(output)) }); - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var interactionService = CreateInteractionService(console, executionContext); var markdown = "# Header\nThis is **bold** and *italic* text with `code`."; @@ -164,7 +164,7 @@ public void DisplayMarkdown_WithPlainText_DoesNotThrow() Out = new AnsiConsoleOutput(new StringWriter(output)) }); - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var interactionService = CreateInteractionService(console, executionContext); var plainText = "This is just plain text without any markdown."; @@ -189,7 +189,7 @@ public async Task ShowStatusAsync_InDebugMode_DisplaysSubtleMessageInsteadOfSpin Out = new AnsiConsoleOutput(new StringWriter(output)) }); - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), debugMode: true); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log", debugMode: true); var interactionService = CreateInteractionService(console, executionContext); var statusText = "Processing request..."; var result = "test result"; @@ -216,7 +216,7 @@ public void ShowStatus_InDebugMode_DisplaysSubtleMessageInsteadOfSpinner() Out = new AnsiConsoleOutput(new StringWriter(output)) }); - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), debugMode: true); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log", debugMode: true); var interactionService = CreateInteractionService(console, executionContext); var statusText = "Processing synchronous request..."; var actionCalled = false; @@ -235,7 +235,7 @@ public void ShowStatus_InDebugMode_DisplaysSubtleMessageInsteadOfSpinner() public async Task PromptForStringAsync_WhenInteractiveInputNotSupported_ThrowsInvalidOperationException() { // Arrange - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var hostEnvironment = TestHelpers.CreateNonInteractiveHostEnvironment(); var interactionService = CreateInteractionService(AnsiConsole.Console, executionContext, hostEnvironment); @@ -249,7 +249,7 @@ public async Task PromptForStringAsync_WhenInteractiveInputNotSupported_ThrowsIn public async Task PromptForSelectionAsync_WhenInteractiveInputNotSupported_ThrowsInvalidOperationException() { // Arrange - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var hostEnvironment = TestHelpers.CreateNonInteractiveHostEnvironment(); var interactionService = CreateInteractionService(AnsiConsole.Console, executionContext, hostEnvironment); var choices = new[] { "option1", "option2" }; @@ -264,7 +264,7 @@ public async Task PromptForSelectionAsync_WhenInteractiveInputNotSupported_Throw public async Task PromptForSelectionsAsync_WhenInteractiveInputNotSupported_ThrowsInvalidOperationException() { // Arrange - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var hostEnvironment = TestHelpers.CreateNonInteractiveHostEnvironment(); var interactionService = CreateInteractionService(AnsiConsole.Console, executionContext, hostEnvironment); var choices = new[] { "option1", "option2" }; @@ -279,7 +279,7 @@ public async Task PromptForSelectionsAsync_WhenInteractiveInputNotSupported_Thro public async Task ConfirmAsync_WhenInteractiveInputNotSupported_ThrowsInvalidOperationException() { // Arrange - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var hostEnvironment = TestHelpers.CreateNonInteractiveHostEnvironment(); var interactionService = CreateInteractionService(AnsiConsole.Console, executionContext, hostEnvironment); @@ -301,7 +301,7 @@ public async Task ShowStatusAsync_NestedCall_DoesNotThrowException() Out = new AnsiConsoleOutput(new StringWriter(output)) }); - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var interactionService = CreateInteractionService(console, executionContext); var outerStatusText = "Outer operation..."; @@ -334,7 +334,7 @@ public void ShowStatus_NestedCall_DoesNotThrowException() Out = new AnsiConsoleOutput(new StringWriter(output)) }); - var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo("."), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var interactionService = CreateInteractionService(console, executionContext); var outerStatusText = "Outer synchronous operation..."; diff --git a/tests/Aspire.Cli.Tests/Mcp/ListAppHostsToolTests.cs b/tests/Aspire.Cli.Tests/Mcp/ListAppHostsToolTests.cs index 736a02e2383..02104bee4f7 100644 --- a/tests/Aspire.Cli.Tests/Mcp/ListAppHostsToolTests.cs +++ b/tests/Aspire.Cli.Tests/Mcp/ListAppHostsToolTests.cs @@ -168,7 +168,7 @@ private static CliExecutionContext CreateCliExecutionContext(DirectoryInfo worki { var hivesDirectory = new DirectoryInfo(Path.Combine(workingDirectory.FullName, ".aspire", "hives")); var cacheDirectory = new DirectoryInfo(Path.Combine(workingDirectory.FullName, ".aspire", "cache")); - return new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks"))); + return new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); } private static AppHostAuxiliaryBackchannel CreateAppHostConnection(string hash, string socketPath, AppHostInformation appHostInfo, bool isInScope) diff --git a/tests/Aspire.Cli.Tests/Mcp/MockPackagingService.cs b/tests/Aspire.Cli.Tests/Mcp/MockPackagingService.cs index c1d55866cb9..27505f5e9a3 100644 --- a/tests/Aspire.Cli.Tests/Mcp/MockPackagingService.cs +++ b/tests/Aspire.Cli.Tests/Mcp/MockPackagingService.cs @@ -55,7 +55,9 @@ public static CliExecutionContext CreateTestContext() new DirectoryInfo(Path.GetTempPath()), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "hives")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "cache")), - new DirectoryInfo(Path.Combine(Path.GetTempPath(), "sdks"))); + new DirectoryInfo(Path.Combine(Path.GetTempPath(), "sdks")), + new DirectoryInfo(Path.Combine(Path.GetTempPath(), "logs")), + "test.log"); } } diff --git a/tests/Aspire.Cli.Tests/NuGet/NuGetPackagePrefetcherTests.cs b/tests/Aspire.Cli.Tests/NuGet/NuGetPackagePrefetcherTests.cs index cdd95194ccd..ff18dfaa44b 100644 --- a/tests/Aspire.Cli.Tests/NuGet/NuGetPackagePrefetcherTests.cs +++ b/tests/Aspire.Cli.Tests/NuGet/NuGetPackagePrefetcherTests.cs @@ -15,7 +15,7 @@ public void CliExecutionContextSetsCommand() var workingDir = new DirectoryInfo(Environment.CurrentDirectory); var hivesDir = new DirectoryInfo(Path.Combine(Environment.CurrentDirectory, "hives")); var cacheDir = new DirectoryInfo(Path.Combine(workingDir.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(workingDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(workingDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); Assert.Null(executionContext.Command); diff --git a/tests/Aspire.Cli.Tests/Packaging/NuGetConfigMergerSnapshotTests.cs b/tests/Aspire.Cli.Tests/Packaging/NuGetConfigMergerSnapshotTests.cs index e1fc3f227f5..aea7ee84d36 100644 --- a/tests/Aspire.Cli.Tests/Packaging/NuGetConfigMergerSnapshotTests.cs +++ b/tests/Aspire.Cli.Tests/Packaging/NuGetConfigMergerSnapshotTests.cs @@ -63,7 +63,7 @@ public async Task Merge_WithSimpleNuGetConfig_ProducesExpectedXml(string channel // Add a deterministic PR hive for testing realistic PR channel mappings. hivesDir.CreateSubdirectory("pr-1234"); var cacheDir = new DirectoryInfo(Path.Combine(root.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(root, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(root, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var packagingService = CreatePackagingService(executionContext); // Existing config purposely minimal (no packageSourceMapping yet) @@ -112,7 +112,7 @@ public async Task Merge_WithBrokenSdkState_ProducesExpectedXml(string channelNam // Add a deterministic PR hive for testing realistic PR channel mappings. hivesDir.CreateSubdirectory("pr-1234"); var cacheDir2 = new DirectoryInfo(Path.Combine(root.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(root, hivesDir, cacheDir2, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(root, hivesDir, cacheDir2, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var packagingService = CreatePackagingService(executionContext); // Existing config purposely minimal (no packageSourceMapping yet) @@ -174,7 +174,7 @@ public async Task Merge_WithDailyFeedWithExtraMappingsIsPreserved_ProducesExpect // Add a deterministic PR hive for testing realistic PR channel mappings. hivesDir.CreateSubdirectory("pr-1234"); var cacheDir3 = new DirectoryInfo(Path.Combine(root.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(root, hivesDir, cacheDir3, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(root, hivesDir, cacheDir3, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var packagingService = CreatePackagingService(executionContext); // Existing config purposely minimal (no packageSourceMapping yet) @@ -235,7 +235,7 @@ public async Task Merge_WithExtraInternalFeedIncorrectlyMapped_ProducesExpectedX // Add a deterministic PR hive for testing realistic PR channel mappings. hivesDir.CreateSubdirectory("pr-1234"); var cacheDir4 = new DirectoryInfo(Path.Combine(root.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(root, hivesDir, cacheDir4, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(root, hivesDir, cacheDir4, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var packagingService = CreatePackagingService(executionContext); // Existing config purposely minimal (no packageSourceMapping yet) @@ -294,7 +294,7 @@ public async Task Merge_ExtraPatternOnDailyFeedWhenOnPrFeedGetsConsolidatedWithO // Add a deterministic PR hive for testing realistic PR channel mappings. hivesDir.CreateSubdirectory("pr-1234"); var cacheDir5 = new DirectoryInfo(Path.Combine(root.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(root, hivesDir, cacheDir5, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(root, hivesDir, cacheDir5, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var packagingService = CreatePackagingService(executionContext); // Existing config purposely minimal (no packageSourceMapping yet) diff --git a/tests/Aspire.Cli.Tests/Packaging/PackagingServiceTests.cs b/tests/Aspire.Cli.Tests/Packaging/PackagingServiceTests.cs index d68f78f1229..5928d77e2d5 100644 --- a/tests/Aspire.Cli.Tests/Packaging/PackagingServiceTests.cs +++ b/tests/Aspire.Cli.Tests/Packaging/PackagingServiceTests.cs @@ -45,7 +45,7 @@ public async Task GetChannelsAsync_WhenStagingChannelDisabled_DoesNotIncludeStag var tempDir = workspace.WorkspaceRoot; var hivesDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "hives")); var cacheDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var features = new TestFeatures(); var configuration = new ConfigurationBuilder().Build(); @@ -80,7 +80,7 @@ public async Task GetChannelsAsync_WhenStagingChannelEnabled_IncludesStagingChan var tempDir = workspace.WorkspaceRoot; var hivesDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "hives")); var cacheDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var features = new TestFeatures(); features.SetFeature(KnownFeatures.StagingChannelEnabled, true); @@ -124,7 +124,7 @@ public async Task GetChannelsAsync_WhenStagingChannelEnabledWithOverrideFeed_Use var tempDir = workspace.WorkspaceRoot; var hivesDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "hives")); var cacheDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var features = new TestFeatures(); features.SetFeature(KnownFeatures.StagingChannelEnabled, true); @@ -157,7 +157,7 @@ public async Task GetChannelsAsync_WhenStagingChannelEnabledWithAzureDevOpsFeedO var tempDir = workspace.WorkspaceRoot; var hivesDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "hives")); var cacheDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var features = new TestFeatures(); features.SetFeature(KnownFeatures.StagingChannelEnabled, true); @@ -190,7 +190,7 @@ public async Task GetChannelsAsync_WhenStagingChannelEnabledWithInvalidOverrideF var tempDir = workspace.WorkspaceRoot; var hivesDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "hives")); var cacheDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var features = new TestFeatures(); features.SetFeature(KnownFeatures.StagingChannelEnabled, true); @@ -222,7 +222,7 @@ public async Task GetChannelsAsync_WhenStagingChannelEnabledWithQualityOverride_ var tempDir = workspace.WorkspaceRoot; var hivesDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "hives")); var cacheDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var features = new TestFeatures(); features.SetFeature(KnownFeatures.StagingChannelEnabled, true); @@ -253,7 +253,7 @@ public async Task GetChannelsAsync_WhenStagingChannelEnabledWithQualityBoth_Uses var tempDir = workspace.WorkspaceRoot; var hivesDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "hives")); var cacheDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var features = new TestFeatures(); features.SetFeature(KnownFeatures.StagingChannelEnabled, true); @@ -284,7 +284,7 @@ public async Task GetChannelsAsync_WhenStagingChannelEnabledWithInvalidQuality_D var tempDir = workspace.WorkspaceRoot; var hivesDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "hives")); var cacheDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var features = new TestFeatures(); features.SetFeature(KnownFeatures.StagingChannelEnabled, true); @@ -315,7 +315,7 @@ public async Task GetChannelsAsync_WhenStagingChannelEnabledWithoutQualityOverri var tempDir = workspace.WorkspaceRoot; var hivesDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "hives")); var cacheDir = new DirectoryInfo(Path.Combine(tempDir.FullName, ".aspire", "cache")); - var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var features = new TestFeatures(); features.SetFeature(KnownFeatures.StagingChannelEnabled, true); @@ -355,7 +355,7 @@ public async Task NuGetConfigMerger_WhenChannelRequiresGlobalPackagesFolder_Adds .Build(); var packagingService = new PackagingService( - new CliExecutionContext(tempDir, tempDir, tempDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))), + new CliExecutionContext(tempDir, tempDir, tempDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"), new FakeNuGetPackageCache(), features, configuration); @@ -399,7 +399,7 @@ public async Task GetChannelsAsync_WhenStagingChannelEnabled_StagingAppearsAfter Directory.CreateDirectory(Path.Combine(hivesDir.FullName, "pr-10167")); Directory.CreateDirectory(Path.Combine(hivesDir.FullName, "pr-11832")); - var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var features = new TestFeatures(); features.SetFeature(KnownFeatures.StagingChannelEnabled, true); @@ -455,7 +455,7 @@ public async Task GetChannelsAsync_WhenStagingChannelDisabled_OrderIsDefaultStab hivesDir.Create(); Directory.CreateDirectory(Path.Combine(hivesDir.FullName, "pr-12345")); - var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(tempDir, hivesDir, cacheDir, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var features = new TestFeatures(); // Staging disabled by default diff --git a/tests/Aspire.Cli.Tests/Projects/ProjectLocatorTests.cs b/tests/Aspire.Cli.Tests/Projects/ProjectLocatorTests.cs index ece3256a945..0864fa78149 100644 --- a/tests/Aspire.Cli.Tests/Projects/ProjectLocatorTests.cs +++ b/tests/Aspire.Cli.Tests/Projects/ProjectLocatorTests.cs @@ -26,7 +26,7 @@ private static Aspire.Cli.CliExecutionContext CreateExecutionContext(DirectoryIn var settingsDirectory = workingDirectory.CreateSubdirectory(".aspire"); var hivesDirectory = settingsDirectory.CreateSubdirectory("hives"); var cacheDirectory = new DirectoryInfo(Path.Combine(workingDirectory.FullName, ".aspire", "cache")); - return new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + return new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); } [Fact] diff --git a/tests/Aspire.Cli.Tests/Projects/ProjectUpdaterTests.cs b/tests/Aspire.Cli.Tests/Projects/ProjectUpdaterTests.cs index 76f97f60422..0ccafc41816 100644 --- a/tests/Aspire.Cli.Tests/Projects/ProjectUpdaterTests.cs +++ b/tests/Aspire.Cli.Tests/Projects/ProjectUpdaterTests.cs @@ -893,7 +893,7 @@ private static Aspire.Cli.CliExecutionContext CreateExecutionContext(DirectoryIn var settingsDirectory = workingDirectory.CreateSubdirectory(".aspire"); var hivesDirectory = settingsDirectory.CreateSubdirectory("hives"); var cacheDirectory = new DirectoryInfo(Path.Combine(workingDirectory.FullName, ".aspire", "cache")); - return new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + return new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); } [Fact] diff --git a/tests/Aspire.Cli.Tests/Templating/DotNetTemplateFactoryTests.cs b/tests/Aspire.Cli.Tests/Templating/DotNetTemplateFactoryTests.cs index 7193d5a2436..cb47f0170c3 100644 --- a/tests/Aspire.Cli.Tests/Templating/DotNetTemplateFactoryTests.cs +++ b/tests/Aspire.Cli.Tests/Templating/DotNetTemplateFactoryTests.cs @@ -333,7 +333,7 @@ private static DotNetTemplateFactory CreateTemplateFactory(TestFeatures features var workingDirectory = new DirectoryInfo("/tmp"); var hivesDirectory = new DirectoryInfo("/tmp/hives"); var cacheDirectory = new DirectoryInfo("/tmp/cache"); - var executionContext = new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes"))); + var executionContext = new CliExecutionContext(workingDirectory, hivesDirectory, cacheDirectory, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-runtimes")), new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-logs")), "test.log"); var configurationService = new FakeConfigurationService(); return new DotNetTemplateFactory( diff --git a/tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs b/tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs index 81bf85fed3e..16e703f807c 100644 --- a/tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs +++ b/tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs @@ -32,6 +32,7 @@ using Aspire.Cli.Utils.EnvironmentChecker; using Aspire.Cli.Packaging; using Aspire.Cli.Caching; +using Aspire.Cli.Diagnostics; namespace Aspire.Cli.Tests.Utils; @@ -74,6 +75,11 @@ public static IServiceCollection CreateServiceCollection(TemporaryWorkspace work services.AddLogging(b => b.SetMinimumLevel(LogLevel.Trace)).AddXunitLogging(outputHelper); + // Register a FileLoggerProvider that writes to a test-specific temp directory + var testLogsDirectory = Path.Combine(options.WorkingDirectory.FullName, ".aspire", "logs"); + var fileLoggerProvider = new FileLoggerProvider(testLogsDirectory, TimeProvider.System); + services.AddSingleton(fileLoggerProvider); + services.AddMemoryCache(); services.AddSingleton(options.ConsoleEnvironmentFactory); @@ -207,7 +213,9 @@ private CliExecutionContext CreateDefaultCliExecutionContextFactory(IServiceProv { var hivesDirectory = new DirectoryInfo(Path.Combine(WorkingDirectory.FullName, ".aspire", "hives")); var cacheDirectory = new DirectoryInfo(Path.Combine(WorkingDirectory.FullName, ".aspire", "cache")); - return new CliExecutionContext(WorkingDirectory, hivesDirectory, cacheDirectory, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks"))); + var logsDirectory = new DirectoryInfo(Path.Combine(WorkingDirectory.FullName, ".aspire", "logs")); + var logFilePath = Path.Combine(logsDirectory.FullName, "test.log"); + return new CliExecutionContext(WorkingDirectory, hivesDirectory, cacheDirectory, new DirectoryInfo(Path.Combine(Path.GetTempPath(), "aspire-test-sdks")), logsDirectory, logFilePath); } public DirectoryInfo WorkingDirectory { get; set; }