Skip to content

Commit 02102ad

Browse files
committed
fix cleanup
1 parent f38a6b0 commit 02102ad

File tree

4 files changed

+97
-4
lines changed

4 files changed

+97
-4
lines changed

Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Writers/CloudFormationWriter.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,15 +224,22 @@ private void ProcessLambdaFunctionEventAttributes(ILambdaFunctionSerializable la
224224
break;
225225
case AttributeModel<FunctionUrlAttribute> functionUrlAttributeModel:
226226
ProcessFunctionUrlAttribute(lambdaFunction, functionUrlAttributeModel.Data);
227+
_templateWriter.SetToken($"Resources.{lambdaFunction.ResourceName}.Metadata.SyncedFunctionUrlConfig", true);
227228
hasFunctionUrl = true;
228229
break;
229230
}
230231
}
231232

232-
// Remove FunctionUrlConfig if the attribute was removed
233+
// Remove FunctionUrlConfig only if it was previously created by Annotations (tracked via metadata).
234+
// This preserves any manually-added FunctionUrlConfig that was not created by the source generator.
233235
if (!hasFunctionUrl)
234236
{
235-
_templateWriter.RemoveToken($"Resources.{lambdaFunction.ResourceName}.Properties.FunctionUrlConfig");
237+
var syncedFunctionUrlConfigPath = $"Resources.{lambdaFunction.ResourceName}.Metadata.SyncedFunctionUrlConfig";
238+
if (_templateWriter.GetToken<bool>(syncedFunctionUrlConfigPath, false))
239+
{
240+
_templateWriter.RemoveToken($"Resources.{lambdaFunction.ResourceName}.Properties.FunctionUrlConfig");
241+
_templateWriter.RemoveToken(syncedFunctionUrlConfigPath);
242+
}
236243
}
237244

