From 823e65d7426e80122caa61563b1f0938b5d05d7f Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Mon, 18 Nov 2024 14:45:39 -0500 Subject: [PATCH 1/7] Use MSBuild to find target framework --- aws-extensions-for-dotnet-cli.sln | 7 ++ .../Utilities.cs | 69 ++++++++++++++++++- .../UtilitiesTests.cs | 1 + .../Directory.Build.props | 5 ++ .../TestFunctionBuildProps/Function.cs | 14 ++++ .../TestFunctionBuildProps/Readme.md | 49 +++++++++++++ .../TestFunctionBuildProps.csproj | 16 +++++ .../aws-lambda-tools-defaults.json | 16 +++++ 8 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 testapps/TestFunctionBuildProps/Directory.Build.props create mode 100644 testapps/TestFunctionBuildProps/TestFunctionBuildProps/Function.cs create mode 100644 testapps/TestFunctionBuildProps/TestFunctionBuildProps/Readme.md create mode 100644 testapps/TestFunctionBuildProps/TestFunctionBuildProps/TestFunctionBuildProps.csproj create mode 100644 testapps/TestFunctionBuildProps/TestFunctionBuildProps/aws-lambda-tools-defaults.json diff --git a/aws-extensions-for-dotnet-cli.sln b/aws-extensions-for-dotnet-cli.sln index c3e5653..2833590 100644 --- a/aws-extensions-for-dotnet-cli.sln +++ b/aws-extensions-for-dotnet-cli.sln @@ -67,6 +67,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestNativeAotNet8WebApp", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestIntegerFunction", "testapps\TestIntegerFunction\TestIntegerFunction.csproj", "{D7F1DFA4-066B-469C-B04C-DF032CF152C1}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFunctionBuildProps", "testapps\TestFunctionBuildProps\TestFunctionBuildProps\TestFunctionBuildProps.csproj", "{AFA71B8E-F0AA-4704-8C4E-C11130F82B13}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -169,6 +171,10 @@ Global {D7F1DFA4-066B-469C-B04C-DF032CF152C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {D7F1DFA4-066B-469C-B04C-DF032CF152C1}.Release|Any CPU.ActiveCfg = Release|Any CPU {D7F1DFA4-066B-469C-B04C-DF032CF152C1}.Release|Any CPU.Build.0 = Release|Any CPU + {AFA71B8E-F0AA-4704-8C4E-C11130F82B13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AFA71B8E-F0AA-4704-8C4E-C11130F82B13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AFA71B8E-F0AA-4704-8C4E-C11130F82B13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AFA71B8E-F0AA-4704-8C4E-C11130F82B13}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -200,6 +206,7 @@ Global {AD31D053-97C5-4262-B187-EC42BFD51A9F} = {BB3CF729-8213-4DDD-85AE-A5E7754F3944} {69FFA03C-D29F-40E0-9E7F-572D5E10AF77} = {BB3CF729-8213-4DDD-85AE-A5E7754F3944} {D7F1DFA4-066B-469C-B04C-DF032CF152C1} = {BB3CF729-8213-4DDD-85AE-A5E7754F3944} + {AFA71B8E-F0AA-4704-8C4E-C11130F82B13} = {BB3CF729-8213-4DDD-85AE-A5E7754F3944} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DBFC70D6-49A2-40A1-AB08-5D9504AB7112} diff --git a/src/Amazon.Common.DotNetCli.Tools/Utilities.cs b/src/Amazon.Common.DotNetCli.Tools/Utilities.cs index 6daa6c8..49a9c42 100644 --- a/src/Amazon.Common.DotNetCli.Tools/Utilities.cs +++ b/src/Amazon.Common.DotNetCli.Tools/Utilities.cs @@ -18,6 +18,7 @@ using System.Text.RegularExpressions; using System.Collections; using System.Xml; +using System.Text.Json; namespace Amazon.Common.DotNetCli.Tools { @@ -208,13 +209,75 @@ public static string DeterminePublishLocation(string workingDirectory, string pr public static string LookupTargetFrameworkFromProjectFile(string projectLocation) { var projectFile = FindProjectFileInDirectory(projectLocation); + if (string.IsNullOrEmpty(projectFile)) + { + throw new FileNotFoundException("Could not find a project file in the specified directory."); + } - var xdoc = XDocument.Load(projectFile); + var arguments = new[] + { + "msbuild", + projectFile, + "--getProperty:TargetFramework,TargetFrameworks", + "-nologo" + }; + + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "dotnet", + Arguments = string.Join(" ", arguments), + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + } + }; + + process.Start(); + string output = process.StandardOutput.ReadToEnd(); + string error = process.StandardError.ReadToEnd(); + process.WaitForExit(); - var element = xdoc.XPathSelectElement("//PropertyGroup/TargetFramework"); - return element?.Value; + if (process.ExitCode != 0) + { + throw new Exception($"MSBuild process exited with code {process.ExitCode}. Error: {error}"); + } + + try + { + using JsonDocument doc = JsonDocument.Parse(output); + JsonElement root = doc.RootElement; + JsonElement properties = root.GetProperty("Properties"); + + if (properties.TryGetProperty("TargetFramework", out JsonElement targetFramework)) + { + string framework = targetFramework.GetString(); + if (!string.IsNullOrEmpty(framework)) + { + return framework; + } + } + + if (properties.TryGetProperty("TargetFrameworks", out JsonElement targetFrameworks)) + { + string frameworks = targetFrameworks.GetString(); + if (!string.IsNullOrEmpty(frameworks)) + { + return frameworks.Split(';')[0]; + } + } + } + catch (JsonException ex) + { + throw new Exception($"Failed to parse MSBuild output: {ex.Message}. Output: {output}"); + } + + return null; } + /// /// Retrieve the `OutputType` property of a given project /// diff --git a/test/Amazon.Common.DotNetCli.Tools.Test/UtilitiesTests.cs b/test/Amazon.Common.DotNetCli.Tools.Test/UtilitiesTests.cs index 320c4cb..09f2161 100644 --- a/test/Amazon.Common.DotNetCli.Tools.Test/UtilitiesTests.cs +++ b/test/Amazon.Common.DotNetCli.Tools.Test/UtilitiesTests.cs @@ -13,6 +13,7 @@ public class UtilitiesTests [InlineData("../../../../../testapps/TestFunction", "net6.0")] [InlineData("../../../../../testapps/ServerlessWithYamlFunction", "net6.0")] [InlineData("../../../../../testapps/TestBeanstalkWebApp", "netcoreapp3.1")] + [InlineData("../../../../../testapps/TestFunctionBuildProps/TestFunctionBuildProps", "net6.0")] public void CheckFramework(string projectPath, string expectedFramework) { var assembly = this.GetType().GetTypeInfo().Assembly; diff --git a/testapps/TestFunctionBuildProps/Directory.Build.props b/testapps/TestFunctionBuildProps/Directory.Build.props new file mode 100644 index 0000000..81e7fd0 --- /dev/null +++ b/testapps/TestFunctionBuildProps/Directory.Build.props @@ -0,0 +1,5 @@ + + + net6.0 + + diff --git a/testapps/TestFunctionBuildProps/TestFunctionBuildProps/Function.cs b/testapps/TestFunctionBuildProps/TestFunctionBuildProps/Function.cs new file mode 100644 index 0000000..f478313 --- /dev/null +++ b/testapps/TestFunctionBuildProps/TestFunctionBuildProps/Function.cs @@ -0,0 +1,14 @@ +using Amazon.Lambda.Core; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace TestFunctionBuildProps; + +public class Function +{ + public string FunctionHandler(string input, ILambdaContext context) + { + return input.ToUpper(); + } +} diff --git a/testapps/TestFunctionBuildProps/TestFunctionBuildProps/Readme.md b/testapps/TestFunctionBuildProps/TestFunctionBuildProps/Readme.md new file mode 100644 index 0000000..4212791 --- /dev/null +++ b/testapps/TestFunctionBuildProps/TestFunctionBuildProps/Readme.md @@ -0,0 +1,49 @@ +# AWS Lambda Empty Function Project + +This starter project consists of: +* Function.cs - class file containing a class with a single function handler method +* aws-lambda-tools-defaults.json - default argument settings for use with Visual Studio and command line deployment tools for AWS + +You may also have a test project depending on the options selected. + +The generated function handler is a simple method accepting a string argument that returns the uppercase equivalent of the input string. Replace the body of this method, and parameters, to suit your needs. + +## Here are some steps to follow from Visual Studio: + +To deploy your function to AWS Lambda, right click the project in Solution Explorer and select *Publish to AWS Lambda*. + +To view your deployed function open its Function View window by double-clicking the function name shown beneath the AWS Lambda node in the AWS Explorer tree. + +To perform testing against your deployed function use the Test Invoke tab in the opened Function View window. + +To configure event sources for your deployed function, for example to have your function invoked when an object is created in an Amazon S3 bucket, use the Event Sources tab in the opened Function View window. + +To update the runtime configuration of your deployed function use the Configuration tab in the opened Function View window. + +To view execution logs of invocations of your function use the Logs tab in the opened Function View window. + +## Here are some steps to follow to get started from the command line: + +Once you have edited your template and code you can deploy your application using the [Amazon.Lambda.Tools Global Tool](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) from the command line. + +Install Amazon.Lambda.Tools Global Tools if not already installed. +``` + dotnet tool install -g Amazon.Lambda.Tools +``` + +If already installed check if new version is available. +``` + dotnet tool update -g Amazon.Lambda.Tools +``` + +Execute unit tests +``` + cd "TestFunctionBuildProps/test/TestFunctionBuildProps.Tests" + dotnet test +``` + +Deploy function to AWS Lambda +``` + cd "TestFunctionBuildProps/src/TestFunctionBuildProps" + dotnet lambda deploy-function +``` diff --git a/testapps/TestFunctionBuildProps/TestFunctionBuildProps/TestFunctionBuildProps.csproj b/testapps/TestFunctionBuildProps/TestFunctionBuildProps/TestFunctionBuildProps.csproj new file mode 100644 index 0000000..db9ca90 --- /dev/null +++ b/testapps/TestFunctionBuildProps/TestFunctionBuildProps/TestFunctionBuildProps.csproj @@ -0,0 +1,16 @@ + + + enable + enable + true + Lambda + + true + + true + + + + + + \ No newline at end of file diff --git a/testapps/TestFunctionBuildProps/TestFunctionBuildProps/aws-lambda-tools-defaults.json b/testapps/TestFunctionBuildProps/TestFunctionBuildProps/aws-lambda-tools-defaults.json new file mode 100644 index 0000000..a5932b1 --- /dev/null +++ b/testapps/TestFunctionBuildProps/TestFunctionBuildProps/aws-lambda-tools-defaults.json @@ -0,0 +1,16 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "default", + "region": "us-west-2", + "configuration": "Release", + "function-architecture": "x86_64", + "function-runtime": "dotnet8", + "function-memory-size": 512, + "function-timeout": 30, + "function-handler": "TestFunctionBuildProps::TestFunctionBuildProps.Function::FunctionHandler" +} \ No newline at end of file From 88836893ae413e26228198e38ef14b2732c145fa Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Mon, 18 Nov 2024 14:46:59 -0500 Subject: [PATCH 2/7] remove extra spacing --- src/Amazon.Common.DotNetCli.Tools/Utilities.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Amazon.Common.DotNetCli.Tools/Utilities.cs b/src/Amazon.Common.DotNetCli.Tools/Utilities.cs index 49a9c42..6075537 100644 --- a/src/Amazon.Common.DotNetCli.Tools/Utilities.cs +++ b/src/Amazon.Common.DotNetCli.Tools/Utilities.cs @@ -277,7 +277,6 @@ public static string LookupTargetFrameworkFromProjectFile(string projectLocation return null; } - /// /// Retrieve the `OutputType` property of a given project /// From 6f1429b934f1bcbd93844ea61f090dcd5c721871 Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Mon, 18 Nov 2024 14:53:22 -0500 Subject: [PATCH 3/7] Add dev config --- .../changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json diff --git a/.autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json b/.autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json new file mode 100644 index 0000000..5a53809 --- /dev/null +++ b/.autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json @@ -0,0 +1,11 @@ +{ + "Projects": [ + { + "Name": "Amazon.Lambda.Tools", + "Type": "Patch", + "ChangelogMessages": [ + "Use MSBuild to find target framework" + ] + } + ] +} \ No newline at end of file From cb686049c07d42caddf60ff6287fd2cc82a15596 Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Tue, 19 Nov 2024 11:40:26 -0500 Subject: [PATCH 4/7] Create generic function --- .../Utilities.cs | 183 ++++++++---------- .../TestFunctionBuildProps/Readme.md | 49 ----- 2 files changed, 82 insertions(+), 150 deletions(-) delete mode 100644 testapps/TestFunctionBuildProps/TestFunctionBuildProps/Readme.md diff --git a/src/Amazon.Common.DotNetCli.Tools/Utilities.cs b/src/Amazon.Common.DotNetCli.Tools/Utilities.cs index 6075537..b0a9dcb 100644 --- a/src/Amazon.Common.DotNetCli.Tools/Utilities.cs +++ b/src/Amazon.Common.DotNetCli.Tools/Utilities.cs @@ -206,20 +206,23 @@ public static string DeterminePublishLocation(string workingDirectory, string pr return path; } - public static string LookupTargetFrameworkFromProjectFile(string projectLocation) + + // + /// Looks up specified properties from a project file. + /// + /// The location of the project file. + /// The names of the properties to look up. + /// A dictionary of property names and their values. + public static Dictionary LookupProjectProperties(string projectLocation, params string[] propertyNames) { var projectFile = FindProjectFileInDirectory(projectLocation); - if (string.IsNullOrEmpty(projectFile)) - { - throw new FileNotFoundException("Could not find a project file in the specified directory."); - } - - var arguments = new[] + var properties = new Dictionary(); + var arguments = new List { "msbuild", projectFile, - "--getProperty:TargetFramework,TargetFrameworks", - "-nologo" + "-nologo", + $"--getProperty:{string.Join(',', propertyNames)}" }; var process = new Process @@ -234,105 +237,94 @@ public static string LookupTargetFrameworkFromProjectFile(string projectLocation CreateNoWindow = true } }; - - process.Start(); - string output = process.StandardOutput.ReadToEnd(); - string error = process.StandardError.ReadToEnd(); - process.WaitForExit(); - - if (process.ExitCode != 0) - { - throw new Exception($"MSBuild process exited with code {process.ExitCode}. Error: {error}"); - } - try { - using JsonDocument doc = JsonDocument.Parse(output); - JsonElement root = doc.RootElement; - JsonElement properties = root.GetProperty("Properties"); + process.Start(); + string output = process.StandardOutput.ReadToEnd(); + string error = process.StandardError.ReadToEnd(); + process.WaitForExit(); - if (properties.TryGetProperty("TargetFramework", out JsonElement targetFramework)) + if (process.ExitCode == 0) { - string framework = targetFramework.GetString(); - if (!string.IsNullOrEmpty(framework)) + using JsonDocument doc = JsonDocument.Parse(output); + JsonElement root = doc.RootElement; + JsonElement propertiesElement = root.GetProperty("Properties"); + + foreach (var property in propertyNames) { - return framework; + if (propertiesElement.TryGetProperty(property, out JsonElement propertyValue)) + { + properties[property] = propertyValue.GetString(); + } } } - - if (properties.TryGetProperty("TargetFrameworks", out JsonElement targetFrameworks)) + else { - string frameworks = targetFrameworks.GetString(); - if (!string.IsNullOrEmpty(frameworks)) - { - return frameworks.Split(';')[0]; - } + Console.WriteLine($"MSBuild process exited with code {process.ExitCode}. Error: {error}"); + // Fallback to XML parsing + properties = LookupProjectPropertiesFromXml(projectFile, propertyNames); } } - catch (JsonException ex) + catch (Exception ex) { - throw new Exception($"Failed to parse MSBuild output: {ex.Message}. Output: {output}"); + Console.WriteLine($"Error executing MSBuild or parsing output: {ex.Message}"); + // Fallback to XML parsing + properties = LookupProjectPropertiesFromXml(projectFile, propertyNames); } - return null; + return properties; } - /// - /// Retrieve the `OutputType` property of a given project - /// - /// Path of the project - /// The value of the `OutputType` property - public static string LookupOutputTypeFromProjectFile(string projectLocation) + private static Dictionary LookupProjectPropertiesFromXml(string projectFile, string[] propertyNames) { - var process = new Process(); - var output = string.Empty; - var msbuildProcessFailed = false; + var properties = new Dictionary(); try { - process.StartInfo = new ProcessStartInfo() - { - FileName = "dotnet", - Arguments = $"msbuild {projectLocation} -getProperty:OutputType", - RedirectStandardOutput = true, - UseShellExecute = false, - WindowStyle = ProcessWindowStyle.Hidden - }; - - process.Start(); - output = process.StandardOutput.ReadToEnd(); - var hasExited = process.WaitForExit(5000); - - // If it hasn't completed in the specified timeout, stop the process and give up - if (!hasExited) - { - process.Kill(); - msbuildProcessFailed = true; - } - - // If it has completed but unsuccessfully, give up - if (process.ExitCode != 0) + var xdoc = XDocument.Load(projectFile); + foreach (var propertyName in propertyNames) { - msbuildProcessFailed = true; + var element = xdoc.XPathSelectElement($"//PropertyGroup/{propertyName}"); + if (element != null && !string.IsNullOrWhiteSpace(element.Value)) + { + properties[propertyName] = element.Value; + } } } - catch (Exception) + catch (Exception ex) { - // swallow any exceptions related to `dotnet msbuild` - msbuildProcessFailed = true; + Console.WriteLine($"Error parsing project file XML: {ex.Message}"); } + return properties; + } - if (msbuildProcessFailed) + /// + /// Looks up the target framework from a project file. + /// + /// The location of the project file. + /// The target framework of the project. + public static string LookupTargetFrameworkFromProjectFile(string projectLocation) + { + var properties = LookupProjectProperties(projectLocation, "TargetFramework", "TargetFrameworks"); + if (properties.TryGetValue("TargetFramework", out var targetFramework) && !string.IsNullOrEmpty(targetFramework)) { - var projectFile = FindProjectFileInDirectory(projectLocation); - var xdoc = XDocument.Load(projectFile); - var element = xdoc.XPathSelectElement("//PropertyGroup/OutputType"); - output = element?.Value; + return targetFramework; + } + if (properties.TryGetValue("TargetFrameworks", out var targetFrameworks) && !string.IsNullOrEmpty(targetFrameworks)) + { + return targetFrameworks.Split(';')[0]; } + return null; + } - return - string.IsNullOrEmpty(output) ? - null : - output.Trim(); + /// + /// Retrieve the `OutputType` property of a given project + /// + /// Path of the project + /// The value of the `OutputType` property + public static string LookupOutputTypeFromProjectFile(string projectLocation) + { + var properties = LookupProjectProperties(projectLocation, "OutputType"); + return properties.TryGetValue("OutputType", out var outputType) ? outputType.Trim() : null; } public static bool LookPublishAotFlag(string projectLocation, string msBuildParameters) @@ -350,20 +342,15 @@ public static bool LookPublishAotFlag(string projectLocation, string msBuildPara } } - // If the property wasn't provided in msBuildParameters, fall back to searching project file - var projectFile = FindProjectFileInDirectory(projectLocation); - - var xdoc = XDocument.Load(projectFile); - - var element = xdoc.XPathSelectElement("//PropertyGroup/PublishAot"); - - if (bool.TryParse(element?.Value, out bool result)) + var properties = LookupProjectProperties(projectLocation, "PublishAot"); + if (properties.TryGetValue("PublishAot", out var publishAot)) { - return result; + return bool.TryParse(publishAot, out var result) && result; } - return false; } + + public static bool HasExplicitSelfContainedFlag(string projectLocation, string msBuildParameters) { if (msBuildParameters != null && msBuildParameters.IndexOf("--self-contained", StringComparison.InvariantCultureIgnoreCase) != -1) @@ -371,22 +358,16 @@ public static bool HasExplicitSelfContainedFlag(string projectLocation, string m return true; } - // If the property wasn't provided in msBuildParameters, fall back to searching project file - var projectFile = FindProjectFileInDirectory(projectLocation); - - var xdoc = XDocument.Load(projectFile); - - var element = xdoc.XPathSelectElement("//PropertyGroup/SelfContained"); - - if (bool.TryParse(element?.Value, out _)) + var properties = LookupProjectProperties(projectLocation, "SelfContained"); + if (properties.TryGetValue("SelfContained", out var selfContained)) { - return true; + return bool.TryParse(selfContained, out _); } return false; } - public static string FindProjectFileInDirectory(string directory) + private static string FindProjectFileInDirectory(string directory) { if (File.Exists(directory)) return directory; diff --git a/testapps/TestFunctionBuildProps/TestFunctionBuildProps/Readme.md b/testapps/TestFunctionBuildProps/TestFunctionBuildProps/Readme.md deleted file mode 100644 index 4212791..0000000 --- a/testapps/TestFunctionBuildProps/TestFunctionBuildProps/Readme.md +++ /dev/null @@ -1,49 +0,0 @@ -# AWS Lambda Empty Function Project - -This starter project consists of: -* Function.cs - class file containing a class with a single function handler method -* aws-lambda-tools-defaults.json - default argument settings for use with Visual Studio and command line deployment tools for AWS - -You may also have a test project depending on the options selected. - -The generated function handler is a simple method accepting a string argument that returns the uppercase equivalent of the input string. Replace the body of this method, and parameters, to suit your needs. - -## Here are some steps to follow from Visual Studio: - -To deploy your function to AWS Lambda, right click the project in Solution Explorer and select *Publish to AWS Lambda*. - -To view your deployed function open its Function View window by double-clicking the function name shown beneath the AWS Lambda node in the AWS Explorer tree. - -To perform testing against your deployed function use the Test Invoke tab in the opened Function View window. - -To configure event sources for your deployed function, for example to have your function invoked when an object is created in an Amazon S3 bucket, use the Event Sources tab in the opened Function View window. - -To update the runtime configuration of your deployed function use the Configuration tab in the opened Function View window. - -To view execution logs of invocations of your function use the Logs tab in the opened Function View window. - -## Here are some steps to follow to get started from the command line: - -Once you have edited your template and code you can deploy your application using the [Amazon.Lambda.Tools Global Tool](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) from the command line. - -Install Amazon.Lambda.Tools Global Tools if not already installed. -``` - dotnet tool install -g Amazon.Lambda.Tools -``` - -If already installed check if new version is available. -``` - dotnet tool update -g Amazon.Lambda.Tools -``` - -Execute unit tests -``` - cd "TestFunctionBuildProps/test/TestFunctionBuildProps.Tests" - dotnet test -``` - -Deploy function to AWS Lambda -``` - cd "TestFunctionBuildProps/src/TestFunctionBuildProps" - dotnet lambda deploy-function -``` From 9245d438d736d217feb61a313f22cc3ca4654827 Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Tue, 19 Nov 2024 13:22:39 -0500 Subject: [PATCH 5/7] add timeout and update targetframeworks logic --- src/Amazon.Common.DotNetCli.Tools/Utilities.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Amazon.Common.DotNetCli.Tools/Utilities.cs b/src/Amazon.Common.DotNetCli.Tools/Utilities.cs index b0a9dcb..c88fbf1 100644 --- a/src/Amazon.Common.DotNetCli.Tools/Utilities.cs +++ b/src/Amazon.Common.DotNetCli.Tools/Utilities.cs @@ -242,7 +242,7 @@ public static Dictionary LookupProjectProperties(string projectL process.Start(); string output = process.StandardOutput.ReadToEnd(); string error = process.StandardError.ReadToEnd(); - process.WaitForExit(); + process.WaitForExit(5000); if (process.ExitCode == 0) { @@ -311,7 +311,11 @@ public static string LookupTargetFrameworkFromProjectFile(string projectLocation } if (properties.TryGetValue("TargetFrameworks", out var targetFrameworks) && !string.IsNullOrEmpty(targetFrameworks)) { - return targetFrameworks.Split(';')[0]; + var frameworks = targetFrameworks.Split(';'); + if (frameworks.Length > 1 ){ + return null; + } + return frameworks[0]; } return null; } From cb98714723a261987211ea47a043b8cbf8accd22 Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Wed, 20 Nov 2024 13:37:19 -0500 Subject: [PATCH 6/7] PR comments --- .../8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json | 2 +- .../Utilities.cs | 35 +++++++++++-------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/.autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json b/.autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json index 5a53809..9b1af88 100644 --- a/.autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json +++ b/.autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json @@ -4,7 +4,7 @@ "Name": "Amazon.Lambda.Tools", "Type": "Patch", "ChangelogMessages": [ - "Use MSBuild to find target framework" + "Update logic for finding project properties to use MSBuild instead of parsing the project file directly. See https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2022 for more details." ] } ] diff --git a/src/Amazon.Common.DotNetCli.Tools/Utilities.cs b/src/Amazon.Common.DotNetCli.Tools/Utilities.cs index c88fbf1..70db558 100644 --- a/src/Amazon.Common.DotNetCli.Tools/Utilities.cs +++ b/src/Amazon.Common.DotNetCli.Tools/Utilities.cs @@ -208,7 +208,7 @@ public static string DeterminePublishLocation(string workingDirectory, string pr // - /// Looks up specified properties from a project file. + /// Looks up specified properties from a project. /// /// The location of the project file. /// The names of the properties to look up. @@ -240,34 +240,41 @@ public static Dictionary LookupProjectProperties(string projectL try { process.Start(); - string output = process.StandardOutput.ReadToEnd(); + string output = process.StandardOutput.ReadToEnd().Trim(); string error = process.StandardError.ReadToEnd(); process.WaitForExit(5000); if (process.ExitCode == 0) { - using JsonDocument doc = JsonDocument.Parse(output); - JsonElement root = doc.RootElement; - JsonElement propertiesElement = root.GetProperty("Properties"); - - foreach (var property in propertyNames) + if (propertyNames.Length == 1) + { + // If only one property was requested, the output is the direct value + properties[propertyNames[0]] = output; + } + else { - if (propertiesElement.TryGetProperty(property, out JsonElement propertyValue)) + // Multiple properties were requested, so we expect JSON output + using JsonDocument doc = JsonDocument.Parse(output); + JsonElement root = doc.RootElement; + JsonElement propertiesElement = root.GetProperty("Properties"); + + foreach (var property in propertyNames) { - properties[property] = propertyValue.GetString(); + if (propertiesElement.TryGetProperty(property, out JsonElement propertyValue)) + { + properties[property] = propertyValue.GetString(); + } } } } else { - Console.WriteLine($"MSBuild process exited with code {process.ExitCode}. Error: {error}"); // Fallback to XML parsing properties = LookupProjectPropertiesFromXml(projectFile, propertyNames); } } - catch (Exception ex) + catch (Exception) { - Console.WriteLine($"Error executing MSBuild or parsing output: {ex.Message}"); // Fallback to XML parsing properties = LookupProjectPropertiesFromXml(projectFile, propertyNames); } @@ -275,6 +282,7 @@ public static Dictionary LookupProjectProperties(string projectL return properties; } + private static Dictionary LookupProjectPropertiesFromXml(string projectFile, string[] propertyNames) { var properties = new Dictionary(); @@ -290,9 +298,8 @@ private static Dictionary LookupProjectPropertiesFromXml(string } } } - catch (Exception ex) + catch (Exception) { - Console.WriteLine($"Error parsing project file XML: {ex.Message}"); } return properties; } From af70e6c1e2c65b50d3d4ed9fc26392356190bd9c Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Thu, 21 Nov 2024 11:44:12 -0500 Subject: [PATCH 7/7] Fix self contained bug --- .autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json | 3 ++- src/Amazon.Common.DotNetCli.Tools/Utilities.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json b/.autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json index 9b1af88..7f8d57f 100644 --- a/.autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json +++ b/.autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json @@ -4,7 +4,8 @@ "Name": "Amazon.Lambda.Tools", "Type": "Patch", "ChangelogMessages": [ - "Update logic for finding project properties to use MSBuild instead of parsing the project file directly. See https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2022 for more details." + "Update logic for finding project properties to use MSBuild instead of parsing the project file directly. See https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2022 for more details.", + "Fix 'SelfContained' property reading logic to actually read the value from the properties. Previously we were only checking that the value could be parsed and not reading the actual value." ] } ] diff --git a/src/Amazon.Common.DotNetCli.Tools/Utilities.cs b/src/Amazon.Common.DotNetCli.Tools/Utilities.cs index 70db558..f067728 100644 --- a/src/Amazon.Common.DotNetCli.Tools/Utilities.cs +++ b/src/Amazon.Common.DotNetCli.Tools/Utilities.cs @@ -372,7 +372,7 @@ public static bool HasExplicitSelfContainedFlag(string projectLocation, string m var properties = LookupProjectProperties(projectLocation, "SelfContained"); if (properties.TryGetValue("SelfContained", out var selfContained)) { - return bool.TryParse(selfContained, out _); + return bool.TryParse(selfContained, out var isSelfContained) && isSelfContained; } return false;