diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/Components.cs b/src/Cli/Microsoft.TemplateEngine.Cli/Components.cs
index 57eb7b1d9347..34870595d00e 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/Components.cs
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/Components.cs
@@ -14,7 +14,8 @@ public static class Components
(typeof(IPostActionProcessor), new ChmodPostActionProcessor()),
(typeof(IPostActionProcessor), new InstructionDisplayPostActionProcessor()),
(typeof(IPostActionProcessor), new ProcessStartPostActionProcessor()),
- (typeof(IPostActionProcessor), new AddJsonPropertyPostActionProcessor())
+ (typeof(IPostActionProcessor), new AddJsonPropertyPostActionProcessor()),
+ (typeof(IPostActionProcessor), new CreateOrUpdateDotnetConfigPostActionProcessor()),
};
}
}
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs b/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs
index 18d737c820d9..f7b0a86e0e80 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs
@@ -19,7 +19,7 @@ namespace Microsoft.TemplateEngine.Cli {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class LocalizableStrings {
@@ -458,6 +458,15 @@ internal static string CliTemplateSearchCoordinator_Info_SearchInProgress {
}
}
+ ///
+ /// Looks up a localized string similar to The colon separator "::" has been deprecated in favor of the at symbol "@" for separating the package from the version in dotnet new install. In your case, this means {0}@{1} instead of {0}::{1}..
+ ///
+ internal static string Colon_Separator_Deprecated {
+ get {
+ return ResourceManager.GetString("Colon_Separator_Deprecated", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Author.
///
@@ -1394,6 +1403,51 @@ internal static string PossibleValuesHeader {
}
}
+ ///
+ /// Looks up a localized string similar to Created new section in 'dotnet.config' file.
+ ///
+ internal static string PostAction_CreateDotnetConfig_CreatedNewSection {
+ get {
+ return ResourceManager.GetString("PostAction_CreateDotnetConfig_CreatedNewSection", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'..
+ ///
+ internal static string PostAction_CreateDotnetConfig_ManuallyUpdate {
+ get {
+ return ResourceManager.GetString("PostAction_CreateDotnetConfig_ManuallyUpdate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Successfully created 'dotnet.config' file..
+ ///
+ internal static string PostAction_CreateDotnetConfig_Succeeded {
+ get {
+ return ResourceManager.GetString("PostAction_CreateDotnetConfig_Succeeded", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The required value in 'dotnet.config' is already set..
+ ///
+ internal static string PostAction_CreateDotnetConfig_ValueAlreadyExist {
+ get {
+ return ResourceManager.GetString("PostAction_CreateDotnetConfig_ValueAlreadyExist", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Post action argument '{0}' is mandatory, but not configured..
+ ///
+ internal static string PostAction_DotnetConfig_Error_ArgumentNotConfigured {
+ get {
+ return ResourceManager.GetString("PostAction_DotnetConfig_Error_ArgumentNotConfigured", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Post action argument '{0}' is not a valid boolean value..
///
@@ -1870,35 +1924,21 @@ internal static string TemplatePackageCoordinator_Install_Info_OverrideNotice {
return ResourceManager.GetString("TemplatePackageCoordinator_Install_Info_OverrideNotice", resourceCulture);
}
}
-
- ///
- /// Looks up a localized string similar to The following template packages will be installed:.
- ///
- internal static string TemplatePackageCoordinator_Install_Info_PackageIsAvailable
- {
- get
- {
- return ResourceManager.GetString("TemplatePackageCoordinator_Install_Info_PackageIsAvailable", resourceCulture);
- }
- }
-
+
///
- /// Looks up a localized string indicating that :: as a separator is deprecated in favor of @.
+ /// Looks up a localized string similar to The following template package(s) are already available:.
///
- internal static string Colon_Separator_Deprecated
- {
+ internal static string TemplatePackageCoordinator_Install_Info_PackageIsAvailable {
get {
- return ResourceManager.GetString("Colon_Separator_Deprecated", resourceCulture);
+ return ResourceManager.GetString("TemplatePackageCoordinator_Install_Info_PackageIsAvailable", resourceCulture);
}
}
-
+
///
/// Looks up a localized string similar to The following template packages will be installed:.
///
- internal static string TemplatePackageCoordinator_Install_Info_PackagesToBeInstalled
- {
- get
- {
+ internal static string TemplatePackageCoordinator_Install_Info_PackagesToBeInstalled {
+ get {
return ResourceManager.GetString("TemplatePackageCoordinator_Install_Info_PackagesToBeInstalled", resourceCulture);
}
}
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx b/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx
index 3f38783adb27..d7de5f7d82b2 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx
@@ -953,4 +953,23 @@ The header is followed by the list of parameters and their errors (might be seve
Attempting to find json file '{0}' in '{1}'
+
+ Post action argument '{0}' is mandatory, but not configured.
+
+
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
\ No newline at end of file
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/Microsoft.TemplateEngine.Cli.csproj b/src/Cli/Microsoft.TemplateEngine.Cli/Microsoft.TemplateEngine.Cli.csproj
index 228c9cd613d2..d8fb3406268a 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/Microsoft.TemplateEngine.Cli.csproj
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/Microsoft.TemplateEngine.Cli.csproj
@@ -16,6 +16,7 @@
+
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/CreateOrUpdateDotnetConfigPostActionProcessor.cs b/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/CreateOrUpdateDotnetConfigPostActionProcessor.cs
new file mode 100644
index 000000000000..9afbf5e899a0
--- /dev/null
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/CreateOrUpdateDotnetConfigPostActionProcessor.cs
@@ -0,0 +1,131 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.DotNet.Cli.Utils;
+using Microsoft.Extensions.Configuration;
+using Microsoft.TemplateEngine.Abstractions;
+using Microsoft.TemplateEngine.Abstractions.PhysicalFileSystem;
+
+namespace Microsoft.TemplateEngine.Cli.PostActionProcessors
+{
+ internal sealed class CreateOrUpdateDotnetConfigPostActionProcessor : PostActionProcessorBase
+ {
+ private const string SectionArgument = "section";
+ private const string KeyArgument = "key";
+ private const string ValueArgument = "value";
+
+ public override Guid Id => ActionProcessorId;
+
+ internal static Guid ActionProcessorId { get; } = new Guid("597E7933-0D87-452C-B094-8FA0EEF7FD97");
+
+ protected override bool ProcessInternal(
+ IEngineEnvironmentSettings environment,
+ IPostAction action,
+ ICreationEffects creationEffects,
+ ICreationResult templateCreationResult,
+ string outputBasePath)
+ {
+ if (!action.Args.TryGetValue(SectionArgument, out string? sectionName))
+ {
+ Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_DotnetConfig_Error_ArgumentNotConfigured, SectionArgument));
+ return false;
+ }
+
+ if (!action.Args.TryGetValue(KeyArgument, out string? key))
+ {
+ Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_DotnetConfig_Error_ArgumentNotConfigured, KeyArgument));
+ return false;
+ }
+
+ if (!action.Args.TryGetValue(ValueArgument, out string? value))
+ {
+ Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_DotnetConfig_Error_ArgumentNotConfigured, ValueArgument));
+ return false;
+ }
+
+ var fileSystem = environment.Host.FileSystem;
+ var repoRoot = GetRootDirectory(fileSystem, outputBasePath);
+ var dotnetConfigFilePath = Path.Combine(repoRoot, "dotnet.config");
+ if (!fileSystem.FileExists(dotnetConfigFilePath))
+ {
+ fileSystem.WriteAllText(dotnetConfigFilePath, $"""
+ [{sectionName}]
+ {key} = "{value}"
+
+ """);
+
+ Reporter.Output.WriteLine(LocalizableStrings.PostAction_CreateDotnetConfig_Succeeded);
+ return true;
+ }
+
+ var builder = new ConfigurationBuilder();
+ using var stream = fileSystem.OpenRead(dotnetConfigFilePath);
+ builder.AddIniStream(stream);
+ IConfigurationRoot config = builder.Build();
+ var section = config.GetSection(sectionName);
+
+ if (!section.Exists())
+ {
+ var existingContent = fileSystem.ReadAllText(dotnetConfigFilePath);
+ fileSystem.WriteAllText(dotnetConfigFilePath, $"""
+ {existingContent}
+
+ [{sectionName}]
+ {key} = "{value}"
+
+ """);
+
+ Reporter.Output.WriteLine(LocalizableStrings.PostAction_CreateDotnetConfig_CreatedNewSection);
+ return true;
+ }
+
+ string? existingValue = section[key];
+ if (string.IsNullOrEmpty(existingValue))
+ {
+ // The section exists, but the key/value pair does not.
+ Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_CreateDotnetConfig_ManuallyUpdate, $"{key} = \"{value}\"", $"[{sectionName}]"));
+ return false;
+ }
+
+ if (existingValue.Equals(value, StringComparison.Ordinal))
+ {
+ // The key already exists with the same value, nothing to do.
+ Reporter.Output.WriteLine(LocalizableStrings.PostAction_CreateDotnetConfig_ValueAlreadyExist);
+ return true;
+ }
+
+ Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_CreateDotnetConfig_ManuallyUpdate, $"{key} = \"{value}\"", $"[{sectionName}]"));
+ return false;
+ }
+
+ private static string GetRootDirectory(IPhysicalFileSystem fileSystem, string outputBasePath)
+ {
+ string? currentDirectory = outputBasePath;
+ string? directoryWithSln = null;
+ while (currentDirectory is not null)
+ {
+ if (fileSystem.FileExists(Path.Combine(currentDirectory, "dotnet.config")) ||
+ fileSystem.DirectoryExists(Path.Combine(currentDirectory, ".git")))
+ {
+ return currentDirectory;
+ }
+
+ // DirectoryExists here should always be true in practice, but for the way tests are mocking the file system, it's not.
+ // The check was added to prevent test failures similar to:
+ // System.IO.DirectoryNotFoundException : Could not find a part of the path '/Users/runner/work/1/s/artifacts/bin/Microsoft.TemplateEngine.Cli.UnitTests/Release/sandbox'.
+ // We get to this exception when doing `EnumerateFiles` on a directory that was virtually created in memory (not really available on disk).
+ // EnumerateFiles tries to access the physical file system, which then fails.
+ if (fileSystem.DirectoryExists(currentDirectory) &&
+ (fileSystem.EnumerateFiles(currentDirectory, "*.sln", SearchOption.TopDirectoryOnly).Any() ||
+ fileSystem.EnumerateFiles(currentDirectory, "*.slnx", SearchOption.TopDirectoryOnly).Any()))
+ {
+ directoryWithSln = currentDirectory;
+ }
+
+ currentDirectory = Directory.GetParent(currentDirectory)?.FullName;
+ }
+
+ return directoryWithSln ?? outputBasePath;
+ }
+ }
+}
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf
index 45f6d58a1ba7..2a4a247003b1 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf
@@ -830,6 +830,31 @@ The header is followed by the list of parameters and their errors (might be seve
Chcete tuto akci spustit? [{0}(ano)|{1}(ne)]
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.Argument post-action {0} není platná logická hodnota.
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf
index eb67ab8bf9bf..2bf7017b7241 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf
@@ -830,6 +830,31 @@ 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)]?
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.Das Post-Aktionsargument „{0}“ ist kein gültiger boolescher Wert.
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf
index 748e66f30a00..5b9822e43d7b 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf
@@ -830,6 +830,31 @@ The header is followed by the list of parameters and their errors (might be seve
¿Quiere ejecutar esta acción [{0}(yes)|{1}(no)]?
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.El argumento de la acción publicado '{0}' no es un valor booleano válido.
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf
index d86722e36e60..b25d0abe8451 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf
@@ -830,6 +830,31 @@ 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)] ?
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.L’argument post-action « {0} » n’est pas une valeur booléenne valide.
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf
index 45d8e4f02e4e..2d8e48dbaf41 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.it.xlf
@@ -830,6 +830,31 @@ The header is followed by the list of parameters and their errors (might be seve
Eseguire questa azione [{0} (sì) |{1} (no)]?
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.L'argomento dell'azione successiva '{0}' non è un valore booleano valido.
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf
index 2f9a5c77a259..8c189ad07d9f 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ja.xlf
@@ -830,6 +830,31 @@ The header is followed by the list of parameters and their errors (might be seve
このアクションを実行しますか[{0} (はい) |{1} (いいえ)] ですか?
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.事後アクションの引数 '{0}' は有効なブール値ではありません。
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf
index 11699454506d..01d53932780b 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ko.xlf
@@ -830,6 +830,31 @@ The header is followed by the list of parameters and their errors (might be seve
이 작업을 실행하시겠어요 [{0} (예) |{1} (아니요)]?
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.사후 작업 인수 '{0}'은(는) 올바른 부울 값이 아닙니다.
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf
index 6e5167124b31..e35d2f20dcfa 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pl.xlf
@@ -830,6 +830,31 @@ The header is followed by the list of parameters and their errors (might be seve
Chcesz uruchomić tę akcję [{0}(tak)|{1}(nie)]?
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.Argument akcji „{0}” nie jest prawidłową wartością logiczną.
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 24f89179cb85..5f09b05a889f 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.pt-BR.xlf
@@ -830,6 +830,31 @@ The header is followed by the list of parameters and their errors (might be seve
Deseja executar esta ação [{0}(yes)|{1}(no)]?
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.O argumento de pós-ação '{0}' não é um valor booleano válido.
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf
index 6578a4d5bf14..e16f4f2f2508 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.ru.xlf
@@ -830,6 +830,31 @@ The header is followed by the list of parameters and their errors (might be seve
Вы хотите выполнить это действие [{0}(да)|{1}(нет)]?
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.Аргумент после действия "{0}" не является допустимым логическим значением.
diff --git a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf
index a0d71cff2b96..9cf57a18b1ff 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.tr.xlf
@@ -830,6 +830,31 @@ 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)]?
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.'{0}' eylem sonrası bağımsız değişkeni, geçerli bir boole değeri değil.
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 f75d8ad68dae..be2844f845b7 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hans.xlf
@@ -830,6 +830,31 @@ The header is followed by the list of parameters and their errors (might be seve
是否要运行此操作 [{0}(是)|{1}(否)]?
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.Post 操作参数“{0}”不是有效的布尔值。
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 56c64a9d9b91..df84bc90c6dd 100644
--- a/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf
+++ b/src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.zh-Hant.xlf
@@ -830,6 +830,31 @@ The header is followed by the list of parameters and their errors (might be seve
是否要執行此動作 [{0}(是)|{1}(否)]?
+
+ Created new section in 'dotnet.config' file
+ Created new section in 'dotnet.config' file
+ {Locked="dotnet.config"}
+
+
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ Updating existing values in 'dotnet.config' is not yet supported. Please, manually update 'dotnet.config' to have '{0}' under section '{1}'.
+ {Locked="dotnet.config"}
+
+
+ Successfully created 'dotnet.config' file.
+ Successfully created 'dotnet.config' file.
+ {Locked="dotnet.config"}
+
+
+ The required value in 'dotnet.config' is already set.
+ The required value in 'dotnet.config' is already set.
+ {Locked="dotnet.config"}
+
+
+ Post action argument '{0}' is mandatory, but not configured.
+ Post action argument '{0}' is mandatory, but not configured.
+
+ Post action argument '{0}' is not a valid boolean value.Post 巨集指令引數 '{0}' 不是有效的布林值。
diff --git a/test/Microsoft.TemplateEngine.Cli.UnitTests/PostActionTests/CreateOrUpdateDotnetConfigPostActionTests.cs b/test/Microsoft.TemplateEngine.Cli.UnitTests/PostActionTests/CreateOrUpdateDotnetConfigPostActionTests.cs
new file mode 100644
index 000000000000..6d66a0c6b895
--- /dev/null
+++ b/test/Microsoft.TemplateEngine.Cli.UnitTests/PostActionTests/CreateOrUpdateDotnetConfigPostActionTests.cs
@@ -0,0 +1,223 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.CompilerServices;
+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;
+
+public class CreateOrUpdateDotnetConfigPostActionTests : IClassFixture
+{
+ private readonly IEngineEnvironmentSettings _engineEnvironmentSettings;
+
+ public CreateOrUpdateDotnetConfigPostActionTests(EnvironmentSettingsHelper environmentSettingsHelper)
+ {
+ _engineEnvironmentSettings = environmentSettingsHelper.CreateEnvironment(hostIdentifier: GetType().Name, virtualize: true);
+ }
+
+ [Theory]
+ [InlineData("section")]
+ [InlineData("key")]
+ [InlineData("value")]
+ public void MissingArgumentShouldFail(string missingArgumentName)
+ {
+ string targetBasePath = GetTargetPath();
+
+ var dictionary = new Dictionary
+ {
+ ["section"] = "dotnet.test.runner",
+ ["key"] = "name",
+ ["value"] = "Microsoft.Testing.Platform"
+ };
+ dictionary.Remove(missingArgumentName);
+
+ IPostAction postAction = new MockPostAction(default, default, default, default, default!)
+ {
+ ActionId = CreateOrUpdateDotnetConfigPostActionProcessor.ActionProcessorId,
+ Args = dictionary,
+ };
+
+ Mock mockReporter = new();
+
+ mockReporter.Setup(r => r.WriteLine(It.IsAny()))
+ .Verifiable();
+
+ Reporter.SetError(mockReporter.Object);
+
+ CreateOrUpdateDotnetConfigPostActionProcessor processor = new();
+
+ bool result = processor.Process(
+ _engineEnvironmentSettings,
+ postAction,
+ new MockCreationEffects(),
+ new MockCreationResult(),
+ targetBasePath);
+
+ Assert.False(result);
+
+ mockReporter.Verify(r => r.WriteLine(string.Format(LocalizableStrings.PostAction_DotnetConfig_Error_ArgumentNotConfigured, missingArgumentName)), Times.Once);
+ }
+
+ [Fact]
+ public void CreatesDotnetConfigWhenDoesNotExist()
+ {
+ string targetBasePath = GetTargetPath();
+ string dotnetConfigPath = Path.Combine(targetBasePath, "dotnet.config");
+
+ IPostAction postAction = CreatePostActionForMTP();
+
+ Mock mockReporter = new();
+
+ mockReporter.Setup(r => r.WriteLine(It.IsAny()))
+ .Verifiable();
+
+ Reporter.SetOutput(mockReporter.Object);
+
+ CreateOrUpdateDotnetConfigPostActionProcessor processor = new();
+
+ _engineEnvironmentSettings.Host.FileSystem.FileExists(dotnetConfigPath).Should().BeFalse();
+
+ bool result = processor.Process(
+ _engineEnvironmentSettings,
+ postAction,
+ new MockCreationEffects(),
+ new MockCreationResult(),
+ targetBasePath);
+
+ Assert.True(result);
+
+ _engineEnvironmentSettings.Host.FileSystem.FileExists(dotnetConfigPath).Should().BeTrue();
+ _engineEnvironmentSettings.Host.FileSystem.ReadAllText(dotnetConfigPath).Should().Be("""
+ [dotnet.test.runner]
+ name = "Microsoft.Testing.Platform"
+
+ """);
+
+ mockReporter.Verify(r => r.WriteLine(LocalizableStrings.PostAction_CreateDotnetConfig_Succeeded), Times.Once);
+ }
+
+ [Fact]
+ public void CreatesNewSectionWhenFileExistsButSectionDoesNot()
+ {
+ string targetBasePath = GetTargetPath();
+ string dotnetConfigPath = Path.Combine(targetBasePath, "dotnet.config");
+
+ IPostAction postAction = CreatePostActionForMTP();
+ CreateDotnetConfig(dotnetConfigPath, "mysection", "mykey", "myvalue");
+ Mock mockReporter = new();
+
+ mockReporter.Setup(r => r.WriteLine(It.IsAny()))
+ .Verifiable();
+
+ Reporter.SetOutput(mockReporter.Object);
+
+ CreateOrUpdateDotnetConfigPostActionProcessor processor = new();
+
+ _engineEnvironmentSettings.Host.FileSystem.FileExists(dotnetConfigPath).Should().BeTrue();
+ _engineEnvironmentSettings.Host.FileSystem.ReadAllText(dotnetConfigPath).Should().Be("""
+ [mysection]
+ mykey = "myvalue"
+
+ """);
+
+ bool result = processor.Process(
+ _engineEnvironmentSettings,
+ postAction,
+ new MockCreationEffects(),
+ new MockCreationResult(),
+ targetBasePath);
+
+ Assert.True(result);
+
+ _engineEnvironmentSettings.Host.FileSystem.FileExists(dotnetConfigPath).Should().BeTrue();
+ _engineEnvironmentSettings.Host.FileSystem.ReadAllText(dotnetConfigPath).Should().Be("""
+ [mysection]
+ mykey = "myvalue"
+
+
+ [dotnet.test.runner]
+ name = "Microsoft.Testing.Platform"
+
+ """);
+
+ mockReporter.Verify(r => r.WriteLine(LocalizableStrings.PostAction_CreateDotnetConfig_CreatedNewSection), Times.Once);
+ }
+
+ [Fact]
+ public void DoesNothingIfNoUpdatesNeedToHappen()
+ {
+ string targetBasePath = GetTargetPath();
+ string dotnetConfigPath = Path.Combine(targetBasePath, "dotnet.config");
+
+ IPostAction postAction = CreatePostActionForMTP();
+ CreateDotnetConfig(dotnetConfigPath, "dotnet.test.runner", "name", "Microsoft.Testing.Platform");
+ Mock mockReporter = new();
+
+ mockReporter.Setup(r => r.WriteLine(It.IsAny()))
+ .Verifiable();
+
+ Reporter.SetOutput(mockReporter.Object);
+
+ CreateOrUpdateDotnetConfigPostActionProcessor processor = new();
+
+ _engineEnvironmentSettings.Host.FileSystem.FileExists(dotnetConfigPath).Should().BeTrue();
+ _engineEnvironmentSettings.Host.FileSystem.ReadAllText(dotnetConfigPath).Should().Be("""
+ [dotnet.test.runner]
+ name = "Microsoft.Testing.Platform"
+
+ """);
+
+ bool result = processor.Process(
+ _engineEnvironmentSettings,
+ postAction,
+ new MockCreationEffects(),
+ new MockCreationResult(),
+ targetBasePath);
+
+ Assert.True(result);
+
+ _engineEnvironmentSettings.Host.FileSystem.FileExists(dotnetConfigPath).Should().BeTrue();
+ _engineEnvironmentSettings.Host.FileSystem.ReadAllText(dotnetConfigPath).Should().Be("""
+ [dotnet.test.runner]
+ name = "Microsoft.Testing.Platform"
+
+ """);
+
+ mockReporter.Verify(r => r.WriteLine(LocalizableStrings.PostAction_CreateDotnetConfig_ValueAlreadyExist), Times.Once);
+ }
+
+ private static IPostAction CreatePostActionForMTP()
+ => new MockPostAction(default, default, default, default, default!)
+ {
+ ActionId = CreateOrUpdateDotnetConfigPostActionProcessor.ActionProcessorId,
+ Args = new Dictionary
+ {
+ ["section"] = "dotnet.test.runner",
+ ["key"] = "name",
+ ["value"] = "Microsoft.Testing.Platform",
+ },
+ };
+
+ private void CreateDotnetConfig(string dotnetConfigPath, string section, string key, string value)
+ => _engineEnvironmentSettings.Host.FileSystem.WriteAllText(dotnetConfigPath, $"""
+ [{section}]
+ {key} = "{value}"
+
+ """);
+
+ private string GetTargetPath([CallerMemberName] string testName = "")
+ {
+ string targetBasePath = Path.Combine(_engineEnvironmentSettings.GetTempVirtualizedPath(), testName);
+ _engineEnvironmentSettings.Host.FileSystem.CreateDirectory(targetBasePath);
+
+ // This is done to not let the preprocessor logic go above our base path directory.
+ _engineEnvironmentSettings.Host.FileSystem.CreateDirectory(Path.Combine(targetBasePath, ".git"));
+ return targetBasePath;
+ }
+}
diff --git a/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/AddNewSection/.template.config/template.json b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/AddNewSection/.template.config/template.json
new file mode 100644
index 000000000000..18b058625a93
--- /dev/null
+++ b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/AddNewSection/.template.config/template.json
@@ -0,0 +1,29 @@
+{
+ "author": "Test Asset",
+ "classifications": [ "Test Asset" ],
+ "name": "TestAssets.PostActions.CreateOrUpdateDotnetConfig.AddNewSection",
+ "generatorVersions": "[1.0.0.0-*)",
+ "groupIdentity": "TestAssets.PostActions.CreateOrUpdateDotnetConfig.AddNewSection",
+ "precedence": "100",
+ "identity": "TestAssets.PostActions.CreateOrUpdateDotnetConfig.AddNewSection",
+ "shortName": "TestAssets.PostActions.CreateOrUpdateDotnetConfig.AddNewSection",
+ "sourceName": "AddNewSection",
+ "primaryOutputs": [
+ {
+ "path": "AddNewSection.csproj"
+ }
+ ],
+ "postActions": [
+ {
+ "description": "Add dotnet.config",
+ "manualInstructions": [ { "text": "Create dotnet.config manually." } ],
+ "args": {
+ "section": "SectionFromTemplateJson",
+ "key": "KeyFromTemplateJson",
+ "value": "ValueFromTemplateJson"
+ },
+ "actionId": "597E7933-0D87-452C-B094-8FA0EEF7FD97",
+ "continueOnError": true
+ }
+ ]
+}
diff --git a/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/AddNewSection/AddNewSection.csproj b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/AddNewSection/AddNewSection.csproj
new file mode 100644
index 000000000000..ba7e2d463888
--- /dev/null
+++ b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/AddNewSection/AddNewSection.csproj
@@ -0,0 +1,8 @@
+
+
+
+ Exe
+ $(CurrentTargetFramework)
+
+
+
diff --git a/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/AddNewSection/Program.cs b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/AddNewSection/Program.cs
new file mode 100644
index 000000000000..38a7692a4297
--- /dev/null
+++ b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/AddNewSection/Program.cs
@@ -0,0 +1,14 @@
+using System;
+using Newtonsoft.Json;
+
+namespace Basic
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Console.WriteLine("Hello World!");
+ string result = JsonConvert.SerializeObject(new { a = "test" });
+ }
+ }
+}
diff --git a/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/AddNewSection/dotnet.config b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/AddNewSection/dotnet.config
new file mode 100644
index 000000000000..d658b6c3fdd3
--- /dev/null
+++ b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/AddNewSection/dotnet.config
@@ -0,0 +1,2 @@
+[existing-section]
+mykey = "myvalue"
\ No newline at end of file
diff --git a/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/CreateNonExisting/.template.config/template.json b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/CreateNonExisting/.template.config/template.json
new file mode 100644
index 000000000000..93c23963f8d7
--- /dev/null
+++ b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/CreateNonExisting/.template.config/template.json
@@ -0,0 +1,29 @@
+{
+ "author": "Test Asset",
+ "classifications": [ "Test Asset" ],
+ "name": "TestAssets.PostActions.CreateOrUpdateDotnetConfig.CreateNonExisting",
+ "generatorVersions": "[1.0.0.0-*)",
+ "groupIdentity": "TestAssets.PostActions.CreateOrUpdateDotnetConfig.CreateNonExisting",
+ "precedence": "100",
+ "identity": "TestAssets.PostActions.CreateOrUpdateDotnetConfig.CreateNonExisting",
+ "shortName": "TestAssets.PostActions.CreateOrUpdateDotnetConfig.CreateNonExisting",
+ "sourceName": "CreateNonExisting",
+ "primaryOutputs": [
+ {
+ "path": "CreateNonExisting.csproj"
+ }
+ ],
+ "postActions": [
+ {
+ "description": "Add dotnet.config",
+ "manualInstructions": [ { "text": "Create dotnet.config manually." } ],
+ "args": {
+ "section": "SectionFromTemplateJson",
+ "key": "KeyFromTemplateJson",
+ "value": "ValueFromTemplateJson"
+ },
+ "actionId": "597E7933-0D87-452C-B094-8FA0EEF7FD97",
+ "continueOnError": true
+ }
+ ]
+}
diff --git a/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/CreateNonExisting/CreateNonExisting.csproj b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/CreateNonExisting/CreateNonExisting.csproj
new file mode 100644
index 000000000000..ba7e2d463888
--- /dev/null
+++ b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/CreateNonExisting/CreateNonExisting.csproj
@@ -0,0 +1,8 @@
+
+
+
+ Exe
+ $(CurrentTargetFramework)
+
+
+
diff --git a/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/CreateNonExisting/Program.cs b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/CreateNonExisting/Program.cs
new file mode 100644
index 000000000000..38a7692a4297
--- /dev/null
+++ b/test/TestAssets/TestPackages/dotnet-new/test_templates/PostActions/CreateOrUpdateDotnetConfig/CreateNonExisting/Program.cs
@@ -0,0 +1,14 @@
+using System;
+using Newtonsoft.Json;
+
+namespace Basic
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Console.WriteLine("Hello World!");
+ string result = JsonConvert.SerializeObject(new { a = "test" });
+ }
+ }
+}
diff --git a/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.Linux.verified.txt b/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.Linux.verified.txt
index 948efa0f8d7b..c69514a6ee7b 100644
--- a/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.Linux.verified.txt
+++ b/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.Linux.verified.txt
@@ -31,6 +31,8 @@
TestAssets.PostActions.AddProjectToSolution.... TestAssets.PostActions.AddProjectToSolution.BasicInSolutionRoot Test Asset
TestAssets.PostActions.AddProjectToSolution.... TestAssets.PostActions.AddProjectToSolution.BasicWithFiles Test Asset
TestAssets.PostActions.AddProjectToSolution.... TestAssets.PostActions.AddProjectToSolution.BasicWithIndexes Test Asset
+ TestAssets.PostActions.CreateOrUpdateDotnetC... TestAssets.PostActions.CreateOrUpdateDotnetConfig.AddNewSection Test Asset
+ TestAssets.PostActions.CreateOrUpdateDotnetC... TestAssets.PostActions.CreateOrUpdateDotnetConfig.CreateNonExisting Test Asset
TestAssets.PostActions.Instructions.Basic TestAssets.PostActions.Instructions.Basic Test Asset
TestAssets.PostActions.RestoreNuGet.Basic TestAssets.PostActions.RestoreNuGet.Basic Test Asset
TestAssets.PostActions.RestoreNuGet.BasicWit... TestAssets.PostActions.RestoreNuGet.BasicWithFiles Test Asset
diff --git a/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.OSX.verified.txt b/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.OSX.verified.txt
index 948efa0f8d7b..c69514a6ee7b 100644
--- a/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.OSX.verified.txt
+++ b/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.OSX.verified.txt
@@ -31,6 +31,8 @@
TestAssets.PostActions.AddProjectToSolution.... TestAssets.PostActions.AddProjectToSolution.BasicInSolutionRoot Test Asset
TestAssets.PostActions.AddProjectToSolution.... TestAssets.PostActions.AddProjectToSolution.BasicWithFiles Test Asset
TestAssets.PostActions.AddProjectToSolution.... TestAssets.PostActions.AddProjectToSolution.BasicWithIndexes Test Asset
+ TestAssets.PostActions.CreateOrUpdateDotnetC... TestAssets.PostActions.CreateOrUpdateDotnetConfig.AddNewSection Test Asset
+ TestAssets.PostActions.CreateOrUpdateDotnetC... TestAssets.PostActions.CreateOrUpdateDotnetConfig.CreateNonExisting Test Asset
TestAssets.PostActions.Instructions.Basic TestAssets.PostActions.Instructions.Basic Test Asset
TestAssets.PostActions.RestoreNuGet.Basic TestAssets.PostActions.RestoreNuGet.Basic Test Asset
TestAssets.PostActions.RestoreNuGet.BasicWit... TestAssets.PostActions.RestoreNuGet.BasicWithFiles Test Asset
diff --git a/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.Windows.verified.txt b/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.Windows.verified.txt
index 8f48b106823e..f2c16d05d10d 100644
--- a/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.Windows.verified.txt
+++ b/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.Windows.verified.txt
@@ -31,6 +31,8 @@
TestAssets.PostActions.AddProjectToSolution.... TestAssets.PostActions.AddProjectToSolution.BasicWithFiles Test Asset
TestAssets.PostActions.AddProjectToSolution.... TestAssets.PostActions.AddProjectToSolution.BasicWithIndexes Test Asset
TestAssets.PostActions.AddProjectToSolution.... TestAssets.PostActions.AddProjectToSolution.Basic Test Asset
+ TestAssets.PostActions.CreateOrUpdateDotnetC... TestAssets.PostActions.CreateOrUpdateDotnetConfig.AddNewSection Test Asset
+ TestAssets.PostActions.CreateOrUpdateDotnetC... TestAssets.PostActions.CreateOrUpdateDotnetConfig.CreateNonExisting Test Asset
TestAssets.PostActions.Instructions.Basic TestAssets.PostActions.Instructions.Basic Test Asset
TestAssets.PostActions.RestoreNuGet.BasicWit... TestAssets.PostActions.RestoreNuGet.BasicWithFiles Test Asset
TestAssets.PostActions.RestoreNuGet.Basic TestAssets.PostActions.RestoreNuGet.Basic Test Asset
diff --git a/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.verified.txt b/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.verified.txt
index 3264f4ecfdd7..0a6b5d625e43 100644
--- a/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.verified.txt
+++ b/test/dotnet-new.IntegrationTests/Approvals/DotnetNewDetailsTest.CanDisplayDetails_InstalledPackage_LocalPackage.verified.txt
@@ -31,6 +31,8 @@
TestAssets.PostActions.AddProjectToSolution.... TestAssets.PostActions.AddProjectToSolution.BasicWithFiles Test Asset
TestAssets.PostActions.AddProjectToSolution.... TestAssets.PostActions.AddProjectToSolution.BasicWithIndexes Test Asset
TestAssets.PostActions.AddProjectToSolution.... TestAssets.PostActions.AddProjectToSolution.Basic Test Asset
+ TestAssets.PostActions.CreateOrUpdateDotnetC... TestAssets.PostActions.CreateOrUpdateDotnetConfig.AddNewSection Test Asset
+ TestAssets.PostActions.CreateOrUpdateDotnetC... TestAssets.PostActions.CreateOrUpdateDotnetConfig.CreateNonExisting Test Asset
TestAssets.PostActions.Instructions.Basic TestAssets.PostActions.Instructions.Basic Test Asset
TestAssets.PostActions.RestoreNuGet.BasicWit... TestAssets.PostActions.RestoreNuGet.BasicWithFiles Test Asset
TestAssets.PostActions.RestoreNuGet.Basic TestAssets.PostActions.RestoreNuGet.Basic Test Asset
diff --git a/test/dotnet-new.IntegrationTests/PostActionTests.cs b/test/dotnet-new.IntegrationTests/PostActionTests.cs
index 3e9c6a391914..3acada973357 100644
--- a/test/dotnet-new.IntegrationTests/PostActionTests.cs
+++ b/test/dotnet-new.IntegrationTests/PostActionTests.cs
@@ -3,6 +3,7 @@
using System.Text.Json.Nodes;
using Microsoft.DotNet.Cli.Utils;
+using Microsoft.TemplateEngine.TestHelper;
using Microsoft.TemplateEngine.Utils;
namespace Microsoft.DotNet.Cli.New.IntegrationTests
@@ -1215,5 +1216,72 @@ public void AddJsonProperty_FailsWhenJsonFileNotFoundInEligableDirectories()
File.Delete(jsonFileLocation);
}
+
+ [Fact]
+ public void CreateOrUpdateDotnetConfig_CreateNonExisting()
+ {
+ string templateLocation = _testAssetsManager.CopyTestAsset("PostActions/CreateOrUpdateDotnetConfig/CreateNonExisting", testAssetSubdirectory: DotnetNewTestTemplatesBasePath).WithSource().Path;
+ string expectedTemplateName = "TestAssets.PostActions.CreateOrUpdateDotnetConfig.CreateNonExisting";
+ string home = CreateTemporaryFolder(folderName: "Home");
+ string workingDirectory = CreateTemporaryFolder();
+ string outputDirectory = TestUtils.CreateTemporaryFolder();
+ InstallTestTemplate(templateLocation, _log, home, workingDirectory);
+
+ var commandResult = new DotnetNewCommand(_log, expectedTemplateName, "-n", "MyProject", "-o", outputDirectory)
+ .WithCustomHive(home)
+ .WithWorkingDirectory(workingDirectory)
+ .Execute();
+
+ commandResult
+ .Should()
+ .ExitWith(0)
+ .And.NotHaveStdErr()
+ .And.HaveStdOutContaining($"The template \"{expectedTemplateName}\" was created successfully.")
+ .And.HaveStdOutContaining("Successfully created 'dotnet.config' file.")
+ .And.NotHaveStdOutContaining("Manual instructions");
+
+ Assert.Equal(
+ """
+ [SectionFromTemplateJson]
+ KeyFromTemplateJson = "ValueFromTemplateJson"
+
+ """,
+ File.ReadAllText(Path.Combine(outputDirectory, "dotnet.config")));
+ }
+
+ [Fact]
+ public void CreateOrUpdateDotnetConfig_AddNewSection()
+ {
+ string templateLocation = _testAssetsManager.CopyTestAsset("PostActions/CreateOrUpdateDotnetConfig/AddNewSection", testAssetSubdirectory: DotnetNewTestTemplatesBasePath).WithSource().Path;
+ string expectedTemplateName = "TestAssets.PostActions.CreateOrUpdateDotnetConfig.AddNewSection";
+ string home = CreateTemporaryFolder(folderName: "Home");
+ string workingDirectory = CreateTemporaryFolder();
+ string outputDirectory = TestUtils.CreateTemporaryFolder();
+ InstallTestTemplate(templateLocation, _log, home, workingDirectory);
+
+ var commandResult = new DotnetNewCommand(_log, expectedTemplateName, "-n", "MyProject", "-o", outputDirectory)
+ .WithCustomHive(home)
+ .WithWorkingDirectory(workingDirectory)
+ .Execute();
+
+ commandResult
+ .Should()
+ .ExitWith(0)
+ .And.NotHaveStdErr()
+ .And.HaveStdOutContaining($"The template \"{expectedTemplateName}\" was created successfully.")
+ .And.HaveStdOutContaining("Created new section in 'dotnet.config' file")
+ .And.NotHaveStdOutContaining("Manual instructions");
+
+ Assert.Equal(
+ """
+ [existing-section]
+ mykey = "myvalue"
+
+ [SectionFromTemplateJson]
+ KeyFromTemplateJson = "ValueFromTemplateJson"
+
+ """,
+ File.ReadAllText(Path.Combine(outputDirectory, "dotnet.config")));
+ }
}
}