From faec4ce49194f619513227173f0d7ab070156d15 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 8 Jun 2021 09:46:06 +0200 Subject: [PATCH 01/25] feat(logger): add option to clear state per invocation --- aws_lambda_powertools/logging/logger.py | 19 +++++-- docs/core/logger.md | 72 ++++++++++++++++++++++++- tests/functional/test_logger.py | 20 +++++++ 3 files changed, 106 insertions(+), 5 deletions(-) diff --git a/aws_lambda_powertools/logging/logger.py b/aws_lambda_powertools/logging/logger.py index 3231f30eccd..ca01a5762a0 100644 --- a/aws_lambda_powertools/logging/logger.py +++ b/aws_lambda_powertools/logging/logger.py @@ -260,12 +260,18 @@ def _configure_sampling(self): ) def inject_lambda_context( - self, lambda_handler: Callable[[Dict, Any], Any] = None, log_event: bool = None, correlation_id_path: str = None + self, + lambda_handler: Callable[[Dict, Any], Any] = None, + log_event: bool = None, + correlation_id_path: str = None, + clear_custom_keys: bool = False, ): """Decorator to capture Lambda contextual info and inject into logger Parameters ---------- + clear_custom_keys : bool, optional + Instructs logger to remove any custom keys previously added lambda_handler : Callable Method to inject the lambda context log_event : bool, optional @@ -311,7 +317,10 @@ def handler(event, context): if lambda_handler is None: logger.debug("Decorator called with parameters") return functools.partial( - self.inject_lambda_context, log_event=log_event, correlation_id_path=correlation_id_path + self.inject_lambda_context, + log_event=log_event, + correlation_id_path=correlation_id_path, + clear_custom_keys=clear_custom_keys, ) log_event = resolve_truthy_env_var_choice( @@ -322,7 +331,11 @@ def handler(event, context): def decorate(event, context): lambda_context = build_lambda_context_model(context) cold_start = _is_cold_start() - self.append_keys(cold_start=cold_start, **lambda_context.__dict__) + + if clear_custom_keys: + self.structure_logs(cold_start=cold_start, **lambda_context.__dict__) + else: + self.append_keys(cold_start=cold_start, **lambda_context.__dict__) if correlation_id_path: self.set_correlation_id(jmespath.search(correlation_id_path, event)) diff --git a/docs/core/logger.md b/docs/core/logger.md index a544bf91e4b..d0e2f22a6d8 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -231,8 +231,9 @@ We provide [built-in JMESPath expressions](#built-in-correlation-id-expressions) ### Appending additional keys -!!! info "Keys might be persisted across invocations" - Always set additional keys as part of your handler to ensure they have the latest value. Additional keys are kept in memory as part of a Logger instance and might be reused in non-cold start scenarios. +!!! info "Custom keys are persisted across warm invocations" + Always set additional keys as part of your handler to ensure they have the latest value, or explicitly clear them with `clear_custom_keys=True`as explained above. + You can append additional keys using either mechanism: @@ -426,6 +427,73 @@ You can remove any additional key from Logger state using `remove_keys`. } ``` +#### Removing all custom keys + +Logger is commonly initialized in the global scope. Due to [Lambda Execution Context reuse](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html), this means that custom keys can be persisted across invocations. If you want all custom keys to be deleted, you can use `clear_custom_keys=True` param in `inject_lambda_context` decorator. + +!!! info + This is useful when you add multiple custom keys conditionally, instead of setting a default `None` value if not present. Any key with `None` value is automatically removed by Logger. + +!!! danger "This can have unintended side effects if you use Layers" + Lambda Layers code is imported before the Lambda handler. + + This means that `clear_custom_keys=True` will instruct Logger to remove any keys previously added before Lambda handler execution proceeds. + + You can either avoid running any code as part of Lambda Layers global scope, or override keys with their latest value as part of handler's execution. + +=== "collect.py" + + ```python hl_lines="5 8" + from aws_lambda_powertools import Logger + + logger = Logger(service="payment") + + @logger.inject_lambda_context(clear_custom_keys=True) + def handler(event, context): + if event.get("special_key"): + # Should only be available in the first request log + # as the second request doesn't contain `special_key` + logger.append_keys(debugging_key="value") + + logger.info("Collecting payment") + ``` + +=== "#1 request" + + ```json hl_lines="7" + { + "level": "INFO", + "location": "collect.handler:10", + "message": "Collecting payment", + "timestamp": "2021-05-03 11:47:12,494+0200", + "service": "payment", + "special_key": "debug_key", + "cold_start": true, + "lambda_function_name": "test", + "lambda_function_memory_size": 128, + "lambda_function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test", + "lambda_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72" + } + ``` + +=== "#2 request" + + ```json hl_lines="7" + { + "level": "INFO", + "location": "collect.handler:10", + "message": "Collecting payment", + "timestamp": "2021-05-03 11:47:12,494+0200", + "service": "payment", + "cold_start": false, + "lambda_function_name": "test", + "lambda_function_memory_size": 128, + "lambda_function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test", + "lambda_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72" + } + ``` + + ### Logging exceptions Use `logger.exception` method to log contextual information about exceptions. Logger will include `exception_name` and `exception` keys to aid troubleshooting and error enumeration. diff --git a/tests/functional/test_logger.py b/tests/functional/test_logger.py index ba6e82b72af..320c2ea1b7d 100644 --- a/tests/functional/test_logger.py +++ b/tests/functional/test_logger.py @@ -562,3 +562,23 @@ def handler(event, context): # THEN we should output to a file not stdout log = log_file.read_text() assert "custom handler" in log + + +def test_clear_keys_on_inject_lambda_context(lambda_context, stdout, service_name): + # GIVEN + logger = Logger(service=service_name, stream=stdout) + + # WHEN clear_custom_key is set and a key was conditionally added in the first invocation + @logger.inject_lambda_context(clear_custom_keys=True) + def handler(event, context): + if event.get("add_key"): + logger.append_keys(my_key="value") + logger.info("Foo") + + # THEN custom key should only exist in the first log + handler({"add_key": True}, lambda_context) + handler({}, lambda_context) + + first_log, second_log = capture_multiple_logging_statements_output(stdout) + assert "my_key" in first_log + assert "my_key" not in second_log From 9019f302cc19f7b4cb024f4640cf1ebff8add456 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 8 Jun 2021 09:56:18 +0200 Subject: [PATCH 02/25] refactor: rename to remove_custom_keys --- aws_lambda_powertools/logging/logger.py | 8 ++++---- docs/core/logger.md | 8 ++++---- tests/functional/test_logger.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/aws_lambda_powertools/logging/logger.py b/aws_lambda_powertools/logging/logger.py index ca01a5762a0..ef64e0d502b 100644 --- a/aws_lambda_powertools/logging/logger.py +++ b/aws_lambda_powertools/logging/logger.py @@ -264,13 +264,13 @@ def inject_lambda_context( lambda_handler: Callable[[Dict, Any], Any] = None, log_event: bool = None, correlation_id_path: str = None, - clear_custom_keys: bool = False, + remove_custom_keys: bool = False, ): """Decorator to capture Lambda contextual info and inject into logger Parameters ---------- - clear_custom_keys : bool, optional + remove_custom_keys : bool, optional Instructs logger to remove any custom keys previously added lambda_handler : Callable Method to inject the lambda context @@ -320,7 +320,7 @@ def handler(event, context): self.inject_lambda_context, log_event=log_event, correlation_id_path=correlation_id_path, - clear_custom_keys=clear_custom_keys, + remove_custom_keys=remove_custom_keys, ) log_event = resolve_truthy_env_var_choice( @@ -332,7 +332,7 @@ def decorate(event, context): lambda_context = build_lambda_context_model(context) cold_start = _is_cold_start() - if clear_custom_keys: + if remove_custom_keys: self.structure_logs(cold_start=cold_start, **lambda_context.__dict__) else: self.append_keys(cold_start=cold_start, **lambda_context.__dict__) diff --git a/docs/core/logger.md b/docs/core/logger.md index d0e2f22a6d8..b2ac0bf568f 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -232,7 +232,7 @@ We provide [built-in JMESPath expressions](#built-in-correlation-id-expressions) ### Appending additional keys !!! info "Custom keys are persisted across warm invocations" - Always set additional keys as part of your handler to ensure they have the latest value, or explicitly clear them with `clear_custom_keys=True`as explained above. + Always set additional keys as part of your handler to ensure they have the latest value, or explicitly clear them with `remove_custom_keys=True`as explained above. You can append additional keys using either mechanism: @@ -429,7 +429,7 @@ You can remove any additional key from Logger state using `remove_keys`. #### Removing all custom keys -Logger is commonly initialized in the global scope. Due to [Lambda Execution Context reuse](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html), this means that custom keys can be persisted across invocations. If you want all custom keys to be deleted, you can use `clear_custom_keys=True` param in `inject_lambda_context` decorator. +Logger is commonly initialized in the global scope. Due to [Lambda Execution Context reuse](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html), this means that custom keys can be persisted across invocations. If you want all custom keys to be deleted, you can use `remove_custom_keys=True` param in `inject_lambda_context` decorator. !!! info This is useful when you add multiple custom keys conditionally, instead of setting a default `None` value if not present. Any key with `None` value is automatically removed by Logger. @@ -437,7 +437,7 @@ Logger is commonly initialized in the global scope. Due to [Lambda Execution Con !!! danger "This can have unintended side effects if you use Layers" Lambda Layers code is imported before the Lambda handler. - This means that `clear_custom_keys=True` will instruct Logger to remove any keys previously added before Lambda handler execution proceeds. + This means that `remove_custom_keys=True` will instruct Logger to remove any keys previously added before Lambda handler execution proceeds. You can either avoid running any code as part of Lambda Layers global scope, or override keys with their latest value as part of handler's execution. @@ -448,7 +448,7 @@ Logger is commonly initialized in the global scope. Due to [Lambda Execution Con logger = Logger(service="payment") - @logger.inject_lambda_context(clear_custom_keys=True) + @logger.inject_lambda_context(remove_custom_keys=True) def handler(event, context): if event.get("special_key"): # Should only be available in the first request log diff --git a/tests/functional/test_logger.py b/tests/functional/test_logger.py index 320c2ea1b7d..10297ba5e39 100644 --- a/tests/functional/test_logger.py +++ b/tests/functional/test_logger.py @@ -568,8 +568,8 @@ def test_clear_keys_on_inject_lambda_context(lambda_context, stdout, service_nam # GIVEN logger = Logger(service=service_name, stream=stdout) - # WHEN clear_custom_key is set and a key was conditionally added in the first invocation - @logger.inject_lambda_context(clear_custom_keys=True) + # WHEN remove_custom_keys is set and a key was conditionally added in the first invocation + @logger.inject_lambda_context(remove_custom_keys=True) def handler(event, context): if event.get("add_key"): logger.append_keys(my_key="value") From d1b7c2208269bf7857e8b8e38aaa2f70726ec84d Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 8 Jun 2021 10:00:36 +0200 Subject: [PATCH 03/25] refactor: rename to clear_state --- aws_lambda_powertools/logging/logger.py | 8 ++++---- docs/core/logger.md | 10 +++++----- tests/functional/test_logger.py | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/aws_lambda_powertools/logging/logger.py b/aws_lambda_powertools/logging/logger.py index ef64e0d502b..689409d9813 100644 --- a/aws_lambda_powertools/logging/logger.py +++ b/aws_lambda_powertools/logging/logger.py @@ -264,13 +264,13 @@ def inject_lambda_context( lambda_handler: Callable[[Dict, Any], Any] = None, log_event: bool = None, correlation_id_path: str = None, - remove_custom_keys: bool = False, + clear_state: bool = False, ): """Decorator to capture Lambda contextual info and inject into logger Parameters ---------- - remove_custom_keys : bool, optional + clear_state : bool, optional Instructs logger to remove any custom keys previously added lambda_handler : Callable Method to inject the lambda context @@ -320,7 +320,7 @@ def handler(event, context): self.inject_lambda_context, log_event=log_event, correlation_id_path=correlation_id_path, - remove_custom_keys=remove_custom_keys, + clear_state=clear_state, ) log_event = resolve_truthy_env_var_choice( @@ -332,7 +332,7 @@ def decorate(event, context): lambda_context = build_lambda_context_model(context) cold_start = _is_cold_start() - if remove_custom_keys: + if clear_state: self.structure_logs(cold_start=cold_start, **lambda_context.__dict__) else: self.append_keys(cold_start=cold_start, **lambda_context.__dict__) diff --git a/docs/core/logger.md b/docs/core/logger.md index b2ac0bf568f..675768b3de7 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -232,7 +232,7 @@ We provide [built-in JMESPath expressions](#built-in-correlation-id-expressions) ### Appending additional keys !!! info "Custom keys are persisted across warm invocations" - Always set additional keys as part of your handler to ensure they have the latest value, or explicitly clear them with `remove_custom_keys=True`as explained above. + Always set additional keys as part of your handler to ensure they have the latest value, or explicitly clear them with `clear_state=True`as explained above. You can append additional keys using either mechanism: @@ -427,9 +427,9 @@ You can remove any additional key from Logger state using `remove_keys`. } ``` -#### Removing all custom keys +#### Clearing all state -Logger is commonly initialized in the global scope. Due to [Lambda Execution Context reuse](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html), this means that custom keys can be persisted across invocations. If you want all custom keys to be deleted, you can use `remove_custom_keys=True` param in `inject_lambda_context` decorator. +Logger is commonly initialized in the global scope. Due to [Lambda Execution Context reuse](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html), this means that custom keys can be persisted across invocations. If you want all custom keys to be deleted, you can use `clear_state=True` param in `inject_lambda_context` decorator. !!! info This is useful when you add multiple custom keys conditionally, instead of setting a default `None` value if not present. Any key with `None` value is automatically removed by Logger. @@ -437,7 +437,7 @@ Logger is commonly initialized in the global scope. Due to [Lambda Execution Con !!! danger "This can have unintended side effects if you use Layers" Lambda Layers code is imported before the Lambda handler. - This means that `remove_custom_keys=True` will instruct Logger to remove any keys previously added before Lambda handler execution proceeds. + This means that `clear_state=True` will instruct Logger to remove any keys previously added before Lambda handler execution proceeds. You can either avoid running any code as part of Lambda Layers global scope, or override keys with their latest value as part of handler's execution. @@ -448,7 +448,7 @@ Logger is commonly initialized in the global scope. Due to [Lambda Execution Con logger = Logger(service="payment") - @logger.inject_lambda_context(remove_custom_keys=True) + @logger.inject_lambda_context(clear_state=True) def handler(event, context): if event.get("special_key"): # Should only be available in the first request log diff --git a/tests/functional/test_logger.py b/tests/functional/test_logger.py index 10297ba5e39..44249af6250 100644 --- a/tests/functional/test_logger.py +++ b/tests/functional/test_logger.py @@ -564,12 +564,12 @@ def handler(event, context): assert "custom handler" in log -def test_clear_keys_on_inject_lambda_context(lambda_context, stdout, service_name): +def test_clear_state_on_inject_lambda_context(lambda_context, stdout, service_name): # GIVEN logger = Logger(service=service_name, stream=stdout) - # WHEN remove_custom_keys is set and a key was conditionally added in the first invocation - @logger.inject_lambda_context(remove_custom_keys=True) + # WHEN clear_state is set and a key was conditionally added in the first invocation + @logger.inject_lambda_context(clear_state=True) def handler(event, context): if event.get("add_key"): logger.append_keys(my_key="value") From a6916762e40d12fafb23c9e23b048e56e3f30cdb Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Tue, 8 Jun 2021 10:23:44 +0200 Subject: [PATCH 04/25] docs: fix anchor --- docs/core/logger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/logger.md b/docs/core/logger.md index 675768b3de7..45119ca51d6 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -232,7 +232,7 @@ We provide [built-in JMESPath expressions](#built-in-correlation-id-expressions) ### Appending additional keys !!! info "Custom keys are persisted across warm invocations" - Always set additional keys as part of your handler to ensure they have the latest value, or explicitly clear them with `clear_state=True`as explained above. + Always set additional keys as part of your handler to ensure they have the latest value, or explicitly clear them with [`clear_state=True`](#clearing-all-state). You can append additional keys using either mechanism: From b67020b1e9046cbe154470feae2f2a4cc500221f Mon Sep 17 00:00:00 2001 From: Alexander Melnyk Date: Tue, 7 Jun 2022 18:51:07 +0200 Subject: [PATCH 05/25] bump layer version for version 1.26.1 release --- docs/index.md | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/index.md b/docs/index.md index 7c42615092f..83d841de153 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,7 +14,7 @@ A suite of utilities for AWS Lambda functions to ease adopting best practices su Powertools is available in the following formats: -* **Lambda Layer**: [**arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:19**](#){: .copyMe}:clipboard: +* **Lambda Layer**: [**arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:20**](#){: .copyMe}:clipboard: * **PyPi**: **`pip install aws-lambda-powertools`** ???+ hint "Support this project by using Lambda Layers :heart:" @@ -33,23 +33,23 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: | Region | Layer ARN |--------------------------- | --------------------------- - | `us-east-1` | [arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `us-east-2` | [arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `us-west-1` | [arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `us-west-2` | [arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `ap-south-1` | [arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `eu-central-1` | [arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `eu-west-1` | [arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `eu-west-2` | [arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `eu-west-3` | [arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `eu-north-1` | [arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `ca-central-1` | [arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: - | `sa-east-1` | [arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPython:19](#){: .copyMe}:clipboard: + | `us-east-1` | [arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `us-east-2` | [arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `us-west-1` | [arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `us-west-2` | [arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `ap-south-1` | [arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `eu-central-1` | [arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `eu-west-1` | [arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `eu-west-2` | [arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `eu-west-3` | [arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `eu-north-1` | [arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `ca-central-1` | [arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: + | `sa-east-1` | [arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPython:20](#){: .copyMe}:clipboard: ??? question "Can't find our Lambda Layer for your preferred AWS region?" You can use [Serverless Application Repository (SAR)](#sar) method, our [CDK Layer Construct](https://github.com/aws-samples/cdk-lambda-powertools-python-layer){target="_blank"}, or PyPi like you normally would for any other library. @@ -63,7 +63,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: Type: AWS::Serverless::Function Properties: Layers: - - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPython:19 + - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPython:20 ``` === "Serverless framework" @@ -73,7 +73,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: hello: handler: lambda_function.lambda_handler layers: - - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPython:19 + - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPython:20 ``` === "CDK" @@ -89,7 +89,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: powertools_layer = aws_lambda.LayerVersion.from_layer_version_arn( self, id="lambda-powertools", - layer_version_arn=f"arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPython:19" + layer_version_arn=f"arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPython:20" ) aws_lambda.Function(self, 'sample-app-lambda', @@ -138,7 +138,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: role = aws_iam_role.iam_for_lambda.arn handler = "index.test" runtime = "python3.9" - layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:19"] + layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:20"] source_code_hash = filebase64sha256("lambda_function_payload.zip") } @@ -157,7 +157,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: ? Do you want to configure advanced settings? Yes ... ? Do you want to enable Lambda layers for this function? Yes - ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPython:19 + ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPython:20 ❯ amplify push -y @@ -168,7 +168,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: - Name: ? Which setting do you want to update? Lambda layers configuration ? Do you want to enable Lambda layers for this function? Yes - ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPython:19 + ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPython:20 ? Do you want to edit the local lambda function now? No ``` @@ -176,7 +176,7 @@ You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https: Change {region} to your AWS region, e.g. `eu-west-1` ```bash title="AWS CLI" - aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:19 --region {region} + aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPython:20 --region {region} ``` The pre-signed URL to download this Lambda Layer will be within `Location` key. From 5d5e7b8343e92226fc333cd26337af419e2207fb Mon Sep 17 00:00:00 2001 From: Heitor Lessa Date: Wed, 8 Jun 2022 07:55:54 +0200 Subject: [PATCH 06/25] chore(metrics): revert dimensions test before splitting (#1243) --- tests/functional/test_metrics.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/functional/test_metrics.py b/tests/functional/test_metrics.py index 4dbefd34603..6cf33a3eaa4 100644 --- a/tests/functional/test_metrics.py +++ b/tests/functional/test_metrics.py @@ -319,9 +319,20 @@ def test_schema_no_metrics(service, namespace): my_metrics.serialize_metric_set() -def test_exceed_number_of_dimensions(metric, namespace, monkeypatch): - # GIVEN we we have more dimensions than CloudWatch supports - # and that service dimension is injected like a user-defined dimension (N+1) +def test_exceed_number_of_dimensions(metric, namespace): + # GIVEN we have more dimensions than CloudWatch supports + dimensions = [{"name": f"test_{i}", "value": "test"} for i in range(11)] + + # WHEN we attempt to serialize them into a valid EMF object + # THEN it should fail validation and raise SchemaValidationError + with pytest.raises(SchemaValidationError, match="Maximum number of dimensions exceeded.*"): + with single_metric(**metric, namespace=namespace) as my_metric: + for dimension in dimensions: + my_metric.add_dimension(**dimension) + + +def test_exceed_number_of_dimensions_with_service(metric, namespace, monkeypatch): + # GIVEN we have service set and add more dimensions than CloudWatch supports (N+1) monkeypatch.setenv("POWERTOOLS_SERVICE_NAME", "test_service") dimensions = [{"name": f"test_{i}", "value": "test"} for i in range(9)] From 02d680aaea90ba129469b22533669762ac54ff68 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 10 Jun 2022 05:12:46 +0200 Subject: [PATCH 07/25] chore(governance): warn message on closed issues --- .github/workflows/on_closed_issues.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/workflows/on_closed_issues.yml diff --git a/.github/workflows/on_closed_issues.yml b/.github/workflows/on_closed_issues.yml new file mode 100644 index 00000000000..a6dadcd843d --- /dev/null +++ b/.github/workflows/on_closed_issues.yml @@ -0,0 +1,12 @@ +name: Closed Issue Message +on: + issues: + types: [closed] +jobs: + auto_comment: + runs-on: ubuntu-latest + steps: + - uses: aws-actions/closed-issue-message@v1 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + message: "Comments on closed issues are hard for our team to see." From 53461bef67afed9fd78680d4b4ab3adadc54dda2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jun 2022 11:44:42 +0200 Subject: [PATCH 08/25] chore(deps-dev): bump mypy from 0.960 to 0.961 (#1241) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 50 +++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/poetry.lock b/poetry.lock index b74407a612b..fbf8566c437 100644 --- a/poetry.lock +++ b/poetry.lock @@ -597,7 +597,7 @@ python-versions = ">=3.6" [[package]] name = "mypy" -version = "0.960" +version = "0.961" description = "Optional static typing for Python" category = "dev" optional = false @@ -1101,7 +1101,7 @@ pydantic = ["pydantic", "email-validator"] [metadata] lock-version = "1.1" python-versions = "^3.6.2" -content-hash = "3338b6725aca49dba6d26d5db7019ba23c2281af6e4f7f581a4760da3af546e3" +content-hash = "9bda13a93fe23b834f33b9c8547f4e45c98c504fc3d2af8055dee51f791dba3d" [metadata.files] atomicwrites = [ @@ -1405,29 +1405,29 @@ mkdocs-material-extensions = [ {file = "mkdocs_material_extensions-1.0.3-py3-none-any.whl", hash = "sha256:a82b70e533ce060b2a5d9eb2bc2e1be201cf61f901f93704b4acf6e3d5983a44"}, ] mypy = [ - {file = "mypy-0.960-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3a3e525cd76c2c4f90f1449fd034ba21fcca68050ff7c8397bb7dd25dd8b8248"}, - {file = "mypy-0.960-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7a76dc4f91e92db119b1be293892df8379b08fd31795bb44e0ff84256d34c251"}, - {file = "mypy-0.960-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffdad80a92c100d1b0fe3d3cf1a4724136029a29afe8566404c0146747114382"}, - {file = "mypy-0.960-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7d390248ec07fa344b9f365e6ed9d205bd0205e485c555bed37c4235c868e9d5"}, - {file = "mypy-0.960-cp310-cp310-win_amd64.whl", hash = "sha256:925aa84369a07846b7f3b8556ccade1f371aa554f2bd4fb31cb97a24b73b036e"}, - {file = "mypy-0.960-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:239d6b2242d6c7f5822163ee082ef7a28ee02e7ac86c35593ef923796826a385"}, - {file = "mypy-0.960-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f1ba54d440d4feee49d8768ea952137316d454b15301c44403db3f2cb51af024"}, - {file = "mypy-0.960-cp36-cp36m-win_amd64.whl", hash = "sha256:cb7752b24528c118a7403ee955b6a578bfcf5879d5ee91790667c8ea511d2085"}, - {file = "mypy-0.960-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:826a2917c275e2ee05b7c7b736c1e6549a35b7ea5a198ca457f8c2ebea2cbecf"}, - {file = "mypy-0.960-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3eabcbd2525f295da322dff8175258f3fc4c3eb53f6d1929644ef4d99b92e72d"}, - {file = "mypy-0.960-cp37-cp37m-win_amd64.whl", hash = "sha256:f47322796c412271f5aea48381a528a613f33e0a115452d03ae35d673e6064f8"}, - {file = "mypy-0.960-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2c7f8bb9619290836a4e167e2ef1f2cf14d70e0bc36c04441e41487456561409"}, - {file = "mypy-0.960-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fbfb873cf2b8d8c3c513367febde932e061a5f73f762896826ba06391d932b2a"}, - {file = "mypy-0.960-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc537885891382e08129d9862553b3d00d4be3eb15b8cae9e2466452f52b0117"}, - {file = "mypy-0.960-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:481f98c6b24383188c928f33dd2f0776690807e12e9989dd0419edd5c74aa53b"}, - {file = "mypy-0.960-cp38-cp38-win_amd64.whl", hash = "sha256:29dc94d9215c3eb80ac3c2ad29d0c22628accfb060348fd23d73abe3ace6c10d"}, - {file = "mypy-0.960-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:33d53a232bb79057f33332dbbb6393e68acbcb776d2f571ba4b1d50a2c8ba873"}, - {file = "mypy-0.960-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8d645e9e7f7a5da3ec3bbcc314ebb9bb22c7ce39e70367830eb3c08d0140b9ce"}, - {file = "mypy-0.960-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:85cf2b14d32b61db24ade8ac9ae7691bdfc572a403e3cb8537da936e74713275"}, - {file = "mypy-0.960-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a85a20b43fa69efc0b955eba1db435e2ffecb1ca695fe359768e0503b91ea89f"}, - {file = "mypy-0.960-cp39-cp39-win_amd64.whl", hash = "sha256:0ebfb3f414204b98c06791af37a3a96772203da60636e2897408517fcfeee7a8"}, - {file = "mypy-0.960-py3-none-any.whl", hash = "sha256:bfd4f6536bd384c27c392a8b8f790fd0ed5c0cf2f63fc2fed7bce56751d53026"}, - {file = "mypy-0.960.tar.gz", hash = "sha256:d4fccf04c1acf750babd74252e0f2db6bd2ac3aa8fe960797d9f3ef41cf2bfd4"}, + {file = "mypy-0.961-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:697540876638ce349b01b6786bc6094ccdaba88af446a9abb967293ce6eaa2b0"}, + {file = "mypy-0.961-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b117650592e1782819829605a193360a08aa99f1fc23d1d71e1a75a142dc7e15"}, + {file = "mypy-0.961-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bdd5ca340beffb8c44cb9dc26697628d1b88c6bddf5c2f6eb308c46f269bb6f3"}, + {file = "mypy-0.961-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3e09f1f983a71d0672bbc97ae33ee3709d10c779beb613febc36805a6e28bb4e"}, + {file = "mypy-0.961-cp310-cp310-win_amd64.whl", hash = "sha256:e999229b9f3198c0c880d5e269f9f8129c8862451ce53a011326cad38b9ccd24"}, + {file = "mypy-0.961-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b24be97351084b11582fef18d79004b3e4db572219deee0212078f7cf6352723"}, + {file = "mypy-0.961-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f4a21d01fc0ba4e31d82f0fff195682e29f9401a8bdb7173891070eb260aeb3b"}, + {file = "mypy-0.961-cp36-cp36m-win_amd64.whl", hash = "sha256:439c726a3b3da7ca84a0199a8ab444cd8896d95012c4a6c4a0d808e3147abf5d"}, + {file = "mypy-0.961-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5a0b53747f713f490affdceef835d8f0cb7285187a6a44c33821b6d1f46ed813"}, + {file = "mypy-0.961-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0e9f70df36405c25cc530a86eeda1e0867863d9471fe76d1273c783df3d35c2e"}, + {file = "mypy-0.961-cp37-cp37m-win_amd64.whl", hash = "sha256:b88f784e9e35dcaa075519096dc947a388319cb86811b6af621e3523980f1c8a"}, + {file = "mypy-0.961-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d5aaf1edaa7692490f72bdb9fbd941fbf2e201713523bdb3f4038be0af8846c6"}, + {file = "mypy-0.961-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9f5f5a74085d9a81a1f9c78081d60a0040c3efb3f28e5c9912b900adf59a16e6"}, + {file = "mypy-0.961-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f4b794db44168a4fc886e3450201365c9526a522c46ba089b55e1f11c163750d"}, + {file = "mypy-0.961-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:64759a273d590040a592e0f4186539858c948302c653c2eac840c7a3cd29e51b"}, + {file = "mypy-0.961-cp38-cp38-win_amd64.whl", hash = "sha256:63e85a03770ebf403291ec50097954cc5caf2a9205c888ce3a61bd3f82e17569"}, + {file = "mypy-0.961-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f1332964963d4832a94bebc10f13d3279be3ce8f6c64da563d6ee6e2eeda932"}, + {file = "mypy-0.961-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:006be38474216b833eca29ff6b73e143386f352e10e9c2fbe76aa8549e5554f5"}, + {file = "mypy-0.961-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9940e6916ed9371809b35b2154baf1f684acba935cd09928952310fbddaba648"}, + {file = "mypy-0.961-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a5ea0875a049de1b63b972456542f04643daf320d27dc592d7c3d9cd5d9bf950"}, + {file = "mypy-0.961-cp39-cp39-win_amd64.whl", hash = "sha256:1ece702f29270ec6af25db8cf6185c04c02311c6bb21a69f423d40e527b75c56"}, + {file = "mypy-0.961-py3-none-any.whl", hash = "sha256:03c6cc893e7563e7b2949b969e63f02c000b32502a1b4d1314cabe391aa87d66"}, + {file = "mypy-0.961.tar.gz", hash = "sha256:f730d56cb924d371c26b8eaddeea3cc07d78ff51c521c6d04899ac6904b75492"}, ] mypy-boto3-appconfig = [ {file = "mypy-boto3-appconfig-1.23.0.post1.tar.gz", hash = "sha256:78442ffc2850a5234f72a4c2b3d5eeae87e3e1cc67e689bb3bee33e35cbb31a9"}, diff --git a/pyproject.toml b/pyproject.toml index 9eeedcd63c5..d84203020d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,7 +53,7 @@ flake8-eradicate = "^1.2.1" flake8-bugbear = "^22.4.25" mkdocs-git-revision-date-plugin = "^0.3.2" mike = "^0.6.0" -mypy = "^0.960" +mypy = "^0.961" mkdocs-material = "^8.2.7" mypy-boto3-secretsmanager = "^1.23.8" mypy-boto3-ssm = "^1.23.0" From b1df21096488307313e10deb43c2de4146554d9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jun 2022 11:50:06 +0200 Subject: [PATCH 09/25] chore(deps-dev): bump mypy-boto3-ssm from 1.23.0.post1 to 1.24.0 (#1231) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index fbf8566c437..c712072e8c5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -649,8 +649,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-ssm" -version = "1.23.0.post1" -description = "Type annotations for boto3.SSM 1.23.0 service generated with mypy-boto3-builder 7.5.14" +version = "1.24.0" +description = "Type annotations for boto3.SSM 1.24.0 service generated with mypy-boto3-builder 7.6.1" category = "dev" optional = false python-versions = ">=3.6" @@ -1101,7 +1101,7 @@ pydantic = ["pydantic", "email-validator"] [metadata] lock-version = "1.1" python-versions = "^3.6.2" -content-hash = "9bda13a93fe23b834f33b9c8547f4e45c98c504fc3d2af8055dee51f791dba3d" +content-hash = "f20dd9dd1c910264a423e919871afe7510e6a8fffef0eb05a94e004ac8485b6c" [metadata.files] atomicwrites = [ @@ -1442,8 +1442,8 @@ mypy-boto3-secretsmanager = [ {file = "mypy_boto3_secretsmanager-1.23.8-py3-none-any.whl", hash = "sha256:fbf5aa340ee239d7ed50b37b70afb2d9869980f4567ebe47ee9241c5a94486d9"}, ] mypy-boto3-ssm = [ - {file = "mypy-boto3-ssm-1.23.0.post1.tar.gz", hash = "sha256:78333811d184432ddfaa1d14bfb9586badc763d5ff8c876b7a224ebe629f9de8"}, - {file = "mypy_boto3_ssm-1.23.0.post1-py3-none-any.whl", hash = "sha256:f6a21fdd2c8d34be3b621c9ec1b7fb981221a1125cc61945cfacd634f065c951"}, + {file = "mypy-boto3-ssm-1.24.0.tar.gz", hash = "sha256:bab58398947c3627a4e7610cd0f57b525c12fd1d0a6bb862400b6af0a4e684fc"}, + {file = "mypy_boto3_ssm-1.24.0-py3-none-any.whl", hash = "sha256:1f17055abb8d70f25e6ece2ef4c0dc74d585744c25a3a833c2985d74165ac0c6"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, diff --git a/pyproject.toml b/pyproject.toml index d84203020d7..44a8adf4125 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,7 +56,7 @@ mike = "^0.6.0" mypy = "^0.961" mkdocs-material = "^8.2.7" mypy-boto3-secretsmanager = "^1.23.8" -mypy-boto3-ssm = "^1.23.0" +mypy-boto3-ssm = "^1.24.0" mypy-boto3-appconfig = "^1.23.0" mypy-boto3-dynamodb = "^1.23.0" From 3c249a001762caf54c89d78ed401be8e2e9e82ce Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 10 Jun 2022 12:02:01 +0200 Subject: [PATCH 10/25] chore(governance): auto-merge mypy-stub dependabot --- .github/workflows/auto-merge.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/auto-merge.yml diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml new file mode 100644 index 00000000000..385df1fc44b --- /dev/null +++ b/.github/workflows/auto-merge.yml @@ -0,0 +1,23 @@ +name: auto-merge + +on: pull_request + +permissions: + contents: write + +jobs: + dependabot: + runs-on: ubuntu-latest + if: ${{ github.actor == 'dependabot[bot]' }} + steps: + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v1.1.1 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + - name: Enable auto-merge for mypy-boto3 stubs Dependabot PRs + if: ${{contains(steps.metadata.outputs.dependency-names, 'mypy-boto3')}} # && steps.metadata.outputs.update-type == 'version-update:semver-patch' + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} From 1775ee6d778fda7e180287df21df89869b4e4e70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jun 2022 12:03:06 +0200 Subject: [PATCH 11/25] chore(deps-dev): bump mypy-boto3-secretsmanager from 1.23.8 to 1.24.0 (#1232) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index c712072e8c5..aac5c2af598 100644 --- a/poetry.lock +++ b/poetry.lock @@ -638,8 +638,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-secretsmanager" -version = "1.23.8" -description = "Type annotations for boto3.SecretsManager 1.23.8 service generated with mypy-boto3-builder 7.6.0" +version = "1.24.0" +description = "Type annotations for boto3.SecretsManager 1.24.0 service generated with mypy-boto3-builder 7.6.1" category = "dev" optional = false python-versions = ">=3.6" @@ -1101,7 +1101,7 @@ pydantic = ["pydantic", "email-validator"] [metadata] lock-version = "1.1" python-versions = "^3.6.2" -content-hash = "f20dd9dd1c910264a423e919871afe7510e6a8fffef0eb05a94e004ac8485b6c" +content-hash = "2e80fd14c2c6a463a568775c152ac18435968a68b12a1c3b3d0aefc21ed0d42c" [metadata.files] atomicwrites = [ @@ -1438,8 +1438,8 @@ mypy-boto3-dynamodb = [ {file = "mypy_boto3_dynamodb-1.23.0.post1-py3-none-any.whl", hash = "sha256:fed40bd6e987d4dbe2551b2a33106f23965111570e0a84e9e7a3caf65d1c79f9"}, ] mypy-boto3-secretsmanager = [ - {file = "mypy-boto3-secretsmanager-1.23.8.tar.gz", hash = "sha256:f6679b6e3844ac1e766efefedbffcf09924c02b1cdd05af5f8675d80383d6243"}, - {file = "mypy_boto3_secretsmanager-1.23.8-py3-none-any.whl", hash = "sha256:fbf5aa340ee239d7ed50b37b70afb2d9869980f4567ebe47ee9241c5a94486d9"}, + {file = "mypy-boto3-secretsmanager-1.24.0.tar.gz", hash = "sha256:6680c322df031b08ef79fcdb8ffdfb08d57d4925392f641348336926dc5c6b2e"}, + {file = "mypy_boto3_secretsmanager-1.24.0-py3-none-any.whl", hash = "sha256:7da281c49ae91e60fdbcd0015379ae4cc9dc9ff911836ee78a2652310e09f53e"}, ] mypy-boto3-ssm = [ {file = "mypy-boto3-ssm-1.24.0.tar.gz", hash = "sha256:bab58398947c3627a4e7610cd0f57b525c12fd1d0a6bb862400b6af0a4e684fc"}, diff --git a/pyproject.toml b/pyproject.toml index 44a8adf4125..8e7531515a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ mkdocs-git-revision-date-plugin = "^0.3.2" mike = "^0.6.0" mypy = "^0.961" mkdocs-material = "^8.2.7" -mypy-boto3-secretsmanager = "^1.23.8" +mypy-boto3-secretsmanager = "^1.24.0" mypy-boto3-ssm = "^1.24.0" mypy-boto3-appconfig = "^1.23.0" mypy-boto3-dynamodb = "^1.23.0" From 73acee13cc157cbe0362e3060e8557e64e2a92f7 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 10 Jun 2022 12:26:15 +0200 Subject: [PATCH 12/25] chore(governance): auto-merge to use squash --- .github/workflows/auto-merge.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 385df1fc44b..c4cd8036191 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -1,6 +1,8 @@ name: auto-merge -on: pull_request +on: + pull_request: + workflow_dispatch: permissions: contents: write @@ -17,7 +19,7 @@ jobs: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Enable auto-merge for mypy-boto3 stubs Dependabot PRs if: ${{contains(steps.metadata.outputs.dependency-names, 'mypy-boto3')}} # && steps.metadata.outputs.update-type == 'version-update:semver-patch' - run: gh pr merge --auto --merge "$PR_URL" + run: gh pr merge --auto --merge --squash "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} From d8aed9f62d9e4660b57cc884f2582637017675ee Mon Sep 17 00:00:00 2001 From: Heitor Lessa Date: Fri, 10 Jun 2022 12:29:31 +0200 Subject: [PATCH 13/25] chore(governance): auto-merge workflow_dispatch off --- .github/workflows/auto-merge.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index c4cd8036191..d4d797b3761 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -2,7 +2,8 @@ name: auto-merge on: pull_request: - workflow_dispatch: + +# workflow_dispatch: permissions: contents: write From 707ad043f5d18a4dd93de5d5b669177a057c486d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jun 2022 12:30:24 +0200 Subject: [PATCH 14/25] chore(deps-dev): bump mypy-boto3-dynamodb from 1.23.0.post1 to 1.24.0 (#1234) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index aac5c2af598..447da346993 100644 --- a/poetry.lock +++ b/poetry.lock @@ -627,8 +627,8 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-dynamodb" -version = "1.23.0.post1" -description = "Type annotations for boto3.DynamoDB 1.23.0 service generated with mypy-boto3-builder 7.5.14" +version = "1.24.0" +description = "Type annotations for boto3.DynamoDB 1.24.0 service generated with mypy-boto3-builder 7.6.1" category = "dev" optional = false python-versions = ">=3.6" @@ -1101,7 +1101,7 @@ pydantic = ["pydantic", "email-validator"] [metadata] lock-version = "1.1" python-versions = "^3.6.2" -content-hash = "2e80fd14c2c6a463a568775c152ac18435968a68b12a1c3b3d0aefc21ed0d42c" +content-hash = "394b4077fb1b157eabcf97003c7289d1e7d90f9173b2ab014348102a15802ffe" [metadata.files] atomicwrites = [ @@ -1434,8 +1434,8 @@ mypy-boto3-appconfig = [ {file = "mypy_boto3_appconfig-1.23.0.post1-py3-none-any.whl", hash = "sha256:a3175229be86dc1aab8722a6338086ddcf941a61d1dd791344b8654b01075bfa"}, ] mypy-boto3-dynamodb = [ - {file = "mypy-boto3-dynamodb-1.23.0.post1.tar.gz", hash = "sha256:4670825645d041881f3f37a70b38e4b771171942808e49a011a63a9ea6cf494c"}, - {file = "mypy_boto3_dynamodb-1.23.0.post1-py3-none-any.whl", hash = "sha256:fed40bd6e987d4dbe2551b2a33106f23965111570e0a84e9e7a3caf65d1c79f9"}, + {file = "mypy-boto3-dynamodb-1.24.0.tar.gz", hash = "sha256:a7de204a173dffbee972357a69bf5e59fda169a587017e0d3c5446676342aa2e"}, + {file = "mypy_boto3_dynamodb-1.24.0-py3-none-any.whl", hash = "sha256:866f0f8ae44e266ea051f57179bf40132d8e89e6fa23abab6e71421b3c0cd794"}, ] mypy-boto3-secretsmanager = [ {file = "mypy-boto3-secretsmanager-1.24.0.tar.gz", hash = "sha256:6680c322df031b08ef79fcdb8ffdfb08d57d4925392f641348336926dc5c6b2e"}, diff --git a/pyproject.toml b/pyproject.toml index 8e7531515a0..4dd9e60959f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,7 +58,7 @@ mkdocs-material = "^8.2.7" mypy-boto3-secretsmanager = "^1.24.0" mypy-boto3-ssm = "^1.24.0" mypy-boto3-appconfig = "^1.23.0" -mypy-boto3-dynamodb = "^1.23.0" +mypy-boto3-dynamodb = "^1.24.0" [tool.poetry.extras] From a7f9e734bbdcb9dcb3829bf154f9cf65700b9e30 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 10 Jun 2022 12:34:48 +0200 Subject: [PATCH 15/25] chore(governance): auto-merge on all PR events --- .github/workflows/auto-merge.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index d4d797b3761..14bacb12f69 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -2,8 +2,7 @@ name: auto-merge on: pull_request: - -# workflow_dispatch: + types: [opened, edited, synchronize] permissions: contents: write @@ -20,7 +19,7 @@ jobs: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Enable auto-merge for mypy-boto3 stubs Dependabot PRs if: ${{contains(steps.metadata.outputs.dependency-names, 'mypy-boto3')}} # && steps.metadata.outputs.update-type == 'version-update:semver-patch' - run: gh pr merge --auto --merge --squash "$PR_URL" + run: gh pr merge --auto --squash "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} From e1a8f89ed38d8c29191bba97bebc0d445d01a508 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jun 2022 11:44:01 +0100 Subject: [PATCH 16/25] chore(deps-dev): bump mypy-boto3-appconfig from 1.23.0.post1 to 1.24.0 (#1233) Bumps [mypy-boto3-appconfig](https://github.com/youtype/mypy_boto3_builder) from 1.23.0.post1 to 1.24.0. - [Release notes](https://github.com/youtype/mypy_boto3_builder/releases) - [Commits](https://github.com/youtype/mypy_boto3_builder/commits) --- updated-dependencies: - dependency-name: mypy-boto3-appconfig dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 447da346993..f67f25b12ca 100644 --- a/poetry.lock +++ b/poetry.lock @@ -616,8 +616,8 @@ reports = ["lxml"] [[package]] name = "mypy-boto3-appconfig" -version = "1.23.0.post1" -description = "Type annotations for boto3.AppConfig 1.23.0 service generated with mypy-boto3-builder 7.5.14" +version = "1.24.0" +description = "Type annotations for boto3.AppConfig 1.24.0 service generated with mypy-boto3-builder 7.6.1" category = "dev" optional = false python-versions = ">=3.6" @@ -1101,7 +1101,7 @@ pydantic = ["pydantic", "email-validator"] [metadata] lock-version = "1.1" python-versions = "^3.6.2" -content-hash = "394b4077fb1b157eabcf97003c7289d1e7d90f9173b2ab014348102a15802ffe" +content-hash = "e457c68bd754118733c7ad1c54d389f4aa3b06164d947fae5d682566e202b776" [metadata.files] atomicwrites = [ @@ -1430,8 +1430,8 @@ mypy = [ {file = "mypy-0.961.tar.gz", hash = "sha256:f730d56cb924d371c26b8eaddeea3cc07d78ff51c521c6d04899ac6904b75492"}, ] mypy-boto3-appconfig = [ - {file = "mypy-boto3-appconfig-1.23.0.post1.tar.gz", hash = "sha256:78442ffc2850a5234f72a4c2b3d5eeae87e3e1cc67e689bb3bee33e35cbb31a9"}, - {file = "mypy_boto3_appconfig-1.23.0.post1-py3-none-any.whl", hash = "sha256:a3175229be86dc1aab8722a6338086ddcf941a61d1dd791344b8654b01075bfa"}, + {file = "mypy-boto3-appconfig-1.24.0.tar.gz", hash = "sha256:3bb38c2819b78c72fd9c031058edf5e547ad549d58e052928a4f397823a51dbd"}, + {file = "mypy_boto3_appconfig-1.24.0-py3-none-any.whl", hash = "sha256:ca53b0b9606f13257dd0feb800d36531f2eba54f46bd9db7765f69baf9583485"}, ] mypy-boto3-dynamodb = [ {file = "mypy-boto3-dynamodb-1.24.0.tar.gz", hash = "sha256:a7de204a173dffbee972357a69bf5e59fda169a587017e0d3c5446676342aa2e"}, diff --git a/pyproject.toml b/pyproject.toml index 4dd9e60959f..4d97e790f03 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ mypy = "^0.961" mkdocs-material = "^8.2.7" mypy-boto3-secretsmanager = "^1.24.0" mypy-boto3-ssm = "^1.24.0" -mypy-boto3-appconfig = "^1.23.0" +mypy-boto3-appconfig = "^1.24.0" mypy-boto3-dynamodb = "^1.24.0" From 23020999b80a45cd8506aed828221c78c1ffcf68 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jun 2022 12:46:49 +0200 Subject: [PATCH 17/25] chore(deps): bump actions/setup-python from 3 to 4 (#1244) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/publish.yml | 2 +- .github/workflows/python_build.yml | 2 +- .github/workflows/python_docs.yml | 2 +- .github/workflows/rebuild_latest_docs.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6a4bb3b3cf5..218df1aef35 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -48,7 +48,7 @@ jobs: with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: "3.8" - name: Set release notes tag diff --git a/.github/workflows/python_build.yml b/.github/workflows/python_build.yml index 3e41e0fddb6..e709cfa04f6 100644 --- a/.github/workflows/python_build.yml +++ b/.github/workflows/python_build.yml @@ -23,7 +23,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies diff --git a/.github/workflows/python_docs.yml b/.github/workflows/python_docs.yml index 9bee2c43392..295ecb334c8 100644 --- a/.github/workflows/python_docs.yml +++ b/.github/workflows/python_docs.yml @@ -17,7 +17,7 @@ jobs: with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: "3.8" - name: Install dependencies diff --git a/.github/workflows/rebuild_latest_docs.yml b/.github/workflows/rebuild_latest_docs.yml index ca4e117e6dc..b185556f2ff 100644 --- a/.github/workflows/rebuild_latest_docs.yml +++ b/.github/workflows/rebuild_latest_docs.yml @@ -25,7 +25,7 @@ jobs: with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: "3.8" - name: Set release notes tag From 954189db33e9273256091b0d1ff410163a770bf0 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 10 Jun 2022 14:46:13 +0200 Subject: [PATCH 18/25] chore(governance): add release label on pr merge --- .github/workflows/on_merged_pr.yml | 46 ++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/on_merged_pr.yml diff --git a/.github/workflows/on_merged_pr.yml b/.github/workflows/on_merged_pr.yml new file mode 100644 index 00000000000..03784e006f9 --- /dev/null +++ b/.github/workflows/on_merged_pr.yml @@ -0,0 +1,46 @@ +on: + pull_request_target: + types: + - closed + +env: + RELEASE_LABEL: "pending-release" + MAINTAINERS_TEAM: "@awslabs/aws-lambda-powertools-python" + +jobs: + release_label_on_merge: + if: github.event.pull_request.merged == true && github.event.pull_request.user.login != 'dependabot[bot]' + runs-on: ubuntu-latest + steps: + - name: "Label PR related issue for release" + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const prBody = context.payload.body; + const prNumber = context.payload.number; + const releaseLabel = process.env.RELEASE_LABEL; + + const RELATED_ISSUE_REGEX = /Issue number:.+(\d)/ + + const matcher = new RegExp(RELATED_ISSUE_REGEX) + const isMatch = matcher.exec(prBody) + if (isMatch != null) { + let relatedIssueNumber = isMatch[1] + console.info(`Auto-labeling related issue ${relatedIssueNumber} for release`) + + await github.rest.issues.addLabels({ + issue_number: relatedIssueNumber, + owner: context.repo.owner, + repo: context.repo.repo, + labels: [releaseLabel] + }) + } else { + let msg = `${MAINTAINERS_TEAM} No related issues found. Please ensure '${RELEASE_LABEL}.' label is applied before releasing.`; + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + body: msg, + issue_number: prNumber, + }); + } From cac196575ee28634d1926d9ce9db999d7ba9e4d0 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 10 Jun 2022 14:49:44 +0200 Subject: [PATCH 19/25] chore(governance): enforce safe scope on pr merge labelling --- .github/workflows/on_merged_pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/on_merged_pr.yml b/.github/workflows/on_merged_pr.yml index 03784e006f9..046c98a834e 100644 --- a/.github/workflows/on_merged_pr.yml +++ b/.github/workflows/on_merged_pr.yml @@ -1,5 +1,5 @@ on: - pull_request_target: + pull_request: types: - closed From 91411f3a324aecb655c949ee3fdd9ad5caa8490e Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 10 Jun 2022 15:04:54 +0200 Subject: [PATCH 20/25] chore(governance): limit build workflow to code changes only --- .github/workflows/python_build.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/python_build.yml b/.github/workflows/python_build.yml index e709cfa04f6..c0cdcc85cff 100644 --- a/.github/workflows/python_build.yml +++ b/.github/workflows/python_build.yml @@ -2,10 +2,22 @@ name: Code quality on: pull_request: + paths: + - "aws_lambda_powertools/**" + - "tests/**" + - "pyproject.toml" + - "poetry.lock" + - "mypy.ini" branches: - develop - master push: + paths: + - "aws_lambda_powertools/**" + - "tests/**" + - "pyproject.toml" + - "poetry.lock" + - "mypy.ini" branches: - develop - master From 78976b501dfe64b6c70774c6f84f3f1394e3c964 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 10 Jun 2022 16:59:41 +0200 Subject: [PATCH 21/25] chore(governance): check for related issue in new PRs --- .github/workflows/lib/export_pr_details.yml | 75 +++++++++++++++++++++ .github/workflows/on_opened_pr.yml | 58 ++++++++++++++++ .github/workflows/record_pr.yml | 3 + .gitignore | 2 + 4 files changed, 138 insertions(+) create mode 100644 .github/workflows/lib/export_pr_details.yml create mode 100644 .github/workflows/on_opened_pr.yml diff --git a/.github/workflows/lib/export_pr_details.yml b/.github/workflows/lib/export_pr_details.yml new file mode 100644 index 00000000000..e41df94aca8 --- /dev/null +++ b/.github/workflows/lib/export_pr_details.yml @@ -0,0 +1,75 @@ +on: + workflow_call: + inputs: + record_pr_workflow_id: + required: true + type: number + secrets: + token: + required: true + # Map the workflow outputs to job outputs + outputs: + prNumber: + description: "The first output string" + value: ${{ jobs.export_pr_details.outputs.prNumber }} + prTitle: + description: "The second output string" + value: ${{ jobs.export_pr_details.outputs.prTitle }} + prBody: + description: "The second output string" + value: ${{ jobs.export_pr_details.outputs.prBody }} + prAuthor: + description: "The second output string" + value: ${{ jobs.export_pr_details.outputs.prAuthor }} + prAction: + description: "The second output string" + value: ${{ jobs.export_pr_details.outputs.prAction }} + +name: Export Pull Request details from fork +jobs: + export_pr_details: + runs-on: ubuntu-latest + # Map the job outputs to step outputs + outputs: + prNumber: ${{ steps.prNumber.outputs.prNumber }} + prTitle: ${{ steps.prTitle.outputs.prTitle }} + prBody: ${{ steps.prBody.outputs.prBody }} + prAuthor: ${{ steps.prAuthor.outputs.prAuthor }} + prAction: ${{ steps.prAction.outputs.prAction }} + steps: + - name: "Download artifact" + uses: actions/github-script@v6 + # For security, we only download artifacts tied to the successful PR recording workflow + with: + github-token: ${{ inputs.token }} + script: | + const fs = require('fs'); + + const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: ${{inputs.record_pr_workflow_id}}, + }); + + const matchArtifact = artifacts.data.artifacts.filter(artifact => artifact.name == "pr")[0]; + + const artifact = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + }); + + fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(artifact.data)); + # NodeJS standard library doesn't provide ZIP capabilities; use system `unzip` command instead + - run: unzip pr.zip + - id: prNumber + run: echo ::set-output name=prNumber::$(cat ./number) + - id: prTitle + run: echo ::set-output name=prTitle::$(cat ./title) + - id: prBody + run: echo ::set-output name=prBody::$(cat ./body) + - id: prAuthor + run: echo ::set-output name=prAuthor::$(cat ./author) + - id: prAction + run: echo ::set-output name=prAction::$(cat ./action) diff --git a/.github/workflows/on_opened_pr.yml b/.github/workflows/on_opened_pr.yml new file mode 100644 index 00000000000..e2505ff15bc --- /dev/null +++ b/.github/workflows/on_opened_pr.yml @@ -0,0 +1,58 @@ +on: + workflow_run: + workflows: ["Record PR number"] + types: + - completed + +env: + BLOCK_LABEL: "do-not-merge" + BLOCK_REASON_LABEL: "need-issue" + +jobs: + get_pr_details: + if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' + uses: ./.github/workflows/lib/export_pr_details.yml + with: + record_pr_workflow_id: ${{ github.event.workflow_run.id }} + secrets: + token: ${{ secrets.GITHUB_TOKEN }} + check_related_issue: + needs: get_pr_details + if: > + ${{ needs.get_pr_details.outputs.prAuthor != 'dependabot[bot]' && + needs.get_pr_details.outputs.prAction == 'opened' + }} + runs-on: ubuntu-latest + steps: + - name: "Ensure related issue is present" + uses: actions/github-script@v6 + with: + # Maintenance: convert into a standalone JS like post_release.js + script: | + const prBody = ${{ needs.get_pr_details.outputs.prBody }}; + const prNumber = ${{ needs.get_pr_details.outputs.prNumber }}; + const blockLabel = process.env.BLOCK_LABEL; + const blockReasonLabel = process.env.BLOCK_REASON_LABEL; + + const RELATED_ISSUE_REGEX = /Issue number:.+(\d)/ + + const matcher = new RegExp(RELATED_ISSUE_REGEX) + const isMatch = matcher.exec(prBody) + if (isMatch == null) { + console.info(`No related issue found, maybe the author didn't use the template but there is one.`) + + let msg = `⚠️ No related issues found. Please ensure there is an open issue related to this change to avoid significant delays or closure. ⚠️`; + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + body: msg, + issue_number: prNumber, + }); + + await github.rest.issues.addLabels({ + issue_number: prNumber, + owner: context.repo.owner, + repo: context.repo.repo, + labels: [blockLabel, blockReasonLabel] + }) + } diff --git a/.github/workflows/record_pr.yml b/.github/workflows/record_pr.yml index ce252d57c11..fcee8876286 100644 --- a/.github/workflows/record_pr.yml +++ b/.github/workflows/record_pr.yml @@ -15,6 +15,9 @@ jobs: mkdir -p ./pr echo ${{ github.event.number }} > ./pr/number echo "${{ github.event.pull_request.title }}" > ./pr/title + echo "${{ github.event.pull_request.body }}" > ./pr/body + echo "${{ github.event.pull_request.user.login }}" > ./pr/author + echo "${{ github.event.action }}" > ./pr/action - uses: actions/upload-artifact@v3 with: name: pr diff --git a/.gitignore b/.gitignore index c5d27c9789a..5d28e3a615f 100644 --- a/.gitignore +++ b/.gitignore @@ -304,3 +304,5 @@ api/ site/ !404.html !docs/overrides/*.html + +!.github/workflows/lib From 2bd87225d16c42fbadd40d95d624f2d367b7df5e Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Fri, 10 Jun 2022 17:03:55 +0200 Subject: [PATCH 22/25] chore(governance): address gh reusable workflow limitation --- .github/workflows/{lib => }/export_pr_details.yml | 0 .github/workflows/on_opened_pr.yml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{lib => }/export_pr_details.yml (100%) diff --git a/.github/workflows/lib/export_pr_details.yml b/.github/workflows/export_pr_details.yml similarity index 100% rename from .github/workflows/lib/export_pr_details.yml rename to .github/workflows/export_pr_details.yml diff --git a/.github/workflows/on_opened_pr.yml b/.github/workflows/on_opened_pr.yml index e2505ff15bc..b9837abadeb 100644 --- a/.github/workflows/on_opened_pr.yml +++ b/.github/workflows/on_opened_pr.yml @@ -11,7 +11,7 @@ env: jobs: get_pr_details: if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' - uses: ./.github/workflows/lib/export_pr_details.yml + uses: ./.github/workflows/export_pr_details.yml with: record_pr_workflow_id: ${{ github.event.workflow_run.id }} secrets: From d1b8e8378e234d492f361e067370a3ace311f3ba Mon Sep 17 00:00:00 2001 From: Heitor Lessa Date: Thu, 16 Jun 2022 16:00:55 +0200 Subject: [PATCH 23/25] fix(event-handler): body to empty string in CORS preflight (ALB non-compliant) (#1249) --- .../event_handler/api_gateway.py | 2 +- .../functional/event_handler/test_api_gateway.py | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py index e6d1af01dfc..78cee8f2051 100644 --- a/aws_lambda_powertools/event_handler/api_gateway.py +++ b/aws_lambda_powertools/event_handler/api_gateway.py @@ -595,7 +595,7 @@ def _not_found(self, method: str) -> ResponseBuilder: if method == "OPTIONS": logger.debug("Pre-flight request detected. Returning CORS with null response") headers["Access-Control-Allow-Methods"] = ",".join(sorted(self._cors_methods)) - return ResponseBuilder(Response(status_code=204, content_type=None, headers=headers, body=None)) + return ResponseBuilder(Response(status_code=204, content_type=None, headers=headers, body="")) handler = self._lookup_exception_handler(NotFoundError) if handler: diff --git a/tests/functional/event_handler/test_api_gateway.py b/tests/functional/event_handler/test_api_gateway.py index 1ca28f869cf..0c6d1954836 100644 --- a/tests/functional/event_handler/test_api_gateway.py +++ b/tests/functional/event_handler/test_api_gateway.py @@ -236,6 +236,19 @@ def handler(event, context): assert "Access-Control-Allow-Origin" not in result["headers"] +def test_cors_preflight_body_is_empty_not_null(): + # GIVEN CORS is configured + app = ALBResolver(cors=CORSConfig()) + + event = {"path": "/my/request", "httpMethod": "OPTIONS"} + + # WHEN calling the event handler + result = app(event, {}) + + # THEN there body should be empty strings + assert result["body"] == "" + + def test_compress(): # GIVEN a function that has compress=True # AND an event with a "Accept-Encoding" that include gzip @@ -485,7 +498,7 @@ def post_no_cors(): # THEN return no content # AND include Access-Control-Allow-Methods of the cors methods used assert result["statusCode"] == 204 - assert result["body"] is None + assert result["body"] == "" headers = result["headers"] assert "Content-Type" not in headers assert "Access-Control-Allow-Origin" in result["headers"] From 165aa45c928204d0e6fe4e54312a04fdee0e6ee8 Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Thu, 16 Jun 2022 16:10:51 +0200 Subject: [PATCH 24/25] chore(governance): fix workflow action requirements & syntax --- .github/workflows/on_merged_pr.yml | 3 ++- .github/workflows/on_opened_pr.yml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/on_merged_pr.yml b/.github/workflows/on_merged_pr.yml index 046c98a834e..29b4ed27ad3 100644 --- a/.github/workflows/on_merged_pr.yml +++ b/.github/workflows/on_merged_pr.yml @@ -20,6 +20,7 @@ jobs: const prBody = context.payload.body; const prNumber = context.payload.number; const releaseLabel = process.env.RELEASE_LABEL; + const maintainersTeam = process.env.MAINTAINERS_TEAM const RELATED_ISSUE_REGEX = /Issue number:.+(\d)/ @@ -36,7 +37,7 @@ jobs: labels: [releaseLabel] }) } else { - let msg = `${MAINTAINERS_TEAM} No related issues found. Please ensure '${RELEASE_LABEL}.' label is applied before releasing.`; + let msg = `${maintainersTeam} No related issues found. Please ensure '${RELEASE_LABEL}.' label is applied before releasing.`; await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, diff --git a/.github/workflows/on_opened_pr.yml b/.github/workflows/on_opened_pr.yml index b9837abadeb..578a50d252a 100644 --- a/.github/workflows/on_opened_pr.yml +++ b/.github/workflows/on_opened_pr.yml @@ -27,6 +27,7 @@ jobs: - name: "Ensure related issue is present" uses: actions/github-script@v6 with: + github-token: ${{ secrets.GITHUB_TOKEN }} # Maintenance: convert into a standalone JS like post_release.js script: | const prBody = ${{ needs.get_pr_details.outputs.prBody }}; From 8ce04559fcf12fddf86b059e8cc8a22cf3f25c2d Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Thu, 16 Jun 2022 16:17:35 +0200 Subject: [PATCH 25/25] chore: bump to 1.26.2 --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ pyproject.toml | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03f7ad2919f..1ca92b6a72a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,33 @@ All notable changes to this project will be documented in this file. This project follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format for changes and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.26.2 - 2022-06-16 + +### Bug Fixes + +* **event-handler:** body to empty string in CORS preflight (ALB non-compliant) ([#1249](https://github.com/awslabs/aws-lambda-powertools-python/issues/1249)) + +### Maintenance + +* **deps:** bump actions/setup-python from 3 to 4 ([#1244](https://github.com/awslabs/aws-lambda-powertools-python/issues/1244)) +* **deps-dev:** bump mypy from 0.960 to 0.961 ([#1241](https://github.com/awslabs/aws-lambda-powertools-python/issues/1241)) +* **deps-dev:** bump mypy-boto3-ssm from 1.23.0.post1 to 1.24.0 ([#1231](https://github.com/awslabs/aws-lambda-powertools-python/issues/1231)) +* **deps-dev:** bump mypy-boto3-secretsmanager from 1.23.8 to 1.24.0 ([#1232](https://github.com/awslabs/aws-lambda-powertools-python/issues/1232)) +* **deps-dev:** bump mypy-boto3-dynamodb from 1.23.0.post1 to 1.24.0 ([#1234](https://github.com/awslabs/aws-lambda-powertools-python/issues/1234)) +* **deps-dev:** bump mypy-boto3-appconfig from 1.23.0.post1 to 1.24.0 ([#1233](https://github.com/awslabs/aws-lambda-powertools-python/issues/1233)) +* **governance:** fix workflow action requirements & syntax +* **governance:** add release label on pr merge +* **governance:** auto-merge on all PR events +* **governance:** enforce safe scope on pr merge labelling +* **governance:** auto-merge workflow_dispatch off +* **governance:** auto-merge to use squash +* **governance:** limit build workflow to code changes only +* **governance:** auto-merge mypy-stub dependabot +* **governance:** check for related issue in new PRs +* **governance:** address gh reusable workflow limitation +* **governance:** warn message on closed issues +* **metrics:** revert dimensions test before splitting ([#1243](https://github.com/awslabs/aws-lambda-powertools-python/issues/1243)) + ## 1.26.1 - 2022-06-07 ### Bug Fixes diff --git a/pyproject.toml b/pyproject.toml index 4d97e790f03..53b73908361 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "aws_lambda_powertools" -version = "1.26.1" +version = "1.26.2" description = "A suite of utilities for AWS Lambda functions to ease adopting best practices such as tracing, structured logging, custom metrics, batching, idempotency, feature flags, and more." authors = ["Amazon Web Services"] include = ["aws_lambda_powertools/py.typed", "THIRD-PARTY-LICENSES"]