238245
SynchronizeEventsAndProperties(currentSyncedEvents, currentSyncedEventProperties, lambdaFunction);

Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/functionUrlExample.template

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"TestServerlessAppFunctionUrlExampleGetItemsGenerated": {
77
"Type": "AWS::Serverless::Function",
88
"Metadata": {
9-
"Tool": "Amazon.Lambda.Annotations"
9+
"Tool": "Amazon.Lambda.Annotations",
10+
"SyncedFunctionUrlConfig": true
1011
},
1112
"Properties": {
1213
"MemorySize": 512,

Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/WriterTests/FunctionUrlTests.cs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,90 @@ public void FunctionUrlConfigRemovedWhenAttributeRemoved(CloudFormationTemplateF
282282
Assert.False(templateWriter.Exists("Resources.TestMethod.Properties.FunctionUrlConfig"));
283283
}
284284

285+
[Theory]
286+
[InlineData(CloudFormationTemplateFormat.Json)]
287+
[InlineData(CloudFormationTemplateFormat.Yaml)]
288+
public void ManualFunctionUrlConfigPreservedWhenNoAttribute(CloudFormationTemplateFormat templateFormat)
289+
{
290+
// Simulate a template where FunctionUrlConfig was manually added (no SyncedFunctionUrlConfig metadata)
291+
var content = templateFormat == CloudFormationTemplateFormat.Json
292+
? @"{
293+
'AWSTemplateFormatVersion': '2010-09-09',
294+
'Transform': 'AWS::Serverless-2016-10-31',
295+
'Resources': {
296+
'TestMethod': {
297+
'Type': 'AWS::Serverless::Function',
298+
'Metadata': {
299+
'Tool': 'Amazon.Lambda.Annotations'
300+
},
301+
'Properties': {
302+
'Runtime': 'dotnet8',
303+
'CodeUri': '',
304+
'MemorySize': 512,
305+
'Timeout': 30,
306+
'Policies': ['AWSLambdaBasicExecutionRole'],
307+
'PackageType': 'Image',
308+
'ImageUri': '.',
309+
'ImageConfig': { 'Command': ['MyAssembly::MyNamespace.MyType::Handler'] },
310+
'FunctionUrlConfig': {
311+
'AuthType': 'AWS_IAM'
312+
}
313+
}
314+
}
315+
}
316+
}"
317+
: "AWSTemplateFormatVersion: '2010-09-09'\nTransform: AWS::Serverless-2016-10-31\nResources:\n TestMethod:\n Type: AWS::Serverless::Function\n Metadata:\n Tool: Amazon.Lambda.Annotations\n Properties:\n Runtime: dotnet8\n CodeUri: ''\n MemorySize: 512\n Timeout: 30\n Policies:\n - AWSLambdaBasicExecutionRole\n PackageType: Image\n ImageUri: .\n ImageConfig:\n Command:\n - 'MyAssembly::MyNamespace.MyType::Handler'\n FunctionUrlConfig:\n AuthType: AWS_IAM";
318+
319+
var mockFileManager = GetMockFileManager(content);
320+
var lambdaFunctionModel = GetLambdaFunctionModel("MyAssembly::MyNamespace.MyType::Handler",
321+
"TestMethod", 30, 512, null, null);
322+
// No FunctionUrl attribute
323+
lambdaFunctionModel.Attributes = new List<AttributeModel>();
324+
var cloudFormationWriter = GetCloudFormationWriter(mockFileManager, _directoryManager, templateFormat, _diagnosticReporter);
325+
var report = GetAnnotationReport(new List<ILambdaFunctionSerializable> { lambdaFunctionModel });
326+
ITemplateWriter templateWriter = templateFormat == CloudFormationTemplateFormat.Json ? new JsonWriter() : new YamlWriter();
327+
328+
cloudFormationWriter.ApplyReport(report);
329+
330+
templateWriter.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
331+
// The manually-added FunctionUrlConfig should be preserved
332+
Assert.True(templateWriter.Exists("Resources.TestMethod.Properties.FunctionUrlConfig"));
333+
Assert.Equal("AWS_IAM", templateWriter.GetToken<string>("Resources.TestMethod.Properties.FunctionUrlConfig.AuthType"));
334+
}
335+
336+
[Theory]
337+
[InlineData(CloudFormationTemplateFormat.Json)]
338+
[InlineData(CloudFormationTemplateFormat.Yaml)]
339+
public void FunctionUrlMetadataTrackedAndCleanedUp(CloudFormationTemplateFormat templateFormat)
340+
{
341+
// First pass: create FunctionUrlConfig via attribute
342+
var mockFileManager = GetMockFileManager(string.Empty);
343+
var lambdaFunctionModel = GetLambdaFunctionModel("MyAssembly::MyNamespace.MyType::Handler",
344+
"TestMethod", 30, 512, null, null);
345+
lambdaFunctionModel.Attributes = new List<AttributeModel>
346+
{
347+
new AttributeModel<FunctionUrlAttribute> { Data = new FunctionUrlAttribute() }
348+
};
349+
var cloudFormationWriter = GetCloudFormationWriter(mockFileManager, _directoryManager, templateFormat, _diagnosticReporter);
350+
ITemplateWriter templateWriter = templateFormat == CloudFormationTemplateFormat.Json ? new JsonWriter() : new YamlWriter();
351+
352+
cloudFormationWriter.ApplyReport(GetAnnotationReport(new List<ILambdaFunctionSerializable> { lambdaFunctionModel }));
353+
templateWriter.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
354+
355+
// Verify metadata is set
356+
Assert.True(templateWriter.Exists("Resources.TestMethod.Properties.FunctionUrlConfig"));
357+
Assert.True(templateWriter.GetToken<bool>("Resources.TestMethod.Metadata.SyncedFunctionUrlConfig"));
358+
359+
// Second pass: remove the attribute
360+
lambdaFunctionModel.Attributes = new List<AttributeModel>();
361+
cloudFormationWriter.ApplyReport(GetAnnotationReport(new List<ILambdaFunctionSerializable> { lambdaFunctionModel }));
362+
templateWriter.Parse(mockFileManager.ReadAllText(ServerlessTemplateFilePath));
363+
364+
// Verify both FunctionUrlConfig and metadata are cleaned up
365+
Assert.False(templateWriter.Exists("Resources.TestMethod.Properties.FunctionUrlConfig"));
366+
Assert.False(templateWriter.Exists("Resources.TestMethod.Metadata.SyncedFunctionUrlConfig"));
367+
}
368+
285369
[Theory]
286370
[InlineData(CloudFormationTemplateFormat.Json)]
287371
[InlineData(CloudFormationTemplateFormat.Yaml)]

Libraries/test/TestServerlessApp/serverless.template

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1343,7 +1343,8 @@
13431343
"TestServerlessAppFunctionUrlExampleGetItemsGenerated": {
13441344
"Type": "AWS::Serverless::Function",
13451345
"Metadata": {
1346-
"Tool": "Amazon.Lambda.Annotations"
1346+
"Tool": "Amazon.Lambda.Annotations",
1347+
"SyncedFunctionUrlConfig": true
13471348
},
13481349
"Properties": {
13491350
"MemorySize": 512,

0 commit comments

Comments
 (0)