From 0a9c885175cfc534d840c84e79c1c93cd89a9e66 Mon Sep 17 00:00:00 2001 From: Phil Asmar Date: Fri, 6 Dec 2024 20:47:35 -0500 Subject: [PATCH] feat: switch to Spectre.Console for a better CLI experience --- .../Amazon.Lambda.TestTool.csproj | 3 +- .../src/Amazon.Lambda.TestTool/AppRunner.cs | 15 - .../Commands/CommandFactory.cs | 102 ------- .../Commands/RunCommand.cs | 86 ++++++ .../Components/Pages/Home.razor | 17 +- .../Components/Pages/SaveRequestDialog.razor | 9 +- .../src/Amazon.Lambda.TestTool/Constants.cs | 1 + .../Extensions/ServiceCollectionExtensions.cs | 4 +- .../Models/ApplicationOptions.cs | 25 -- .../Models/EventContainer.cs | 11 +- .../Processes/TestToolProcess.cs | 13 +- .../src/Amazon.Lambda.TestTool/Program.cs | 20 +- .../SampleRequests/LambdaRequest.cs | 13 +- .../SampleRequests/SampleRequestManager.cs | 219 +++++++-------- .../Services/DirectoryManager.cs | 6 + .../Services/IDirectoryManager.cs | 6 + .../Services/LambdaRuntimeAPI.cs | 26 +- .../Services/RuntimeApiDataStore.cs | 265 +++++++++--------- .../Services/TypeRegistrar.cs | 31 ++ .../Services/TypeResolver.cs | 26 ++ .../Amazon.Lambda.TestTool/Utilities/Utils.cs | 10 +- .../RuntimeApiTests.cs | 3 +- 22 files changed, 457 insertions(+), 454 deletions(-) delete mode 100644 Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/AppRunner.cs delete mode 100644 Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Commands/CommandFactory.cs create mode 100644 Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Commands/RunCommand.cs delete mode 100644 Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Models/ApplicationOptions.cs create mode 100644 Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Services/DirectoryManager.cs create mode 100644 Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Services/IDirectoryManager.cs create mode 100644 Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Services/TypeRegistrar.cs create mode 100644 Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Services/TypeResolver.cs diff --git a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Amazon.Lambda.TestTool.csproj b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Amazon.Lambda.TestTool.csproj index 04c5f39a7..7afdd2e7a 100644 --- a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Amazon.Lambda.TestTool.csproj +++ b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Amazon.Lambda.TestTool.csproj @@ -15,7 +15,8 @@ - + + diff --git a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/AppRunner.cs b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/AppRunner.cs deleted file mode 100644 index 07189b99f..000000000 --- a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/AppRunner.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.CommandLine; -using System.Text; - -namespace Amazon.Lambda.TestTool; - -public class AppRunner( - ICommandFactory commandFactory) -{ - public async Task Run(string[] args) - { - Console.OutputEncoding = Encoding.UTF8; - - return await commandFactory.BuildRootCommand().InvokeAsync(args); - } -} \ No newline at end of file diff --git a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Commands/CommandFactory.cs b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Commands/CommandFactory.cs deleted file mode 100644 index 83622e85c..000000000 --- a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Commands/CommandFactory.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System.CommandLine; -using System.Diagnostics; -using Amazon.Lambda.TestTool.Extensions; -using Amazon.Lambda.TestTool.Models; -using Amazon.Lambda.TestTool.Processes; -using Amazon.Lambda.TestTool.Services; - -namespace Amazon.Lambda.TestTool; - -public interface ICommandFactory -{ - Command BuildRootCommand(); -} - -public class CommandFactory( - IToolInteractiveService toolInteractiveService) : ICommandFactory -{ - private static readonly object RootCommandLock = new(); - - public Command BuildRootCommand() - { - // Name is important to set here to show correctly in the CLI usage help. - var rootCommand = new RootCommand - { - Name = "lambda-test-tool", - Description = Constants.ProductName, - }; - - Option hostOption = new("--host", () => Constants.DefaultHost, "The hostname or IP address used for the test tool's web interface. Any host other than an explicit IP address or localhost (e.g. '*', '+' or 'example.com') binds to all public IPv4 and IPv6 addresses."); - Option portOption = new("--port", () => Constants.DefaultPort,"The port number used for the test tool's web interface."); - Option noLaunchWindowOption = new("--no-launch-window","Disable auto launching the test tool's web interface in a browser."); - Option pauseExitOption = new("--pause-exit",() => true, "If set to true the test tool will pause waiting for a key input before exiting. The is useful when executing from an IDE so you can avoid having the output window immediately disappear after executing the Lambda code. The default value is true."); - Option disableLogsOption = new("--disable-logs",() => false); - - lock (RootCommandLock) - { - rootCommand.Add(hostOption); - rootCommand.Add(portOption); - rootCommand.Add(noLaunchWindowOption); - rootCommand.Add(pauseExitOption); - rootCommand.Add(disableLogsOption); - } - - rootCommand.SetHandler(async (context) => - { - try - { - var lambdaOptions = new ApplicationOptions - { - Host = context.ParseResult.GetValueForOption(hostOption) ?? Constants.DefaultHost, - Port = context.ParseResult.GetValueForOption(portOption), - NoLaunchWindow = context.ParseResult.GetValueForOption(noLaunchWindowOption), - PauseExit = context.ParseResult.GetValueForOption(pauseExitOption), - DisableLogs = context.ParseResult.GetValueForOption(disableLogsOption) - }; - - var process = TestToolProcess.Startup(lambdaOptions); - - if (!lambdaOptions.NoLaunchWindow) - { - try - { - var info = new ProcessStartInfo - { - UseShellExecute = true, - FileName = process.ServiceUrl - }; - Process.Start(info); - } - catch (Exception e) - { - toolInteractiveService.WriteErrorLine($"Error launching browser: {e.Message}"); - } - } - - await process.RunningTask; - - context.ExitCode = CommandReturnCodes.Success; - } - catch (Exception e) when (e.IsExpectedException()) - { - toolInteractiveService.WriteErrorLine(string.Empty); - toolInteractiveService.WriteErrorLine(e.Message); - - context.ExitCode = CommandReturnCodes.UserError; - } - catch (Exception e) - { - // This is a bug - toolInteractiveService.WriteErrorLine( - $"Unhandled exception.{Environment.NewLine}" + - $"This is a bug.{Environment.NewLine}" + - $"Please copy the stack trace below and file a bug at {Constants.LinkGithubRepo}. " + - e.PrettyPrint()); - - context.ExitCode = CommandReturnCodes.UnhandledException; - } - }); - - return rootCommand; - } -} \ No newline at end of file diff --git a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Commands/RunCommand.cs b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Commands/RunCommand.cs new file mode 100644 index 000000000..0857dd8d0 --- /dev/null +++ b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Commands/RunCommand.cs @@ -0,0 +1,86 @@ +using System.ComponentModel; +using System.Diagnostics; +using Amazon.Lambda.TestTool.Extensions; +using Amazon.Lambda.TestTool.Models; +using Amazon.Lambda.TestTool.Processes; +using Amazon.Lambda.TestTool.Services; +using Spectre.Console.Cli; + +namespace Amazon.Lambda.TestTool.Commands; + +public sealed class RunCommand( + IToolInteractiveService toolInteractiveService) : AsyncCommand +{ + public sealed class Settings : CommandSettings + { + [CommandOption("--host ")] + [Description( + "The hostname or IP address used for the test tool's web interface. Any host other than an explicit IP address or localhost (e.g. '*', '+' or 'example.com') binds to all public IPv4 and IPv6 addresses.")] + [DefaultValue(Constants.DefaultHost)] + public string Host { get; set; } = Constants.DefaultHost; + + [CommandOption("-p|--port ")] + [Description("The port number used for the test tool's web interface.")] + [DefaultValue(Constants.DefaultPort)] + public int Port { get; set; } = Constants.DefaultPort; + + [CommandOption("--no-launch-window")] + [Description("Disable auto launching the test tool's web interface in a browser.")] + public bool NoLaunchWindow { get; set; } + + [CommandOption("--pause-exit")] + [Description("If set to true the test tool will pause waiting for a key input before exiting. The is useful when executing from an IDE so you can avoid having the output window immediately disappear after executing the Lambda code. The default value is true.")] + public bool PauseExit { get; set; } + + [CommandOption("--disable-logs")] + [Description("Disables logging in the application")] + public bool DisableLogs { get; set; } + } + + public override async Task ExecuteAsync(CommandContext context, Settings settings) + { + try + { + var process = TestToolProcess.Startup(settings); + + if (!settings.NoLaunchWindow) + { + try + { + var info = new ProcessStartInfo + { + UseShellExecute = true, + FileName = process.ServiceUrl + }; + Process.Start(info); + } + catch (Exception e) + { + toolInteractiveService.WriteErrorLine($"Error launching browser: {e.Message}"); + } + } + + await process.RunningTask; + + return CommandReturnCodes.Success; + } + catch (Exception e) when (e.IsExpectedException()) + { + toolInteractiveService.WriteErrorLine(string.Empty); + toolInteractiveService.WriteErrorLine(e.Message); + + return CommandReturnCodes.UserError; + } + catch (Exception e) + { + // This is a bug + toolInteractiveService.WriteErrorLine( + $"Unhandled exception.{Environment.NewLine}" + + $"This is a bug.{Environment.NewLine}" + + $"Please copy the stack trace below and file a bug at {Constants.LinkGithubRepo}. " + + e.PrettyPrint()); + + return CommandReturnCodes.UnhandledException; + } + } +} \ No newline at end of file diff --git a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Components/Pages/Home.razor b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Components/Pages/Home.razor index 7ceeffaf1..5b933013f 100644 --- a/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Components/Pages/Home.razor +++ b/Tools/LambdaTestTool-v2/src/Amazon.Lambda.TestTool/Components/Pages/Home.razor @@ -1,14 +1,15 @@ @page "/" +@using Amazon.Lambda.TestTool.Commands @using Amazon.Lambda.TestTool.Services @using Amazon.Lambda.TestTool.Models @using Amazon.Lambda.TestTool.SampleRequests; @using Amazon.Lambda.TestTool.Utilities @using Microsoft.AspNetCore.Http; -@inject IHttpContextAccessor httpContextAccessor -@inject ApplicationOptions LambdaOptions +@inject IHttpContextAccessor HttpContextAccessor @inject IRuntimeApiDataStore RuntimeApiModel +@inject IDirectoryManager DirectoryManager Lambd Function Tester @@ -16,7 +17,7 @@

For Lambda functions written as executable assemblies, i.e. custom runtimes functions and top level statement functions, this page can be used for testing the functions locally. - Set the AWS_LAMBDA_RUNTIME_API environment variable to @httpContextAccessor?.HttpContext?.Request?.Host while debugging executable assembly + Set the AWS_LAMBDA_RUNTIME_API environment variable to @HttpContextAccessor?.HttpContext?.Request?.Host while debugging executable assembly Lambda function. More information can be found in the documentation.

@@ -26,10 +27,10 @@