diff --git a/src/Fallout.Cli/Commands/CakeCleanCommand.cs b/src/Fallout.Cli/Commands/CakeCleanCommand.cs new file mode 100644 index 00000000..07205c4a --- /dev/null +++ b/src/Fallout.Cli/Commands/CakeCleanCommand.cs @@ -0,0 +1,30 @@ +using System.Linq; +using Fallout.Cli.Prompts; +using Fallout.Common; +using Fallout.Common.IO; + +namespace Fallout.Cli.Commands; + +/// +/// fallout :cake-clean: lists and optionally deletes the *.cake scripts. +/// +public sealed class CakeCleanCommand : IFalloutCommand +{ + private readonly IConsolePrompts _prompts; + + public CakeCleanCommand(IConsolePrompts prompts) => _prompts = prompts; + + public string Name => "cake-clean"; + + public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript) + { + var cakeFiles = Program.GetCakeFiles().ToList(); + Host.Information("Found .cake files:"); + cakeFiles.ForEach(x => Host.Debug($" - {x}")); + + if (_prompts.PromptForConfirmation("Delete?")) + cakeFiles.ForEach(x => x.DeleteFile()); + + return 0; + } +} diff --git a/src/Fallout.Cli/Commands/CakeConvertCommand.cs b/src/Fallout.Cli/Commands/CakeConvertCommand.cs new file mode 100644 index 00000000..5e0157e9 --- /dev/null +++ b/src/Fallout.Cli/Commands/CakeConvertCommand.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.Linq; +using Fallout.Cli.Prompts; +using Fallout.Common; +using Fallout.Common.Execution; +using Fallout.Common.IO; +using Fallout.Solutions; +using Fallout.Common.Utilities; +using static Fallout.Common.EnvironmentInfo; + +namespace Fallout.Cli.Commands; + +/// +/// fallout :cake-convert: best-effort conversion of *.cake scripts to Fallout C#. +/// +public sealed class CakeConvertCommand : IFalloutCommand +{ + private readonly IConsolePrompts _prompts; + + public CakeConvertCommand(IConsolePrompts prompts) => _prompts = prompts; + + public string Name => "cake-convert"; + + // The .cake syntax-rewriting helpers (GetCakeFiles/GetCakeConvertedContent/GetCakePackages) and + // the shared GetConfiguration/AddOrReplacePackage helpers remain on Program until the #392 + // collapse PR; GetCakeConvertedContent/GetCakePackages are also exercised directly by tests. + public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript) + { + Program.PrintInfo(); + Logging.Configure(); + Telemetry.ConvertCake(); + ProjectModelTasks.Initialize(); + + Host.Warning( + new[] + { + "Converting .cake files is a best effort approach using syntax rewriting.", + "Compile errors are to be expected, however, the following elements are currently covered:", + " - Target definitions", + " - Default targets", + " - Parameter declarations", + " - Absolute paths", + " - Globbing patterns", + " - Tool invocations (dotnet CLI, SignTool)", + " - Addin and tool references", + }.JoinNewLine()); + + Host.Debug(); + if (!_prompts.PromptForConfirmation("Continue?")) + return 0; + Host.Debug(); + + if (buildScript == null && + _prompts.PromptForConfirmation("Should a Fallout project be created for better results?")) + { + Program.Setup(args, rootDirectory: null, buildScript: null); + } + + var buildScriptFile = WorkingDirectory / Program.CurrentBuildScriptName; + var buildProjectFile = buildScriptFile.Exists() + ? Program.GetConfiguration(buildScriptFile, evaluate: true) + .GetValueOrDefault(Program.BUILD_PROJECT_FILE, defaultValue: null) + : null; + + foreach (var cakeFile in Program.GetCakeFiles()) + { + var outputFile = cakeFile.Parent / cakeFile.NameWithoutExtension.Capitalize() + ".cs"; + var content = Program.GetCakeConvertedContent(cakeFile.ReadAllText()); + outputFile.WriteAllText(content); + } + + if (buildProjectFile != null) + { + var packages = Program.GetCakeFiles().SelectMany(x => Program.GetCakePackages(x.ReadAllText())); + foreach (var package in packages) + Program.AddOrReplacePackage(package.Id, package.Version, package.Type, buildProjectFile); + } + + return 0; + } +} diff --git a/src/Fallout.Cli/Program.Cake.cs b/src/Fallout.Cli/Program.Cake.cs index 6169798d..5d9b7d76 100644 --- a/src/Fallout.Cli/Program.Cake.cs +++ b/src/Fallout.Cli/Program.Cake.cs @@ -19,74 +19,10 @@ partial class Program { public const string CAKE_FILE_PATTERN = "*.cake"; - public static int CakeConvert(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript) - { - PrintInfo(); - Logging.Configure(); - Telemetry.ConvertCake(); - ProjectModelTasks.Initialize(); - - Host.Warning( - new[] - { - "Converting .cake files is a best effort approach using syntax rewriting.", - "Compile errors are to be expected, however, the following elements are currently covered:", - " - Target definitions", - " - Default targets", - " - Parameter declarations", - " - Absolute paths", - " - Globbing patterns", - " - Tool invocations (dotnet CLI, SignTool)", - " - Addin and tool references", - }.JoinNewLine()); - - Host.Debug(); - if (!PromptForConfirmation("Continue?")) - return 0; - Host.Debug(); - - if (buildScript == null && - PromptForConfirmation("Should a NUKE project be created for better results?")) - { - Setup(args, rootDirectory: null, buildScript: null); - } - - var buildScriptFile = WorkingDirectory / CurrentBuildScriptName; - var buildProjectFile = buildScriptFile.Exists() - ? GetConfiguration(buildScriptFile, evaluate: true) - .GetValueOrDefault(BUILD_PROJECT_FILE, defaultValue: null) - : null; - - foreach (var cakeFile in GetCakeFiles()) - { - var outputFile = cakeFile.Parent / cakeFile.NameWithoutExtension.Capitalize() + ".cs"; - var content = GetCakeConvertedContent(cakeFile.ReadAllText()); - outputFile.WriteAllText(content); - } - - if (buildProjectFile != null) - { - var packages = GetCakeFiles().SelectMany(x => GetCakePackages(x.ReadAllText())); - foreach (var package in packages) - AddOrReplacePackage(package.Id, package.Version, package.Type, buildProjectFile); - } - - return 0; - } - - public static int CakeClean(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript) - { - var cakeFiles = GetCakeFiles().ToList(); - Host.Information("Found .cake files:"); - cakeFiles.ForEach(x => Host.Debug($" - {x}")); - - if (PromptForConfirmation("Delete?")) - cakeFiles.ForEach(x => x.DeleteFile()); - - return 0; - } - - private static IEnumerable GetCakeFiles() + // Residual after the :cake-convert/:cake-clean commands moved to CakeConvertCommand/ + // CakeCleanCommand: these .cake syntax-rewriting helpers stay on Program until the #392 collapse + // PR (GetCakeConvertedContent/GetCakePackages are exercised directly by tests). + internal static IEnumerable GetCakeFiles() { return (TryGetRootDirectoryFrom(WorkingDirectory) ?? WorkingDirectory).GlobFiles($"**/{CAKE_FILE_PATTERN}"); } diff --git a/src/Fallout.Cli/Program.cs b/src/Fallout.Cli/Program.cs index 933f7843..7548a71d 100644 --- a/src/Fallout.Cli/Program.cs +++ b/src/Fallout.Cli/Program.cs @@ -66,8 +66,11 @@ private static void RegisterCommands(IServiceCollection services) // Legacy handlers still living on Program, adapted until they are extracted into command // types. Each conversion deletes one line here plus its Program.X.cs partial. - services.AddSingleton(new DelegateCommand("cake-convert", CakeConvert)); - services.AddSingleton(new DelegateCommand("cake-clean", CakeClean)); + services.AddSingleton(); + services.AddSingleton(); + + // Legacy handlers still living on Program, adapted until they are extracted into command + // types. Each conversion deletes one line here plus its Program.X.cs partial. services.AddSingleton(new DelegateCommand("GetNextDirectory", GetNextDirectory)); services.AddSingleton(new DelegateCommand("PopDirectory", PopDirectory)); services.AddSingleton(new DelegateCommand("PushWithCurrentRootDirectory", PushWithCurrentRootDirectory)); diff --git a/tests/Fallout.Cli.Tests/Commands/CakeCleanCommandTests.cs b/tests/Fallout.Cli.Tests/Commands/CakeCleanCommandTests.cs new file mode 100644 index 00000000..a44a4954 --- /dev/null +++ b/tests/Fallout.Cli.Tests/Commands/CakeCleanCommandTests.cs @@ -0,0 +1,21 @@ +using Fallout.Cli.Commands; +using FluentAssertions; +using Xunit; + +namespace Fallout.Cli.Tests.Commands; + +public class CakeCleanCommandTests +{ + [Fact] + public void Name_IsCakeClean() + => new CakeCleanCommand(new FakeConsolePrompts()).Name.Should().Be("cake-clean"); + + [Fact] + public void Execute_WhenDeletionDeclined_ReturnsZeroAndDeletesNothing() + { + // ConfirmationResult = false → the "Delete?" prompt is declined, so no .cake files are removed. + var prompts = new FakeConsolePrompts { ConfirmationResult = false }; + + new CakeCleanCommand(prompts).Execute([], rootDirectory: null, buildScript: null).Should().Be(0); + } +}