diff --git a/Localization/Resources/de-DE/Resources.de-DE.resx b/Localization/Resources/de-DE/Resources.de-DE.resx index 71517b84..eecde663 100644 --- a/Localization/Resources/de-DE/Resources.de-DE.resx +++ b/Localization/Resources/de-DE/Resources.de-DE.resx @@ -1441,9 +1441,6 @@ Warnung: Die Verwendung dieses Arguments kann dazu führen, dass das Token proto Es wurde kein Vorgang angegeben. Verwenden Sie „--help“, um verfügbare Vorgänge anzuzeigen. - - Der Vorgang der DSC-Ressource ist fehlgeschlagen - Gibt an, ob sich eine Instanz im gewünschten Zustand befindet diff --git a/Localization/Resources/es-ES/Resources.es-ES.resx b/Localization/Resources/es-ES/Resources.es-ES.resx index 414179ed..a13dee7c 100644 --- a/Localization/Resources/es-ES/Resources.es-ES.resx +++ b/Localization/Resources/es-ES/Resources.es-ES.resx @@ -1441,9 +1441,6 @@ Advertencia: El uso de este argumento puede resultar en que se registre el token No se especificó ninguna operación. Utilice --help para ver las operaciones disponibles. - - La operación del recurso DSC ha fallado - Indica si una instancia se encuentra en el estado deseado diff --git a/Localization/Resources/fr-FR/Resources.fr-FR.resx b/Localization/Resources/fr-FR/Resources.fr-FR.resx index 411cb7a5..5b22d7d8 100644 --- a/Localization/Resources/fr-FR/Resources.fr-FR.resx +++ b/Localization/Resources/fr-FR/Resources.fr-FR.resx @@ -1441,9 +1441,6 @@ Avertissement : l’utilisation de cet argument peut entraîner la journalisati Aucune opération n’est spécifiée. Utilisez --help pour voir les opérations disponibles. - - Nous n’avons pas pu effectuer l’opération de la ressource DSC - Indique si un instance est dans l’état souhaité diff --git a/Localization/Resources/it-IT/Resources.it-IT.resx b/Localization/Resources/it-IT/Resources.it-IT.resx index 1c8f9379..97b6afc3 100644 --- a/Localization/Resources/it-IT/Resources.it-IT.resx +++ b/Localization/Resources/it-IT/Resources.it-IT.resx @@ -1441,9 +1441,6 @@ Avviso: l'uso di questo argomento può comportare la registrazione del token. Va Nessuna operazione specificata. Usa --help per visualizzare le operazioni disponibili. - - Operazione sulla risorsa DSC non riuscita - Indica se un'istanza si trova nello stato desiderato diff --git a/Localization/Resources/ja-JP/Resources.ja-JP.resx b/Localization/Resources/ja-JP/Resources.ja-JP.resx index 4a9421c5..14bb81d1 100644 --- a/Localization/Resources/ja-JP/Resources.ja-JP.resx +++ b/Localization/Resources/ja-JP/Resources.ja-JP.resx @@ -1441,9 +1441,6 @@ エラー: 操作が指定されていません。--help を使用して、使用可能な操作を確認してください。 - - DSC リソース操作に失敗しました - インスタンスが目的の状態であるかどうかを示します diff --git a/Localization/Resources/ko-KR/Resources.ko-KR.resx b/Localization/Resources/ko-KR/Resources.ko-KR.resx index 335ada25..33802483 100644 --- a/Localization/Resources/ko-KR/Resources.ko-KR.resx +++ b/Localization/Resources/ko-KR/Resources.ko-KR.resx @@ -1441,9 +1441,6 @@ 지정된 작업이 없습니다. --help를 사용하여 사용 가능한 작업을 확인하세요. - - DSC 리소스 작업이 실패했습니다. - 인스턴스가 원하는 상태인지 여부를 나타냅니다. diff --git a/Localization/Resources/pt-BR/Resources.pt-BR.resx b/Localization/Resources/pt-BR/Resources.pt-BR.resx index 397df8e3..274ee180 100644 --- a/Localization/Resources/pt-BR/Resources.pt-BR.resx +++ b/Localization/Resources/pt-BR/Resources.pt-BR.resx @@ -1441,9 +1441,6 @@ Aviso: o uso desse argumento pode fazer com que o token seja registrado. Consid Nenhuma operação especificada. Use --help para ver as operações disponíveis. - - Falha na operação do recurso DSC - Indica se uma instância está no estado desejado diff --git a/Localization/Resources/ru-RU/Resources.ru-RU.resx b/Localization/Resources/ru-RU/Resources.ru-RU.resx index c2819724..c5c30b6e 100644 --- a/Localization/Resources/ru-RU/Resources.ru-RU.resx +++ b/Localization/Resources/ru-RU/Resources.ru-RU.resx @@ -1441,9 +1441,6 @@ Операция не указана. Используйте параметр --help для просмотра доступных операций. - - Сбой операции с ресурсом DSC - Указывает, находится ли экземпляр в желаемом состоянии diff --git a/Localization/Resources/zh-CN/Resources.zh-CN.resx b/Localization/Resources/zh-CN/Resources.zh-CN.resx index e09d7fe8..214b87ef 100644 --- a/Localization/Resources/zh-CN/Resources.zh-CN.resx +++ b/Localization/Resources/zh-CN/Resources.zh-CN.resx @@ -1441,9 +1441,6 @@ 未指定任何操作。使用 --help 查看可用操作。 - - DSC 资源操作失败 - 指示实例是否处于所需状态 diff --git a/Localization/Resources/zh-TW/Resources.zh-TW.resx b/Localization/Resources/zh-TW/Resources.zh-TW.resx index 258271be..6d9fec26 100644 --- a/Localization/Resources/zh-TW/Resources.zh-TW.resx +++ b/Localization/Resources/zh-TW/Resources.zh-TW.resx @@ -1441,9 +1441,6 @@ 未指定任何作業。使用 --help 查看可用的作業。 - - DSC 資源作業失敗 - 指出實例是否處於預期狀態 diff --git a/src/WingetCreateCLI/Commands/DscCommand.cs b/src/WingetCreateCLI/Commands/DscCommand.cs index c703acd3..9d14f103 100644 --- a/src/WingetCreateCLI/Commands/DscCommand.cs +++ b/src/WingetCreateCLI/Commands/DscCommand.cs @@ -96,13 +96,7 @@ public override async Task Execute() { if (methodFlag) { - if (!methodAction()) - { - Logger.ErrorLocalized(nameof(Resources.DscResourceOperationFailed_Message)); - return false; - } - - return true; + return methodAction(); } } diff --git a/src/WingetCreateCLI/Commands/DscCommands/BaseDscCommand.cs b/src/WingetCreateCLI/Commands/DscCommands/BaseDscCommand.cs index 5f25db86..aa3387c7 100644 --- a/src/WingetCreateCLI/Commands/DscCommands/BaseDscCommand.cs +++ b/src/WingetCreateCLI/Commands/DscCommands/BaseDscCommand.cs @@ -85,10 +85,34 @@ public static List GetAvailableCommands() /// True if the command was successful; otherwise, false. public abstract bool Schema(); + /// + /// Writes a JSON output line to the console. + /// + /// The JSON token to be written. + protected static void WriteJsonOutputLine(JToken token) + { + Console.WriteLine(token.ToString(Formatting.None)); + } + + /// + /// Writes a JSON output line to the error stream. + /// + /// The message level. + /// The message to be written. + protected static void WriteMessageOutputLine(DscMessageLevel level, string message) + { + var token = new JObject + { + [GetMessageLevel(level)] = message, + }; + Console.Error.WriteLine(token.ToString(Formatting.None)); + } + /// /// Creates a Json schema for a DSC resource object. /// /// The type of the resource object. + /// The name of the command for which the schema is being created. /// A Json object representing the schema. protected JObject CreateSchema(string commandName) where T : BaseResourceObject, new() @@ -106,11 +130,21 @@ protected JObject CreateSchema(string commandName) } /// - /// Writes a JSON output line to the console. + /// Gets the message level as a string based on the provided DscMessageLevel enum value. /// - /// The JSON token to be written. - protected void WriteJsonOutputLine(JToken token) + /// The DscMessageLevel enum value. + /// A string representation of the message level. + /// Thrown when the provided message level is not recognized. + private static string GetMessageLevel(DscMessageLevel level) { - Console.WriteLine(token.ToString(Formatting.None)); + return level switch + { + DscMessageLevel.Error => "error", + DscMessageLevel.Warning => "warn", + DscMessageLevel.Info => "info", + DscMessageLevel.Debug => "debug", + DscMessageLevel.Trace => "trace", + _ => throw new ArgumentOutOfRangeException(nameof(level), level, null), + }; } } diff --git a/src/WingetCreateCLI/Commands/DscCommands/DscSettingsCommand.cs b/src/WingetCreateCLI/Commands/DscCommands/DscSettingsCommand.cs index fd6538da..06844760 100644 --- a/src/WingetCreateCLI/Commands/DscCommands/DscSettingsCommand.cs +++ b/src/WingetCreateCLI/Commands/DscCommands/DscSettingsCommand.cs @@ -3,7 +3,6 @@ namespace Microsoft.WingetCreateCLI.Commands.DscCommands; -using Microsoft.WingetCreateCLI.Logging; using Microsoft.WingetCreateCLI.Models.DscModels; using Microsoft.WingetCreateCLI.Properties; using Newtonsoft.Json.Linq; @@ -29,7 +28,7 @@ public override bool Set(JToken input) { if (input == null) { - Logger.ErrorLocalized(nameof(Resources.DscInputRequired_Message), nameof(this.Set)); + WriteMessageOutputLine(DscMessageLevel.Error, string.Format(Resources.DscInputRequired_Message, nameof(this.Set))); return false; } @@ -45,8 +44,8 @@ public override bool Set(JToken input) data.Set(); } - this.WriteJsonOutputLine(data.Output.ToJson()); - this.WriteJsonOutputLine(diff); + WriteJsonOutputLine(data.Output.ToJson()); + WriteJsonOutputLine(diff); return true; } @@ -55,7 +54,7 @@ public override bool Test(JToken input) { if (input == null) { - Logger.ErrorLocalized(nameof(Resources.DscInputRequired_Message), nameof(this.Test)); + WriteMessageOutputLine(DscMessageLevel.Error, string.Format(Resources.DscInputRequired_Message, nameof(this.Test))); return false; } @@ -64,8 +63,8 @@ public override bool Test(JToken input) data.Get(); data.Output.InDesiredState = data.Test(); - this.WriteJsonOutputLine(data.Output.ToJson()); - this.WriteJsonOutputLine(data.DiffJson()); + WriteJsonOutputLine(data.Output.ToJson()); + WriteJsonOutputLine(data.DiffJson()); return true; } @@ -74,14 +73,14 @@ public override bool Export(JToken input) { var data = new SettingsFunctionData(); data.Get(); - this.WriteJsonOutputLine(data.Output.ToJson()); + WriteJsonOutputLine(data.Output.ToJson()); return true; } /// public override bool Schema() { - this.WriteJsonOutputLine(this.CreateSchema(CommandName)); + WriteJsonOutputLine(this.CreateSchema(CommandName)); return true; } } diff --git a/src/WingetCreateCLI/Models/DscModels/DscMessageLevel.cs b/src/WingetCreateCLI/Models/DscModels/DscMessageLevel.cs new file mode 100644 index 00000000..f98bc75b --- /dev/null +++ b/src/WingetCreateCLI/Models/DscModels/DscMessageLevel.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. + +namespace Microsoft.WingetCreateCLI.Models.DscModels; + +/// +/// Specifies the severity level of a message. +/// +public enum DscMessageLevel +{ + /// + /// Represents an error message. + /// + Error, + + /// + /// Represents a warning message. + /// + Warning, + + /// + /// Represents an informational message. + /// + Info, + + /// + /// Represents a debug message. + /// + Debug, + + /// + /// Represents a trace message. + /// + Trace, +} diff --git a/src/WingetCreateCLI/Properties/Resources.Designer.cs b/src/WingetCreateCLI/Properties/Resources.Designer.cs index d2b0f9e0..67cecdbf 100644 --- a/src/WingetCreateCLI/Properties/Resources.Designer.cs +++ b/src/WingetCreateCLI/Properties/Resources.Designer.cs @@ -843,15 +843,6 @@ public static string DscResourceNameNotFound_Message { } } - /// - /// Looks up a localized string similar to DSC resource operation failed. - /// - public static string DscResourceOperationFailed_Message { - get { - return ResourceManager.GetString("DscResourceOperationFailed_Message", resourceCulture); - } - } - /// /// Looks up a localized string similar to No operation specified. Use --help to see available operations.. /// diff --git a/src/WingetCreateCLI/Properties/Resources.resx b/src/WingetCreateCLI/Properties/Resources.resx index e5791b33..ac75be2c 100644 --- a/src/WingetCreateCLI/Properties/Resources.resx +++ b/src/WingetCreateCLI/Properties/Resources.resx @@ -1441,9 +1441,6 @@ Warning: Using this argument may result in the token being logged. Consider an a No operation specified. Use --help to see available operations. - - DSC resource operation failed - Indicates whether an instance is in the desired state diff --git a/src/WingetCreateCLI/WingetCreateCLI.csproj b/src/WingetCreateCLI/WingetCreateCLI.csproj index c43df76f..b29439bf 100644 --- a/src/WingetCreateCLI/WingetCreateCLI.csproj +++ b/src/WingetCreateCLI/WingetCreateCLI.csproj @@ -98,10 +98,6 @@ - - - - diff --git a/src/WingetCreateTests/WingetCreateTests/Models/DscExecuteResult.cs b/src/WingetCreateTests/WingetCreateTests/Models/DscExecuteResult.cs index 5c4fb083..a9c11410 100644 --- a/src/WingetCreateTests/WingetCreateTests/Models/DscExecuteResult.cs +++ b/src/WingetCreateTests/WingetCreateTests/Models/DscExecuteResult.cs @@ -6,6 +6,7 @@ namespace Microsoft.WingetCreateUnitTests.Models; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using Microsoft.WingetCreateCLI.Models.DscModels; using Newtonsoft.Json; @@ -18,11 +19,13 @@ public class DscExecuteResult /// Initializes a new instance of the class. /// /// Value indicating whether the command execution was successful. - /// Output of the command execution. - public DscExecuteResult(bool success, string output) + /// Output stream content. + /// Error stream content. + public DscExecuteResult(bool success, string output, string error) { this.Success = success; this.Output = output; + this.Error = error; } /// @@ -31,10 +34,29 @@ public DscExecuteResult(bool success, string output) public bool Success { get; } /// - /// Gets the output result of the operation. + /// Gets the output stream content of the operation. /// public string Output { get; } + /// + /// Gets the error stream content of the operation. + /// + public string Error { get; } + + /// + /// Gets the messages from the error stream. + /// + /// List of messages with their levels. + public List<(DscMessageLevel Level, string Message)> Messages() + { + var lines = this.Error.Split([Environment.NewLine], StringSplitOptions.RemoveEmptyEntries); + return lines.SelectMany(line => + { + var map = JsonConvert.DeserializeObject>(line); + return map.Select(kvp => (this.GetMessageLevel(kvp.Key), kvp.Value)).ToList(); + }).ToList(); + } + /// /// Gets the output as settings state. /// @@ -58,4 +80,23 @@ public SettingsResourceObject OutputState() var diff = JsonConvert.DeserializeObject>(lines[1]); return (settingsObject, diff); } + + /// + /// Gets the message level from a string representation. + /// + /// The string representation of the message level. + /// The level as . + /// Thrown when the level is unknown. + private DscMessageLevel GetMessageLevel(string level) + { + return level switch + { + "error" => DscMessageLevel.Error, + "warn" => DscMessageLevel.Warning, + "info" => DscMessageLevel.Info, + "debug" => DscMessageLevel.Debug, + "trace" => DscMessageLevel.Trace, + _ => throw new ArgumentOutOfRangeException(nameof(level), level, "Unknown message level"), + }; + } } diff --git a/src/WingetCreateTests/WingetCreateTests/TestUtils.cs b/src/WingetCreateTests/WingetCreateTests/TestUtils.cs index 99f5e916..9058ab5c 100644 --- a/src/WingetCreateTests/WingetCreateTests/TestUtils.cs +++ b/src/WingetCreateTests/WingetCreateTests/TestUtils.cs @@ -224,11 +224,14 @@ public static void DeleteCachedFiles(List testFileNames) /// Result of executing the DSC command. public static async Task ExecuteDscCommandAsync(params string[] args) { - var sw = new StringWriter(); - Console.SetOut(sw); + var outSw = new StringWriter(); + var errSw = new StringWriter(); + Console.SetOut(outSw); + Console.SetError(errSw); var executeResult = await Parser.Default.ParseArguments(args).Value.Execute(); - var output = sw.ToString(); - return new(executeResult, output); + var output = outSw.ToString(); + var errorOutput = errSw.ToString(); + return new(executeResult, output, errorOutput); } } } diff --git a/src/WingetCreateTests/WingetCreateTests/UnitTests/DscCommandTests.cs b/src/WingetCreateTests/WingetCreateTests/UnitTests/DscCommandTests.cs index 46783c86..079567e9 100644 --- a/src/WingetCreateTests/WingetCreateTests/UnitTests/DscCommandTests.cs +++ b/src/WingetCreateTests/WingetCreateTests/UnitTests/DscCommandTests.cs @@ -86,6 +86,5 @@ public async Task DscSettingsResourceFailedOperation_ErrorMessage() // Assert Assert.That(result.Success, Is.False); - Assert.That(result.Output, Does.Contain(Resources.DscResourceOperationFailed_Message)); } } diff --git a/src/WingetCreateTests/WingetCreateTests/UnitTests/DscSettingsCommandTests.cs b/src/WingetCreateTests/WingetCreateTests/UnitTests/DscSettingsCommandTests.cs index b9d170c8..ee19ba32 100644 --- a/src/WingetCreateTests/WingetCreateTests/UnitTests/DscSettingsCommandTests.cs +++ b/src/WingetCreateTests/WingetCreateTests/UnitTests/DscSettingsCommandTests.cs @@ -112,10 +112,13 @@ public async Task DscSettingsResource_SetEmpty_Fail() { // Act var result = await TestUtils.ExecuteDscCommandAsync(DscSettingsCommand.CommandName, "--set", string.Empty); + var messages = result.Messages(); // Assert Assert.That(result.Success, Is.False); - Assert.That(result.Output, Does.Contain(string.Format(Resources.DscInputRequired_Message, nameof(DscSettingsCommand.Set)))); + Assert.That(messages.Count, Is.EqualTo(1)); + Assert.That(messages[0].Level, Is.EqualTo(DscMessageLevel.Error)); + Assert.That(messages[0].Message, Is.EqualTo(string.Format(Resources.DscInputRequired_Message, nameof(DscSettingsCommand.Set)))); } /// @@ -127,10 +130,13 @@ public async Task DscSettingsResource_TestEmpty_Fail() { // Act var result = await TestUtils.ExecuteDscCommandAsync(DscSettingsCommand.CommandName, "--test", string.Empty); + var messages = result.Messages(); // Assert Assert.That(result.Success, Is.False); - Assert.That(result.Output, Does.Contain(string.Format(Resources.DscInputRequired_Message, nameof(DscSettingsCommand.Test)))); + Assert.That(messages.Count, Is.EqualTo(1)); + Assert.That(messages[0].Level, Is.EqualTo(DscMessageLevel.Error)); + Assert.That(messages[0].Message, Is.EqualTo(string.Format(Resources.DscInputRequired_Message, nameof(DscSettingsCommand.Test)))); } ///