-
Notifications
You must be signed in to change notification settings - Fork 494
Add [ScheduleEvent] annotation attribute and source generator support #2323
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
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "Projects": [ | ||
| { | ||
| "Name": "Amazon.Lambda.Annotations", | ||
| "Type": "Minor", | ||
| "ChangelogMessages": [ | ||
| "Added [ScheduleEvent] annotation attribute for declaratively configuring schedule-triggered Lambda functions with support for rate and cron expressions, description, input, and enabled state." | ||
| ] | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| using Amazon.Lambda.Annotations.Schedule; | ||
| using Microsoft.CodeAnalysis; | ||
| using System; | ||
|
|
||
| namespace Amazon.Lambda.Annotations.SourceGenerator.Models.Attributes | ||
| { | ||
| /// <summary> | ||
| /// Builder for <see cref="ScheduleEventAttribute"/>. | ||
| /// </summary> | ||
| public class ScheduleEventAttributeBuilder | ||
| { | ||
| public static ScheduleEventAttribute Build(AttributeData att) | ||
| { | ||
| if (att.ConstructorArguments.Length != 1) | ||
| { | ||
| throw new NotSupportedException($"{TypeFullNames.ScheduleEventAttribute} must have constructor with 1 argument."); | ||
| } | ||
| var schedule = att.ConstructorArguments[0].Value as string; | ||
| var data = new ScheduleEventAttribute(schedule); | ||
|
|
||
| foreach (var pair in att.NamedArguments) | ||
| { | ||
| if (pair.Key == nameof(data.ResourceName) && pair.Value.Value is string resourceName) | ||
| { | ||
| data.ResourceName = resourceName; | ||
| } | ||
| else if (pair.Key == nameof(data.Description) && pair.Value.Value is string description) | ||
| { | ||
| data.Description = description; | ||
| } | ||
| else if (pair.Key == nameof(data.Input) && pair.Value.Value is string input) | ||
| { | ||
| data.Input = input; | ||
| } | ||
| else if (pair.Key == nameof(data.Enabled) && pair.Value.Value is bool enabled) | ||
| { | ||
| data.Enabled = enabled; | ||
| } | ||
| } | ||
|
|
||
| return data; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
| using Amazon.Lambda.Annotations.SourceGenerator.Extensions; | ||
| using Amazon.Lambda.Annotations.SourceGenerator.Models; | ||
| using Amazon.Lambda.Annotations.SourceGenerator.Models.Attributes; | ||
| using Amazon.Lambda.Annotations.Schedule; | ||
| using Amazon.Lambda.Annotations.SQS; | ||
| using Microsoft.CodeAnalysis; | ||
| using System.Collections.Generic; | ||
|
|
@@ -61,6 +62,7 @@ internal static bool ValidateFunction(GeneratorExecutionContext context, IMethod | |
| // Validate Events | ||
| ValidateApiGatewayEvents(lambdaFunctionModel, methodLocation, diagnostics); | ||
| ValidateSqsEvents(lambdaFunctionModel, methodLocation, diagnostics); | ||
| ValidateScheduleEvents(lambdaFunctionModel, methodLocation, diagnostics); | ||
| ValidateAlbEvents(lambdaFunctionModel, methodLocation, diagnostics); | ||
| ValidateS3Events(lambdaFunctionModel, methodLocation, diagnostics); | ||
|
|
||
|
|
@@ -110,6 +112,16 @@ internal static bool ValidateDependencies(GeneratorExecutionContext context, IMe | |
| } | ||
| } | ||
|
|
||
| // Check for references to "Amazon.Lambda.CloudWatchEvents" if the Lambda method is annotated with ScheduleEvent attribute. | ||
| if (lambdaMethodSymbol.HasAttribute(context, TypeFullNames.ScheduleEventAttribute)) | ||
| { | ||
| if (context.Compilation.ReferencedAssemblyNames.FirstOrDefault(x => x.Name == "Amazon.Lambda.CloudWatchEvents") == null) | ||
| { | ||
| diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.MissingDependencies, methodLocation, "Amazon.Lambda.CloudWatchEvents")); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
|
|
@@ -420,6 +432,43 @@ private static void ValidateS3Events(LambdaFunctionModel lambdaFunctionModel, Lo | |
| } | ||
| } | ||
|
|
||
| private static void ValidateScheduleEvents(LambdaFunctionModel lambdaFunctionModel, Location methodLocation, List<Diagnostic> diagnostics) | ||
| { | ||
| if (!lambdaFunctionModel.LambdaMethod.Events.Contains(EventType.Schedule)) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| foreach (var att in lambdaFunctionModel.Attributes) | ||
| { | ||
| if (att.Type.FullName != TypeFullNames.ScheduleEventAttribute) | ||
| continue; | ||
|
|
||
| var scheduleEventAttribute = ((AttributeModel<ScheduleEventAttribute>)att).Data; | ||
| var validationErrors = scheduleEventAttribute.Validate(); | ||
| validationErrors.ForEach(errorMessage => diagnostics.Add(Diagnostic.Create(DiagnosticDescriptors.InvalidScheduleEventAttribute, methodLocation, errorMessage))); | ||
| } | ||
|
|
||
| // Validate method parameters | ||
| var parameters = lambdaFunctionModel.LambdaMethod.Parameters; | ||
| if (parameters.Count > 2 || | ||
| (parameters.Count >= 1 && parameters[0].Type.FullName != TypeFullNames.ScheduledEvent) || | ||
| (parameters.Count == 2 && parameters[1].Type.FullName != TypeFullNames.ILambdaContext)) | ||
| { | ||
| var errorMessage = $"When using the {nameof(ScheduleEventAttribute)}, the Lambda method can accept at most 2 parameters. " + | ||
| $"The first parameter must be of type {TypeFullNames.ScheduledEvent}. " + | ||
| $"The second parameter is optional and must be of type {TypeFullNames.ILambdaContext}."; | ||
| diagnostics.Add(Diagnostic.Create(DiagnosticDescriptors.InvalidLambdaMethodSignature, methodLocation, errorMessage)); | ||
| } | ||
|
Comment on lines
+452
to
+462
|
||
|
|
||
| // Validate return type - must be void or Task | ||
| if (!lambdaFunctionModel.LambdaMethod.ReturnsVoid && !lambdaFunctionModel.LambdaMethod.ReturnsVoidTask) | ||
| { | ||
| var errorMessage = $"When using the {nameof(ScheduleEventAttribute)}, the Lambda method can return either void or {TypeFullNames.Task}"; | ||
| diagnostics.Add(Diagnostic.Create(DiagnosticDescriptors.InvalidLambdaMethodSignature, methodLocation, errorMessage)); | ||
| } | ||
| } | ||
|
|
||
| private static bool ReportDiagnostics(DiagnosticReporter diagnosticReporter, List<Diagnostic> diagnostics) | ||
| { | ||
| var isValid = true; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new diagnostic descriptor uses ID
AWSLambda0139, but the PR description calls out a new diagnosticAWSLambda0132for ScheduleEventAttribute validation. Please reconcile the diagnostic ID in code vs. the PR description (and any external docs) so consumers know which ID to expect.