From ad027efc80b4359b325b85cd2ca002dd4e9fa3c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Wed, 3 Jul 2024 17:36:52 +0200 Subject: [PATCH] JsonPropertyPostAction: allow to create file and path --- .../LocalizableStrings.Designer.cs | 18 ++ .../LocalizableStrings.resx | 53 +++-- .../AddJsonPropertyPostActionProcessor.cs | 65 ++++-- .../xlf/LocalizableStrings.cs.xlf | 10 + .../xlf/LocalizableStrings.de.xlf | 10 + .../xlf/LocalizableStrings.es.xlf | 10 + .../xlf/LocalizableStrings.fr.xlf | 10 + .../xlf/LocalizableStrings.it.xlf | 10 + .../xlf/LocalizableStrings.ja.xlf | 10 + .../xlf/LocalizableStrings.ko.xlf | 10 + .../xlf/LocalizableStrings.pl.xlf | 10 + .../xlf/LocalizableStrings.pt-BR.xlf | 10 + .../xlf/LocalizableStrings.ru.xlf | 10 + .../xlf/LocalizableStrings.tr.xlf | 10 + .../xlf/LocalizableStrings.zh-Hans.xlf | 10 + .../xlf/LocalizableStrings.zh-Hant.xlf | 10 + .../AddJsonPropertyPostActionTests.cs | 221 ++++++++++++++++-- 17 files changed, 426 insertions(+), 61 deletions(-) diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs b/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs index aaaa927343de..96ebca073460 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs +++ b/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs @@ -1394,6 +1394,15 @@ internal static string PossibleValuesHeader { } } + /// + /// Looks up a localized string similar to Post action argument '{0}' is not a valid boolean value.. + /// + internal static string PostAction_ModifyJson_Error_ArgumentNotBoolean { + get { + return ResourceManager.GetString("PostAction_ModifyJson_Error_ArgumentNotBoolean", resourceCulture); + } + } + /// /// Looks up a localized string similar to Post action argument '{0}' is mandatory, but not configured.. /// @@ -1439,6 +1448,15 @@ internal static string PostAction_ModifyJson_Succeeded { } } + /// + /// Looks up a localized string similar to Attempting to find json file '{0}' in '{1}'. + /// + internal static string PostAction_ModifyJson_Verbose_AttemptingToFindJsonFile { + get { + return ResourceManager.GetString("PostAction_ModifyJson_Verbose_AttemptingToFindJsonFile", resourceCulture); + } + } + /// /// Looks up a localized string similar to Failed to run the command: argument 'executable' is missing in post action configuration.. /// diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx b/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx index dd607ed27b6c..05bab0edbd86 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx +++ b/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx @@ -307,7 +307,7 @@ Moderate - represents nuget api severity of level 1. + represents nuget api severity of level 1. High @@ -859,67 +859,64 @@ The header is followed by the list of parameters and their errors (might be seve To list installed templates, run: - + Package identifier - + Specifies a concrete version for displaying details. If not specified the last is taken. - + Authors - + Details - + Source Feed - + Package version - + Reserved - + Languages - - + License Metadata - + License Expression - + License - + License Url - + Owners - + Repository Url - + Short Names - - + Tags - - + Templates - + No NuGet sources are defined or enabled - + Failed to load NuGet sources configured for the folder {0} - + Could not parse NuGet source '{0}', so it was discarded @@ -947,4 +944,10 @@ The header is followed by the list of parameters and their errors (might be seve Trusted information about NuGet package origin; if a package has PrefixReserved indicator - + + Post action argument '{0}' is not a valid boolean value. + + + Attempting to find json file '{0}' in '{1}' + + \ No newline at end of file diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/AddJsonPropertyPostActionProcessor.cs b/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/AddJsonPropertyPostActionProcessor.cs index 619f062b6a53..68a0855d97ef 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/AddJsonPropertyPostActionProcessor.cs +++ b/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/AddJsonPropertyPostActionProcessor.cs @@ -4,6 +4,7 @@ using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Nodes; + using Microsoft.DotNet.Cli.Utils; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.PhysicalFileSystem; @@ -12,6 +13,8 @@ namespace Microsoft.TemplateEngine.Cli.PostActionProcessors { internal class AddJsonPropertyPostActionProcessor : PostActionProcessorBase { + private const string AllowFileCreationArgument = "allowFileCreation"; + private const string AllowPathCreationArgument = "allowPathCreation"; private const string JsonFileNameArgument = "jsonFileName"; private const string ParentPropertyPathArgument = "parentPropertyPath"; private const string NewJsonPropertyNameArgument = "newJsonPropertyName"; @@ -46,12 +49,25 @@ protected override bool ProcessInternal( return false; } - IReadOnlyList jsonFiles = FindFilesInCurrentProjectOrSolutionFolder(environment.Host.FileSystem, outputBasePath, matchPattern: jsonFileName, maxAllowedAboveDirectories: 1); + IReadOnlyList jsonFiles = FindFilesInCurrentFolderOrParentFolder(environment.Host.FileSystem, outputBasePath, jsonFileName); if (jsonFiles.Count == 0) { - Reporter.Error.WriteLine(LocalizableStrings.PostAction_ModifyJson_Error_NoJsonFile); - return false; + if (!bool.TryParse(action.Args.GetValueOrDefault(AllowFileCreationArgument, "false"), out bool createFile)) + { + Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Error_ArgumentNotBoolean, AllowFileCreationArgument)); + return false; + } + + if (!createFile) + { + Reporter.Error.WriteLine(LocalizableStrings.PostAction_ModifyJson_Error_NoJsonFile); + return false; + } + + string newJsonFilePath = Path.Combine(outputBasePath, jsonFileName); + environment.Host.FileSystem.WriteAllText(newJsonFilePath, "{}"); + jsonFiles = new List { newJsonFilePath }; } if (jsonFiles.Count > 1) @@ -73,7 +89,8 @@ protected override bool ProcessInternal( newJsonElementProperties!.ParentProperty, ":", newJsonElementProperties.NewJsonPropertyName, - newJsonElementProperties.NewJsonPropertyValue); + newJsonElementProperties.NewJsonPropertyValue, + action); if (newJsonContent == null) { @@ -87,7 +104,7 @@ protected override bool ProcessInternal( return true; } - private static JsonNode? AddElementToJson(IPhysicalFileSystem fileSystem, string targetJsonFile, string? propertyPath, string propertyPathSeparator, string newJsonPropertyName, string newJsonPropertyValue) + private static JsonNode? AddElementToJson(IPhysicalFileSystem fileSystem, string targetJsonFile, string? propertyPath, string propertyPathSeparator, string newJsonPropertyName, string newJsonPropertyValue, IPostAction action) { JsonNode? jsonContent = JsonNode.Parse(fileSystem.ReadAllText(targetJsonFile), nodeOptions: null, documentOptions: DeserializerOptions); @@ -96,7 +113,13 @@ protected override bool ProcessInternal( return null; } - JsonNode? parentProperty = FindJsonNode(jsonContent, propertyPath, propertyPathSeparator); + if (!bool.TryParse(action.Args.GetValueOrDefault(AllowPathCreationArgument, "false"), out bool createPath)) + { + Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Error_ArgumentNotBoolean, AllowPathCreationArgument)); + return false; + } + + JsonNode? parentProperty = FindJsonNode(jsonContent, propertyPath, propertyPathSeparator, createPath); if (parentProperty == null) { @@ -116,7 +139,7 @@ protected override bool ProcessInternal( return jsonContent; } - private static JsonNode? FindJsonNode(JsonNode content, string? nodePath, string pathSeparator) + private static JsonNode? FindJsonNode(JsonNode content, string? nodePath, string pathSeparator, bool createPath) { if (nodePath == null) { @@ -134,18 +157,22 @@ protected override bool ProcessInternal( return null; } - node = node[property]; + JsonNode? childNode = node[property]; + if (childNode is null && createPath) + { + node[property] = childNode = new JsonObject(); + } + + node = childNode; } return node; } - private static IReadOnlyList FindFilesInCurrentProjectOrSolutionFolder( + private static string[] FindFilesInCurrentFolderOrParentFolder( IPhysicalFileSystem fileSystem, string startPath, - string matchPattern, - Func? secondaryFilter = null, - int maxAllowedAboveDirectories = 250) + string matchPattern) { string? directory = fileSystem.DirectoryExists(startPath) ? startPath : Path.GetDirectoryName(startPath); @@ -158,22 +185,20 @@ private static IReadOnlyList FindFilesInCurrentProjectOrSolutionFolder( do { - List filesInDir = fileSystem.EnumerateFileSystemEntries(directory, matchPattern, SearchOption.AllDirectories).ToList(); - List matches = new(); - - matches = secondaryFilter == null ? filesInDir : filesInDir.Where(x => secondaryFilter(x)).ToList(); + Reporter.Verbose.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Verbose_AttemptingToFindJsonFile, matchPattern, directory)); + string[] filesInDir = fileSystem.EnumerateFileSystemEntries(directory, matchPattern, SearchOption.AllDirectories).ToArray(); - if (matches.Count > 0) + if (filesInDir.Length > 0) { - return matches; + return filesInDir; } directory = Path.GetPathRoot(directory) != directory ? Directory.GetParent(directory)?.FullName : null; numberOfUpLevels++; } - while (directory != null && numberOfUpLevels <= maxAllowedAboveDirectories); + while (directory != null && numberOfUpLevels <= 1); - return new List(); + return Array.Empty(); } private class JsonContentParameters diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf index aeaadf8612f4..832d3c3d0367 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve Chcete tuto akci spustit? [{0}(ano)|{1}(ne)] + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. Argument „{0}“ po akci je povinný, ale není nakonfigurovaný. @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve {0} byl úspěšně změněn. + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. Příkaz se nepodařilo spustit. V konfiguraci akce publikování chybí argument executable. diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf index dc1bb13aef69..9d09cc5425b2 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve Möchten Sie diese Aktion ausführen [{0} (ja) |{1} (nein)]? + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. Das Postaktionsargument "{0}" ist obligatorisch, aber nicht konfiguriert. @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve {0} erfolgreich geändert. + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. Fehler beim Ausführen des Befehls: das Argument "Ausführbare Datei" fehlt in der Konfiguration der nachfolgenden Aktion. diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf index d4b4b1f37611..dfceed7d9791 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve ¿Quiere ejecutar esta acción [{0}(yes)|{1}(no)]? + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. El argumento de acción posterior '{0}' es obligatorio, pero no está configurado. @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve {0} modificado correctamente. + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. No se pudo ejecutar el comando: falta el argumento "executable" en la configuración de la acción posterior. diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf index b06daec2e1a0..dc4a7e3ecfc7 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve Voulez-vous exécuter cette action [{0} (yes) |{1} (no)] ? + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. L'argument de publication de l'action '{0}' est obligatoire, mais n'est pas configuré. @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve Modifié avec succès {0}. + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. Échec de l’exécution de la commande : l’argument « Exécutable » est manquant dans la configuration de l’action de publication. diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf index 4d17a1c6f8ec..c72a0079c4f2 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve Eseguire questa azione [{0} (sì) |{1} (no)]? + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. L'argomento post-azione '{0}' è obbligatorio, ma non configurato. @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve Modifica di {0} completata. + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. Non è stato possibile eseguire il comando: argomento "eseguibile" mancante nella configurazione dell'azione post. diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf index d0b01c5aa96f..e5d354ce85df 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve このアクションを実行しますか[{0} (はい) |{1} (いいえ)] ですか? + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. 事後アクション引数 '{0}' は必須ですが、構成されていません。 @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve {0} が正常に変更されました。 + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. コマンドの実行は失敗しました: 引数 'executable' がPOST アクションの構成に存在しません。 diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf index 61e93bbd5e25..4249b91d6cd7 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve 이 작업을 실행하시겠어요 [{0} (예) |{1} (아니요)]? + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. '{0}' 게시물 매크로 함수 인수가 필수이지만 구성되지 않았습니다. @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve {0}을(를) 수정했습니다. + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. 명령을 실행하지 못했습니다. 게시 작업 구성에 'executable' 인수가 없습니다. diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf index 70154b9a40c1..23cc4f066fa5 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve Chcesz uruchomić tę akcję [{0}(tak)|{1}(nie)]? + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. Argument po wystąpieniu akcji „{0}” jest obowiązkowy, ale nie jest skonfigurowany. @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve Pomyślnie zmodyfikowano {0}. + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. Nie można uruchomić polecenia: brak argumentu "executable" w konfiguracji akcji post. diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf index 9f1efc54d0d7..6e26bb078114 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve Deseja executar esta ação [{0}(yes)|{1}(no)]? + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. O argumento pós-ação '{0}' é obrigatório, mas não configurado. @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve Modificado com sucesso {0}. + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. Falha ao executar o comando: o argumento 'executável' está ausente na configuração pós-ação. diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf index c60b3dde870e..64d24799e119 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve Вы хотите выполнить это действие [{0}(да)|{1}(нет)]? + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. Аргумент после действия "{0}" является обязательным, но не настроен. @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve Успешное изменение {0}. + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. Не удалось выполнить команду: аргумент executable отсутствует в конфигурации действия публикации. diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf index 25151df45489..d611f7f585f6 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve Bu eylemi çalıştırmak istiyor musunuz [{0}(evet)|{1}(hayır)]? + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. '{0}' eylem sonrası bağımsız değişkeni zorunlu, ancak yapılandırılmamış. @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve {0} başarıyla değiştirildi. + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. Komut çalıştırılamadı: Gönderme eylemi yapılandırmasında 'executable' bağımsız değişkeni eksik. diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf index 4c8e5deccbfe..08bf8872676d 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve 是否要运行此操作 [{0}(是)|{1}(否)]? + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. 发布操作参数“{0}”是必需的,但未进行配置。 @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve 已成功修改 {0}。 + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. 无法运行命令: 在发布操作配置中缺少参数“可执行”。 diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf index 0b1534e847f3..6023fda5c481 100644 --- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf +++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf @@ -825,6 +825,11 @@ The header is followed by the list of parameters and their errors (might be seve 是否要執行此動作 [{0}(是)|{1}(否)]? + + Post action argument '{0}' is not a valid boolean value. + Post action argument '{0}' is not a valid boolean value. + + Post action argument '{0}' is mandatory, but not configured. 動作後引數 '{0}' 是強制的,但未設定。 @@ -850,6 +855,11 @@ The header is followed by the list of parameters and their errors (might be seve 已成功修改 {0}。 + + Attempting to find json file '{0}' in '{1}' + Attempting to find json file '{0}' in '{1}' + + Failed to run the command: argument 'executable' is missing in post action configuration. 無法執行命令: 後續動作設定中遺漏引數 'executable'。 diff --git a/test/Microsoft.TemplateEngine.Cli.UnitTests/PostActionTests/AddJsonPropertyPostActionTests.cs b/test/Microsoft.TemplateEngine.Cli.UnitTests/PostActionTests/AddJsonPropertyPostActionTests.cs index 179a9de0eec1..6e43810e538e 100644 --- a/test/Microsoft.TemplateEngine.Cli.UnitTests/PostActionTests/AddJsonPropertyPostActionTests.cs +++ b/test/Microsoft.TemplateEngine.Cli.UnitTests/PostActionTests/AddJsonPropertyPostActionTests.cs @@ -2,11 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Nodes; + using Microsoft.DotNet.Cli.Utils; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Cli.PostActionProcessors; using Microsoft.TemplateEngine.Mocks; using Microsoft.TemplateEngine.TestHelper; + using Moq; namespace Microsoft.TemplateEngine.Cli.UnitTests.PostActionTests @@ -132,8 +134,8 @@ public void FailsWhenMandatoryArgumentsNotConfigured(ModifyJsonPostActionTestCas } [Theory] - [MemberData(nameof(ModifyJsonPostActionTestCase.SuccessTestCases), MemberType = typeof(ModifyJsonPostActionTestCase))] - public void CanSuccessfullyModifyJsonFile(ModifyJsonPostActionTestCase testCase) + [MemberData(nameof(ModifyJsonPostActionTestCase<(JsonNode, bool)>.SuccessTestCases), MemberType = typeof(ModifyJsonPostActionTestCase<(JsonNode, bool)>))] + public void CanSuccessfullyModifyJsonFile(ModifyJsonPostActionTestCase<(JsonNode, bool)> testCase) { string targetBasePath = _engineEnvironmentSettings.GetTempVirtualizedPath(); @@ -164,7 +166,183 @@ public void CanSuccessfullyModifyJsonFile(ModifyJsonPostActionTestCase Assert.NotNull(modifiedJsonContent); - testCase.AssertionCallback(modifiedJsonContent); + testCase.AssertionCallback((modifiedJsonContent, false)); + } + + [Theory] + [MemberData(nameof(ModifyJsonPostActionTestCase<(JsonNode, bool)>.SuccessTestCases), MemberType = typeof(ModifyJsonPostActionTestCase<(JsonNode, bool)>))] + public void CanSuccessfullyCreateAndModifyJsonFileWhenAllowFileCreationAndPathCreationAreSet(ModifyJsonPostActionTestCase<(JsonNode, bool)> testCase) + { + string targetBasePath = _engineEnvironmentSettings.GetTempVirtualizedPath(); + + string jsonFileName = Guid.NewGuid().ToString("N") + ".json"; + testCase.PostActionArgs["jsonFileName"] = jsonFileName; + testCase.PostActionArgs["allowFileCreation"] = "true"; + testCase.PostActionArgs["allowPathCreation"] = "true"; + IPostAction postAction = new MockPostAction(default, default, default, default, default!) + { + ActionId = AddJsonPropertyPostActionProcessor.ActionProcessorId, + Args = testCase.PostActionArgs + }; + + AddJsonPropertyPostActionProcessor processor = new(); + + bool result = processor.Process( + _engineEnvironmentSettings, + postAction, + new MockCreationEffects(), + new MockCreationResult(), + targetBasePath); + + Assert.True(result); + + string jsonFilePath = Path.Combine(targetBasePath, jsonFileName); + JsonNode? modifiedJsonContent = JsonNode.Parse(_engineEnvironmentSettings.Host.FileSystem.ReadAllText(jsonFilePath)); + + Assert.NotNull(modifiedJsonContent); + + testCase.AssertionCallback((modifiedJsonContent, true)); + } + + [Theory] + [MemberData(nameof(ModifyJsonPostActionTestCase<(JsonNode, bool)>.SuccessTestCases), MemberType = typeof(ModifyJsonPostActionTestCase<(JsonNode, bool)>))] + public void CanSuccessfullyModifyJsonFileWhenPathDoesNotExistAndAllowPathCreationIsSet(ModifyJsonPostActionTestCase<(JsonNode, bool)> testCase) + { + string targetBasePath = _engineEnvironmentSettings.GetTempVirtualizedPath(); + + string jsonFileName = Guid.NewGuid().ToString("N") + ".json"; + testCase.PostActionArgs["jsonFileName"] = jsonFileName; + testCase.PostActionArgs["allowPathCreation"] = "true"; + + string jsonFilePath = CreateJsonFile(targetBasePath, jsonFileName, "{}"); + + IPostAction postAction = new MockPostAction(default, default, default, default, default!) + { + ActionId = AddJsonPropertyPostActionProcessor.ActionProcessorId, + Args = testCase.PostActionArgs + }; + + AddJsonPropertyPostActionProcessor processor = new(); + + bool result = processor.Process( + _engineEnvironmentSettings, + postAction, + new MockCreationEffects(), + new MockCreationResult(), + targetBasePath); + + Assert.True(result); + + JsonNode? modifiedJsonContent = JsonNode.Parse(_engineEnvironmentSettings.Host.FileSystem.ReadAllText(jsonFilePath)); + + Assert.NotNull(modifiedJsonContent); + + testCase.AssertionCallback((modifiedJsonContent, true)); + } + + [Fact] + public void FailsWhenFileExistsButPathDoesNotExistAndAllowPathCreationIsNotSet() + { + string targetBasePath = _engineEnvironmentSettings.GetTempVirtualizedPath(); + + string jsonFileName = Guid.NewGuid().ToString("N") + ".json"; + string originalJsonContent = "{}"; + string jsonFilePath = CreateJsonFile(targetBasePath, jsonFileName, originalJsonContent); + + IPostAction postAction = new MockPostAction(default, default, default, default, default!) + { + ActionId = AddJsonPropertyPostActionProcessor.ActionProcessorId, + Args = new Dictionary + { + ["jsonFileName"] = jsonFileName, + ["allowPathCreation"] = "false", + ["parentPropertyPath"] = "", + ["newJsonPropertyName"] = "lastName", + ["newJsonPropertyValue"] = "Watson" + } + }; + + AddJsonPropertyPostActionProcessor processor = new(); + + bool result = processor.Process( + _engineEnvironmentSettings, + postAction, + new MockCreationEffects(), + new MockCreationResult(), + targetBasePath); + + Assert.False(result); + + Assert.Equal(originalJsonContent, _engineEnvironmentSettings.Host.FileSystem.ReadAllText(jsonFilePath)); + } + + [Fact] + public void FailsWhenFileDoesNotExistAndAllowFileCreationIsNotSet() + { + string jsonFileName = Guid.NewGuid().ToString("N") + ".json"; + + IPostAction postAction = new MockPostAction(default, default, default, default, default!) + { + ActionId = AddJsonPropertyPostActionProcessor.ActionProcessorId, + Args = new Dictionary + { + ["jsonFileName"] = jsonFileName, + ["allowFileCreation"] = "false", + ["parentPropertyPath"] = "", + ["newJsonPropertyName"] = "lastName", + ["newJsonPropertyValue"] = "Watson" + } + }; + + AddJsonPropertyPostActionProcessor processor = new(); + + string targetBasePath = _engineEnvironmentSettings.GetTempVirtualizedPath(); + bool result = processor.Process( + _engineEnvironmentSettings, + postAction, + new MockCreationEffects(), + new MockCreationResult(), + targetBasePath); + + Assert.False(result); + + string jsonFilePath = Path.Combine(targetBasePath, jsonFileName); + Assert.False(_engineEnvironmentSettings.Host.FileSystem.FileExists(jsonFilePath)); + } + + [Fact] + public void FailsWhenFileDoesNotExistAndAllowFileCreationIsSetButAllowPathCreationIsNotSet() + { + string jsonFileName = Guid.NewGuid().ToString("N") + ".json"; + + IPostAction postAction = new MockPostAction(default, default, default, default, default!) + { + ActionId = AddJsonPropertyPostActionProcessor.ActionProcessorId, + Args = new Dictionary + { + ["jsonFileName"] = jsonFileName, + ["allowFileCreation"] = "true", + ["allowPathCreation"] = "false", + ["parentPropertyPath"] = "", + ["newJsonPropertyName"] = "lastName", + ["newJsonPropertyValue"] = "Watson" + } + }; + + AddJsonPropertyPostActionProcessor processor = new(); + + string targetBasePath = _engineEnvironmentSettings.GetTempVirtualizedPath(); + bool result = processor.Process( + _engineEnvironmentSettings, + postAction, + new MockCreationEffects(), + new MockCreationResult(), + targetBasePath); + + Assert.False(result); + + string jsonFilePath = Path.Combine(targetBasePath, jsonFileName); + Assert.Equal("{}", _engineEnvironmentSettings.Host.FileSystem.ReadAllText(jsonFilePath)); } private string CreateJsonFile(string targetBasePath, string fileName, string jsonContent) @@ -182,7 +360,7 @@ public record ModifyJsonPostActionTestCase( Dictionary PostActionArgs, Action AssertionCallback) { - private static readonly ModifyJsonPostActionTestCase[] _successTestCases = + private static readonly ModifyJsonPostActionTestCase<(JsonNode ResultingJson, bool IsNewJson)>[] _successTestCases = { new( "Can add simple property", @@ -194,10 +372,9 @@ public record ModifyJsonPostActionTestCase( ["newJsonPropertyName"] = "lastName", ["newJsonPropertyValue"] = "Watson" }, - (JsonNode modifiedJsonContent) => + tuple => { - Assert.NotNull(modifiedJsonContent["person"]!["lastName"]); - Assert.Equal("Watson", modifiedJsonContent["person"]!["lastName"]!.ToString()); + Assert.Equal("Watson", tuple.ResultingJson["person"]!["lastName"]!.ToString()); }), new( @@ -210,10 +387,9 @@ public record ModifyJsonPostActionTestCase( ["newJsonPropertyName"] = "address", ["newJsonPropertyValue"] = @"{""street"": ""street name"", ""zip"": ""zipcode""}" }, - (JsonNode modifiedJsonContent) => + tuple => { - Assert.NotNull(modifiedJsonContent["person"]!["address"]); - Assert.Equal("street name", modifiedJsonContent["person"]!["address"]!["street"]!.ToString()); + Assert.Equal("street name", tuple.ResultingJson["person"]!["address"]!["street"]!.ToString()); }), new( @@ -226,10 +402,16 @@ public record ModifyJsonPostActionTestCase( ["newJsonPropertyName"] = "secondProperty", ["newJsonPropertyValue"] = "bar" }, - (JsonNode modifiedJsonContent) => + tuple => { - Assert.NotNull(modifiedJsonContent["secondProperty"]); - Assert.Equal(@"{""firstProperty"":""foo"",""secondProperty"":""bar""}", modifiedJsonContent.ToJsonString()); + if (tuple.IsNewJson) + { + Assert.Equal(@"{""secondProperty"":""bar""}", tuple.ResultingJson.ToJsonString()); + } + else + { + Assert.Equal(@"{""firstProperty"":""foo"",""secondProperty"":""bar""}", tuple.ResultingJson.ToJsonString()); + } }), new( @@ -242,9 +424,16 @@ public record ModifyJsonPostActionTestCase( ["newJsonPropertyName"] = "foo", ["newJsonPropertyValue"] = "bar" }, - (JsonNode modifiedJsonContent) => + tuple => { - Assert.Equal(@"{""rootProperty"":{""subProperty1"":{""subProperty2"":{""subProperty3"":{""name"":""test"",""foo"":""bar""}}}}}", modifiedJsonContent.ToJsonString()); + if (tuple.IsNewJson) + { + Assert.Equal(@"{""rootProperty"":{""subProperty1"":{""subProperty2"":{""subProperty3"":{""foo"":""bar""}}}}}", tuple.ResultingJson.ToJsonString()); + } + else + { + Assert.Equal(@"{""rootProperty"":{""subProperty1"":{""subProperty2"":{""subProperty3"":{""name"":""test"",""foo"":""bar""}}}}}", tuple.ResultingJson.ToJsonString()); + } }) }; @@ -297,7 +486,7 @@ public record ModifyJsonPostActionTestCase( public static IEnumerable SuccessTestCases() { - foreach (ModifyJsonPostActionTestCase testCase in _successTestCases) + foreach (ModifyJsonPostActionTestCase<(JsonNode, bool)> testCase in _successTestCases) { yield return new[] { testCase }; }