-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: Adding the sam list testable resources command, tests, and table output format support for all sam list commands #4081
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
Changes from all commits
d964112
5cc31a5
70b3ba8
fc81ceb
97ec32d
3e200f2
bcdf40b
93f55cd
60915f1
a5418f6
a3d150a
5dff9e2
bafaea2
8e084ff
719cfd5
c7499e4
ee2015a
2c62cd9
de4439b
ef1f273
08bf419
1358e61
cf5c191
3aa02da
5bc4247
ae4e2f0
38fc5f0
86166a7
3c8f6a1
3bf1d89
0b5e407
bf8e4f3
7740f30
435abd7
7d0c721
68d5a02
57c199e
657f6cd
e374d52
5bebdbc
eb6639d
b088203
5367428
523915d
84382cf
c549ce6
a820f04
6d35129
defa233
282c914
e98ac15
562d2ad
c5d91eb
7fd3179
8d9a798
91a06a3
3479342
da1eda7
4cd1506
0851eb3
9de6afa
26fb5f0
13c7edb
e7c17d2
9ab5674
c105195
502e463
72b5a63
a6e4f1a
0ce203c
f9c0be0
955c500
e9c6358
ae421a8
23fa28a
040e7df
81002a6
12273f2
99ad642
db4a279
95d1758
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,42 @@ | ||
| """ | ||
| The table consumer for 'sam list' | ||
| """ | ||
| from typing import Dict, Any | ||
| from samcli.lib.list.list_interfaces import ListInfoPullerConsumer | ||
| from samcli.commands._utils.table_print import pprint_column_names, pprint_columns | ||
|
|
||
|
|
||
| class StringConsumerTableOutput(ListInfoPullerConsumer): | ||
| """ | ||
| Outputs data in table format | ||
| """ | ||
|
|
||
| def consume(self, data: Dict[Any, Any]) -> None: | ||
| """ | ||
| Outputs the data in a table format | ||
| Parameters | ||
| ---------- | ||
| data: Dict[Any, Any] | ||
| The data to be outputted | ||
| """ | ||
|
|
||
| @pprint_column_names( | ||
| format_string=data["format_string"], | ||
| format_kwargs=data["format_args"], | ||
| table_header=data["table_name"], | ||
| ) | ||
| def print_table_rows(**kwargs): | ||
| """ | ||
| Prints the rows of the table based on the data provided | ||
| """ | ||
| for entry in data["data"]: | ||
| pprint_columns( | ||
| columns=entry, | ||
| width=kwargs["width"], | ||
| margin=kwargs["margin"], | ||
| format_string=data["format_string"], | ||
| format_args=kwargs["format_args"], | ||
| columns_dict=data["format_args"].copy(), | ||
| ) | ||
|
|
||
| print_table_rows() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| """ | ||
| Display of the Testable Resources of a SAM stack | ||
| """ | ||
| import logging | ||
| from typing import Optional | ||
|
|
||
| from samcli.commands.list.cli_common.list_common_context import ListContext | ||
| from samcli.lib.list.testable_resources.testable_resources_producer import TestableResourcesProducer | ||
| from samcli.lib.list.mapper_consumer_factory import MapperConsumerFactory | ||
| from samcli.lib.list.list_interfaces import ProducersEnum | ||
|
|
||
| LOG = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class TestableResourcesContext(ListContext): | ||
| """ | ||
| Context class for testable resources | ||
| """ | ||
|
|
||
| def __init__( | ||
| self, stack_name: str, output: str, region: Optional[str], profile: Optional[str], template_file: Optional[str] | ||
| ): | ||
| """ | ||
| Parameters | ||
| ---------- | ||
| stack_name: str | ||
| The name of the stack | ||
| output: str | ||
| The format of the output, either json or table | ||
| region: Optional[str] | ||
| The region of the stack | ||
| profile: Optional[str] | ||
| Optional profile to be used | ||
| template_file: Optional[str] | ||
| The location of the template file. If one is not specified, the default will be "template.yaml" in the CWD | ||
| """ | ||
| super().__init__() | ||
| self.stack_name = stack_name | ||
| self.output = output | ||
| self.region = region | ||
| self.profile = profile | ||
| self.template_file = template_file | ||
| self.iam_client = None | ||
| self.cloudcontrol_client = None | ||
| self.apigateway_client = None | ||
| self.apigatewayv2_client = None | ||
|
|
||
| def __enter__(self): | ||
| self.init_clients() | ||
| return self | ||
|
|
||
| def __exit__(self, *args): | ||
| pass | ||
|
|
||
| def init_clients(self) -> None: | ||
| """ | ||
| Initialize the clients being used by sam list. | ||
| """ | ||
| super().init_clients() | ||
| self.iam_client = self.client_provider("iam") | ||
| self.cloudcontrol_client = self.client_provider("cloudcontrol") | ||
| self.apigateway_client = self.client_provider("apigateway") | ||
| self.apigatewayv2_client = self.client_provider("apigatewayv2") | ||
|
|
||
| def run(self) -> None: | ||
| """ | ||
| Get the resources for a stack | ||
| """ | ||
| factory = MapperConsumerFactory() | ||
| container = factory.create(producer=ProducersEnum.TESTABLE_RESOURCES_PRODUCER, output=self.output) | ||
| testable_resource_producer = TestableResourcesProducer( | ||
| stack_name=self.stack_name, | ||
| region=self.region, | ||
| profile=self.profile, | ||
| template_file=self.template_file, | ||
| cloudformation_client=self.cloudformation_client, | ||
| iam_client=self.iam_client, | ||
| cloudcontrol_client=self.cloudcontrol_client, | ||
| apigateway_client=self.apigateway_client, | ||
| apigatewayv2_client=self.apigatewayv2_client, | ||
| mapper=container.mapper, | ||
| consumer=container.consumer, | ||
| ) | ||
| testable_resource_producer.produce() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,14 +4,48 @@ | |
| from samcli.lib.list.list_interfaces import MapperConsumerFactoryInterface | ||
| from samcli.lib.list.data_to_json_mapper import DataToJsonMapper | ||
| from samcli.commands.list.json_consumer import StringConsumerJsonOutput | ||
| from samcli.commands.list.table_consumer import StringConsumerTableOutput | ||
| from samcli.lib.list.mapper_consumer_container import MapperConsumerContainer | ||
| from samcli.lib.list.list_interfaces import ProducersEnum | ||
| from samcli.lib.list.stack_outputs.stack_output_to_table_mapper import StackOutputToTableMapper | ||
| from samcli.lib.list.resources.resources_to_table_mapper import ResourcesToTableMapper | ||
| from samcli.lib.list.testable_resources.testable_resources_to_table_mapper import TestableResourcesToTableMapper | ||
| from samcli.lib.list.list_interfaces import ProducersEnum, Mapper | ||
|
|
||
|
|
||
| class MapperConsumerFactory(MapperConsumerFactoryInterface): | ||
| """ | ||
| Factory class to create factory objects that map a given producer and output format to a mapper and a consumer | ||
| """ | ||
|
|
||
| def create(self, producer: ProducersEnum, output: str) -> MapperConsumerContainer: | ||
| # Will add conditions here to return different sorts of containers later on | ||
| data_to_json_mapper = DataToJsonMapper() | ||
| json_consumer = StringConsumerJsonOutput() | ||
| container = MapperConsumerContainer(data_to_json_mapper, json_consumer) | ||
| """ | ||
| Creates a MapperConsumerContainer that contains the resulting mapper and consumer given | ||
| the producer and output format | ||
|
|
||
| Parameters | ||
| ---------- | ||
| producer: ProducersEnum | ||
| An enum representing the producers (stack-outputs, resources, or testable-resources producer) | ||
| output: str | ||
| The output format, either json or table | ||
|
|
||
| Returns | ||
| ------- | ||
| container: MapperConsumerContainer | ||
| A MapperConsumerContainer containing the resulting mapper and consumer to be used by the producer | ||
| """ | ||
| if output == "json": | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something to think about: could we have this more generally across SAM CLI commands, instead of re-implementing for each? Similar to how AWS CLI has This would help tremendously in providing a consistent experience, and many commands would improve with parsable outputs (e.g. |
||
| data_to_json_mapper = DataToJsonMapper() | ||
| json_consumer = StringConsumerJsonOutput() | ||
| container = MapperConsumerContainer(data_to_json_mapper, json_consumer) | ||
| return container | ||
| table_mapper: Mapper | ||
| table_consumer = StringConsumerTableOutput() | ||
| if producer == ProducersEnum.STACK_OUTPUTS_PRODUCER: | ||
| table_mapper = StackOutputToTableMapper() | ||
| elif producer == ProducersEnum.RESOURCES_PRODUCER: | ||
| table_mapper = ResourcesToTableMapper() | ||
| elif producer == ProducersEnum.TESTABLE_RESOURCES_PRODUCER: | ||
| table_mapper = TestableResourcesToTableMapper() | ||
| container = MapperConsumerContainer(table_mapper, table_consumer) | ||
| return container | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| """ | ||
| Implementation of the resources to table mapper | ||
| """ | ||
| from typing import Dict, Any | ||
| from collections import OrderedDict | ||
| from samcli.lib.list.list_interfaces import Mapper | ||
|
|
||
|
|
||
| class ResourcesToTableMapper(Mapper): | ||
| """ | ||
| Mapper class for mapping resources data for table output | ||
| """ | ||
|
|
||
| def map(self, data: list) -> Dict[Any, Any]: | ||
| """ | ||
| Maps data to the format needed for consumption by the table consumer | ||
|
|
||
| Parameters | ||
| ---------- | ||
| data: list | ||
| List of dictionaries containing the entries of the resources data | ||
|
|
||
| Returns | ||
| ------- | ||
| table_data: Dict[Any, Any] | ||
| Dictionary containing the information and data needed for the table | ||
| consumer to output the data in table format | ||
| """ | ||
| entry_list = [] | ||
| for resource in data: | ||
| entry_list.append( | ||
| [ | ||
| resource.get("LogicalResourceId", "-"), | ||
| resource.get("PhysicalResourceId", "-"), | ||
| ] | ||
| ) | ||
| table_data = { | ||
| "format_string": "{Logical ID:<{0}} {Physical ID:<{1}}", | ||
| "format_args": OrderedDict( | ||
| { | ||
| "Logical ID": "Logical ID", | ||
| "Physical ID": "Physical ID", | ||
| } | ||
| ), | ||
| "table_name": "Resources", | ||
| "data": entry_list, | ||
| } | ||
| return table_data |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| """ | ||
| Implementation of the stack output to table mapper | ||
| """ | ||
| from typing import Dict, Any | ||
| from collections import OrderedDict | ||
| from samcli.lib.list.list_interfaces import Mapper | ||
|
|
||
|
|
||
| class StackOutputToTableMapper(Mapper): | ||
| """ | ||
| Mapper class for mapping stack-outputs data for table output | ||
| """ | ||
|
|
||
| def map(self, data: list) -> Dict[Any, Any]: | ||
| """ | ||
| Maps data to the format needed for consumption by the table consumer | ||
|
|
||
| Parameters | ||
| ---------- | ||
| data: list | ||
| List of dictionaries containing the entries of the stack outputs data | ||
|
|
||
| Returns | ||
| ------- | ||
| table_data: Dict[Any, Any] | ||
| Dictionary containing the information and data needed for the table consumer | ||
| to output the data in table format | ||
| """ | ||
| entry_list = [] | ||
| for stack_output in data: | ||
| entry_list.append( | ||
| [ | ||
| stack_output.get("OutputKey", "-"), | ||
| stack_output.get("OutputValue", "-"), | ||
| stack_output.get("Description", "-"), | ||
| ] | ||
| ) | ||
| table_data = { | ||
| "format_string": "{OutputKey:<{0}} {OutputValue:<{1}} {Description:<{2}}", | ||
| "format_args": OrderedDict( | ||
| {"OutputKey": "OutputKey", "OutputValue": "OutputValue", "Description": "Description"} | ||
| ), | ||
| "table_name": "Stack Outputs", | ||
| "data": entry_list, | ||
| } | ||
| return table_data |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| """ | ||
| The container for Testable Resources | ||
| """ | ||
| from typing import Any | ||
| from dataclasses import dataclass | ||
|
|
||
|
|
||
| @dataclass | ||
| class TestableResDef: | ||
| """ | ||
| Dataclass for containing entries of testable resources data | ||
| """ | ||
|
|
||
| LogicalResourceId: str | ||
| PhysicalResourceId: str | ||
| CloudEndpointOrFunctionURL: Any | ||
| Methods: Any |
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.
Lets ensure that every class and function has docstrings as well as call parameters explained.
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.
Added docstrings