Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use MSBuild to find target framework #348

Merged
merged 7 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .autover/changes/8a5204e4-83ec-45ac-8c75-27512ae9cdf8.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"Projects": [
{
"Name": "Amazon.Lambda.Tools",
"Type": "Patch",
"ChangelogMessages": [
"Use MSBuild to find target framework"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add more explanation here for the significance of this for customers. Not sure everyone would know what this implies.

]
}
]
}
7 changes: 7 additions & 0 deletions aws-extensions-for-dotnet-cli.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down
68 changes: 65 additions & 3 deletions src/Amazon.Common.DotNetCli.Tools/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.Text.RegularExpressions;
using System.Collections;
using System.Xml;
using System.Text.Json;

namespace Amazon.Common.DotNetCli.Tools
{
Expand Down Expand Up @@ -208,11 +209,72 @@ 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[]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We look up TargetFramework, OutputType, and PublishAot from the project file in this class. I would like to see this logic generalized so that we can have a method that takes in the project and a params of property names and returns back a dictionary of values. I don't really want 3 different code paths starting the dotnet process which will end up drifting.

The shared method should have the fallback logic I describe below that if the process fails parse the project xml like it does today so we don't risk any breaking behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure will update!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated in latest commit

{
"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();

if (process.ExitCode != 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the process failed we should fallback to the original XML parsing logic. There could be CI systems that are still deploying .NET 6 and only have .NET 6 SDK installed. The -getoutput command was added in .NET 8.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah good point! i will update accordingly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated in latest commit

{
throw new Exception($"MSBuild process exited with code {process.ExitCode}. Error: {error}");
}

var element = xdoc.XPathSelectElement("//PropertyGroup/TargetFramework");
return element?.Value;
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;
}

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions test/Amazon.Common.DotNetCli.Tools.Test/UtilitiesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions testapps/TestFunctionBuildProps/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project>
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
</Project>
14 changes: 14 additions & 0 deletions testapps/TestFunctionBuildProps/TestFunctionBuildProps/Function.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}
49 changes: 49 additions & 0 deletions testapps/TestFunctionBuildProps/TestFunctionBuildProps/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# AWS Lambda Empty Function Project
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't really need the readme for checked in for the test apps.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated in latest commit


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
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<AWSProjectType>Lambda</AWSProjectType>
<!-- This property makes the build directory similar to a publish directory and helps the AWS .NET Lambda Mock Test Tool find project dependencies. -->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<!-- Generate ready to run images during publishing to improve cold start time. -->
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Amazon.Lambda.Core" Version="2.4.0" />
<PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="2.4.4" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -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"
}