diff --git a/samcli/cli/command.py b/samcli/cli/command.py index a5ba816847..c941f1b3bc 100644 --- a/samcli/cli/command.py +++ b/samcli/cli/command.py @@ -9,9 +9,9 @@ import click from click import Group -from samcli.cli.formatters import RootCommandHelpTextFormatter +from samcli.cli.formatters import RootCommandHelpTextFormatter, get_terminal_width from samcli.cli.root.command_list import SAM_CLI_COMMANDS -from samcli.cli.row_modifiers import HighlightNewRowNameModifier, RowDefinition, ShowcaseRowModifier +from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier logger = logging.getLogger(__name__) @@ -62,6 +62,18 @@ class BaseCommand(Group): class CustomFormatterContext(click.Context): formatter_class = RootCommandHelpTextFormatter + def __init__(self, *args, **kwargs): + if "max_content_width" not in kwargs: + kwargs["max_content_width"] = 140 + # Explicitly set terminal width if not provided to ensure proper text wrapping + # Apply right padding to prevent text from wrapping at the terminal edge + if "terminal_width" not in kwargs: + terminal_width = get_terminal_width() + if terminal_width is not None: + # Apply padding but ensure minimum width of 60 + kwargs["terminal_width"] = max(terminal_width - 5, 60) + super().__init__(*args, **kwargs) + context_class = CustomFormatterContext def __init__(self, *args, cmd_packages=None, **kwargs): @@ -106,7 +118,8 @@ def format_options(self, ctx: click.Context, formatter: RootCommandHelpTextForma # mypy raises argument needs to be HelpFormatter as super class defines it. # NOTE(sriram-mv): Re-order options so that they come after the commands. self.format_commands(ctx, formatter) - opts = [RowDefinition(name="", text="\n")] + + opts = [] for param in self.get_params(ctx): row = param.get_help_record(ctx) if row is not None: @@ -118,19 +131,15 @@ def format_options(self, ctx: click.Context, formatter: RootCommandHelpTextForma formatter.write_rd(opts) with formatter.indented_section(name="Examples", extra_indents=1): - formatter.write_rd( - [ - RowDefinition( - name="", - text="\n", - ), - RowDefinition( - name="Get Started:", - text=click.style(f"$ {ctx.command_path} init"), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - ], - ) + with formatter.indented_section(name="Get Started", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=click.style(f"$ {ctx.command_path} init"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ], + ) def format_commands(self, ctx: click.Context, formatter: RootCommandHelpTextFormatter): # type: ignore # NOTE(sriram-mv): `ignore` is put in place here for mypy even though it is the correct behavior, @@ -138,13 +147,12 @@ def format_commands(self, ctx: click.Context, formatter: RootCommandHelpTextForm # mypy raises argument needs to be HelpFormatter as super class defines it. with formatter.section("Commands"): with formatter.section("Learn"): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name="docs", text=SAM_CLI_COMMANDS.get("docs", ""), - extra_row_modifiers=[HighlightNewRowNameModifier()], - ) + ), ] ) @@ -173,12 +181,10 @@ def format_commands(self, ctx: click.Context, formatter: RootCommandHelpTextForm RowDefinition( name="sync", text=SAM_CLI_COMMANDS.get("sync", ""), - extra_row_modifiers=[HighlightNewRowNameModifier()], ), RowDefinition( name="remote", text=SAM_CLI_COMMANDS.get("remote", ""), - extra_row_modifiers=[HighlightNewRowNameModifier()], ), ], ) @@ -217,7 +223,6 @@ def format_commands(self, ctx: click.Context, formatter: RootCommandHelpTextForm RowDefinition( name="list", text=SAM_CLI_COMMANDS.get("list", ""), - extra_row_modifiers=[HighlightNewRowNameModifier()], ), RowDefinition( name="delete", diff --git a/samcli/cli/core/command.py b/samcli/cli/core/command.py index 7c45f71aa0..969cdac9f6 100644 --- a/samcli/cli/core/command.py +++ b/samcli/cli/core/command.py @@ -26,10 +26,9 @@ def __init__(self, description, requires_credentials=False, *args, **kwargs): def format_description(self, formatter: RootCommandHelpTextFormatter): with formatter.indented_section(name="Description", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( - text="", name=self.description + self.description_addendum, ), ], @@ -55,17 +54,21 @@ def _format_options( ], key=lambda row_def: row_def.rank, ) + extras = options.get("extras", []) + + # Skip section entirely if no options and no extras + if not opts and not extras: + continue + with formatter.indented_section(name=option_heading, extra_indents=1): - formatter.write_rd(options.get("extras", [RowDefinition()]), **write_rd_overrides) - formatter.write_rd( - [RowDefinition(name="", text="\n")] - + [ - opt - for options in zip(opts, [RowDefinition(name="", text="\n")] * (len(opts))) - for opt in options - ], - **write_rd_overrides, - ) + rows = [] + if extras: + rows.extend(extras) + + if opts: + rows.extend(opts) + + formatter.write_rd(rows, **write_rd_overrides) @staticmethod def convert_param_to_row_definition(ctx: Context, param: Parameter, rank: int): diff --git a/samcli/cli/formatters.py b/samcli/cli/formatters.py index 6a907cec36..c1c6db0def 100644 --- a/samcli/cli/formatters.py +++ b/samcli/cli/formatters.py @@ -2,6 +2,7 @@ Click Help Formatter Classes that are customized for the root command. """ +import shutil from contextlib import contextmanager from typing import Iterator, Optional, Sequence @@ -11,9 +12,24 @@ from samcli.cli.row_modifiers import BaseLineRowModifier, RowDefinition +def get_terminal_width() -> Optional[int]: + """ + Get the current terminal width. + + Returns + ------- + Optional[int] + Terminal width in columns, or None if it cannot be determined. + """ + try: + return shutil.get_terminal_size().columns + except (AttributeError, ValueError, OSError): + return None + + class RootCommandHelpTextFormatter(HelpFormatter): # Picked an additive constant that gives an aesthetically pleasing look. - ADDITIVE_JUSTIFICATION = 10 + ADDITIVE_JUSTIFICATION = 6 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -27,6 +43,14 @@ def __init__(self, *args, **kwargs): self.modifiers = [BaseLineRowModifier()] def write_usage(self, prog: str, args: str = "", prefix: Optional[str] = None) -> None: + """Write the usage line with bold and underlined 'Usage:' prefix and a leading blank line.""" + if prefix is None: + prefix = style("Usage:", bold=True, underline=True) + " " + else: + prefix = style(prefix, bold=True, underline=True) + + # Add a blank line before usage + self.write("\n") super().write_usage(prog=style(prog, bold=True), args=args, prefix=prefix) def write_heading(self, heading: str) -> None: @@ -48,6 +72,28 @@ def write_rd( super().write_dl(modified_rows, col_max=col_max, col_spacing=col_spacing) + def write_text_rows( + self, + rows: Sequence[RowDefinition], + ) -> None: + """Write single-column text rows without two-column layout constraints. + + This is useful for "examples" or other content that should appear as simple + indented text without the padding and wrapping behavior of write_dl. + + Parameters + ---------- + rows : Sequence[RowDefinition] + Rows to write. Only the 'name' field and 'extra_row_modifiers' are used. + """ + for row in rows: + extra_row_modifiers = row.extra_row_modifiers or [] + modified_row = row + for row_modifier in self.modifiers + extra_row_modifiers: + modified_row = row_modifier.apply(row=modified_row, justification_length=self.left_justification_length) + # Write the content with current indentation, no padding + self.write(f"{'':>{self.current_indent}}{modified_row.name.rstrip()}\n") + @contextmanager def section(self, name: str) -> Iterator[None]: with super().section(style(name, bold=True, underline=True)): diff --git a/samcli/cli/lazy_group.py b/samcli/cli/lazy_group.py index 4c37beb2a6..50bd281016 100644 --- a/samcli/cli/lazy_group.py +++ b/samcli/cli/lazy_group.py @@ -7,13 +7,67 @@ import click from click import ClickException +from samcli.cli.formatters import RootCommandHelpTextFormatter +from samcli.cli.row_modifiers import HighlightNewRowNameModifier, RowDefinition + class LazyGroup(click.Group): - def __init__(self, *args, lazy_subcommands=None, **kwargs): + class CustomFormatterContext(click.Context): + formatter_class = RootCommandHelpTextFormatter + + def __init__(self, *args, **kwargs): + if "max_content_width" not in kwargs: + kwargs["max_content_width"] = 140 + super().__init__(*args, **kwargs) + + context_class = CustomFormatterContext + + def __init__(self, *args, lazy_subcommands=None, new_commands=None, **kwargs): + # Set context_settings to use our custom formatter + if "context_settings" not in kwargs: + kwargs["context_settings"] = {} + kwargs["context_settings"]["help_option_names"] = ["-h", "--help"] + super().__init__(*args, **kwargs) # lazy_subcommands is a map of the form: # {command-name} -> {module-name}.{command-object-name} self.lazy_subcommands = lazy_subcommands or {} + # new_commands is a set of command names that should be marked as NEW + self.new_commands = new_commands or set() + + @staticmethod + def _write_rows_with_spacing(formatter: RootCommandHelpTextFormatter, section_name: str, rows: list): + """Helper method to write rows.""" + if rows: + with formatter.indented_section(name=section_name, extra_indents=1): + formatter.write_rd(rows) + + def format_options(self, ctx: click.Context, formatter: RootCommandHelpTextFormatter): # type: ignore + """Format options with spacing between each option.""" + opts = [ + RowDefinition(name=rv[0], text=rv[1]) + for param in self.get_params(ctx) + if (rv := param.get_help_record(ctx)) is not None + ] + + self._write_rows_with_spacing(formatter, "Options", opts) + + # Call format_commands to show the subcommands + self.format_commands(ctx, formatter) + + def format_commands(self, ctx: click.Context, formatter: RootCommandHelpTextFormatter): # type: ignore + """Format commands with spacing between each command.""" + commands = [ + RowDefinition( + name=subcommand, + text=cmd.get_short_help_str(limit=formatter.width), + extra_row_modifiers=[HighlightNewRowNameModifier()] if subcommand in self.new_commands else [], + ) + for subcommand in self.list_commands(ctx) + if (cmd := self.get_command(ctx, subcommand)) is not None and not (hasattr(cmd, "hidden") and cmd.hidden) + ] + + self._write_rows_with_spacing(formatter, "Commands", commands) def list_commands(self, ctx): base = super().list_commands(ctx) diff --git a/samcli/commands/build/core/command.py b/samcli/commands/build/core/command.py index c3e3e2479e..8405a8881f 100644 --- a/samcli/commands/build/core/command.py +++ b/samcli/commands/build/core/command.py @@ -6,52 +6,85 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.build.core.formatters import BuildCommandHelpTextFormatter -from samcli.commands.build.core.options import OPTIONS_INFO +from samcli.commands.build.core.options import ALL_OPTIONS, OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter class BuildCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = BuildCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + additive_justification=3, + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: BuildCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): - formatter.write_rd( - [ - RowDefinition( - text="\n", - ), - RowDefinition( - name=style(f"$ {ctx.command_path}"), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - RowDefinition( - name=style(f"$ {ctx.command_path} FUNCTION_LOGICAL_ID"), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - RowDefinition( - name=style(f"$ {ctx.command_path} --use-container"), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - RowDefinition( - name=style(f"$ {ctx.command_path} --use-container --container-env-var-file env.json"), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - RowDefinition( - name=style(f"$ {ctx.command_path} && {ctx.parent.command_path} local invoke"), # type: ignore - extra_row_modifiers=[ShowcaseRowModifier()], - ), - RowDefinition( - name=style(f"$ {ctx.command_path} && {ctx.parent.command_path} deploy"), # type: ignore - extra_row_modifiers=[ShowcaseRowModifier()], - ), - ], - ) + with formatter.indented_section(name="Build sam project", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path}"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + with formatter.indented_section(name="Build sam project for a specific function", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} FUNCTION_LOGICAL_ID"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + with formatter.indented_section(name="Build sam project using container", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} --use-container"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + with formatter.indented_section( + name="Build sam project using container with environment variable file", extra_indents=1 + ): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} --use-container --container-env-var-file env.json"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + with formatter.indented_section( + name="Build sam project and invoke default function locally", extra_indents=1 + ): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} && {ctx.parent.command_path} local invoke"), # type: ignore + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + with formatter.indented_section(name="Build sam project and deploy", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} && {ctx.parent.command_path} deploy"), # type: ignore + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) - def format_options(self, ctx: Context, formatter: BuildCommandHelpTextFormatter) -> None: # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore # NOTE(sriram-mv): `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/build/core/formatters.py b/samcli/commands/build/core/formatters.py deleted file mode 100644 index 6444732a21..0000000000 --- a/samcli/commands/build/core/formatters.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Build Command Formatter. -""" - -from samcli.cli.formatters import RootCommandHelpTextFormatter -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.build.core.options import ALL_OPTIONS - - -class BuildCommandHelpTextFormatter(RootCommandHelpTextFormatter): - ADDITIVE_JUSTIFICATION = 8 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # NOTE(sriram-mv): Add Additional space after determining the longest option. - # However, do not justify with padding for more than half the width of - # the terminal to retain aesthetics. - self.left_justification_length = min( - max([len(option) for option in ALL_OPTIONS]) + self.ADDITIVE_JUSTIFICATION, - self.width // 2 - self.indent_increment, - ) - self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/build/core/options.py b/samcli/commands/build/core/options.py index dfb1094361..b0214f44fb 100644 --- a/samcli/commands/build/core/options.py +++ b/samcli/commands/build/core/options.py @@ -69,10 +69,9 @@ "Configuration Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, "extras": [ - RowDefinition(name="Learn more about configuration files at:"), RowDefinition( - name="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli" - "-config.html. " + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." ), ], }, diff --git a/samcli/commands/common/formatters.py b/samcli/commands/common/formatters.py index cf31ba588b..faed4485a9 100644 --- a/samcli/commands/common/formatters.py +++ b/samcli/commands/common/formatters.py @@ -2,21 +2,45 @@ Shared formatter for all SAM CLI commands. """ -from samcli.cli.formatters import RootCommandHelpTextFormatter +from samcli.cli.formatters import RootCommandHelpTextFormatter, get_terminal_width from samcli.cli.row_modifiers import BaseLineRowModifier class CommandHelpTextFormatter(RootCommandHelpTextFormatter): """ - Shared formatter for command help text. + Shared formatter for command help text with configurable justification. """ - ADDITIVE_JUSTIFICATION = 17 + DEFAULT_ADDITIVE_JUSTIFICATION = 6 - def __init__(self, options, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self, options, additive_justification=None, width=None, *args, **kwargs): + """ + Initialize the formatter. + + Parameters + ---------- + options : List[str] + List of option names for calculating justification length + additive_justification : int, optional + Override the default additive justification value. + If not provided, uses DEFAULT_ADDITIVE_JUSTIFICATION (6). + width : int, optional + Terminal width. If None, will attempt to detect terminal width. + """ + # If width is None, try to detect terminal width and apply padding + if width is None: + detected_width = get_terminal_width() + if detected_width is not None: + # Apply padding but ensure minimum width of 60 + width = max(detected_width - 5, 60) + + super().__init__(width=width, *args, **kwargs) + justification = ( + additive_justification if additive_justification is not None else self.DEFAULT_ADDITIVE_JUSTIFICATION + ) + max_option_length = max([len(option) for option in options]) if options else 0 self.left_justification_length = min( - max([len(option) for option in options]) + self.ADDITIVE_JUSTIFICATION, + max_option_length + justification, self.width // 2 - self.indent_increment, ) self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/delete/command.py b/samcli/commands/delete/command.py index 8c012b065f..d2a42963b8 100644 --- a/samcli/commands/delete/command.py +++ b/samcli/commands/delete/command.py @@ -10,6 +10,7 @@ from samcli.cli.cli_config_file import ConfigProvider, configuration_option, save_params_option from samcli.cli.main import aws_creds_options, common_options, pass_context, print_cmdline_args from samcli.commands._utils.command_exception_handler import command_exception_handler +from samcli.commands.delete.core.command import DeleteCommand from samcli.commands.delete.delete_context import CONFIG_COMMAND, CONFIG_SECTION from samcli.lib.telemetry.metric import track_command from samcli.lib.utils.version_checker import check_newer_version @@ -20,14 +21,23 @@ stack and all the artifacts which were created using sam deploy. """ +DESCRIPTION = """ + Delete an AWS SAM application by deleting the AWS CloudFormation stack, + the artifacts which were packaged and deployed to Amazon S3 and Amazon ECR, + and the AWS CloudFormation template file from the Amazon S3 bucket. +""" + LOG = logging.getLogger(__name__) @click.command( "delete", + cls=DeleteCommand, short_help=SHORT_HELP, - context_settings={"ignore_unknown_options": False, "allow_interspersed_args": True, "allow_extra_args": True}, help=HELP_TEXT, + description=DESCRIPTION, + requires_credentials=True, + context_settings={"ignore_unknown_options": False, "allow_interspersed_args": True, "allow_extra_args": True}, ) @configuration_option(provider=ConfigProvider(CONFIG_SECTION, [CONFIG_COMMAND])) @click.option( diff --git a/samcli/commands/delete/core/__init__.py b/samcli/commands/delete/core/__init__.py new file mode 100644 index 0000000000..0fa25a0871 --- /dev/null +++ b/samcli/commands/delete/core/__init__.py @@ -0,0 +1,3 @@ +""" +Delete Core Command +""" diff --git a/samcli/commands/delete/core/command.py b/samcli/commands/delete/core/command.py new file mode 100644 index 0000000000..0ea4affdf0 --- /dev/null +++ b/samcli/commands/delete/core/command.py @@ -0,0 +1,51 @@ +""" +Delete Command Class +""" + +from click import Context, style + +from samcli.cli.core.command import CoreCommand +from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.delete.core.options import ALL_OPTIONS, OPTIONS_INFO + + +class DeleteCommand(CoreCommand): + class CustomFormatterContext(Context): + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) + + context_class = CustomFormatterContext + + @staticmethod + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): + with formatter.indented_section(name="Examples", extra_indents=1): + with formatter.indented_section(name="Delete a SAM application", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} --stack-name my-stack"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + with formatter.indented_section(name="Delete without prompts", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} --stack-name my-stack --no-prompts"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter): # type: ignore + self.format_description(formatter) + DeleteCommand.format_examples(ctx, formatter) + CoreCommand._format_options( + ctx=ctx, params=self.get_params(ctx), formatter=formatter, formatting_options=OPTIONS_INFO + ) diff --git a/samcli/commands/delete/core/options.py b/samcli/commands/delete/core/options.py new file mode 100644 index 0000000000..af7b95d8cf --- /dev/null +++ b/samcli/commands/delete/core/options.py @@ -0,0 +1,32 @@ +""" +Delete Command Options +""" + +from typing import Dict + +from samcli.cli.core.options import ALL_COMMON_OPTIONS, add_common_options_info +from samcli.cli.row_modifiers import RowDefinition + +DELETE_OPTION_NAMES = ["stack_name", "no_prompts", "s3_bucket", "s3_prefix"] +AWS_CREDENTIAL_OPTION_NAMES = ["region", "profile"] +CONFIGURATION_OPTION_NAMES = ["config_file", "config_env", "save_params"] + +ALL_OPTIONS = DELETE_OPTION_NAMES + AWS_CREDENTIAL_OPTION_NAMES + CONFIGURATION_OPTION_NAMES + ALL_COMMON_OPTIONS + +OPTIONS_INFO: Dict[str, Dict] = { + "Delete Options": {"option_names": {opt: {"rank": idx} for idx, opt in enumerate(DELETE_OPTION_NAMES)}}, + "AWS Credential Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(AWS_CREDENTIAL_OPTION_NAMES)} + }, + "Configuration Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, + "extras": [ + RowDefinition( + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." + ), + ], + }, +} + +add_common_options_info(OPTIONS_INFO) diff --git a/samcli/commands/deploy/core/command.py b/samcli/commands/deploy/core/command.py index 7d5691ee56..6c2e8c285c 100644 --- a/samcli/commands/deploy/core/command.py +++ b/samcli/commands/deploy/core/command.py @@ -2,61 +2,80 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.deploy.core.formatters import DeployCommandHelpTextFormatter -from samcli.commands.deploy.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.deploy.core.options import ALL_OPTIONS, OPTIONS_INFO COL_SIZE_MODIFIER = 38 class DeployCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = DeployCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: DeployCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): - formatter.write_rd( - [ - RowDefinition( - text="\n", - ), - RowDefinition( - name=style(f"$ {ctx.command_path} --guided"), extra_row_modifiers=[ShowcaseRowModifier()] - ), - RowDefinition( - name=style( - f"$ {ctx.command_path} --template-file packaged.yaml --stack-name " - f"sam-app --capabilities CAPABILITY_IAM" + with formatter.indented_section(name="Deploy with guided prompts", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} --guided"), + extra_row_modifiers=[ShowcaseRowModifier()], ), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - RowDefinition( - name=style( - f"$ {ctx.command_path} --parameter-overrides " - f"'ParameterKey=InstanceType,ParameterValue=t1.micro'" + ] + ) + with formatter.indented_section(name="Deploy with specified parameters", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style( + f"$ {ctx.command_path} --template-file packaged.yaml --stack-name " + f"sam-app --capabilities CAPABILITY_IAM" + ), + extra_row_modifiers=[ShowcaseRowModifier()], ), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - RowDefinition( - name=style( - f"$ {ctx.command_path} --parameter-overrides KeyPairName=MyKey InstanceType=t1.micro" + ] + ) + with formatter.indented_section( + name="Deploy with parameter overrides using CloudFormation syntax", extra_indents=1 + ): + formatter.write_text_rows( + [ + RowDefinition( + name=style( + f"$ {ctx.command_path} --parameter-overrides " + f"'ParameterKey=InstanceType,ParameterValue=t1.micro'" + ), + extra_row_modifiers=[ShowcaseRowModifier()], ), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - ], - col_max=COL_SIZE_MODIFIER, - ) + ] + ) + with formatter.indented_section( + name="Deploy with parameter overrides using shorthand syntax", extra_indents=1 + ): + formatter.write_text_rows( + [ + RowDefinition( + name=style( + f"$ {ctx.command_path} --parameter-overrides KeyPairName=MyKey InstanceType=t1.micro" + ), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) @staticmethod - def format_acronyms(formatter: DeployCommandHelpTextFormatter): + def format_acronyms(formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Acronyms", extra_indents=1): formatter.write_rd( [ - RowDefinition( - text="\n", - ), RowDefinition( name="IAM", text="Identity and Access Management", @@ -91,7 +110,7 @@ def format_acronyms(formatter: DeployCommandHelpTextFormatter): col_max=COL_SIZE_MODIFIER, ) - def format_options(self, ctx: Context, formatter: DeployCommandHelpTextFormatter) -> None: # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore # `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/deploy/core/formatters.py b/samcli/commands/deploy/core/formatters.py deleted file mode 100644 index 52abd37519..0000000000 --- a/samcli/commands/deploy/core/formatters.py +++ /dev/null @@ -1,19 +0,0 @@ -from samcli.cli.formatters import RootCommandHelpTextFormatter -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.deploy.core.options import ALL_OPTIONS - - -class DeployCommandHelpTextFormatter(RootCommandHelpTextFormatter): - # Picked an additive constant that gives an aesthetically pleasing look. - ADDITIVE_JUSTIFICATION = 15 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # Add Additional space after determining the longest option. - # However, do not justify with padding for more than half the width of - # the terminal to retain aesthetics. - self.left_justification_length = min( - max([len(option) for option in ALL_OPTIONS]) + self.ADDITIVE_JUSTIFICATION, - self.width // 2 - self.indent_increment, - ) - self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/deploy/core/options.py b/samcli/commands/deploy/core/options.py index 44503368af..526271be65 100644 --- a/samcli/commands/deploy/core/options.py +++ b/samcli/commands/deploy/core/options.py @@ -78,10 +78,9 @@ "Configuration Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, "extras": [ - RowDefinition(name="Learn more about configuration files at:"), RowDefinition( - name="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli" - "-config.html. " + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." ), ], }, diff --git a/samcli/commands/docs/core/command.py b/samcli/commands/docs/core/command.py index b8220bfe73..788523d043 100644 --- a/samcli/commands/docs/core/command.py +++ b/samcli/commands/docs/core/command.py @@ -11,13 +11,13 @@ from samcli.commands.docs.command_context import COMMAND_NAME, DocsCommandContext from samcli.commands.docs.core.formatter import DocsCommandHelpTextFormatter -HELP_TEXT = "NEW! Open the documentation in a browser." +HELP_TEXT = "Open the documentation in a browser." DESCRIPTION = """ Launch the AWS SAM CLI documentation in a browser! This command will show information about setting up credentials, the AWS SAM CLI lifecycle and other useful details. - The command also be run with sub-commands to open specific pages. + The command can also be run with sub-commands to open specific pages. """ @@ -46,7 +46,7 @@ def format_description(formatter: DocsCommandHelpTextFormatter): A formatter instance to use for formatting the help text """ with formatter.indented_section(name="Description", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( text="", diff --git a/samcli/commands/init/core/command.py b/samcli/commands/init/core/command.py index 2e1697b527..2a0fb13162 100644 --- a/samcli/commands/init/core/command.py +++ b/samcli/commands/init/core/command.py @@ -2,34 +2,34 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.init.core.formatters import InitCommandHelpTextFormatter -from samcli.commands.init.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.init.core.options import ALL_OPTIONS, OPTIONS_INFO class InitCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = InitCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + additive_justification=10, + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: InitCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Interactive Mode", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition(name=style(f"$ {ctx.command_path}"), extra_row_modifiers=[ShowcaseRowModifier()]), ] ) with formatter.indented_section(name="Customized Interactive Mode", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} --name sam-app --runtime nodejs18.x --architecture arm64" @@ -52,11 +52,8 @@ def format_examples(ctx: Context, formatter: InitCommandHelpTextFormatter): ] ) with formatter.indented_section(name="Direct Initialization", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} --location gh:aws-samples/cookiecutter-aws-sam-python"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -83,7 +80,7 @@ def format_examples(ctx: Context, formatter: InitCommandHelpTextFormatter): ], ) - def format_options(self, ctx: Context, formatter: InitCommandHelpTextFormatter) -> None: # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore # `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/init/core/formatters.py b/samcli/commands/init/core/formatters.py deleted file mode 100644 index 2ee8ac2f8c..0000000000 --- a/samcli/commands/init/core/formatters.py +++ /dev/null @@ -1,19 +0,0 @@ -from samcli.cli.formatters import RootCommandHelpTextFormatter -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.init.core.options import ALL_OPTIONS - - -class InitCommandHelpTextFormatter(RootCommandHelpTextFormatter): - # Picked an additive constant that gives an aesthetically pleasing look. - ADDITIVE_JUSTIFICATION = 10 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # Add Additional space after determining the longest option. - # However, do not justify with padding for more than half the width of - # the terminal to retain aesthetics. - self.left_justification_length = min( - max([len(option) for option in ALL_OPTIONS]) + self.ADDITIVE_JUSTIFICATION, - self.width // 2 - self.indent_increment, - ) - self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/init/core/options.py b/samcli/commands/init/core/options.py index 291c2801a3..f6c2c8ce2e 100644 --- a/samcli/commands/init/core/options.py +++ b/samcli/commands/init/core/options.py @@ -35,7 +35,6 @@ OPTIONS_INFO: Dict[str, Dict] = { "Application Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(APPLICATION_OPTIONS)}, - "extras": [RowDefinition(name="")], }, "Non Interactive Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(NON_INTERACTIVE_OPTIONS)} @@ -43,10 +42,8 @@ "Configuration Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, "extras": [ - RowDefinition(name="Learn more about configuration files at:"), RowDefinition( - name="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli" - "-config.html. " + name="Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." ), ], }, diff --git a/samcli/commands/local/callback/fail/core/command.py b/samcli/commands/local/callback/fail/core/command.py index 922c436f5c..123c7ffa07 100644 --- a/samcli/commands/local/callback/fail/core/command.py +++ b/samcli/commands/local/callback/fail/core/command.py @@ -28,9 +28,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): """Format command examples for help text""" with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Send failure callback with no parameters", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(f"$ {ctx.command_path} my-callback-id"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -39,9 +38,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): ) with formatter.indented_section(name="Send failure callback with error message", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(f"$ {ctx.command_path} my-callback-id --error-message 'Task failed'"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -57,9 +55,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): f"$ {ctx.command_path} my-callback-id --error-message 'Task failed' " f"--error-type 'ValidationError' --stack-trace 'at line 42' --error-data '{json_data}'" ) - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(command_example), extra_row_modifiers=[ShowcaseRowModifier()], diff --git a/samcli/commands/local/callback/heartbeat/core/command.py b/samcli/commands/local/callback/heartbeat/core/command.py index 5548b1489b..c1203262d2 100644 --- a/samcli/commands/local/callback/heartbeat/core/command.py +++ b/samcli/commands/local/callback/heartbeat/core/command.py @@ -28,9 +28,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): """Format command examples for help text""" with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Send heartbeat callback", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(f"$ {ctx.command_path} my-callback-id"), extra_row_modifiers=[ShowcaseRowModifier()], diff --git a/samcli/commands/local/callback/succeed/core/command.py b/samcli/commands/local/callback/succeed/core/command.py index 2caea5dedb..1ffdf6bd1d 100644 --- a/samcli/commands/local/callback/succeed/core/command.py +++ b/samcli/commands/local/callback/succeed/core/command.py @@ -28,9 +28,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): """Format command examples for help text""" with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Send success callback with no result", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(f"$ {ctx.command_path} my-callback-id"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -39,9 +38,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): ) with formatter.indented_section(name="Send success callback with result", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(f"$ {ctx.command_path} my-callback-id --result 'Task completed successfully'"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -50,9 +48,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): ) with formatter.indented_section(name="Send success callback with short option", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(f"$ {ctx.command_path} my-callback-id -r 'Success result'"), extra_row_modifiers=[ShowcaseRowModifier()], diff --git a/samcli/commands/local/cli_common/options.py b/samcli/commands/local/cli_common/options.py index a154481421..269ba35af8 100644 --- a/samcli/commands/local/cli_common/options.py +++ b/samcli/commands/local/cli_common/options.py @@ -244,15 +244,12 @@ def warm_containers_common_options(f): "--warm-containers", help=""" \b - Optional. Specifies how AWS SAM CLI manages - containers for each function. + Optional. Specifies how AWS SAM CLI manages containers for each function.' + \b Two modes are available: - EAGER: Containers for all functions are - loaded at startup and persist between - invocations. - LAZY: Containers are only loaded when each - function is first invoked. Those containers - persist for additional invocations. + EAGER: Containers for all functions are loaded at startup and persist between invocations. + LAZY: Containers are only loaded when each function is first invoked. + Those containers persist for additional invocations. """, type=click.Choice(ContainersInitializationMode.__members__, case_sensitive=False), ), diff --git a/samcli/commands/local/execution/get/core/command.py b/samcli/commands/local/execution/get/core/command.py index 7cc41ebc59..a668633eab 100644 --- a/samcli/commands/local/execution/get/core/command.py +++ b/samcli/commands/local/execution/get/core/command.py @@ -19,7 +19,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): execution_id = "c63eec67-3415-4eb4-a495-116aa3a86278" with formatter.indented_section(name="Get execution details", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} {execution_id}"), @@ -29,7 +29,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): ) with formatter.indented_section(name="Get execution details in JSON format", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} {execution_id} --format json"), diff --git a/samcli/commands/local/execution/history/core/command.py b/samcli/commands/local/execution/history/core/command.py index 858107d2da..c593571618 100644 --- a/samcli/commands/local/execution/history/core/command.py +++ b/samcli/commands/local/execution/history/core/command.py @@ -19,7 +19,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): execution_id = "c63eec67-3415-4eb4-a495-116aa3a86278" with formatter.indented_section(name="Get execution history", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} {execution_id}"), @@ -29,7 +29,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): ) with formatter.indented_section(name="Get execution history in JSON format", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} {execution_id} --format json"), diff --git a/samcli/commands/local/execution/stop/core/command.py b/samcli/commands/local/execution/stop/core/command.py index e73e7bccaf..d0d7425c3b 100644 --- a/samcli/commands/local/execution/stop/core/command.py +++ b/samcli/commands/local/execution/stop/core/command.py @@ -19,7 +19,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): execution_id = "c63eec67-3415-4eb4-a495-116aa3a86278" with formatter.indented_section(name="Stop execution without error details", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} {execution_id}"), @@ -30,7 +30,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Stop execution with error message and type", extra_indents=1): error_options = '--error-message "Execution cancelled" --error-type "UserCancellation"' - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} {execution_id} {error_options}"), @@ -46,7 +46,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): '--error-message "Task failed" --error-type "TaskFailure" --error-data \'{"reason":"timeout"}\' ' '--stack-trace "at function1()" --stack-trace "at function2()"' ) - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} {execution_id} {full_options}"), diff --git a/samcli/commands/local/generate_event/core/command.py b/samcli/commands/local/generate_event/core/command.py index 4f0a1aa72c..fefba668e1 100644 --- a/samcli/commands/local/generate_event/core/command.py +++ b/samcli/commands/local/generate_event/core/command.py @@ -20,23 +20,17 @@ class CustomFormatterContext(Context): def format_examples(ctx: Context, formatter: RootCommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Generate event S3 sends to local Lambda function", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} s3 [put/delete]"), extra_row_modifiers=[ShowcaseRowModifier()], ), ] ) - with formatter.indented_section(name="Customize event by adding parameter flags.", extra_indents=1): - formatter.write_rd( + with formatter.indented_section(name="Customize event by adding parameter flags", extra_indents=1): + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} s3 [put/delete] --help"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -50,11 +44,8 @@ def format_examples(ctx: Context, formatter: RootCommandHelpTextFormatter): with formatter.indented_section( name="Test generated event with serverless function locally!", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} s3 [put/delete] --bucket --key | " @@ -70,7 +61,6 @@ def format_commands(self, ctx: Context, formatter: RootCommandHelpTextFormatter) # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. with formatter.indented_section(name="Commands", extra_indents=1): - formatter.write_rd([RowDefinition(text="\n")]) formatter.write_rd([RowDefinition(name=command) for command in self.all_cmds.keys()]) def format_options(self, ctx: Context, formatter: RootCommandHelpTextFormatter) -> None: # type: ignore diff --git a/samcli/commands/local/invoke/cli.py b/samcli/commands/local/invoke/cli.py index 3363a8348e..af261027e4 100644 --- a/samcli/commands/local/invoke/cli.py +++ b/samcli/commands/local/invoke/cli.py @@ -30,6 +30,14 @@ PortAlreadyInUse, ) + +class HiddenChoice(click.Choice): + """Custom Choice type that hides the list of choices in help text.""" + + def get_metavar(self, param): + return "RUNTIME" + + LOG = logging.getLogger(__name__) HELP_TEXT = """ @@ -71,7 +79,7 @@ @click.option( "-r", "--runtime", - type=click.Choice(get_sorted_runtimes(INIT_RUNTIMES)), + type=HiddenChoice(get_sorted_runtimes(INIT_RUNTIMES), case_sensitive=False), help="Lambda runtime used to invoke the function." + click.style(f"\n\nRuntimes: {', '.join(get_sorted_runtimes(INIT_RUNTIMES))}", bold=True), ) diff --git a/samcli/commands/local/invoke/core/command.py b/samcli/commands/local/invoke/core/command.py index 63346a3250..fac983bbea 100644 --- a/samcli/commands/local/invoke/core/command.py +++ b/samcli/commands/local/invoke/core/command.py @@ -8,25 +8,27 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.local.invoke.core.formatters import InvokeCommandHelpTextFormatter -from samcli.commands.local.invoke.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.local.invoke.core.options import ALL_OPTIONS, OPTIONS_INFO class InvokeCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = InvokeCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: InvokeCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Invoke default Lambda function with no event", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path}"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -34,11 +36,8 @@ def format_examples(ctx: Context, formatter: InvokeCommandHelpTextFormatter): ] ) with formatter.indented_section(name="Invoke named Lambda function with no event", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} HelloWorldFunction"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -46,11 +45,8 @@ def format_examples(ctx: Context, formatter: InvokeCommandHelpTextFormatter): ] ) with formatter.indented_section(name="Invoke named Lambda function with an event file", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} HelloWorldFunction -e event.json"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -58,11 +54,8 @@ def format_examples(ctx: Context, formatter: InvokeCommandHelpTextFormatter): ] ) with formatter.indented_section(name="Invoke Lambda function with stdin input", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ echo {json.dumps({'message':'hello!'})} | " @@ -73,11 +66,8 @@ def format_examples(ctx: Context, formatter: InvokeCommandHelpTextFormatter): ] ) with formatter.indented_section(name="Invoke Lambda function with durable execution name", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} HelloWorldFunction --durable-execution-name my-execution" @@ -87,7 +77,7 @@ def format_examples(ctx: Context, formatter: InvokeCommandHelpTextFormatter): ] ) - def format_options(self, ctx: Context, formatter: InvokeCommandHelpTextFormatter) -> None: # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore # NOTE(sriram-mv): `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/local/invoke/core/formatters.py b/samcli/commands/local/invoke/core/formatters.py deleted file mode 100644 index b08fd9bcb4..0000000000 --- a/samcli/commands/local/invoke/core/formatters.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Invoke Command Formatter. -""" - -from samcli.cli.formatters import RootCommandHelpTextFormatter -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.local.invoke.core.options import ALL_OPTIONS - - -class InvokeCommandHelpTextFormatter(RootCommandHelpTextFormatter): - ADDITIVE_JUSTIFICATION = 6 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # NOTE(sriram-mv): Add Additional space after determining the longest option. - # However, do not justify with padding for more than half the width of - # the terminal to retain aesthetics. - self.left_justification_length = min( - max([len(option) for option in ALL_OPTIONS]) + self.ADDITIVE_JUSTIFICATION, - self.width // 2 - self.indent_increment, - ) - self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/local/invoke/core/options.py b/samcli/commands/local/invoke/core/options.py index ef0487f16d..d7f3f21c05 100644 --- a/samcli/commands/local/invoke/core/options.py +++ b/samcli/commands/local/invoke/core/options.py @@ -87,10 +87,9 @@ "Configuration Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, "extras": [ - RowDefinition(name="Learn more about configuration files at:"), RowDefinition( - name="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli" - "-config.html. " + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." ), ], }, diff --git a/samcli/commands/local/local.py b/samcli/commands/local/local.py index 660a78f07e..414736a6cf 100644 --- a/samcli/commands/local/local.py +++ b/samcli/commands/local/local.py @@ -18,6 +18,7 @@ "execution": "samcli.commands.local.execution.cli.cli", "callback": "samcli.commands.local.callback.cli.cli", }, + new_commands={"execution", "callback"}, ) def cli(): """ diff --git a/samcli/commands/local/start_api/core/command.py b/samcli/commands/local/start_api/core/command.py index b3c15f7da0..3c32250661 100644 --- a/samcli/commands/local/start_api/core/command.py +++ b/samcli/commands/local/start_api/core/command.py @@ -6,51 +6,48 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.local.start_api.core.formatters import InvokeStartAPICommandHelpTextFormatter -from samcli.commands.local.start_api.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.local.start_api.core.options import ALL_OPTIONS, OPTIONS_INFO class InvokeAPICommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = InvokeStartAPICommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: InvokeStartAPICommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Setup", extra_indents=1): - formatter.write_rd( - [ - RowDefinition( - text="\n", - ), - RowDefinition( - name="Start the local lambda with Amazon API Gateway endpoint", - ), - RowDefinition( - name=style(f"$ {ctx.command_path}"), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - ] - ) + with formatter.indented_section( + name="Start the local lambda with Amazon API Gateway endpoint:", extra_indents=0 + ): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path}"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) with formatter.indented_section(name="Invoke local Lambda endpoint", extra_indents=1): - formatter.write_rd( - [ - RowDefinition( - text="\n", - ), - RowDefinition( - name="Invoke Lambda function locally using curl", - ), - RowDefinition( - name=style("$ curl http://127.0.0.1:3000/hello"), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - ] - ) - - def format_options(self, ctx: Context, formatter: InvokeStartAPICommandHelpTextFormatter) -> None: # type: ignore + with formatter.indented_section(name="Invoke Lambda function locally using curl:", extra_indents=0): + formatter.write_text_rows( + [ + RowDefinition( + name=style("$ curl http://127.0.0.1:3000/hello"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore # NOTE(sriram-mv): `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/local/start_api/core/formatters.py b/samcli/commands/local/start_api/core/formatters.py deleted file mode 100644 index a353c2d781..0000000000 --- a/samcli/commands/local/start_api/core/formatters.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Invoke API Command Formatter. -""" - -from samcli.cli.formatters import RootCommandHelpTextFormatter -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.local.start_api.core.options import ALL_OPTIONS - - -class InvokeStartAPICommandHelpTextFormatter(RootCommandHelpTextFormatter): - ADDITIVE_JUSTIFICATION = 6 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # NOTE(sriram-mv): Add Additional space after determining the longest option. - # However, do not justify with padding for more than half the width of - # the terminal to retain aesthetics. - self.left_justification_length = min( - max([len(option) for option in ALL_OPTIONS]) + self.ADDITIVE_JUSTIFICATION, - self.width // 2 - self.indent_increment, - ) - self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/local/start_api/core/options.py b/samcli/commands/local/start_api/core/options.py index 750b8c6d15..02a2263920 100644 --- a/samcli/commands/local/start_api/core/options.py +++ b/samcli/commands/local/start_api/core/options.py @@ -81,10 +81,9 @@ "Configuration Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, "extras": [ - RowDefinition(name="Learn more about configuration files at:"), RowDefinition( - name="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli" - "-config.html. " + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." ), ], }, diff --git a/samcli/commands/local/start_lambda/core/command.py b/samcli/commands/local/start_lambda/core/command.py index 0feb264f1d..fca0972282 100644 --- a/samcli/commands/local/start_lambda/core/command.py +++ b/samcli/commands/local/start_lambda/core/command.py @@ -6,107 +6,92 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.local.start_lambda.core.formatters import InvokeStartLambdaCommandHelpTextFormatter -from samcli.commands.local.start_lambda.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.local.start_lambda.core.options import ALL_OPTIONS, OPTIONS_INFO class InvokeLambdaCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = InvokeStartLambdaCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: InvokeStartLambdaCommandHelpTextFormatter): - AWS_SDK_EXAMPLE = """ - self.lambda_client = boto3.client('lambda', + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): + AWS_SDK_EXAMPLE = """self.lambda_client = boto3.client('lambda', endpoint_url="http://127.0.0.1:3001", use_ssl=False, verify=False, config=Config(signature_version=UNSIGNED, read_timeout=0, retries={'max_attempts': 0})) - self.lambda_client.invoke(FunctionName="HelloWorldFunction") + self.lambda_client.invoke(FunctionName="HelloWorldFunction") """ with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Setup", extra_indents=1): - formatter.write_rd( - [ - RowDefinition( - text="\n", - ), - RowDefinition( - name="Start the local lambda endpoint for all functions", - ), - RowDefinition( - name=style(f"$ {ctx.command_path}"), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - ] - ) - formatter.write_rd( - [ - RowDefinition( - text="\n", - ), - RowDefinition( - name="Start the local lambda endpoint for one function", - ), - RowDefinition( - name=style(f"$ {ctx.command_path} HelloWorldFunction"), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - ] - ) - formatter.write_rd( - [ - RowDefinition( - text="\n", - ), - RowDefinition( - name="Start the local lambda endpoint for multiple functions", - ), - RowDefinition( - name=style(f"$ {ctx.command_path} HelloWorldFunctionOne HelloWorldFunctionTwo"), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - ] - ) + with formatter.indented_section( + name="Start the local lambda endpoint for all functions", extra_indents=0 + ): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path}"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + with formatter.indented_section( + name="Start the local lambda endpoint for one function", extra_indents=0 + ): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} HelloWorldFunction"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + with formatter.indented_section( + name="Start the local lambda endpoint for multiple functions", extra_indents=0 + ): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} HelloWorldFunctionOne HelloWorldFunctionTwo"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) with formatter.indented_section(name="Invoke local Lambda endpoint", extra_indents=1): - formatter.write_rd( - [ - RowDefinition( - text="\n", - ), - RowDefinition( - name="Use the AWS CLI.", - ), - RowDefinition( - name=style( - "$ aws lambda invoke --function-name HelloWorldFunction " - "--endpoint-url http://127.0.0.1:3001 --no-verify-ssl out.txt" + with formatter.indented_section(name="Use the AWS CLI:", extra_indents=0): + formatter.write_text_rows( + [ + RowDefinition( + name=style( + "$ aws lambda invoke --function-name HelloWorldFunction " + "--endpoint-url http://127.0.0.1:3001 --no-verify-ssl out.txt" + ), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + with formatter.indented_section(name="Use AWS SDK in automated tests:", extra_indents=0): + formatter.write_text_rows( + [ + RowDefinition( + name=AWS_SDK_EXAMPLE, + extra_row_modifiers=[ShowcaseRowModifier()], ), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - ] - ) - formatter.write_rd( - [ - RowDefinition( - text="\n", - ), - RowDefinition( - name="Use AWS SDK in automated tests.", - ), - RowDefinition( - name=AWS_SDK_EXAMPLE, - extra_row_modifiers=[ShowcaseRowModifier()], - ), - ] - ) + ] + ) - def format_options(self, ctx: Context, formatter: InvokeStartLambdaCommandHelpTextFormatter) -> None: # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore # NOTE(sriram-mv): `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/local/start_lambda/core/formatters.py b/samcli/commands/local/start_lambda/core/formatters.py deleted file mode 100644 index 11f0f66ffd..0000000000 --- a/samcli/commands/local/start_lambda/core/formatters.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Invoke Lambda Command Formatter. -""" - -from samcli.cli.formatters import RootCommandHelpTextFormatter -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.local.start_lambda.core.options import ALL_OPTIONS - - -class InvokeStartLambdaCommandHelpTextFormatter(RootCommandHelpTextFormatter): - ADDITIVE_JUSTIFICATION = 6 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # NOTE(sriram-mv): Add Additional space after determining the longest option. - # However, do not justify with padding for more than half the width of - # the terminal to retain aesthetics. - self.left_justification_length = min( - max([len(option) for option in ALL_OPTIONS]) + self.ADDITIVE_JUSTIFICATION, - self.width // 2 - self.indent_increment, - ) - self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/local/start_lambda/core/options.py b/samcli/commands/local/start_lambda/core/options.py index 4eecf90483..cdc1404e56 100644 --- a/samcli/commands/local/start_lambda/core/options.py +++ b/samcli/commands/local/start_lambda/core/options.py @@ -77,10 +77,9 @@ "Configuration Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, "extras": [ - RowDefinition(name="Learn more about configuration files at:"), RowDefinition( - name="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli" - "-config.html. " + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." ), ], }, diff --git a/samcli/commands/logs/core/command.py b/samcli/commands/logs/core/command.py index b21e061d0a..25abbf7b9c 100644 --- a/samcli/commands/logs/core/command.py +++ b/samcli/commands/logs/core/command.py @@ -2,29 +2,31 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.logs.core.formatters import LogsCommandHelpTextFormatter -from samcli.commands.logs.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.logs.core.options import ALL_OPTIONS, OPTIONS_INFO COL_SIZE_MODIFIER = 38 class LogsCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = LogsCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: LogsCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section( name="Fetch logs with Lambda Function Logical ID and Cloudformation Stack Name" ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} -n HelloWorldFunction --stack-name mystack"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -32,11 +34,8 @@ def format_examples(ctx: Context, formatter: LogsCommandHelpTextFormatter): ] ) with formatter.indented_section(name="View logs for specific time range"): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} -n HelloWorldFunction --stack-name mystack -s " @@ -47,11 +46,8 @@ def format_examples(ctx: Context, formatter: LogsCommandHelpTextFormatter): ] ) with formatter.indented_section(name="Tail new logs"): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} -n HelloWorldFunction --stack-name " f"mystack --tail"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -59,11 +55,8 @@ def format_examples(ctx: Context, formatter: LogsCommandHelpTextFormatter): ] ) with formatter.indented_section(name="Fetch from Cloudwatch log groups"): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} --cw-log-group /aws/lambda/myfunction-123 " @@ -75,11 +68,8 @@ def format_examples(ctx: Context, formatter: LogsCommandHelpTextFormatter): ) with formatter.indented_section(name="Fetch logs from supported resources in Cloudformation stack"): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} ---stack-name mystack"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -88,11 +78,8 @@ def format_examples(ctx: Context, formatter: LogsCommandHelpTextFormatter): ) with formatter.indented_section(name="Fetch logs from resource defined in nested Cloudformation stack"): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} ---stack-name mystack -n MyNestedStack/HelloWorldFunction" @@ -102,7 +89,7 @@ def format_examples(ctx: Context, formatter: LogsCommandHelpTextFormatter): ] ) - def format_options(self, ctx: Context, formatter: LogsCommandHelpTextFormatter) -> None: # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore # `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/logs/core/formatters.py b/samcli/commands/logs/core/formatters.py deleted file mode 100644 index 6a35facce0..0000000000 --- a/samcli/commands/logs/core/formatters.py +++ /dev/null @@ -1,19 +0,0 @@ -from samcli.cli.formatters import RootCommandHelpTextFormatter -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.logs.core.options import ALL_OPTIONS - - -class LogsCommandHelpTextFormatter(RootCommandHelpTextFormatter): - # Picked an additive constant that gives an aesthetically pleasing look. - ADDITIVE_JUSTIFICATION = 22 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # Add Additional space after determining the longest option. - # However, do not justify with padding for more than half the width of - # the terminal to retain aesthetics. - self.left_justification_length = min( - max([len(option) for option in ALL_OPTIONS]) + self.ADDITIVE_JUSTIFICATION, - self.width // 2 - self.indent_increment, - ) - self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/logs/core/options.py b/samcli/commands/logs/core/options.py index 901fc9f652..bf80f3205f 100644 --- a/samcli/commands/logs/core/options.py +++ b/samcli/commands/logs/core/options.py @@ -35,10 +35,9 @@ "Configuration Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, "extras": [ - RowDefinition(name="Learn more about configuration files at:"), RowDefinition( - name="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli" - "-config.html. " + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." ), ], }, diff --git a/samcli/commands/package/core/command.py b/samcli/commands/package/core/command.py index 4178fde5b5..76d5ffa1da 100644 --- a/samcli/commands/package/core/command.py +++ b/samcli/commands/package/core/command.py @@ -8,8 +8,8 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.package.core.formatters import PackageCommandHelpTextFormatter -from samcli.commands.package.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.package.core.options import ALL_OPTIONS, OPTIONS_INFO from samcli.lib.utils.resources import resources_generator COL_SIZE_MODIFIER = 38 @@ -24,45 +24,39 @@ class PackageCommand(CoreCommand): """ class CustomFormatterContext(Context): - formatter_class = PackageCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: PackageCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): - with formatter.indented_section(name="Automatic resolution of S3 buckets", extra_indents=1): - formatter.write_rd( + with formatter.indented_section(name="Automatic resolution of S3 buckets:", extra_indents=1): + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} --resolve-s3"), extra_row_modifiers=[ShowcaseRowModifier()], ), ], - col_max=COL_SIZE_MODIFIER, ) - with formatter.indented_section(name="Get packaged template", extra_indents=1): - formatter.write_rd( + with formatter.indented_section(name="Get packaged template:", extra_indents=1): + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} --resolve-s3 --output-template-file packaged.yaml"), extra_row_modifiers=[ShowcaseRowModifier()], ), ], - col_max=COL_SIZE_MODIFIER, ) - with formatter.indented_section(name="Customized location for uploading artifacts", extra_indents=1): - formatter.write_rd( + with formatter.indented_section(name="Customized location for uploading artifacts:", extra_indents=1): + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} --s3-bucket S3_BUCKET --output-template-file packaged.yaml" @@ -70,11 +64,10 @@ def format_examples(ctx: Context, formatter: PackageCommandHelpTextFormatter): extra_row_modifiers=[ShowcaseRowModifier()], ), ], - col_max=COL_SIZE_MODIFIER, ) @staticmethod - def format_table(formatter: PackageCommandHelpTextFormatter): + def format_table(formatter: CommandHelpTextFormatter): with formatter.section(name="Supported Resources"): pass ctx = click.get_current_context() @@ -94,13 +87,10 @@ def format_table(formatter: PackageCommandHelpTextFormatter): ) @staticmethod - def format_acronyms(formatter: PackageCommandHelpTextFormatter): + def format_acronyms(formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Acronyms", extra_indents=1): formatter.write_rd( [ - RowDefinition( - text="\n", - ), RowDefinition( name="S3", text="Simple Storage Service", @@ -120,7 +110,7 @@ def format_acronyms(formatter: PackageCommandHelpTextFormatter): col_max=COL_SIZE_MODIFIER, ) - def format_options(self, ctx: Context, formatter: PackageCommandHelpTextFormatter) -> None: # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore # `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/package/core/formatters.py b/samcli/commands/package/core/formatters.py deleted file mode 100644 index 5c05ddcbfd..0000000000 --- a/samcli/commands/package/core/formatters.py +++ /dev/null @@ -1,19 +0,0 @@ -from samcli.cli.formatters import RootCommandHelpTextFormatter -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.package.core.options import ALL_OPTIONS - - -class PackageCommandHelpTextFormatter(RootCommandHelpTextFormatter): - # Picked an additive constant that gives an aesthetically pleasing look. - ADDITIVE_JUSTIFICATION = 15 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # Add Additional space after determining the longest option. - # However, do not justify with padding for more than half the width of - # the terminal to retain aesthetics. - self.left_justification_length = min( - max([len(option) for option in ALL_OPTIONS]) + self.ADDITIVE_JUSTIFICATION, - self.width // 2 - self.indent_increment, - ) - self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/package/core/options.py b/samcli/commands/package/core/options.py index c0de5e0ed7..ce386eb689 100644 --- a/samcli/commands/package/core/options.py +++ b/samcli/commands/package/core/options.py @@ -58,10 +58,9 @@ "Configuration Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, "extras": [ - RowDefinition(name="Learn more about configuration files at:"), RowDefinition( - name="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli" - "-config.html. " + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." ), ], }, diff --git a/samcli/commands/pipeline/bootstrap/cli.py b/samcli/commands/pipeline/bootstrap/cli.py index 35a0dbc0c6..43756afa5c 100644 --- a/samcli/commands/pipeline/bootstrap/cli.py +++ b/samcli/commands/pipeline/bootstrap/cli.py @@ -12,6 +12,7 @@ from samcli.cli.main import aws_creds_options, common_options, pass_context, print_cmdline_args from samcli.commands._utils.click_mutex import ClickMutex from samcli.commands._utils.command_exception_handler import command_exception_handler +from samcli.commands.pipeline.bootstrap.core.command import PipelineBootstrapCommand from samcli.commands.pipeline.bootstrap.oidc_config import ( BitbucketOidcConfig, GitHubOidcConfig, @@ -38,7 +39,15 @@ OPENID_CONNECT = "OpenID Connect (OIDC)" -@click.command("bootstrap", short_help=SHORT_HELP, help=HELP_TEXT, context_settings=dict(max_content_width=120)) +@click.command( + "bootstrap", + cls=PipelineBootstrapCommand, + short_help=SHORT_HELP, + help=HELP_TEXT, + description="", + requires_credentials=True, + context_settings=dict(max_content_width=120), +) @configuration_option(provider=ConfigProvider(section="parameters")) @click.option( "--interactive/--no-interactive", diff --git a/samcli/commands/pipeline/bootstrap/core/__init__.py b/samcli/commands/pipeline/bootstrap/core/__init__.py new file mode 100644 index 0000000000..c8454954a1 --- /dev/null +++ b/samcli/commands/pipeline/bootstrap/core/__init__.py @@ -0,0 +1 @@ +"""Pipeline bootstrap core command""" diff --git a/samcli/commands/pipeline/bootstrap/core/command.py b/samcli/commands/pipeline/bootstrap/core/command.py new file mode 100644 index 0000000000..2086a27aae --- /dev/null +++ b/samcli/commands/pipeline/bootstrap/core/command.py @@ -0,0 +1,32 @@ +"""Pipeline bootstrap core command""" + +from typing import Dict + +from click import Context + +from samcli.cli.core.command import CoreCommand +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.pipeline.bootstrap.core.options import ALL_OPTIONS, OPTIONS_INFO + + +class PipelineBootstrapCommand(CoreCommand): + class CustomFormatterContext(Context): + def make_formatter(self) -> CommandHelpTextFormatter: + return CommandHelpTextFormatter( + additive_justification=1, + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) + + context_class = CustomFormatterContext + + @staticmethod + def _get_options_info() -> Dict: + return OPTIONS_INFO + + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore + self.format_description(formatter) + CoreCommand._format_options( + ctx=ctx, params=self.get_params(ctx), formatter=formatter, formatting_options=OPTIONS_INFO + ) diff --git a/samcli/commands/pipeline/bootstrap/core/options.py b/samcli/commands/pipeline/bootstrap/core/options.py new file mode 100644 index 0000000000..b044bfcf77 --- /dev/null +++ b/samcli/commands/pipeline/bootstrap/core/options.py @@ -0,0 +1,64 @@ +"""Pipeline bootstrap options""" + +from typing import Dict + +from samcli.cli.row_modifiers import RowDefinition + +BOOTSTRAP_OPTION_NAMES = [ + "interactive", + "stage", + "pipeline_user", + "pipeline_execution_role", + "cloudformation_execution_role", + "bucket", + "create_image_repository", + "image_repository", + "confirm_changeset", + "permissions_provider", + "oidc_provider_url", + "oidc_client_id", + "github_org", + "github_repo", + "deployment_branch", + "oidc_provider", + "gitlab_group", + "gitlab_project", + "bitbucket_repo_uuid", + "cicd_provider", +] +AWS_CREDENTIAL_OPTION_NAMES = ["region", "profile"] +CONFIGURATION_OPTION_NAMES = ["config_env", "config_file", "save_params"] +BETA_OPTION_NAMES = ["beta_features"] +OTHER_OPTION_NAMES = ["help", "debug"] + +ALL_OPTIONS = ( + BOOTSTRAP_OPTION_NAMES + + AWS_CREDENTIAL_OPTION_NAMES + + CONFIGURATION_OPTION_NAMES + + BETA_OPTION_NAMES + + OTHER_OPTION_NAMES +) + +OPTIONS_INFO: Dict[str, Dict] = { + "Bootstrap Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(BOOTSTRAP_OPTION_NAMES)}, + }, + "AWS Credential Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(AWS_CREDENTIAL_OPTION_NAMES)}, + }, + "Configuration Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, + "extras": [ + RowDefinition( + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." + ), + ], + }, + "Beta Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(BETA_OPTION_NAMES)}, + }, + "Other Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(OTHER_OPTION_NAMES)}, + }, +} diff --git a/samcli/commands/pipeline/init/cli.py b/samcli/commands/pipeline/init/cli.py index de1f20851e..fa6ffd6dfc 100644 --- a/samcli/commands/pipeline/init/cli.py +++ b/samcli/commands/pipeline/init/cli.py @@ -10,6 +10,7 @@ from samcli.cli.main import common_options as cli_framework_options from samcli.cli.main import pass_context from samcli.commands._utils.command_exception_handler import command_exception_handler +from samcli.commands.pipeline.init.core.command import PipelineInitCommand from samcli.commands.pipeline.init.interactive_init_flow import InteractiveInitFlow from samcli.lib.telemetry.metric import track_command @@ -24,7 +25,9 @@ """ -@click.command("init", help=HELP_TEXT, short_help=SHORT_HELP) +@click.command( + "init", cls=PipelineInitCommand, help=HELP_TEXT, short_help=SHORT_HELP, description="", requires_credentials=False +) @configuration_option(provider=ConfigProvider(section="parameters")) @click.option( "--bootstrap", diff --git a/samcli/commands/pipeline/init/core/__init__.py b/samcli/commands/pipeline/init/core/__init__.py new file mode 100644 index 0000000000..ffbc5a128b --- /dev/null +++ b/samcli/commands/pipeline/init/core/__init__.py @@ -0,0 +1 @@ +"""Pipeline init core command""" diff --git a/samcli/commands/pipeline/init/core/command.py b/samcli/commands/pipeline/init/core/command.py new file mode 100644 index 0000000000..d68ea5b37e --- /dev/null +++ b/samcli/commands/pipeline/init/core/command.py @@ -0,0 +1,31 @@ +"""Pipeline init core command""" + +from typing import Dict + +from click import Context + +from samcli.cli.core.command import CoreCommand +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.pipeline.init.core.options import ALL_OPTIONS, OPTIONS_INFO + + +class PipelineInitCommand(CoreCommand): + class CustomFormatterContext(Context): + def make_formatter(self) -> CommandHelpTextFormatter: + return CommandHelpTextFormatter( + additive_justification=1, + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) + + context_class = CustomFormatterContext + + @staticmethod + def _get_options_info() -> Dict: + return OPTIONS_INFO + + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore + CoreCommand._format_options( + ctx=ctx, params=self.get_params(ctx), formatter=formatter, formatting_options=OPTIONS_INFO + ) diff --git a/samcli/commands/pipeline/init/core/options.py b/samcli/commands/pipeline/init/core/options.py new file mode 100644 index 0000000000..27cbbcdc63 --- /dev/null +++ b/samcli/commands/pipeline/init/core/options.py @@ -0,0 +1,33 @@ +"""Pipeline init options""" + +from typing import Dict + +from samcli.cli.row_modifiers import RowDefinition + +PIPELINE_INIT_OPTION_NAMES = ["bootstrap"] +CONFIGURATION_OPTION_NAMES = ["config_env", "config_file", "save_params"] +BETA_OPTION_NAMES = ["beta_features"] +OTHER_OPTION_NAMES = ["help", "debug"] + +ALL_OPTIONS = PIPELINE_INIT_OPTION_NAMES + CONFIGURATION_OPTION_NAMES + BETA_OPTION_NAMES + OTHER_OPTION_NAMES + +OPTIONS_INFO: Dict[str, Dict] = { + "Pipeline Init Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(PIPELINE_INIT_OPTION_NAMES)}, + }, + "Configuration Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, + "extras": [ + RowDefinition( + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." + ), + ], + }, + "Beta Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(BETA_OPTION_NAMES)}, + }, + "Other Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(OTHER_OPTION_NAMES)}, + }, +} diff --git a/samcli/commands/publish/command.py b/samcli/commands/publish/command.py index fe253c4f85..1e589dc22a 100644 --- a/samcli/commands/publish/command.py +++ b/samcli/commands/publish/command.py @@ -12,6 +12,7 @@ from samcli.commands._utils.command_exception_handler import command_exception_handler from samcli.commands._utils.options import template_common_option from samcli.commands._utils.template import TemplateFailedParsingException, TemplateNotFoundException, get_template_data +from samcli.commands.publish.core.command import PublishCommand from samcli.lib.telemetry.metric import track_command from samcli.lib.utils.version_checker import check_newer_version from samcli.vendor.serverlessrepo.publish import CREATE_APPLICATION @@ -20,20 +21,17 @@ SAM_PUBLISH_DOC = "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template-publishing-applications.html" # pylint: disable=line-too-long # noqa SAM_PACKAGE_DOC = "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-package.html" # pylint: disable=line-too-long # noqa -HELP_TEXT = """ + +DESCRIPTION = """ Use this command to publish a packaged AWS SAM template to the AWS Serverless Application Repository to share within your team, -across your organization, or with the community at large.\n -\b +across your organization, or with the community at large. + This command expects the template's Metadata section to contain an AWS::ServerlessRepo::Application section with application metadata for publishing. For more details on this metadata section, see {} \b -Examples --------- -To publish an application -$ sam publish -t packaged.yaml --region """.format(SAM_PUBLISH_DOC) SHORT_HELP = "Publish a packaged AWS SAM template to the AWS Serverless Application Repository." SERVERLESSREPO_CONSOLE_URL = "https://console.aws.amazon.com/serverlessrepo/home?region={}#/published-applications/{}" @@ -46,7 +44,14 @@ """ -@click.command("publish", help=HELP_TEXT, short_help=SHORT_HELP) +@click.command( + "publish", + cls=PublishCommand, + short_help=SHORT_HELP, + description=DESCRIPTION, + requires_credentials=True, + context_settings={"max_content_width": 120}, +) @configuration_option(provider=ConfigProvider(section="parameters")) @template_common_option @click.option("--semantic-version", help=SEMANTIC_VERSION_HELP) diff --git a/samcli/commands/publish/core/__init__.py b/samcli/commands/publish/core/__init__.py new file mode 100644 index 0000000000..441c2f01bc --- /dev/null +++ b/samcli/commands/publish/core/__init__.py @@ -0,0 +1,3 @@ +""" +Publish Command Core +""" diff --git a/samcli/commands/publish/core/command.py b/samcli/commands/publish/core/command.py new file mode 100644 index 0000000000..9c4d65e7e3 --- /dev/null +++ b/samcli/commands/publish/core/command.py @@ -0,0 +1,42 @@ +""" +Publish Command Class +""" + +from click import Context, style + +from samcli.cli.core.command import CoreCommand +from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.publish.core.options import ALL_OPTIONS, OPTIONS_INFO + + +class PublishCommand(CoreCommand): + class CustomFormatterContext(Context): + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) + + context_class = CustomFormatterContext + + @staticmethod + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): + with formatter.indented_section(name="Examples", extra_indents=1): + with formatter.indented_section(name="Publish a packaged application", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} -t packaged.yaml --region us-east-1"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter): # type: ignore + self.format_description(formatter) + PublishCommand.format_examples(ctx, formatter) + CoreCommand._format_options( + ctx=ctx, params=self.get_params(ctx), formatter=formatter, formatting_options=OPTIONS_INFO + ) diff --git a/samcli/commands/publish/core/options.py b/samcli/commands/publish/core/options.py new file mode 100644 index 0000000000..c7e68ca863 --- /dev/null +++ b/samcli/commands/publish/core/options.py @@ -0,0 +1,32 @@ +""" +Publish Command Options +""" + +from typing import Dict + +from samcli.cli.core.options import ALL_COMMON_OPTIONS, add_common_options_info +from samcli.cli.row_modifiers import RowDefinition + +PUBLISH_OPTION_NAMES = ["template_file", "semantic_version", "fail_on_same_version"] +AWS_CREDENTIAL_OPTION_NAMES = ["region", "profile"] +CONFIGURATION_OPTION_NAMES = ["config_file", "config_env", "save_params"] + +ALL_OPTIONS = PUBLISH_OPTION_NAMES + AWS_CREDENTIAL_OPTION_NAMES + CONFIGURATION_OPTION_NAMES + ALL_COMMON_OPTIONS + +OPTIONS_INFO: Dict[str, Dict] = { + "Publish Options": {"option_names": {opt: {"rank": idx} for idx, opt in enumerate(PUBLISH_OPTION_NAMES)}}, + "AWS Credential Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(AWS_CREDENTIAL_OPTION_NAMES)} + }, + "Configuration Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, + "extras": [ + RowDefinition( + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." + ), + ], + }, +} + +add_common_options_info(OPTIONS_INFO) diff --git a/samcli/commands/remote/callback/fail/core/command.py b/samcli/commands/remote/callback/fail/core/command.py index 9fda8317e2..e50b6f4ae9 100644 --- a/samcli/commands/remote/callback/fail/core/command.py +++ b/samcli/commands/remote/callback/fail/core/command.py @@ -28,9 +28,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): """Format command examples for help text""" with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Send failure callback with no parameters", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(f"$ {ctx.command_path} my-callback-id"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -39,9 +38,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): ) with formatter.indented_section(name="Send failure callback with error message", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(f"$ {ctx.command_path} my-callback-id --error-message 'Task failed'"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -55,9 +53,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): f"$ {ctx.command_path} my-callback-id --error-message 'Task failed' " f"--error-type 'ValidationError' --stack-trace 'at line 42' --error-data '{json_data}'" ) - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(command_example), extra_row_modifiers=[ShowcaseRowModifier()], diff --git a/samcli/commands/remote/callback/heartbeat/core/command.py b/samcli/commands/remote/callback/heartbeat/core/command.py index b7197160cf..41c821f735 100644 --- a/samcli/commands/remote/callback/heartbeat/core/command.py +++ b/samcli/commands/remote/callback/heartbeat/core/command.py @@ -28,9 +28,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): """Format command examples for help text""" with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Send heartbeat callback", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(f"$ {ctx.command_path} my-callback-id"), extra_row_modifiers=[ShowcaseRowModifier()], diff --git a/samcli/commands/remote/callback/succeed/core/command.py b/samcli/commands/remote/callback/succeed/core/command.py index 372b12146d..1837c7d032 100644 --- a/samcli/commands/remote/callback/succeed/core/command.py +++ b/samcli/commands/remote/callback/succeed/core/command.py @@ -28,9 +28,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): """Format command examples for help text""" with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Send success callback with no result", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(f"$ {ctx.command_path} my-callback-id"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -39,9 +38,8 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): ) with formatter.indented_section(name="Send success callback with result", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition(text="\n"), RowDefinition( name=style(f"$ {ctx.command_path} my-callback-id --result 'Task completed successfully'"), extra_row_modifiers=[ShowcaseRowModifier()], diff --git a/samcli/commands/remote/execution/get/core/command.py b/samcli/commands/remote/execution/get/core/command.py index 6299328890..fd772476b3 100644 --- a/samcli/commands/remote/execution/get/core/command.py +++ b/samcli/commands/remote/execution/get/core/command.py @@ -30,7 +30,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): ) with formatter.indented_section(name="Get execution details", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} '{arn_example}'"), @@ -40,7 +40,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): ) with formatter.indented_section(name="Get execution details in JSON format", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} '{arn_example}' --format json"), diff --git a/samcli/commands/remote/execution/history/core/command.py b/samcli/commands/remote/execution/history/core/command.py index b5f2814a18..702e03dfd2 100644 --- a/samcli/commands/remote/execution/history/core/command.py +++ b/samcli/commands/remote/execution/history/core/command.py @@ -29,7 +29,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): ) with formatter.indented_section(name="Get execution history", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} {arn_example}"), @@ -39,7 +39,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): ) with formatter.indented_section(name="Get execution history in JSON format", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} {arn_example} --format json"), diff --git a/samcli/commands/remote/execution/stop/core/command.py b/samcli/commands/remote/execution/stop/core/command.py index cee6229c20..26d1bd76da 100644 --- a/samcli/commands/remote/execution/stop/core/command.py +++ b/samcli/commands/remote/execution/stop/core/command.py @@ -29,7 +29,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): ) with formatter.indented_section(name="Stop execution without error details", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} {arn_example}"), @@ -40,7 +40,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Stop execution with error message and type", extra_indents=1): error_options = '--error-message "Execution cancelled" --error-type "UserCancellation"' - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} {arn_example} {error_options}"), @@ -56,7 +56,7 @@ def format_examples(self, ctx: Context, formatter: CommandHelpTextFormatter): '--error-message "Task failed" --error-type "TaskFailure" --error-data \'{"reason":"timeout"}\' ' '--stack-trace "at function1()" --stack-trace "at function2()"' ) - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} {arn_example} {full_options}"), diff --git a/samcli/commands/remote/invoke/core/command.py b/samcli/commands/remote/invoke/core/command.py index 1009641a21..43cbc31925 100644 --- a/samcli/commands/remote/invoke/core/command.py +++ b/samcli/commands/remote/invoke/core/command.py @@ -8,24 +8,29 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.remote.invoke.core.formatters import RemoteInvokeCommandHelpTextFormatter -from samcli.commands.remote.invoke.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.remote.invoke.core.options import ALL_OPTIONS, OPTIONS_INFO class RemoteInvokeCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = RemoteInvokeCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Lambda Functions", extra_indents=1): with formatter.indented_section( name="Invoke default lambda function with empty event", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} --stack-name hello-world"), @@ -36,7 +41,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte with formatter.indented_section( name="Invoke default lambda function with event passed as text input", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -50,7 +55,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte with formatter.indented_section( name="Invoke named lambda function with an event file", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -62,7 +67,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte ] ) with formatter.indented_section(name="Invoke function with event as stdin input", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -76,7 +81,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte with formatter.indented_section( name="Invoke function using lambda ARN and get the full AWS API response", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -90,7 +95,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte with formatter.indented_section( name="Asynchronously invoke function with additional boto parameters", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -105,7 +110,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Dry invoke a function to validate parameter values and user/role permissions", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -121,7 +126,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Start execution with event passed as text input", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -136,7 +141,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Start execution using its physical-id or ARN with an execution name parameter", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -151,7 +156,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Start execution with an event file and get the full AWS API response", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -166,7 +171,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Start execution with event as stdin input and pass the X-ray trace header to the execution", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -183,7 +188,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Send a message with the MessageBody passed as event", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} --stack-name mock-stack MySQSQueue -e hello-world"), @@ -195,7 +200,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Send a message using its physical-id and pass event using --event-file", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -210,7 +215,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Send a message using its ARN and delay the specified message", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -225,7 +230,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Send a message along with message attributes and get the full AWS API response", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -242,7 +247,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Send a message to a FIFO SQS Queue", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -259,7 +264,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Put a record using the data provided as event", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -274,7 +279,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Put a record using its physical-id and pass event using --event-file", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style(f"$ {ctx.command_path} MyKinesisStreamName" f" --event-file event.json"), @@ -286,7 +291,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Put a record using its ARN and override the key hash", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -302,7 +307,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte name="Put a record with a sequence number for ordering with a PartitionKey", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ RowDefinition( name=style( @@ -316,7 +321,7 @@ def format_examples(ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatte ) @staticmethod - def format_acronyms(formatter: RemoteInvokeCommandHelpTextFormatter): + def format_acronyms(formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Acronyms", extra_indents=1): formatter.write_rd( [ @@ -328,7 +333,7 @@ def format_acronyms(formatter: RemoteInvokeCommandHelpTextFormatter): ] ) - def format_options(self, ctx: Context, formatter: RemoteInvokeCommandHelpTextFormatter) -> None: # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore # NOTE: `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/remote/invoke/core/formatters.py b/samcli/commands/remote/invoke/core/formatters.py deleted file mode 100644 index df1d723ab1..0000000000 --- a/samcli/commands/remote/invoke/core/formatters.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Remote Invoke Command Formatter. -""" - -from samcli.cli.formatters import RootCommandHelpTextFormatter -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.remote.invoke.core.options import ALL_OPTIONS - - -class RemoteInvokeCommandHelpTextFormatter(RootCommandHelpTextFormatter): - ADDITIVE_JUSTIFICATION = 17 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # NOTE: Add Additional space after determining the longest option. - # However, do not justify with padding for more than half the width of - # the terminal to retain aesthetics. - self.left_justification_length = min( - max([len(option) for option in ALL_OPTIONS]) + self.ADDITIVE_JUSTIFICATION, - self.width // 2 - self.indent_increment, - ) - self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/remote/invoke/core/options.py b/samcli/commands/remote/invoke/core/options.py index 1b8ec895bf..6045aefdeb 100644 --- a/samcli/commands/remote/invoke/core/options.py +++ b/samcli/commands/remote/invoke/core/options.py @@ -43,10 +43,9 @@ "Configuration Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, "extras": [ - RowDefinition(name="Learn more about configuration files at:"), RowDefinition( - name="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli" - "-config.html. " + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." ), ], }, diff --git a/samcli/commands/remote/remote.py b/samcli/commands/remote/remote.py index 921f2705a4..990ee422f2 100644 --- a/samcli/commands/remote/remote.py +++ b/samcli/commands/remote/remote.py @@ -16,6 +16,7 @@ "execution": "samcli.commands.remote.execution.cli.cli", "callback": "samcli.commands.remote.callback.cli.cli", }, + new_commands={"execution", "callback"}, ) def cli(): """ diff --git a/samcli/commands/remote/test_event/core/base_options.py b/samcli/commands/remote/test_event/core/base_options.py index dacc6a5c45..53b2344722 100644 --- a/samcli/commands/remote/test_event/core/base_options.py +++ b/samcli/commands/remote/test_event/core/base_options.py @@ -23,10 +23,8 @@ def get_option_names(option_names: List[str]) -> Dict[str, Dict]: CONFIGURATION_OPTION_INFO = { "option_names": get_option_names(CONFIGURATION_OPTION_NAMES), "extras": [ - RowDefinition(name="Learn more about configuration files at:"), RowDefinition( - name="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli" - "-config.html. " + name="Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." # noqa: E501 ), ], } diff --git a/samcli/commands/remote/test_event/core/formatters.py b/samcli/commands/remote/test_event/core/formatters.py deleted file mode 100644 index 26ea664739..0000000000 --- a/samcli/commands/remote/test_event/core/formatters.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -Remote Test Event Command Formatter base. -""" - -from typing import List - -from samcli.cli.formatters import RootCommandHelpTextFormatter -from samcli.cli.row_modifiers import BaseLineRowModifier - - -class RemoteTestEventCommandHelpTextFormatter(RootCommandHelpTextFormatter): - ADDITIVE_JUSTIFICATION = 17 - ALL_OPTIONS: List[str] = [] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # NOTE: Add Additional space after determining the longest option. - # However, do not justify with padding for more than half the width of - # the terminal to retain aesthetics. - self.left_justification_length = min( - max([len(option) for option in self.ALL_OPTIONS]) + self.ADDITIVE_JUSTIFICATION, - self.width // 2 - self.indent_increment, - ) - self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/remote/test_event/delete/core/command.py b/samcli/commands/remote/test_event/delete/core/command.py index ab160cbd67..f7416e021f 100644 --- a/samcli/commands/remote/test_event/delete/core/command.py +++ b/samcli/commands/remote/test_event/delete/core/command.py @@ -6,25 +6,27 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.remote.test_event.delete.core.formatters import RemoteTestEventDeleteCommandHelpTextFormatter -from samcli.commands.remote.test_event.delete.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.remote.test_event.delete.core.options import ALL_OPTIONS, OPTIONS_INFO class RemoteTestEventDeleteCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = RemoteTestEventDeleteCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: RemoteTestEventDeleteCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Delete a test event from default Lambda function", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} --stack-name hello-world --name MyEvent"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -34,11 +36,8 @@ def format_examples(ctx: Context, formatter: RemoteTestEventDeleteCommandHelpTex with formatter.indented_section( name="Delete a test event for a named Lambda function in the stack", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} --stack-name hello-world HelloWorldFunction --name MyEvent" @@ -50,11 +49,8 @@ def format_examples(ctx: Context, formatter: RemoteTestEventDeleteCommandHelpTex with formatter.indented_section( name="Delete a test event for a function using the Lambda ARN", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} arn:aws:lambda:us-west-2:123456789012:function:my-function " @@ -66,7 +62,7 @@ def format_examples(ctx: Context, formatter: RemoteTestEventDeleteCommandHelpTex ) @staticmethod - def format_acronyms(formatter: RemoteTestEventDeleteCommandHelpTextFormatter): + def format_acronyms(formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Acronyms", extra_indents=1): formatter.write_rd( [ @@ -78,7 +74,7 @@ def format_acronyms(formatter: RemoteTestEventDeleteCommandHelpTextFormatter): ] ) - def format_options(self, ctx: Context, formatter: RemoteTestEventDeleteCommandHelpTextFormatter): # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter): # type: ignore # NOTE: `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/remote/test_event/delete/core/formatters.py b/samcli/commands/remote/test_event/delete/core/formatters.py deleted file mode 100644 index 76911c235d..0000000000 --- a/samcli/commands/remote/test_event/delete/core/formatters.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -Delete Test Event Command Formatter. -""" - -from samcli.commands.remote.test_event.core.formatters import RemoteTestEventCommandHelpTextFormatter -from samcli.commands.remote.test_event.delete.core.options import ALL_OPTIONS - - -class RemoteTestEventDeleteCommandHelpTextFormatter(RemoteTestEventCommandHelpTextFormatter): - def __init__(self, *args, **kwargs): - self.ALL_OPTIONS = ALL_OPTIONS - super().__init__(*args, **kwargs) diff --git a/samcli/commands/remote/test_event/get/core/command.py b/samcli/commands/remote/test_event/get/core/command.py index 83597b221d..605ee03b03 100644 --- a/samcli/commands/remote/test_event/get/core/command.py +++ b/samcli/commands/remote/test_event/get/core/command.py @@ -6,25 +6,27 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.remote.test_event.get.core.formatters import RemoteTestEventGetCommandHelpTextFormatter -from samcli.commands.remote.test_event.get.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.remote.test_event.get.core.options import ALL_OPTIONS, OPTIONS_INFO class RemoteTestEventGetCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = RemoteTestEventGetCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: RemoteTestEventGetCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Get a test event from default Lambda function", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} --stack-name hello-world --name MyEvent"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -34,11 +36,8 @@ def format_examples(ctx: Context, formatter: RemoteTestEventGetCommandHelpTextFo with formatter.indented_section( name="Get a test event for a named Lambda function in the stack", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} --stack-name hello-world HelloWorldFunction --name MyEvent" @@ -51,11 +50,8 @@ def format_examples(ctx: Context, formatter: RemoteTestEventGetCommandHelpTextFo name="Get a test event for a named Lambda function in the stack and save the result to a file", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} --stack-name hello-world HelloWorldFunction --name MyEvent " @@ -68,11 +64,8 @@ def format_examples(ctx: Context, formatter: RemoteTestEventGetCommandHelpTextFo with formatter.indented_section( name="Get a test event for a function using the Lambda ARN", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} arn:aws:lambda:us-west-2:123456789012:function:my-function " @@ -84,7 +77,7 @@ def format_examples(ctx: Context, formatter: RemoteTestEventGetCommandHelpTextFo ) @staticmethod - def format_acronyms(formatter: RemoteTestEventGetCommandHelpTextFormatter): + def format_acronyms(formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Acronyms", extra_indents=1): formatter.write_rd( [ @@ -96,7 +89,7 @@ def format_acronyms(formatter: RemoteTestEventGetCommandHelpTextFormatter): ] ) - def format_options(self, ctx: Context, formatter: RemoteTestEventGetCommandHelpTextFormatter): # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter): # type: ignore # NOTE: `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/remote/test_event/get/core/formatters.py b/samcli/commands/remote/test_event/get/core/formatters.py deleted file mode 100644 index 491ecad6e9..0000000000 --- a/samcli/commands/remote/test_event/get/core/formatters.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -Get Test Event Command Formatter. -""" - -from samcli.commands.remote.test_event.core.formatters import RemoteTestEventCommandHelpTextFormatter -from samcli.commands.remote.test_event.get.core.options import ALL_OPTIONS - - -class RemoteTestEventGetCommandHelpTextFormatter(RemoteTestEventCommandHelpTextFormatter): - def __init__(self, *args, **kwargs): - self.ALL_OPTIONS = ALL_OPTIONS - super().__init__(*args, **kwargs) diff --git a/samcli/commands/remote/test_event/list/core/command.py b/samcli/commands/remote/test_event/list/core/command.py index 81c890b615..c9a3957fb8 100644 --- a/samcli/commands/remote/test_event/list/core/command.py +++ b/samcli/commands/remote/test_event/list/core/command.py @@ -6,27 +6,29 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.remote.test_event.list.core.formatters import RemoteTestEventListCommandHelpTextFormatter -from samcli.commands.remote.test_event.list.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.remote.test_event.list.core.options import ALL_OPTIONS, OPTIONS_INFO class RemoteTestEventListCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = RemoteTestEventListCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: RemoteTestEventListCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section( name="List remote test events for default Lambda function", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} --stack-name hello-world"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -36,11 +38,8 @@ def format_examples(ctx: Context, formatter: RemoteTestEventListCommandHelpTextF with formatter.indented_section( name="List remote test events for a named Lambda function in the stack", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} --stack-name hello-world HelloWorldFunction"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -50,11 +49,8 @@ def format_examples(ctx: Context, formatter: RemoteTestEventListCommandHelpTextF with formatter.indented_section( name="List remote test events for a function using Lambda ARN", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} arn:aws:lambda:us-west-2:123456789012:function:my-function" @@ -65,7 +61,7 @@ def format_examples(ctx: Context, formatter: RemoteTestEventListCommandHelpTextF ) @staticmethod - def format_acronyms(formatter: RemoteTestEventListCommandHelpTextFormatter): + def format_acronyms(formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Acronyms", extra_indents=1): formatter.write_rd( [ @@ -77,7 +73,7 @@ def format_acronyms(formatter: RemoteTestEventListCommandHelpTextFormatter): ] ) - def format_options(self, ctx: Context, formatter: RemoteTestEventListCommandHelpTextFormatter): # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter): # type: ignore # NOTE: `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/remote/test_event/list/core/formatters.py b/samcli/commands/remote/test_event/list/core/formatters.py deleted file mode 100644 index d632abe2f7..0000000000 --- a/samcli/commands/remote/test_event/list/core/formatters.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -List Test Events Command Formatter. -""" - -from samcli.commands.remote.test_event.core.formatters import RemoteTestEventCommandHelpTextFormatter -from samcli.commands.remote.test_event.list.core.options import ALL_OPTIONS - - -class RemoteTestEventListCommandHelpTextFormatter(RemoteTestEventCommandHelpTextFormatter): - def __init__(self, *args, **kwargs): - self.ALL_OPTIONS = ALL_OPTIONS - super().__init__(*args, **kwargs) diff --git a/samcli/commands/remote/test_event/put/core/command.py b/samcli/commands/remote/test_event/put/core/command.py index 8ddf824872..8a9a936abd 100644 --- a/samcli/commands/remote/test_event/put/core/command.py +++ b/samcli/commands/remote/test_event/put/core/command.py @@ -8,27 +8,29 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.remote.test_event.put.core.formatters import RemoteTestEventPutCommandHelpTextFormatter -from samcli.commands.remote.test_event.put.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.remote.test_event.put.core.options import ALL_OPTIONS, OPTIONS_INFO class RemoteTestEventPutCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = RemoteTestEventPutCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: RemoteTestEventPutCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section( name="Put a remote test event for default Lambda function using the contents of a file", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} --stack-name hello-world --name MyEvent " @@ -41,11 +43,8 @@ def format_examples(ctx: Context, formatter: RemoteTestEventPutCommandHelpTextFo with formatter.indented_section( name="Put a remote test event for a named Lambda function using the contents of a file", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} --stack-name hello-world HelloWorldFunction --name MyEvent " @@ -58,11 +57,8 @@ def format_examples(ctx: Context, formatter: RemoteTestEventPutCommandHelpTextFo with formatter.indented_section( name="Put a remote test event for a named Lambda function with stdin input", extra_indents=1 ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ echo '{json.dumps({'message':'hello!'})}' | " @@ -77,11 +73,8 @@ def format_examples(ctx: Context, formatter: RemoteTestEventPutCommandHelpTextFo name="Put a test event for a function using the Lambda ARN using the contents of a file", extra_indents=1, ): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style( f"$ {ctx.command_path} arn:aws:lambda:us-west-2:123456789012:function:my-function " @@ -93,7 +86,7 @@ def format_examples(ctx: Context, formatter: RemoteTestEventPutCommandHelpTextFo ) @staticmethod - def format_acronyms(formatter: RemoteTestEventPutCommandHelpTextFormatter): + def format_acronyms(formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Acronyms", extra_indents=1): formatter.write_rd( [ @@ -105,7 +98,7 @@ def format_acronyms(formatter: RemoteTestEventPutCommandHelpTextFormatter): ] ) - def format_options(self, ctx: Context, formatter: RemoteTestEventPutCommandHelpTextFormatter): # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter): # type: ignore # NOTE: `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/remote/test_event/put/core/formatters.py b/samcli/commands/remote/test_event/put/core/formatters.py deleted file mode 100644 index a5ee6315f7..0000000000 --- a/samcli/commands/remote/test_event/put/core/formatters.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -Put Test Event Command Formatter. -""" - -from samcli.commands.remote.test_event.core.formatters import RemoteTestEventCommandHelpTextFormatter -from samcli.commands.remote.test_event.put.core.options import ALL_OPTIONS - - -class RemoteTestEventPutCommandHelpTextFormatter(RemoteTestEventCommandHelpTextFormatter): - def __init__(self, *args, **kwargs): - self.ALL_OPTIONS = ALL_OPTIONS - super().__init__(*args, **kwargs) diff --git a/samcli/commands/sync/command.py b/samcli/commands/sync/command.py index af8ee79734..a3bcbc324f 100644 --- a/samcli/commands/sync/command.py +++ b/samcli/commands/sync/command.py @@ -72,7 +72,7 @@ LOG = logging.getLogger(__name__) HELP_TEXT = """ - NEW! Sync an AWS SAM Project to AWS. + Sync an AWS SAM Project to AWS. """ diff --git a/samcli/commands/sync/core/command.py b/samcli/commands/sync/core/command.py index 0e1d8c2061..f74df1b582 100644 --- a/samcli/commands/sync/core/command.py +++ b/samcli/commands/sync/core/command.py @@ -6,44 +6,58 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.sync.core.formatters import SyncCommandHelpTextFormatter -from samcli.commands.sync.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.sync.core.options import ALL_OPTIONS, OPTIONS_INFO class SyncCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = SyncCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + additive_justification=11, + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: SyncCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): - formatter.write_rd( - [ - RowDefinition( - text="\n", - ), - RowDefinition( - name=style(f"$ {ctx.command_path} " f"--watch --stack-name {{stack}}"), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - RowDefinition( - name=style(f"$ {ctx.command_path} " f"--code --watch --stack-name {{stack}}"), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - RowDefinition( - name=style( - f"$ {ctx.command_path} " - f"--code --stack-name {{stack}} --resource-id {{ChildStack}}/{{ResourceId}}" + with formatter.indented_section(name="Sync with watch mode", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} --watch --stack-name {{stack}}"), + extra_row_modifiers=[ShowcaseRowModifier()], ), - extra_row_modifiers=[ShowcaseRowModifier()], - ), - ], - ) + ] + ) + with formatter.indented_section(name="Sync code changes with watch mode", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} --code --watch --stack-name {{stack}}"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + with formatter.indented_section(name="Sync code changes for specific resource", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style( + f"$ {ctx.command_path} " + f"--code --stack-name {{stack}} --resource-id {{ChildStack}}/{{ResourceId}}" + ), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) @staticmethod - def format_acronyms(formatter: SyncCommandHelpTextFormatter): + def format_acronyms(formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Acronyms", extra_indents=1): formatter.write_rd( [ @@ -80,7 +94,7 @@ def format_acronyms(formatter: SyncCommandHelpTextFormatter): ] ) - def format_options(self, ctx: Context, formatter: SyncCommandHelpTextFormatter) -> None: # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore # NOTE(sriram-mv): `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/sync/core/formatters.py b/samcli/commands/sync/core/formatters.py deleted file mode 100644 index a9dec82f76..0000000000 --- a/samcli/commands/sync/core/formatters.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -Sync Command Formatter. -""" - -from samcli.cli.formatters import RootCommandHelpTextFormatter -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.sync.core.options import ALL_OPTIONS - - -class SyncCommandHelpTextFormatter(RootCommandHelpTextFormatter): - # Picked an additive constant that gives an aesthetically pleasing look. - ADDITIVE_JUSTIFICATION = 11 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # NOTE(sriram-mv): Add Additional space after determining the longest option. - # However, do not justify with padding for more than half the width of - # the terminal to retain aesthetics. - self.left_justification_length = min( - max([len(option) for option in ALL_OPTIONS]) + self.ADDITIVE_JUSTIFICATION, - self.width // 2 - self.indent_increment, - ) - self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/sync/core/options.py b/samcli/commands/sync/core/options.py index 509261025c..0d2e34d5e3 100644 --- a/samcli/commands/sync/core/options.py +++ b/samcli/commands/sync/core/options.py @@ -65,10 +65,9 @@ "Configuration Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, "extras": [ - RowDefinition(name="Learn more about configuration files at:"), RowDefinition( - name="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli" - "-config.html. " + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." ), ], }, diff --git a/samcli/commands/traces/command.py b/samcli/commands/traces/command.py index fc0c1bc518..8d405d6757 100644 --- a/samcli/commands/traces/command.py +++ b/samcli/commands/traces/command.py @@ -11,24 +11,30 @@ from samcli.cli.main import common_options as cli_framework_options from samcli.commands._utils.command_exception_handler import command_exception_handler from samcli.commands._utils.options import common_observability_options +from samcli.commands.traces.core.command import TracesCommand from samcli.lib.observability.util import OutputOption from samcli.lib.telemetry.metric import track_command from samcli.lib.utils.version_checker import check_newer_version LOG = logging.getLogger(__name__) -HELP_TEXT = """ -Use this command to fetch AWS X-Ray traces generated by your stack.\n -\b -Run the following command to fetch X-Ray traces by ID. -$ sam traces --trace-id tracing-id-1 --trace-id tracing-id-2 -\b -Run the following command to tail X-Ray traces as they become available. -$ sam traces --tail +SHORT_HELP = "Fetch AWS X-Ray traces" + +HELP_TEXT = """Use this command to fetch AWS X-Ray traces generated by your stack.""" + +DESCRIPTION = """ + Fetch AWS X-Ray traces generated by your stack. """ -@click.command("traces", help=HELP_TEXT, short_help="Fetch AWS X-Ray traces") +@click.command( + "traces", + cls=TracesCommand, + short_help=SHORT_HELP, + help=HELP_TEXT, + description=DESCRIPTION, + context_settings={"max_content_width": 120}, +) @configuration_option(provider=ConfigProvider(section="parameters")) @click.option( "--trace-id", diff --git a/samcli/commands/traces/core/__init__.py b/samcli/commands/traces/core/__init__.py new file mode 100644 index 0000000000..3d6e8dfb83 --- /dev/null +++ b/samcli/commands/traces/core/__init__.py @@ -0,0 +1,3 @@ +""" +Traces Command Core +""" diff --git a/samcli/commands/traces/core/command.py b/samcli/commands/traces/core/command.py new file mode 100644 index 0000000000..ff7448bc73 --- /dev/null +++ b/samcli/commands/traces/core/command.py @@ -0,0 +1,51 @@ +""" +Traces Command Class +""" + +from click import Context, style + +from samcli.cli.core.command import CoreCommand +from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.traces.core.options import ALL_OPTIONS, OPTIONS_INFO + + +class TracesCommand(CoreCommand): + class CustomFormatterContext(Context): + def make_formatter(self): + return CommandHelpTextFormatter( + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) + + context_class = CustomFormatterContext + + @staticmethod + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): + with formatter.indented_section(name="Examples", extra_indents=1): + with formatter.indented_section(name="Fetch traces by ID", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} --trace-id tracing-id-1 --trace-id tracing-id-2"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + with formatter.indented_section(name="Tail traces as they become available", extra_indents=1): + formatter.write_text_rows( + [ + RowDefinition( + name=style(f"$ {ctx.command_path} --tail"), + extra_row_modifiers=[ShowcaseRowModifier()], + ), + ] + ) + + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter): # type: ignore + self.format_description(formatter) + TracesCommand.format_examples(ctx, formatter) + CoreCommand._format_options( + ctx=ctx, params=self.get_params(ctx), formatter=formatter, formatting_options=OPTIONS_INFO + ) diff --git a/samcli/commands/traces/core/options.py b/samcli/commands/traces/core/options.py new file mode 100644 index 0000000000..312ec4ca21 --- /dev/null +++ b/samcli/commands/traces/core/options.py @@ -0,0 +1,32 @@ +""" +Traces Command Options +""" + +from typing import Dict + +from samcli.cli.core.options import ALL_COMMON_OPTIONS, add_common_options_info +from samcli.cli.row_modifiers import RowDefinition + +TRACES_OPTION_NAMES = ["trace_id", "tail", "start_time", "end_time", "output"] +AWS_CREDENTIAL_OPTION_NAMES = ["region", "profile"] +CONFIGURATION_OPTION_NAMES = ["config_file", "config_env", "save_params"] + +ALL_OPTIONS = TRACES_OPTION_NAMES + AWS_CREDENTIAL_OPTION_NAMES + CONFIGURATION_OPTION_NAMES + ALL_COMMON_OPTIONS + +OPTIONS_INFO: Dict[str, Dict] = { + "Traces Options": {"option_names": {opt: {"rank": idx} for idx, opt in enumerate(TRACES_OPTION_NAMES)}}, + "AWS Credential Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(AWS_CREDENTIAL_OPTION_NAMES)} + }, + "Configuration Options": { + "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, + "extras": [ + RowDefinition( + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." + ), + ], + }, +} + +add_common_options_info(OPTIONS_INFO) diff --git a/samcli/commands/validate/core/command.py b/samcli/commands/validate/core/command.py index f1b52b29f8..fade2d6feb 100644 --- a/samcli/commands/validate/core/command.py +++ b/samcli/commands/validate/core/command.py @@ -6,25 +6,28 @@ from samcli.cli.core.command import CoreCommand from samcli.cli.row_modifiers import RowDefinition, ShowcaseRowModifier -from samcli.commands.validate.core.formatters import ValidateCommandHelpTextFormatter -from samcli.commands.validate.core.options import OPTIONS_INFO +from samcli.commands.common.formatters import CommandHelpTextFormatter +from samcli.commands.validate.core.options import ALL_OPTIONS, OPTIONS_INFO class ValidateCommand(CoreCommand): class CustomFormatterContext(Context): - formatter_class = ValidateCommandHelpTextFormatter + def make_formatter(self): + return CommandHelpTextFormatter( + additive_justification=16, + options=ALL_OPTIONS, + width=self.terminal_width, + max_width=self.max_content_width, + ) context_class = CustomFormatterContext @staticmethod - def format_examples(ctx: Context, formatter: ValidateCommandHelpTextFormatter): + def format_examples(ctx: Context, formatter: CommandHelpTextFormatter): with formatter.indented_section(name="Examples", extra_indents=1): with formatter.indented_section(name="Validate and Lint", extra_indents=1): - formatter.write_rd( + formatter.write_text_rows( [ - RowDefinition( - text="\n", - ), RowDefinition( name=style(f"$ {ctx.command_path} --lint"), extra_row_modifiers=[ShowcaseRowModifier()], @@ -32,7 +35,7 @@ def format_examples(ctx: Context, formatter: ValidateCommandHelpTextFormatter): ] ) - def format_options(self, ctx: Context, formatter: ValidateCommandHelpTextFormatter) -> None: # type: ignore + def format_options(self, ctx: Context, formatter: CommandHelpTextFormatter) -> None: # type: ignore # NOTE(sriram-mv): `ignore` is put in place here for mypy even though it is the correct behavior, # as the `formatter_class` can be set in subclass of Command. If ignore is not set, # mypy raises argument needs to be HelpFormatter as super class defines it. diff --git a/samcli/commands/validate/core/formatters.py b/samcli/commands/validate/core/formatters.py deleted file mode 100644 index 69f12b0a4b..0000000000 --- a/samcli/commands/validate/core/formatters.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Validate Command Formatter. -""" - -from samcli.cli.formatters import RootCommandHelpTextFormatter -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.validate.core.options import ALL_OPTIONS - - -class ValidateCommandHelpTextFormatter(RootCommandHelpTextFormatter): - ADDITIVE_JUSTIFICATION = 16 - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - # NOTE(sriram-mv): Add Additional space after determining the longest option. - # However, do not justify with padding for more than half the width of - # the terminal to retain aesthetics. - self.left_justification_length = min( - max([len(option) for option in ALL_OPTIONS]) + self.ADDITIVE_JUSTIFICATION, - self.width // 2 - self.indent_increment, - ) - self.modifiers = [BaseLineRowModifier()] diff --git a/samcli/commands/validate/core/options.py b/samcli/commands/validate/core/options.py index 61eb1d0abf..24efd90896 100644 --- a/samcli/commands/validate/core/options.py +++ b/samcli/commands/validate/core/options.py @@ -33,10 +33,9 @@ "Configuration Options": { "option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)}, "extras": [ - RowDefinition(name="Learn more about configuration files at:"), RowDefinition( - name="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli" - "-config.html. " + name="Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." ), ], }, diff --git a/schema/samcli.json b/schema/samcli.json index 343a22b829..f6c84d0473 100644 --- a/schema/samcli.json +++ b/schema/samcli.json @@ -717,7 +717,7 @@ "properties": { "parameters": { "title": "Parameters for the local start api command", - "description": "Available parameters for the local start api command:\n* terraform_plan_file:\nUsed for passing a custom plan file when executing the Terraform hook.\n* hook_name:\nHook package id to extend AWS SAM CLI commands functionality. \n\nExample: `terraform` to extend AWS SAM CLI commands functionality to support terraform applications. \n\nAvailable Hook Names: ['terraform']\n* skip_prepare_infra:\nSkip preparation stage when there are no infrastructure changes. Only used in conjunction with --hook-name.\n* host:\nLocal hostname or IP address to bind to (default: '127.0.0.1')\n* port:\nLocal port number to listen on (default: '3000')\n* static_dir:\nAny static assets (e.g. CSS/Javascript/HTML) files located in this directory will be presented at /\n* disable_authorizer:\nDisable custom Lambda Authorizers from being parsed and invoked.\n* ssl_cert_file:\nPath to SSL certificate file (default: None)\n* ssl_key_file:\nPath to SSL key file (default: None)\n* template_file:\nAWS SAM template which references built artifacts for resources in the template. (if applicable)\n* env_vars:\nJSON file containing values for Lambda function's environment variables.\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* debug_port:\nWhen specified, Lambda function container will start in debug mode and will expose this port on localhost.\n* debugger_path:\nHost path to a debugger that will be mounted into the Lambda container.\n* debug_args:\nAdditional arguments to be passed to the debugger.\n* container_env_vars:\nJSON file containing additional environment variables to be set within the container when used in a debugging session locally.\n* docker_volume_basedir:\nSpecify the location basedir where the SAM template exists. If Docker is running on a remote machine, Path of the SAM template must be mounted on the Docker machine and modified to match the remote machine.\n* log_file:\nFile to capture output logs.\n* layer_cache_basedir:\nSpecify the location basedir where the lambda layers used by the template will be downloaded to.\n* skip_pull_image:\nSkip pulling down the latest Docker image for Lambda runtime.\n* docker_network:\nName or ID of an existing docker network for AWS Lambda docker containers to connect to, along with the default bridge network. If not specified, the Lambda containers will only connect to the default bridge docker network.\n* force_image_build:\nForce rebuilding the image used for invoking functions with layers.\n* warm_containers:\nOptional. Specifies how AWS SAM CLI manages \ncontainers for each function.\nTwo modes are available:\nEAGER: Containers for all functions are \nloaded at startup and persist between \ninvocations.\nLAZY: Containers are only loaded when each \nfunction is first invoked. Those containers \npersist for additional invocations.\n* debug_function:\nOptional. Specifies the Lambda Function logicalId to apply debug options to when --warm-containers is specified. This parameter applies to --debug-port, --debugger-path, and --debug-args.\n* shutdown:\nEmulate a shutdown event after invoke completes, to test extension handling of shutdown behavior.\n* container_host:\nHost of locally emulated Lambda container. This option is useful when the container runs on a different host than AWS SAM CLI. For example, if one wants to run AWS SAM CLI in a Docker container on macOS, this option could specify `host.docker.internal`\n* container_host_interface:\nIP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.\n* add_host:\nPasses a hostname to IP address mapping to the Docker container's host file. This parameter can be passed multiple times.Example:--add-host example.com:127.0.0.1\n* invoke_image:\nContainer image URIs for invoking functions or starting api and function. One can specify the image URI used for the local function invocation (--invoke-image public.ecr.aws/sam/build-nodejs20.x:latest). One can also specify for each individual function with (--invoke-image Function1=public.ecr.aws/sam/build-nodejs20.x:latest). If a function does not have invoke image specified, the default AWS SAM CLI emulation image will be used.\n* no_memory_limit:\nRemoves the Memory limit during emulation. With this parameter, the underlying container will run without a --memory parameter\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* save_params:\nSave the parameters provided via the command line to the configuration file.", + "description": "Available parameters for the local start api command:\n* terraform_plan_file:\nUsed for passing a custom plan file when executing the Terraform hook.\n* hook_name:\nHook package id to extend AWS SAM CLI commands functionality. \n\nExample: `terraform` to extend AWS SAM CLI commands functionality to support terraform applications. \n\nAvailable Hook Names: ['terraform']\n* skip_prepare_infra:\nSkip preparation stage when there are no infrastructure changes. Only used in conjunction with --hook-name.\n* host:\nLocal hostname or IP address to bind to (default: '127.0.0.1')\n* port:\nLocal port number to listen on (default: '3000')\n* static_dir:\nAny static assets (e.g. CSS/Javascript/HTML) files located in this directory will be presented at /\n* disable_authorizer:\nDisable custom Lambda Authorizers from being parsed and invoked.\n* ssl_cert_file:\nPath to SSL certificate file (default: None)\n* ssl_key_file:\nPath to SSL key file (default: None)\n* template_file:\nAWS SAM template which references built artifacts for resources in the template. (if applicable)\n* env_vars:\nJSON file containing values for Lambda function's environment variables.\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* debug_port:\nWhen specified, Lambda function container will start in debug mode and will expose this port on localhost.\n* debugger_path:\nHost path to a debugger that will be mounted into the Lambda container.\n* debug_args:\nAdditional arguments to be passed to the debugger.\n* container_env_vars:\nJSON file containing additional environment variables to be set within the container when used in a debugging session locally.\n* docker_volume_basedir:\nSpecify the location basedir where the SAM template exists. If Docker is running on a remote machine, Path of the SAM template must be mounted on the Docker machine and modified to match the remote machine.\n* log_file:\nFile to capture output logs.\n* layer_cache_basedir:\nSpecify the location basedir where the lambda layers used by the template will be downloaded to.\n* skip_pull_image:\nSkip pulling down the latest Docker image for Lambda runtime.\n* docker_network:\nName or ID of an existing docker network for AWS Lambda docker containers to connect to, along with the default bridge network. If not specified, the Lambda containers will only connect to the default bridge docker network.\n* force_image_build:\nForce rebuilding the image used for invoking functions with layers.\n* warm_containers:\nOptional. Specifies how AWS SAM CLI manages containers for each function.' \n\nTwo modes are available:\nEAGER: Containers for all functions are loaded at startup and persist between invocations.\nLAZY: Containers are only loaded when each function is first invoked. \n Those containers persist for additional invocations.\n* debug_function:\nOptional. Specifies the Lambda Function logicalId to apply debug options to when --warm-containers is specified. This parameter applies to --debug-port, --debugger-path, and --debug-args.\n* shutdown:\nEmulate a shutdown event after invoke completes, to test extension handling of shutdown behavior.\n* container_host:\nHost of locally emulated Lambda container. This option is useful when the container runs on a different host than AWS SAM CLI. For example, if one wants to run AWS SAM CLI in a Docker container on macOS, this option could specify `host.docker.internal`\n* container_host_interface:\nIP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.\n* add_host:\nPasses a hostname to IP address mapping to the Docker container's host file. This parameter can be passed multiple times.Example:--add-host example.com:127.0.0.1\n* invoke_image:\nContainer image URIs for invoking functions or starting api and function. One can specify the image URI used for the local function invocation (--invoke-image public.ecr.aws/sam/build-nodejs20.x:latest). One can also specify for each individual function with (--invoke-image Function1=public.ecr.aws/sam/build-nodejs20.x:latest). If a function does not have invoke image specified, the default AWS SAM CLI emulation image will be used.\n* no_memory_limit:\nRemoves the Memory limit during emulation. With this parameter, the underlying container will run without a --memory parameter\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* save_params:\nSave the parameters provided via the command line to the configuration file.", "type": "object", "properties": { "terraform_plan_file": { @@ -844,7 +844,7 @@ "warm_containers": { "title": "warm_containers", "type": "string", - "description": "Optional. Specifies how AWS SAM CLI manages \ncontainers for each function.\nTwo modes are available:\nEAGER: Containers for all functions are \nloaded at startup and persist between \ninvocations.\nLAZY: Containers are only loaded when each \nfunction is first invoked. Those containers \npersist for additional invocations.", + "description": "Optional. Specifies how AWS SAM CLI manages containers for each function.' \n\nTwo modes are available:\nEAGER: Containers for all functions are loaded at startup and persist between invocations.\nLAZY: Containers are only loaded when each function is first invoked. \n Those containers persist for additional invocations.", "enum": [ "EAGER", "LAZY" @@ -928,7 +928,7 @@ "properties": { "parameters": { "title": "Parameters for the local start lambda command", - "description": "Available parameters for the local start lambda command:\n* terraform_plan_file:\nUsed for passing a custom plan file when executing the Terraform hook.\n* hook_name:\nHook package id to extend AWS SAM CLI commands functionality. \n\nExample: `terraform` to extend AWS SAM CLI commands functionality to support terraform applications. \n\nAvailable Hook Names: ['terraform']\n* skip_prepare_infra:\nSkip preparation stage when there are no infrastructure changes. Only used in conjunction with --hook-name.\n* host:\nLocal hostname or IP address to bind to (default: '127.0.0.1')\n* port:\nLocal port number to listen on (default: '3001')\n* template_file:\nAWS SAM template which references built artifacts for resources in the template. (if applicable)\n* env_vars:\nJSON file containing values for Lambda function's environment variables.\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* debug_port:\nWhen specified, Lambda function container will start in debug mode and will expose this port on localhost.\n* debugger_path:\nHost path to a debugger that will be mounted into the Lambda container.\n* debug_args:\nAdditional arguments to be passed to the debugger.\n* container_env_vars:\nJSON file containing additional environment variables to be set within the container when used in a debugging session locally.\n* docker_volume_basedir:\nSpecify the location basedir where the SAM template exists. If Docker is running on a remote machine, Path of the SAM template must be mounted on the Docker machine and modified to match the remote machine.\n* log_file:\nFile to capture output logs.\n* layer_cache_basedir:\nSpecify the location basedir where the lambda layers used by the template will be downloaded to.\n* skip_pull_image:\nSkip pulling down the latest Docker image for Lambda runtime.\n* docker_network:\nName or ID of an existing docker network for AWS Lambda docker containers to connect to, along with the default bridge network. If not specified, the Lambda containers will only connect to the default bridge docker network.\n* force_image_build:\nForce rebuilding the image used for invoking functions with layers.\n* warm_containers:\nOptional. Specifies how AWS SAM CLI manages \ncontainers for each function.\nTwo modes are available:\nEAGER: Containers for all functions are \nloaded at startup and persist between \ninvocations.\nLAZY: Containers are only loaded when each \nfunction is first invoked. Those containers \npersist for additional invocations.\n* debug_function:\nOptional. Specifies the Lambda Function logicalId to apply debug options to when --warm-containers is specified. This parameter applies to --debug-port, --debugger-path, and --debug-args.\n* shutdown:\nEmulate a shutdown event after invoke completes, to test extension handling of shutdown behavior.\n* container_host:\nHost of locally emulated Lambda container. This option is useful when the container runs on a different host than AWS SAM CLI. For example, if one wants to run AWS SAM CLI in a Docker container on macOS, this option could specify `host.docker.internal`\n* container_host_interface:\nIP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.\n* add_host:\nPasses a hostname to IP address mapping to the Docker container's host file. This parameter can be passed multiple times.Example:--add-host example.com:127.0.0.1\n* invoke_image:\nContainer image URIs for invoking functions or starting api and function. One can specify the image URI used for the local function invocation (--invoke-image public.ecr.aws/sam/build-nodejs20.x:latest). One can also specify for each individual function with (--invoke-image Function1=public.ecr.aws/sam/build-nodejs20.x:latest). If a function does not have invoke image specified, the default AWS SAM CLI emulation image will be used.\n* no_memory_limit:\nRemoves the Memory limit during emulation. With this parameter, the underlying container will run without a --memory parameter\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* save_params:\nSave the parameters provided via the command line to the configuration file.", + "description": "Available parameters for the local start lambda command:\n* terraform_plan_file:\nUsed for passing a custom plan file when executing the Terraform hook.\n* hook_name:\nHook package id to extend AWS SAM CLI commands functionality. \n\nExample: `terraform` to extend AWS SAM CLI commands functionality to support terraform applications. \n\nAvailable Hook Names: ['terraform']\n* skip_prepare_infra:\nSkip preparation stage when there are no infrastructure changes. Only used in conjunction with --hook-name.\n* host:\nLocal hostname or IP address to bind to (default: '127.0.0.1')\n* port:\nLocal port number to listen on (default: '3001')\n* template_file:\nAWS SAM template which references built artifacts for resources in the template. (if applicable)\n* env_vars:\nJSON file containing values for Lambda function's environment variables.\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* debug_port:\nWhen specified, Lambda function container will start in debug mode and will expose this port on localhost.\n* debugger_path:\nHost path to a debugger that will be mounted into the Lambda container.\n* debug_args:\nAdditional arguments to be passed to the debugger.\n* container_env_vars:\nJSON file containing additional environment variables to be set within the container when used in a debugging session locally.\n* docker_volume_basedir:\nSpecify the location basedir where the SAM template exists. If Docker is running on a remote machine, Path of the SAM template must be mounted on the Docker machine and modified to match the remote machine.\n* log_file:\nFile to capture output logs.\n* layer_cache_basedir:\nSpecify the location basedir where the lambda layers used by the template will be downloaded to.\n* skip_pull_image:\nSkip pulling down the latest Docker image for Lambda runtime.\n* docker_network:\nName or ID of an existing docker network for AWS Lambda docker containers to connect to, along with the default bridge network. If not specified, the Lambda containers will only connect to the default bridge docker network.\n* force_image_build:\nForce rebuilding the image used for invoking functions with layers.\n* warm_containers:\nOptional. Specifies how AWS SAM CLI manages containers for each function.' \n\nTwo modes are available:\nEAGER: Containers for all functions are loaded at startup and persist between invocations.\nLAZY: Containers are only loaded when each function is first invoked. \n Those containers persist for additional invocations.\n* debug_function:\nOptional. Specifies the Lambda Function logicalId to apply debug options to when --warm-containers is specified. This parameter applies to --debug-port, --debugger-path, and --debug-args.\n* shutdown:\nEmulate a shutdown event after invoke completes, to test extension handling of shutdown behavior.\n* container_host:\nHost of locally emulated Lambda container. This option is useful when the container runs on a different host than AWS SAM CLI. For example, if one wants to run AWS SAM CLI in a Docker container on macOS, this option could specify `host.docker.internal`\n* container_host_interface:\nIP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.\n* add_host:\nPasses a hostname to IP address mapping to the Docker container's host file. This parameter can be passed multiple times.Example:--add-host example.com:127.0.0.1\n* invoke_image:\nContainer image URIs for invoking functions or starting api and function. One can specify the image URI used for the local function invocation (--invoke-image public.ecr.aws/sam/build-nodejs20.x:latest). One can also specify for each individual function with (--invoke-image Function1=public.ecr.aws/sam/build-nodejs20.x:latest). If a function does not have invoke image specified, the default AWS SAM CLI emulation image will be used.\n* no_memory_limit:\nRemoves the Memory limit during emulation. With this parameter, the underlying container will run without a --memory parameter\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* save_params:\nSave the parameters provided via the command line to the configuration file.", "type": "object", "properties": { "terraform_plan_file": { @@ -1034,7 +1034,7 @@ "warm_containers": { "title": "warm_containers", "type": "string", - "description": "Optional. Specifies how AWS SAM CLI manages \ncontainers for each function.\nTwo modes are available:\nEAGER: Containers for all functions are \nloaded at startup and persist between \ninvocations.\nLAZY: Containers are only loaded when each \nfunction is first invoked. Those containers \npersist for additional invocations.", + "description": "Optional. Specifies how AWS SAM CLI manages containers for each function.' \n\nTwo modes are available:\nEAGER: Containers for all functions are loaded at startup and persist between invocations.\nLAZY: Containers are only loaded when each function is first invoked. \n Those containers persist for additional invocations.", "enum": [ "EAGER", "LAZY" @@ -1589,7 +1589,7 @@ }, "publish": { "title": "Publish command", - "description": "Use this command to publish a packaged AWS SAM template to\nthe AWS Serverless Application Repository to share within your team,\nacross your organization, or with the community at large.\n\n\nThis command expects the template's Metadata section to contain an\nAWS::ServerlessRepo::Application section with application metadata\nfor publishing. For more details on this metadata section, see\nhttps://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template-publishing-applications.html\n\nExamples\n--------\nTo publish an application\n$ sam publish -t packaged.yaml --region ", + "description": "Publish a packaged AWS SAM template to the AWS Serverless Application Repository.", "properties": { "parameters": { "title": "Parameters for the publish command", @@ -1646,7 +1646,7 @@ }, "traces": { "title": "Traces command", - "description": "Use this command to fetch AWS X-Ray traces generated by your stack.\n\n\nRun the following command to fetch X-Ray traces by ID.\n$ sam traces --trace-id tracing-id-1 --trace-id tracing-id-2\n\nRun the following command to tail X-Ray traces as they become available.\n$ sam traces --tail", + "description": "Use this command to fetch AWS X-Ray traces generated by your stack.", "properties": { "parameters": { "title": "Parameters for the traces command", @@ -1717,7 +1717,7 @@ }, "sync": { "title": "Sync command", - "description": "NEW! Sync an AWS SAM Project to AWS.", + "description": "Sync an AWS SAM Project to AWS.", "properties": { "parameters": { "title": "Parameters for the sync command", @@ -2326,7 +2326,7 @@ }, "docs": { "title": "Docs command", - "description": "NEW! Open the documentation in a browser.", + "description": "Open the documentation in a browser.", "properties": { "parameters": { "title": "Parameters for the docs command", diff --git a/tests/unit/cli/test_command.py b/tests/unit/cli/test_command.py index cd7f052c90..4de6f84f1f 100644 --- a/tests/unit/cli/test_command.py +++ b/tests/unit/cli/test_command.py @@ -51,6 +51,9 @@ def indented_section(self, name, extra_indents=0): def write_rd(self, rows, col_max=None): self.data[list(self.data.keys())[-1]] = [(row.name, "" if self.scrub_text else row.text) for row in rows] + def write_text_rows(self, rows): + self.data[list(self.data.keys())[-1]] = [(row.name, "" if self.scrub_text else row.text) for row in rows] + class TestBaseCommand(TestCase): def setUp(self): @@ -157,15 +160,28 @@ def test_get_options_root_command_text(self, mock_get_params, mock_format_comman mock_get_params.return_value = [MockParams(rv=("--region", "Region"))] cmd = BaseCommand(cmd_packages=self.packages) - expected_output = {"Options": [("", ""), ("--region", "")], "Examples": [("", ""), ("Get Started:", "")]} + # Updated expected output to match compact formatting (no blank lines) + expected_output = { + "Options": [("--region", "")], + "Examples": [], + "Get Started": [("$ init\x1b[0m", "")], + } cmd.format_options(ctx, formatter) - self.assertEqual(formatter.data, expected_output) + # Compare keys and structure, ignoring the exact mock ID in the command path + self.assertEqual(set(formatter.data.keys()), set(expected_output.keys())) + self.assertEqual(formatter.data["Options"], expected_output["Options"]) + self.assertEqual(formatter.data["Examples"], expected_output["Examples"]) + # Check that Get Started section exists and has the right structure + self.assertEqual(len(formatter.data["Get Started"]), 1) + # Check that the item contains "init" command + self.assertIn("init", formatter.data["Get Started"][0][0]) def test_get_command_root_command_text(self): ctx = Mock() formatter = MockFormatter() cmd = BaseCommand() + # Updated expected output to match compact formatting (no blank lines) expected_output = { "Commands": [], "Learn": [("docs", "docs command output")], @@ -177,8 +193,14 @@ def test_get_command_root_command_text(self): ("sync", "sync command output"), ("remote", "remote command output"), ], - "Deploy your App": [("package", "package command output"), ("deploy", "deploy command output")], - "Monitor your App": [("logs", "logs command output"), ("traces", "traces command output")], + "Deploy your App": [ + ("package", "package command output"), + ("deploy", "deploy command output"), + ], + "Monitor your App": [ + ("logs", "logs command output"), + ("traces", "traces command output"), + ], "And More": [ ("list", "list command output"), ("delete", "delete command output"), diff --git a/tests/unit/cli/test_formatters.py b/tests/unit/cli/test_formatters.py index 34347edb33..6c28cb296b 100644 --- a/tests/unit/cli/test_formatters.py +++ b/tests/unit/cli/test_formatters.py @@ -16,8 +16,10 @@ def test_write_usage(self): prog = "sam" args = "validate" prefix = "usage: " + # Expected: blank line, then bold+underlined prefix with bold prog name expected_output = [ - call(f"usage: \x1b[1m{prog}\x1b[0m {args}"), + call("\n"), # Blank line before usage + call(f"\x1b[1m\x1b[4m{prefix}\x1b[0m\x1b[1m{prog}\x1b[0m {args}"), call("\n"), ] with patch.object(self.formatter, "write") as mock_write: diff --git a/tests/unit/commands/buildcmd/core/test_command.py b/tests/unit/commands/buildcmd/core/test_command.py index 431eb526a1..6e6020ab4e 100644 --- a/tests/unit/commands/buildcmd/core/test_command.py +++ b/tests/unit/commands/buildcmd/core/test_command.py @@ -38,27 +38,35 @@ def test_get_options_build_command_text(self, mock_get_params): cmd = BuildCommand(name="sync", requires_credentials=False, description=DESCRIPTION) expected_output = { - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Container Options": [("", ""), ("--use-container", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Extension Options": [("", ""), ("--hook-name", ""), ("", "")], - "Terraform Hook Options": [("", ""), ("--terraform-project-root-path", ""), ("", "")], - "Build Strategy Options": [("", ""), ("--parallel", ""), ("", "")], - "Artifact Location Options": [("", ""), ("--build-dir", ""), ("", "")], - "Template Options": [("", ""), ("--parameter-overrides", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], - "Required Options": [("", ""), ("--template-file", ""), ("", "")], "Description": [(cmd.description + cmd.description_addendum, "")], - "Examples": [ - ("", ""), - ("$ sam build\x1b[0m", ""), - ("$ sam build FUNCTION_LOGICAL_ID\x1b[0m", ""), - ("$ sam build --use-container\x1b[0m", ""), + "Examples": [], + "Build sam project": [("$ sam build\x1b[0m", "")], + "Build sam project for a specific function": [("$ sam build FUNCTION_LOGICAL_ID\x1b[0m", "")], + "Build sam project using container": [("$ sam build --use-container\x1b[0m", "")], + "Build sam project using container with environment variable file": [ ("$ sam build --use-container --container-env-var-file env.json\x1b[0m", ""), + ], + "Build sam project and invoke default function locally": [ ("$ sam build && sam local invoke\x1b[0m", ""), - ("$ sam build && sam deploy\x1b[0m", ""), ], + "Build sam project and deploy": [("$ sam build && sam deploy\x1b[0m", "")], + "Required Options": [("--template-file", "")], + "Template Options": [("--parameter-overrides", "")], + "AWS Credential Options": [("--region", "")], + "Build Strategy Options": [("--parallel", "")], + "Container Options": [("--use-container", "")], + "Artifact Location Options": [("--build-dir", "")], + "Extension Options": [("--hook-name", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], + "Terraform Hook Options": [("--terraform-project-root-path", "")], + "Beta Options": [("--beta-features", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) diff --git a/tests/unit/commands/buildcmd/core/test_formatter.py b/tests/unit/commands/buildcmd/core/test_formatter.py deleted file mode 100644 index 7bec50e881..0000000000 --- a/tests/unit/commands/buildcmd/core/test_formatter.py +++ /dev/null @@ -1,12 +0,0 @@ -from shutil import get_terminal_size -from unittest import TestCase - -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.build.core.formatters import BuildCommandHelpTextFormatter - - -class TestBuildCommandHelpTextFormatter(TestCase): - def test_build_formatter(self): - self.formatter = BuildCommandHelpTextFormatter() - self.assertTrue(self.formatter.left_justification_length <= get_terminal_size().columns // 2) - self.assertIsInstance(self.formatter.modifiers[0], BaseLineRowModifier) diff --git a/tests/unit/commands/deploy/core/test_command.py b/tests/unit/commands/deploy/core/test_command.py index 0562ec7e1e..e01418bb37 100644 --- a/tests/unit/commands/deploy/core/test_command.py +++ b/tests/unit/commands/deploy/core/test_command.py @@ -36,25 +36,40 @@ def test_get_options_deploy_command_text(self, mock_get_params): cmd = DeployCommand(name="deploy", requires_credentials=False, description=DESCRIPTION) expected_output = { - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Additional Options": [("", ""), ("--signing-profiles", ""), ("", "")], - "Deployment Options": [("", ""), ("--no-execute-changeset", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], - "Required Options": [("", ""), ("--stack-name", ""), ("", "")], - "Infrastructure Options": [("", ""), ("--s3-bucket", ""), ("", "")], - "Interactive Options": [("", ""), ("--guided", ""), ("", "")], + "AWS Credential Options": [("--region", "")], + "Additional Options": [("--signing-profiles", "")], + "Deployment Options": [("--no-execute-changeset", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], + "Beta Options": [("--beta-features", "")], + "Other Options": [("--debug", "")], + "Required Options": [("--stack-name", "")], + "Infrastructure Options": [("--s3-bucket", "")], + "Interactive Options": [ + ("Use the guided flag for a step-by-step flow instead of using the required options. ", ""), + ("--guided", ""), + ], "Description": [(cmd.description + cmd.description_addendum, "")], - "Acronyms": [("", ""), ("IAM", ""), ("ARN", ""), ("S3", ""), ("SNS", ""), ("ECR", ""), ("KMS", "")], - "Examples": [ - ("", ""), + "Acronyms": [("IAM", ""), ("ARN", ""), ("S3", ""), ("SNS", ""), ("ECR", ""), ("KMS", "")], + "Examples": [], + "Deploy with guided prompts": [ ("$ sam deploy --guided\x1b[0m", ""), + ], + "Deploy with specified parameters": [ ( "$ sam deploy --template-file packaged.yaml --stack-name sam-app --capabilities CAPABILITY_IAM\x1b[0m", "", ), + ], + "Deploy with parameter overrides using CloudFormation syntax": [ ("$ sam deploy --parameter-overrides 'ParameterKey=InstanceType,ParameterValue=t1.micro'\x1b[0m", ""), + ], + "Deploy with parameter overrides using shorthand syntax": [ ("$ sam deploy --parameter-overrides KeyPairName=MyKey InstanceType=t1.micro\x1b[0m", ""), ], } diff --git a/tests/unit/commands/deploy/core/test_formatter.py b/tests/unit/commands/deploy/core/test_formatter.py deleted file mode 100644 index f050cf7044..0000000000 --- a/tests/unit/commands/deploy/core/test_formatter.py +++ /dev/null @@ -1,12 +0,0 @@ -from shutil import get_terminal_size -from unittest import TestCase - -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.deploy.core.formatters import DeployCommandHelpTextFormatter - - -class TestDeployCommandHelpTextFormatter(TestCase): - def test_deploy_formatter(self): - self.formatter = DeployCommandHelpTextFormatter() - self.assertTrue(self.formatter.left_justification_length <= get_terminal_size().columns // 2) - self.assertIsInstance(self.formatter.modifiers[0], BaseLineRowModifier) diff --git a/tests/unit/commands/docs/core/test_command.py b/tests/unit/commands/docs/core/test_command.py index 0e8dd7b212..66ab6807c4 100644 --- a/tests/unit/commands/docs/core/test_command.py +++ b/tests/unit/commands/docs/core/test_command.py @@ -23,7 +23,7 @@ def test_formatter(self): "Launch the AWS SAM CLI documentation in a browser! " "This command will\n show information about setting up credentials, " "the\n AWS SAM CLI lifecycle and other useful details. \n\n " - "The command also be run with sub-commands to open specific pages." + "The command can also be run with sub-commands to open specific pages." ), description[0][0], ) diff --git a/tests/unit/commands/init/core/test_command.py b/tests/unit/commands/init/core/test_command.py index c304126ded..78aec7955f 100644 --- a/tests/unit/commands/init/core/test_command.py +++ b/tests/unit/commands/init/core/test_command.py @@ -32,12 +32,16 @@ def test_get_options_init_command_text(self, mock_get_params): cmd = InitCommand(name="init", requires_credentials=False, description=DESCRIPTION) expected_output = { - "Additional Options": [("", ""), ("--tracing", ""), ("", "")], - "Application Options": [("", ""), ("--name", ""), ("", "")], - "Beta Options": [("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], + "Additional Options": [("--tracing", "")], + "Application Options": [("--name", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], "Customized Interactive Mode": [ - ("", ""), ("$ sam init --name sam-app --runtime " "nodejs18.x --architecture arm64\x1b[0m", ""), ( "$ sam init --name sam-app --runtime " @@ -49,7 +53,6 @@ def test_get_options_init_command_text(self, mock_get_params): ], "Description": [(cmd.description + cmd.description_addendum, "")], "Direct Initialization": [ - ("", ""), ("$ sam init --location " "gh:aws-samples/cookiecutter-aws-sam-python\x1b[0m", ""), ( "$ sam init --location " @@ -61,9 +64,9 @@ def test_get_options_init_command_text(self, mock_get_params): ("$ sam init --location " "https://example.com/path/to/template.zip\x1b[0m", ""), ], "Examples": [], - "Interactive Mode": [("", ""), ("$ sam init\x1b[0m", "")], - "Non Interactive Options": [("", ""), ("--no-interactive", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "Interactive Mode": [("$ sam init\x1b[0m", "")], + "Non Interactive Options": [("--no-interactive", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) diff --git a/tests/unit/commands/init/core/test_formatter.py b/tests/unit/commands/init/core/test_formatter.py deleted file mode 100644 index c518cdf016..0000000000 --- a/tests/unit/commands/init/core/test_formatter.py +++ /dev/null @@ -1,12 +0,0 @@ -from shutil import get_terminal_size -from unittest import TestCase - -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.init.core.formatters import InitCommandHelpTextFormatter - - -class TestInitCommandHelpTextFormatter(TestCase): - def test_init_formatter(self): - self.formatter = InitCommandHelpTextFormatter() - self.assertTrue(self.formatter.left_justification_length <= get_terminal_size().columns // 2) - self.assertIsInstance(self.formatter.modifiers[0], BaseLineRowModifier) diff --git a/tests/unit/commands/local/callback/fail/core/test_command.py b/tests/unit/commands/local/callback/fail/core/test_command.py index 02e0df97e5..df7d757119 100644 --- a/tests/unit/commands/local/callback/fail/core/test_command.py +++ b/tests/unit/commands/local/callback/fail/core/test_command.py @@ -36,6 +36,7 @@ def test_format_options(self, mock_get_params): MockParams(rv=("--stack-trace", "Stack trace information"), name="stack_trace"), MockParams(rv=("--error-type", "Type of error"), name="error_type"), MockParams(rv=("--error-message", "Detailed error message"), name="error_message"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), ] @@ -46,33 +47,25 @@ def test_format_options(self, mock_get_params): ], "Examples": [], "Send failure callback with no parameters": [ - ("", ""), ("$ sam local callback fail my-callback-id\x1b[0m", ""), ], "Send failure callback with error message": [ - ("", ""), ("$ sam local callback fail my-callback-id --error-message 'Task failed'\x1b[0m", ""), ], "Send failure callback with additional error details": [ - ("", ""), ( "$ sam local callback fail my-callback-id --error-message 'Task failed' --error-type 'ValidationError' --stack-trace 'at line 42' --error-data '{\"code\": 500}'\x1b[0m", "", ), ], "Callback Options": [ - ("", ""), ("--error-data", ""), - ("", ""), ("--stack-trace", ""), - ("", ""), ("--error-type", ""), - ("", ""), ("--error-message", ""), - ("", ""), ], - "Beta Options": [("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } # Act diff --git a/tests/unit/commands/local/callback/heartbeat/core/test_command.py b/tests/unit/commands/local/callback/heartbeat/core/test_command.py index c99fba6fa3..a1b89adc39 100644 --- a/tests/unit/commands/local/callback/heartbeat/core/test_command.py +++ b/tests/unit/commands/local/callback/heartbeat/core/test_command.py @@ -33,6 +33,7 @@ def test_format_options(self, mock_get_params): mock_get_params.return_value = [ MockParams(rv=("callback_id", "Callback ID"), name="callback_id"), MockParams(rv=("--debug", ""), name="debug"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), ] command = LocalCallbackHeartbeatCommand(name="heartbeat", description="Send heartbeat callback") @@ -41,9 +42,9 @@ def test_format_options(self, mock_get_params): ("Send heartbeat callback\x1b[1m\n This command may not require access to AWS credentials.\x1b[0m", "") ], "Examples": [], - "Send heartbeat callback": [("", ""), ("$ sam local callback heartbeat my-callback-id\x1b[0m", "")], - "Beta Options": [("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "Send heartbeat callback": [("$ sam local callback heartbeat my-callback-id\x1b[0m", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } # Act diff --git a/tests/unit/commands/local/callback/succeed/core/test_command.py b/tests/unit/commands/local/callback/succeed/core/test_command.py index 905c3d46c2..0a67bda9a1 100644 --- a/tests/unit/commands/local/callback/succeed/core/test_command.py +++ b/tests/unit/commands/local/callback/succeed/core/test_command.py @@ -34,6 +34,7 @@ def test_format_options(self, mock_get_params): MockParams(rv=("callback_id", "Callback ID"), name="callback_id"), MockParams(rv=("--result", "Result data"), name="result"), MockParams(rv=("--debug", ""), name="debug"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), ] command = LocalCallbackSucceedCommand(name="succeed", description="Send success callback") @@ -43,20 +44,17 @@ def test_format_options(self, mock_get_params): ], "Examples": [], "Send success callback with no result": [ - ("", ""), ("$ sam local callback succeed my-callback-id\x1b[0m", ""), ], "Send success callback with result": [ - ("", ""), ("$ sam local callback succeed my-callback-id --result 'Task completed successfully'\x1b[0m", ""), ], "Send success callback with short option": [ - ("", ""), ("$ sam local callback succeed my-callback-id -r 'Success result'\x1b[0m", ""), ], - "Callback Options": [("", ""), ("--result", ""), ("", "")], - "Beta Options": [("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "Callback Options": [("--result", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } # Act diff --git a/tests/unit/commands/local/execution/get/core/test_command.py b/tests/unit/commands/local/execution/get/core/test_command.py index b3e66588bb..2025eaac5f 100644 --- a/tests/unit/commands/local/execution/get/core/test_command.py +++ b/tests/unit/commands/local/execution/get/core/test_command.py @@ -31,8 +31,9 @@ def test_format_options(self, mock_get_params): mock_get_params.return_value = [ MockParams(rv=("durable_execution_arn", "Durable execution ARN"), name="durable_execution_arn"), + MockParams(rv=("--format", ""), name="format"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), - MockParams(rv=("--help", ""), name="help"), ] command = LocalExecutionGetCommand(name="get", description="Get durable function execution details") @@ -45,20 +46,14 @@ def test_format_options(self, mock_get_params): ], "Examples": [], "Get execution details": [ - ( - "$ sam local execution get c63eec67-3415-4eb4-a495-116aa3a86278\x1b[0m", - "", - ), + ("$ sam local execution get c63eec67-3415-4eb4-a495-116aa3a86278\x1b[0m", ""), ], "Get execution details in JSON format": [ - ( - "$ sam local execution get c63eec67-3415-4eb4-a495-116aa3a86278 --format json\x1b[0m", - "", - ), + ("$ sam local execution get c63eec67-3415-4eb4-a495-116aa3a86278 --format json\x1b[0m", ""), ], - "Formatting Options": [("", "")], - "Beta Options": [("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", ""), ("--help", ""), ("", "")], + "Formatting Options": [("--format", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } # Act diff --git a/tests/unit/commands/local/execution/history/core/test_command.py b/tests/unit/commands/local/execution/history/core/test_command.py index 0bd53de832..feac9ecf4e 100644 --- a/tests/unit/commands/local/execution/history/core/test_command.py +++ b/tests/unit/commands/local/execution/history/core/test_command.py @@ -31,8 +31,9 @@ def test_format_options(self, mock_get_params): mock_get_params.return_value = [ MockParams(rv=("durable_execution_arn", "Durable execution ARN"), name="durable_execution_arn"), + MockParams(rv=("--format", ""), name="format"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), - MockParams(rv=("--help", ""), name="help"), ] command = LocalExecutionHistoryCommand(name="history", description="Get durable function execution history") @@ -45,20 +46,14 @@ def test_format_options(self, mock_get_params): ], "Examples": [], "Get execution history": [ - ( - "$ sam local execution history c63eec67-3415-4eb4-a495-116aa3a86278\x1b[0m", - "", - ), + ("$ sam local execution history c63eec67-3415-4eb4-a495-116aa3a86278\x1b[0m", ""), ], "Get execution history in JSON format": [ - ( - "$ sam local execution history c63eec67-3415-4eb4-a495-116aa3a86278 --format json\x1b[0m", - "", - ), + ("$ sam local execution history c63eec67-3415-4eb4-a495-116aa3a86278 --format json\x1b[0m", ""), ], - "Formatting Options": [("", "")], - "Beta Options": [("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", ""), ("--help", ""), ("", "")], + "Formatting Options": [("--format", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } # Act diff --git a/tests/unit/commands/local/execution/stop/core/test_command.py b/tests/unit/commands/local/execution/stop/core/test_command.py index 6511fb766a..cc884ea24c 100644 --- a/tests/unit/commands/local/execution/stop/core/test_command.py +++ b/tests/unit/commands/local/execution/stop/core/test_command.py @@ -36,8 +36,8 @@ def test_format_options(self, mock_get_params): MockParams(rv=("--error-type", "Error type"), name="error_type"), MockParams(rv=("--error-data", "Error data"), name="error_data"), MockParams(rv=("--stack-trace", "Stack trace entries"), name="stack_trace"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), - MockParams(rv=("--help", ""), name="help"), ] command = LocalExecutionStopCommand(name="stop", description="Stop a durable function execution") @@ -50,10 +50,7 @@ def test_format_options(self, mock_get_params): ], "Examples": [], "Stop execution without error details": [ - ( - "$ sam local execution stop c63eec67-3415-4eb4-a495-116aa3a86278\x1b[0m", - "", - ), + ("$ sam local execution stop c63eec67-3415-4eb4-a495-116aa3a86278\x1b[0m", ""), ], "Stop execution with error message and type": [ ( @@ -68,18 +65,13 @@ def test_format_options(self, mock_get_params): ), ], "Stop Options": [ - ("", ""), ("--error-message", ""), - ("", ""), ("--error-type", ""), - ("", ""), ("--error-data", ""), - ("", ""), ("--stack-trace", ""), - ("", ""), ], - "Beta Options": [("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", ""), ("--help", ""), ("", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } # Act diff --git a/tests/unit/commands/local/generate_event/core/test_command.py b/tests/unit/commands/local/generate_event/core/test_command.py index 941be1b4ef..c0153eb36d 100644 --- a/tests/unit/commands/local/generate_event/core/test_command.py +++ b/tests/unit/commands/local/generate_event/core/test_command.py @@ -25,6 +25,28 @@ def test_get_options_local_invoke_command_text(self, mock_get_params): cmd = CoreGenerateEventCommand(name="local generate-event", requires_credentials=False, description=DESCRIPTION) expected_output = { + "Description": [(cmd.description + cmd.description_addendum, "")], + "Examples": [], + "Generate event S3 sends to local Lambda function": [ + ("$ sam local " "generate-event s3 " "[put/delete]\x1b[0m", ""), + ], + "Customize event by adding parameter flags": [ + ("$ sam local generate-event s3 " "[put/delete] --help\x1b[0m", ""), + ("$ sam local generate-event s3 " "[put/delete] --bucket " " --key \x1b[0m", ""), + ], + "Test generated event with serverless function locally!": [ + ( + "$ sam local " + "generate-event " + "s3 [put/delete] " + "--bucket " + " --key " + " | sam " + "invoke -e " + "-\x1b[0m", + "", + ), + ], "Commands": [ ("alexa-skills-kit", ""), ("alexa-smart-home", ""), @@ -53,31 +75,6 @@ def test_get_options_local_invoke_command_text(self, mock_get_params): ("stepfunctions", ""), ("workmail", ""), ], - "Customize event by adding parameter flags.": [ - ("", ""), - ("$ sam local generate-event s3 " "[put/delete] --help\x1b[0m", ""), - ("$ sam local generate-event s3 " "[put/delete] --bucket " " --key \x1b[0m", ""), - ], - "Description": [(cmd.description + cmd.description_addendum, "")], - "Examples": [], - "Generate event S3 sends to local Lambda function": [ - ("", ""), - ("$ sam local " "generate-event s3 " "[put/delete]\x1b[0m", ""), - ], - "Test generated event with serverless function locally!": [ - ("", ""), - ( - "$ sam local " - "generate-event " - "s3 [put/delete] " - "--bucket " - " --key " - " | sam " - "invoke -e " - "-\x1b[0m", - "", - ), - ], } cmd.format_options(ctx, formatter) self.assertEqual(formatter.data, expected_output) diff --git a/tests/unit/commands/local/invoke/core/test_command.py b/tests/unit/commands/local/invoke/core/test_command.py index cb123b7589..88a4d0404f 100644 --- a/tests/unit/commands/local/invoke/core/test_command.py +++ b/tests/unit/commands/local/invoke/core/test_command.py @@ -39,34 +39,35 @@ def test_get_options_local_invoke_command_text(self, mock_get_params): expected_output = { "Description": [(cmd.description + cmd.description_addendum, "")], "Examples": [], - "Invoke default Lambda function with no event": [("", ""), ("$ sam local invoke\x1b[0m", "")], + "Invoke default Lambda function with no event": [("$ sam local invoke\x1b[0m", "")], "Invoke named Lambda function with no event": [ - ("", ""), ("$ sam local invoke HelloWorldFunction\x1b[0m", ""), ], "Invoke named Lambda function with an event file": [ - ("", ""), ("$ sam local invoke HelloWorldFunction -e event.json\x1b[0m", ""), ], "Invoke Lambda function with stdin input": [ - ("", ""), ('$ echo {"message": "hello!"} | sam local invoke HelloWorldFunction -e -\x1b[0m', ""), ], "Invoke Lambda function with durable execution name": [ - ("", ""), ("$ sam local invoke HelloWorldFunction --durable-execution-name my-execution\x1b[0m", ""), ], - "Required Options": [("", ""), ("--template-file", ""), ("", "")], - "Template Options": [("", ""), ("--parameter-overrides", ""), ("", "")], - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Invoke Options": [("", ""), ("--event", ""), ("", "")], - "Container Options": [("", "")], - "Artifact Location Options": [("", ""), ("--log-file", ""), ("", "")], - "Extension Options": [("", ""), ("--hook_name", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Terraform Hook Options": [("", ""), ("--terraform-plan-file", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "Required Options": [("--template-file", "")], + "Template Options": [("--parameter-overrides", "")], + "AWS Credential Options": [("--region", "")], + "Invoke Options": [("--event", "")], + "Artifact Location Options": [("--log-file", "")], + "Extension Options": [("--hook_name", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], + "Terraform Hook Options": [("--terraform-plan-file", "")], + "Beta Options": [("--beta-features", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) diff --git a/tests/unit/commands/local/invoke/core/test_formatter.py b/tests/unit/commands/local/invoke/core/test_formatter.py deleted file mode 100644 index e17d81a926..0000000000 --- a/tests/unit/commands/local/invoke/core/test_formatter.py +++ /dev/null @@ -1,12 +0,0 @@ -from shutil import get_terminal_size -from unittest import TestCase - -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.local.invoke.core.formatters import InvokeCommandHelpTextFormatter - - -class TestLocalInvokeCommandHelpTextFormatter(TestCase): - def test_local_invoke_formatter(self): - self.formatter = InvokeCommandHelpTextFormatter() - self.assertTrue(self.formatter.left_justification_length <= get_terminal_size().columns // 2) - self.assertIsInstance(self.formatter.modifiers[0], BaseLineRowModifier) diff --git a/tests/unit/commands/local/start_api/core/test_command.py b/tests/unit/commands/local/start_api/core/test_command.py index 53263db84a..16d98b9e85 100644 --- a/tests/unit/commands/local/start_api/core/test_command.py +++ b/tests/unit/commands/local/start_api/core/test_command.py @@ -29,7 +29,7 @@ def test_get_options_local_start_api_command(self, mock_get_params): MockParams(rv=("--host", ""), name="host"), MockParams(rv=("--config-file", ""), name="config_file"), MockParams(rv=("--hook_name", ""), name="hook_name"), - MockParams(rv=("--beta-features", ""), name="beta_features"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--log-file", ""), name="log_file"), MockParams(rv=("--debug", ""), name="debug"), MockParams(rv=("--terraform-plan-file", ""), name="terraform_plan_file"), @@ -37,28 +37,32 @@ def test_get_options_local_start_api_command(self, mock_get_params): cmd = InvokeAPICommand(name="local start-api", requires_credentials=False, description=DESCRIPTION) expected_output = { - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Artifact Location Options": [("", ""), ("--log-file", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Container Options": [("", ""), ("--host", ""), ("", "")], "Description": [(cmd.description + cmd.description_addendum, "")], "Examples": [], - "Extension Options": [("", ""), ("--hook_name", ""), ("", "")], - "Terraform Hook Options": [("", ""), ("--terraform-plan-file", ""), ("", "")], - "Setup": [ - ("", ""), - ("Start the local lambda with Amazon API Gateway endpoint", ""), + "Setup": [], + "Start the local lambda with Amazon API Gateway endpoint:": [ ("$ sam local start-api\x1b[0m", ""), ], - "Invoke local Lambda endpoint": [ - ("", ""), - ("Invoke Lambda function locally using curl", ""), + "Invoke local Lambda endpoint": [], + "Invoke Lambda function locally using curl:": [ ("$ curl http://127.0.0.1:3000/hello\x1b[0m", ""), ], - "Other Options": [("", ""), ("--debug", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Required Options": [("", ""), ("--template-file", ""), ("", "")], - "Template Options": [("", ""), ("--parameter-overrides", ""), ("", "")], + "Required Options": [("--template-file", "")], + "Template Options": [("--parameter-overrides", "")], + "AWS Credential Options": [("--region", "")], + "Container Options": [("--host", "")], + "Artifact Location Options": [("--log-file", "")], + "Extension Options": [("--hook_name", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], + "Terraform Hook Options": [("--terraform-plan-file", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) diff --git a/tests/unit/commands/local/start_api/core/test_formatter.py b/tests/unit/commands/local/start_api/core/test_formatter.py deleted file mode 100644 index ab7be739d7..0000000000 --- a/tests/unit/commands/local/start_api/core/test_formatter.py +++ /dev/null @@ -1,12 +0,0 @@ -from shutil import get_terminal_size -from unittest import TestCase - -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.local.start_api.core.formatters import InvokeStartAPICommandHelpTextFormatter - - -class TestLocalInvokeCommandHelpTextFormatter(TestCase): - def test_local_invoke_formatter(self): - self.formatter = InvokeStartAPICommandHelpTextFormatter() - self.assertTrue(self.formatter.left_justification_length <= get_terminal_size().columns // 2) - self.assertIsInstance(self.formatter.modifiers[0], BaseLineRowModifier) diff --git a/tests/unit/commands/local/start_lambda/core/test_command.py b/tests/unit/commands/local/start_lambda/core/test_command.py index d52e27fadf..cb2ab3e306 100644 --- a/tests/unit/commands/local/start_lambda/core/test_command.py +++ b/tests/unit/commands/local/start_lambda/core/test_command.py @@ -30,7 +30,7 @@ def test_get_options_local_start_lambda_command(self, mock_get_params): MockParams(rv=("--config-file", ""), name="config_file"), MockParams(rv=("--hook_name", ""), name="hook_name"), MockParams(rv=("--log-file", ""), name="log_file"), - MockParams(rv=("--beta-features", ""), name="beta_features"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), MockParams(rv=("--terraform-plan-file", ""), name="terraform_plan_file"), ] @@ -39,29 +39,45 @@ def test_get_options_local_start_lambda_command(self, mock_get_params): expected_output = { "Description": [(cmd.description + cmd.description_addendum, "")], "Examples": [], - "Setup": [ - ("", ""), - ("Start the local lambda endpoint for multiple functions", ""), + "Setup": [], + "Start the local lambda endpoint for all functions": [ + ("$ sam local start-lambda\x1b[0m", ""), + ], + "Start the local lambda endpoint for one function": [ + ("$ sam local start-lambda HelloWorldFunction\x1b[0m", ""), + ], + "Start the local lambda endpoint for multiple functions": [ ("$ sam local start-lambda HelloWorldFunctionOne HelloWorldFunctionTwo\x1b[0m", ""), ], - "Invoke local Lambda endpoint": [ - ("", ""), - ("Use AWS SDK in automated tests.", ""), + "Invoke local Lambda endpoint": [], + "Use the AWS CLI:": [ + ( + "$ aws lambda invoke --function-name HelloWorldFunction --endpoint-url http://127.0.0.1:3001 --no-verify-ssl out.txt\x1b[0m", + "", + ), + ], + "Use AWS SDK in automated tests:": [ + ( + "self.lambda_client = boto3.client('lambda',\n endpoint_url=\"http://127.0.0.1:3001\",\n use_ssl=False,\n verify=False,\n config=Config(signature_version=UNSIGNED,\n read_timeout=0,\n retries={'max_attempts': 0}))\n self.lambda_client.invoke(FunctionName=\"HelloWorldFunction\")\n ", + "", + ), + ], + "Required Options": [("--template-file", "")], + "Template Options": [("--parameter-overrides", "")], + "AWS Credential Options": [("--region", "")], + "Container Options": [("--port", "")], + "Artifact Location Options": [("--log-file", "")], + "Extension Options": [("--hook_name", "")], + "Configuration Options": [ ( - "\n self.lambda_client = boto3.client('lambda',\n endpoint_url=\"http://127.0.0.1:3001\",\n use_ssl=False,\n verify=False,\n config=Config(signature_version=UNSIGNED,\n read_timeout=0,\n retries={'max_attempts': 0}))\n self.lambda_client.invoke(FunctionName=\"HelloWorldFunction\")\n ", + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", "", ), + ("--config-file", ""), ], - "Required Options": [("", ""), ("--template-file", ""), ("", "")], - "Template Options": [("", ""), ("--parameter-overrides", ""), ("", "")], - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Container Options": [("", ""), ("--port", ""), ("", "")], - "Artifact Location Options": [("", ""), ("--log-file", ""), ("", "")], - "Extension Options": [("", ""), ("--hook_name", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Terraform Hook Options": [("", ""), ("--terraform-plan-file", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "Terraform Hook Options": [("--terraform-plan-file", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) diff --git a/tests/unit/commands/local/start_lambda/core/test_formatter.py b/tests/unit/commands/local/start_lambda/core/test_formatter.py deleted file mode 100644 index 2252430048..0000000000 --- a/tests/unit/commands/local/start_lambda/core/test_formatter.py +++ /dev/null @@ -1,12 +0,0 @@ -from shutil import get_terminal_size -from unittest import TestCase - -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.local.start_lambda.core.formatters import InvokeStartLambdaCommandHelpTextFormatter - - -class TestLocalInvokeCommandHelpTextFormatter(TestCase): - def test_local_invoke_formatter(self): - self.formatter = InvokeStartLambdaCommandHelpTextFormatter() - self.assertTrue(self.formatter.left_justification_length <= get_terminal_size().columns // 2) - self.assertIsInstance(self.formatter.modifiers[0], BaseLineRowModifier) diff --git a/tests/unit/commands/logs/core/test_command.py b/tests/unit/commands/logs/core/test_command.py index 5b7b4e334e..eaf5c78ea8 100644 --- a/tests/unit/commands/logs/core/test_command.py +++ b/tests/unit/commands/logs/core/test_command.py @@ -33,14 +33,19 @@ def test_get_options_logs_command_text(self, mock_get_params): cmd = LogsCommand(name="logs", requires_credentials=True, description=DESCRIPTION) expected_output = { - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Additional Options": [("", ""), ("--tail", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], + "AWS Credential Options": [("--region", "")], + "Additional Options": [("--tail", "")], + "Beta Options": [("--beta-features", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], "Description": [(cmd.description + cmd.description_addendum, "")], "Examples": [], "Fetch from Cloudwatch log groups": [ - ("", ""), ( "$ sam logs --cw-log-group " "/aws/lambda/myfunction-123 " @@ -50,22 +55,18 @@ def test_get_options_logs_command_text(self, mock_get_params): ), ], "Fetch logs from resource defined in nested Cloudformation stack": [ - ("", ""), ("$ sam " "logs " "---stack-name " "mystack " "-n " "MyNestedStack/HelloWorldFunction\x1b[0m", ""), ], "Fetch logs from supported resources in Cloudformation stack": [ - ("", ""), ("$ sam logs " "---stack-name " "mystack\x1b[0m", ""), ], "Fetch logs with Lambda Function Logical ID and Cloudformation Stack Name": [ - ("", ""), ("$ " "sam " "logs " "-n " "HelloWorldFunction " "--stack-name " "mystack\x1b[0m", ""), ], - "Log Identifier Options": [("", ""), ("--stack-name", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], - "Tail new logs": [("", ""), ("$ sam logs -n HelloWorldFunction --stack-name mystack " "--tail\x1b[0m", "")], + "Log Identifier Options": [("--stack-name", "")], + "Other Options": [("--debug", "")], + "Tail new logs": [("$ sam logs -n HelloWorldFunction --stack-name mystack " "--tail\x1b[0m", "")], "View logs for specific time range": [ - ("", ""), ("$ sam logs -n HelloWorldFunction " "--stack-name mystack -s '10min ago' " "-e '2min ago'\x1b[0m", ""), ], } diff --git a/tests/unit/commands/logs/core/test_formatter.py b/tests/unit/commands/logs/core/test_formatter.py deleted file mode 100644 index e59e90207b..0000000000 --- a/tests/unit/commands/logs/core/test_formatter.py +++ /dev/null @@ -1,12 +0,0 @@ -from shutil import get_terminal_size -from unittest import TestCase - -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.logs.core.formatters import LogsCommandHelpTextFormatter - - -class TestLogsCommandHelpTextFormatter(TestCase): - def test_logs_formatter(self): - self.formatter = LogsCommandHelpTextFormatter() - self.assertTrue(self.formatter.left_justification_length <= get_terminal_size().columns // 2) - self.assertIsInstance(self.formatter.modifiers[0], BaseLineRowModifier) diff --git a/tests/unit/commands/package/core/test_command.py b/tests/unit/commands/package/core/test_command.py index fdfd571461..f5507cc472 100644 --- a/tests/unit/commands/package/core/test_command.py +++ b/tests/unit/commands/package/core/test_command.py @@ -39,16 +39,6 @@ def test_get_options_package_command_text(self, mock_get_params): cmd = PackageCommand(name="package", requires_credentials=False, description=DESCRIPTION) expected_output = { - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Acronyms": [("", ""), ("S3", ""), ("ECR", ""), ("KMS", "")], - "Additional Options": [("", ""), ("--signing-profiles", ""), ("", "")], - "Automatic resolution of S3 buckets": [("", ""), ("$ sam package --resolve-s3\x1b[0m", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Customized location for uploading artifacts": [ - ("", ""), - ("$ sam package --s3-bucket " "S3_BUCKET " "--output-template-file " "packaged.yaml\x1b[0m", ""), - ], "Description": [ ( "\n" @@ -70,15 +60,29 @@ def test_get_options_package_command_text(self, mock_get_params): ) ], "Examples": [], - "Get packaged template": [ - ("", ""), + "Automatic resolution of S3 buckets:": [("$ sam package --resolve-s3\x1b[0m", "")], + "Get packaged template:": [ ("$ sam package --resolve-s3 --output-template-file " "packaged.yaml\x1b[0m", ""), ], - "Infrastructure Options": [("", ""), ("--s3-prefix", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], - "Package Management Options": [("", ""), ("--force-upload", ""), ("", "")], - "Required Options": [("", ""), ("--s3-bucket", ""), ("", "")], + "Customized location for uploading artifacts:": [ + ("$ sam package --s3-bucket " "S3_BUCKET " "--output-template-file " "packaged.yaml\x1b[0m", ""), + ], "Supported Resources": [("\n", ""), ("mock", "")], + "Acronyms": [("S3", ""), ("ECR", ""), ("KMS", "")], + "Required Options": [("--s3-bucket", "")], + "AWS Credential Options": [("--region", "")], + "Infrastructure Options": [("--s3-prefix", "")], + "Package Management Options": [("--force-upload", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], + "Additional Options": [("--signing-profiles", "")], + "Beta Options": [("--beta-features", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) diff --git a/tests/unit/commands/package/core/test_formatter.py b/tests/unit/commands/package/core/test_formatter.py deleted file mode 100644 index 559b247fd6..0000000000 --- a/tests/unit/commands/package/core/test_formatter.py +++ /dev/null @@ -1,12 +0,0 @@ -from shutil import get_terminal_size -from unittest import TestCase - -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.package.core.formatters import PackageCommandHelpTextFormatter - - -class TestPackageCommandHelpTextFormatter(TestCase): - def test_deploy_formatter(self): - self.formatter = PackageCommandHelpTextFormatter() - self.assertTrue(self.formatter.left_justification_length <= get_terminal_size().columns // 2) - self.assertIsInstance(self.formatter.modifiers[0], BaseLineRowModifier) diff --git a/tests/unit/commands/pipeline/bootstrap/core/__init__.py b/tests/unit/commands/pipeline/bootstrap/core/__init__.py new file mode 100644 index 0000000000..f190cfd285 --- /dev/null +++ b/tests/unit/commands/pipeline/bootstrap/core/__init__.py @@ -0,0 +1 @@ +"""Test pipeline bootstrap core""" diff --git a/tests/unit/commands/pipeline/bootstrap/core/test_command.py b/tests/unit/commands/pipeline/bootstrap/core/test_command.py new file mode 100644 index 0000000000..9ee0701fab --- /dev/null +++ b/tests/unit/commands/pipeline/bootstrap/core/test_command.py @@ -0,0 +1,55 @@ +import unittest +from unittest.mock import Mock, patch +from samcli.commands.pipeline.bootstrap.core.command import PipelineBootstrapCommand +from tests.unit.cli.test_command import MockFormatter + + +class MockParams: + def __init__(self, rv, name): + self.rv = rv + self.name = name + + def get_help_record(self, ctx): + return self.rv + + +class TestPipelineBootstrapCommand(unittest.TestCase): + @patch.object(PipelineBootstrapCommand, "get_params") + def test_get_options_pipeline_bootstrap_command_text(self, mock_get_params): + ctx = Mock() + ctx.command_path = "sam pipeline bootstrap" + formatter = MockFormatter(scrub_text=True) + mock_get_params.return_value = [ + MockParams(rv=("--interactive", ""), name="interactive"), + MockParams(rv=("--stage", ""), name="stage"), + MockParams(rv=("--region", ""), name="region"), + MockParams(rv=("--profile", ""), name="profile"), + MockParams(rv=("--config-env", ""), name="config_env"), + MockParams(rv=("--config-file", ""), name="config_file"), + MockParams(rv=("--beta-features", ""), name="beta_features"), + MockParams(rv=("--debug", ""), name="debug"), + MockParams(rv=("--save-params", ""), name="save_params"), + ] + + cmd = PipelineBootstrapCommand(name="bootstrap", requires_credentials=True, description="") + expected_output = { + "Description": [(cmd.description + cmd.description_addendum, "")], + "Bootstrap Options": [("--interactive", ""), ("--stage", "")], + "AWS Credential Options": [("--region", ""), ("--profile", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/" + "serverless-sam-cli-config.html.", + "", + ), + ("--config-env", ""), + ("--config-file", ""), + ("--save-params", ""), + ], + "Beta Options": [("--beta-features", "")], + "Other Options": [("--debug", "")], + } + + cmd.format_options(ctx, formatter) + self.assertEqual(formatter.data, expected_output) diff --git a/tests/unit/commands/pipeline/init/core/__init__.py b/tests/unit/commands/pipeline/init/core/__init__.py new file mode 100644 index 0000000000..2bebfce69c --- /dev/null +++ b/tests/unit/commands/pipeline/init/core/__init__.py @@ -0,0 +1 @@ +"""Test pipeline init core""" diff --git a/tests/unit/commands/pipeline/init/core/test_command.py b/tests/unit/commands/pipeline/init/core/test_command.py new file mode 100644 index 0000000000..96231c5ef7 --- /dev/null +++ b/tests/unit/commands/pipeline/init/core/test_command.py @@ -0,0 +1,50 @@ +import unittest +from unittest.mock import Mock, patch +from samcli.commands.pipeline.init.core.command import PipelineInitCommand +from tests.unit.cli.test_command import MockFormatter + + +class MockParams: + def __init__(self, rv, name): + self.rv = rv + self.name = name + + def get_help_record(self, ctx): + return self.rv + + +class TestPipelineInitCommand(unittest.TestCase): + @patch.object(PipelineInitCommand, "get_params") + def test_get_options_pipeline_init_command_text(self, mock_get_params): + ctx = Mock() + ctx.command_path = "sam pipeline init" + formatter = MockFormatter(scrub_text=True) + mock_get_params.return_value = [ + MockParams(rv=("--config-env", ""), name="config_env"), + MockParams(rv=("--config-file", ""), name="config_file"), + MockParams(rv=("--bootstrap", ""), name="bootstrap"), + MockParams(rv=("--beta-features", ""), name="beta_features"), + MockParams(rv=("--debug", ""), name="debug"), + MockParams(rv=("--save-params", ""), name="save_params"), + ] + + cmd = PipelineInitCommand(name="init", requires_credentials=False, description="") + expected_output = { + "Pipeline Init Options": [("--bootstrap", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: " + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/" + "serverless-sam-cli-config.html.", + "", + ), + ("--config-env", ""), + ("--config-file", ""), + ("--save-params", ""), + ], + "Beta Options": [("--beta-features", "")], + "Other Options": [("--debug", "")], + } + + cmd.format_options(ctx, formatter) + self.assertEqual(formatter.data, expected_output) diff --git a/tests/unit/commands/publish/core/__init__.py b/tests/unit/commands/publish/core/__init__.py new file mode 100644 index 0000000000..1233d6c2a1 --- /dev/null +++ b/tests/unit/commands/publish/core/__init__.py @@ -0,0 +1,3 @@ +""" +Publish Command Core Tests +""" diff --git a/tests/unit/commands/publish/core/test_command.py b/tests/unit/commands/publish/core/test_command.py new file mode 100644 index 0000000000..a1bbadaf27 --- /dev/null +++ b/tests/unit/commands/publish/core/test_command.py @@ -0,0 +1,61 @@ +import unittest +from unittest.mock import Mock, patch +from samcli.commands.publish.core.command import PublishCommand +from tests.unit.cli.test_command import MockFormatter + + +class MockParams: + def __init__(self, rv, name): + self.rv = rv + self.name = name + + def get_help_record(self, ctx): + return self.rv + + +class TestPublishCommand(unittest.TestCase): + @patch.object(PublishCommand, "get_params") + def test_get_options_publish_command_text(self, mock_get_params): + ctx = Mock() + ctx.command_path = "sam publish" + formatter = MockFormatter(scrub_text=True) + # NOTE(sriram-mv): One option per option section. + mock_get_params.return_value = [ + MockParams(rv=("--region", "Region"), name="region"), + MockParams(rv=("--debug", ""), name="debug"), + MockParams(rv=("--config-file", ""), name="config_file"), + MockParams(rv=("--template-file", ""), name="template_file"), + MockParams(rv=("--semantic-version", ""), name="semantic_version"), + ] + + cmd = PublishCommand( + name="publish", + requires_credentials=True, + description="Use this command to publish a packaged AWS SAM template to\n" + "the AWS Serverless Application Repository to share within your team,\n" + "across your organization, or with the community at large.\n\n" + "This command expects the template's Metadata section to contain an\n" + "AWS::ServerlessRepo::Application section with application metadata\n" + "for publishing. For more details on this metadata section, see\n" + "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template-publishing-applications.html\n", + ) + expected_output = { + "AWS Credential Options": [("--region", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], + "Description": [(cmd.description + cmd.description_addendum, "")], + "Examples": [], + "Publish a packaged application": [ + ("$ sam publish -t packaged.yaml --region us-east-1\x1b[0m", ""), + ], + "Other Options": [("--debug", "")], + "Publish Options": [("--template-file", ""), ("--semantic-version", "")], + } + + cmd.format_options(ctx, formatter) + self.assertEqual(formatter.data, expected_output) diff --git a/tests/unit/commands/remote/callback/fail/core/test_command.py b/tests/unit/commands/remote/callback/fail/core/test_command.py index bf8a900e01..a6c1807755 100644 --- a/tests/unit/commands/remote/callback/fail/core/test_command.py +++ b/tests/unit/commands/remote/callback/fail/core/test_command.py @@ -15,6 +15,8 @@ def get_help_record(self, ctx): class TestRemoteCallbackFailCommand(unittest.TestCase): + maxDiff = None + @patch.object(RemoteCallbackFailCommand, "get_params") def test_remote_callback_fail_options_command_text(self, mock_get_params): ctx = Mock() @@ -27,6 +29,7 @@ def test_remote_callback_fail_options_command_text(self, mock_get_params): MockParams(rv=("--region", "Region"), name="region"), MockParams(rv=("--profile", ""), name="profile"), MockParams(rv=("--config-file", ""), name="config_file"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), ] @@ -36,21 +39,18 @@ def test_remote_callback_fail_options_command_text(self, mock_get_params): ("Test description\x1b[1m\n This command may not require access to AWS credentials.\x1b[0m", "") ], "Examples": [], - "AWS Credential Options": [("", ""), ("--region", ""), ("", ""), ("--profile", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Beta Options": [("", "")], - "Callback Options": [("", ""), ("--error-data", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "AWS Credential Options": [("--region", ""), ("--profile", "")], + "Configuration Options": [("--config-file", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Callback Options": [("--error-data", "")], + "Other Options": [("--debug", "")], "Send failure callback with no parameters": [ - ("", ""), ("$ sam remote callback fail my-callback-id\x1b[0m", ""), ], "Send failure callback with error message": [ - ("", ""), ("$ sam remote callback fail my-callback-id --error-message 'Task failed'\x1b[0m", ""), ], "Send failure callback with all parameters": [ - ("", ""), ( "$ sam remote callback fail my-callback-id --error-message 'Task failed' --error-type 'ValidationError' --stack-trace 'at line 42' --error-data '{\"code\": 500}'\x1b[0m", "", diff --git a/tests/unit/commands/remote/callback/heartbeat/core/test_command.py b/tests/unit/commands/remote/callback/heartbeat/core/test_command.py index 0021c5775f..64d471d21b 100644 --- a/tests/unit/commands/remote/callback/heartbeat/core/test_command.py +++ b/tests/unit/commands/remote/callback/heartbeat/core/test_command.py @@ -26,6 +26,7 @@ def test_remote_callback_heartbeat_options_command_text(self, mock_get_params): MockParams(rv=("--region", "Region"), name="region"), MockParams(rv=("--profile", ""), name="profile"), MockParams(rv=("--config-file", ""), name="config_file"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), ] @@ -37,11 +38,11 @@ def test_remote_callback_heartbeat_options_command_text(self, mock_get_params): ("Test description\x1b[1m\n This command may not require access to AWS credentials.\x1b[0m", "") ], "Examples": [], - "AWS Credential Options": [("", ""), ("--region", ""), ("", ""), ("--profile", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Beta Options": [("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], - "Send heartbeat callback": [("", ""), ("$ sam remote callback heartbeat my-callback-id\x1b[0m", "")], + "AWS Credential Options": [("--region", ""), ("--profile", "")], + "Configuration Options": [("--config-file", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], + "Send heartbeat callback": [("$ sam remote callback heartbeat my-callback-id\x1b[0m", "")], } cmd.format_options(ctx, formatter) self.assertEqual(expected_output, formatter.data) diff --git a/tests/unit/commands/remote/callback/succeed/core/test_command.py b/tests/unit/commands/remote/callback/succeed/core/test_command.py index 93ff420832..6fc9e2ae36 100644 --- a/tests/unit/commands/remote/callback/succeed/core/test_command.py +++ b/tests/unit/commands/remote/callback/succeed/core/test_command.py @@ -15,6 +15,8 @@ def get_help_record(self, ctx): class TestRemoteCallbackSucceedCommand(unittest.TestCase): + maxDiff = None + @patch.object(RemoteCallbackSucceedCommand, "get_params") def test_remote_callback_succeed_options_command_text(self, mock_get_params): ctx = Mock() @@ -27,6 +29,7 @@ def test_remote_callback_succeed_options_command_text(self, mock_get_params): MockParams(rv=("--region", "Region"), name="region"), MockParams(rv=("--profile", ""), name="profile"), MockParams(rv=("--config-file", ""), name="config_file"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), ] @@ -36,17 +39,14 @@ def test_remote_callback_succeed_options_command_text(self, mock_get_params): ("Test description\x1b[1m\n This command may not require access to AWS credentials.\x1b[0m", "") ], "Examples": [], - "AWS Credential Options": [("", ""), ("--region", ""), ("", ""), ("--profile", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Beta Options": [("", "")], - "Callback Options": [("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "AWS Credential Options": [("--region", ""), ("--profile", "")], + "Configuration Options": [("--config-file", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], "Send success callback with no result": [ - ("", ""), ("$ sam remote callback succeed my-callback-id\x1b[0m", ""), ], "Send success callback with result": [ - ("", ""), ("$ sam remote callback succeed my-callback-id --result 'Task completed successfully'\x1b[0m", ""), ], } diff --git a/tests/unit/commands/remote/core/test_formatters.py b/tests/unit/commands/remote/core/test_formatters.py index f78fa21b60..63be4ab716 100644 --- a/tests/unit/commands/remote/core/test_formatters.py +++ b/tests/unit/commands/remote/core/test_formatters.py @@ -11,4 +11,4 @@ def test_remote_execution_formatter(self): formatter = CommandHelpTextFormatter(ALL_OPTIONS) self.assertTrue(formatter.left_justification_length <= get_terminal_size().columns // 2) self.assertIsInstance(formatter.modifiers[0], BaseLineRowModifier) - self.assertEqual(formatter.ADDITIVE_JUSTIFICATION, 17) + self.assertEqual(formatter.DEFAULT_ADDITIVE_JUSTIFICATION, 6) diff --git a/tests/unit/commands/remote/execution/get/core/test_command.py b/tests/unit/commands/remote/execution/get/core/test_command.py index 42aee67e32..8995387f58 100644 --- a/tests/unit/commands/remote/execution/get/core/test_command.py +++ b/tests/unit/commands/remote/execution/get/core/test_command.py @@ -29,6 +29,7 @@ def test_get_options_get_durable_execution_command_text(self, mock_get_params): MockParams(rv=("--region", "Region"), name="region"), MockParams(rv=("--profile", ""), name="profile"), MockParams(rv=("--config-file", ""), name="config_file"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), ] @@ -57,11 +58,11 @@ def test_get_options_get_durable_execution_command_text(self, mock_get_params): ) ], "Acronyms": [("ARN", "")], - "Formatting Options": [("", ""), ("--format", ""), ("", "")], - "Beta Options": [("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], - "AWS Credential Options": [("", ""), ("--region", ""), ("", ""), ("--profile", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], + "Formatting Options": [("--format", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], + "AWS Credential Options": [("--region", ""), ("--profile", "")], + "Configuration Options": [("--config-file", "")], } cmd.format_options(ctx, formatter) self.assertEqual(expected_output, formatter.data) diff --git a/tests/unit/commands/remote/execution/history/core/test_command.py b/tests/unit/commands/remote/execution/history/core/test_command.py index b2d16967a1..7b53d43c25 100644 --- a/tests/unit/commands/remote/execution/history/core/test_command.py +++ b/tests/unit/commands/remote/execution/history/core/test_command.py @@ -29,6 +29,7 @@ def test_remote_execution_history_options_command_text(self, mock_get_params): MockParams(rv=("--region", "Region"), name="region"), MockParams(rv=("--profile", ""), name="profile"), MockParams(rv=("--config-file", ""), name="config_file"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), ] @@ -51,11 +52,11 @@ def test_remote_execution_history_options_command_text(self, mock_get_params): ), ], "Acronyms": [("ARN", "")], - "Formatting Options": [("", ""), ("--format", ""), ("", "")], - "AWS Credential Options": [("", ""), ("--region", ""), ("", ""), ("--profile", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Beta Options": [("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "Formatting Options": [("--format", "")], + "AWS Credential Options": [("--region", ""), ("--profile", "")], + "Configuration Options": [("--config-file", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) self.assertEqual(expected_output, formatter.data) diff --git a/tests/unit/commands/remote/execution/stop/core/test_command.py b/tests/unit/commands/remote/execution/stop/core/test_command.py index cc2e6fd57a..91767c6e10 100644 --- a/tests/unit/commands/remote/execution/stop/core/test_command.py +++ b/tests/unit/commands/remote/execution/stop/core/test_command.py @@ -32,6 +32,7 @@ def test_remote_execution_stop_options_command_text(self, mock_get_params): MockParams(rv=("--region", "Region"), name="region"), MockParams(rv=("--profile", ""), name="profile"), MockParams(rv=("--config-file", ""), name="config_file"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), ] @@ -61,20 +62,15 @@ def test_remote_execution_stop_options_command_text(self, mock_get_params): ], "Acronyms": [("ARN", "")], "Stop Options": [ - ("", ""), ("--error-message", ""), - ("", ""), ("--error-type", ""), - ("", ""), ("--error-data", ""), - ("", ""), ("--stack-trace", ""), - ("", ""), ], - "AWS Credential Options": [("", ""), ("--region", ""), ("", ""), ("--profile", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Beta Options": [("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "AWS Credential Options": [("--region", ""), ("--profile", "")], + "Configuration Options": [("--config-file", "")], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) self.assertEqual(expected_output, formatter.data) diff --git a/tests/unit/commands/remote/invoke/core/test_command.py b/tests/unit/commands/remote/invoke/core/test_command.py index 986e957724..420c2f69ff 100644 --- a/tests/unit/commands/remote/invoke/core/test_command.py +++ b/tests/unit/commands/remote/invoke/core/test_command.py @@ -24,11 +24,12 @@ def test_get_options_remote_invoke_command_text(self, mock_get_params): # NOTE: One option per option section. mock_get_params.return_value = [ MockParams(rv=("--region", "Region"), name="region"), + MockParams(rv=("--profile", ""), name="profile"), MockParams(rv=("--stack-name", ""), name="stack_name"), MockParams(rv=("--parameter", ""), name="parameter"), MockParams(rv=("--event", ""), name="event"), MockParams(rv=("--config-file", ""), name="config_file"), - MockParams(rv=("--beta-features", ""), name="beta_features"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), ] @@ -140,13 +141,19 @@ def test_get_options_remote_invoke_command_text(self, mock_get_params): ), ], "Acronyms": [("ARN", "")], - "Infrastructure Options": [("", ""), ("--stack-name", ""), ("", "")], - "Input Event Options": [("", ""), ("--event", ""), ("", "")], - "Additional Options": [("", ""), ("--parameter", ""), ("", "")], - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "Infrastructure Options": [("--stack-name", "")], + "Input Event Options": [("--event", "")], + "Additional Options": [("--parameter", "")], + "AWS Credential Options": [("--region", ""), ("--profile", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) diff --git a/tests/unit/commands/remote/invoke/core/test_formatter.py b/tests/unit/commands/remote/invoke/core/test_formatter.py deleted file mode 100644 index b21652f4ac..0000000000 --- a/tests/unit/commands/remote/invoke/core/test_formatter.py +++ /dev/null @@ -1,12 +0,0 @@ -from shutil import get_terminal_size -from unittest import TestCase - -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.remote.invoke.core.formatters import RemoteInvokeCommandHelpTextFormatter - - -class TestRemoteInvokeCommandHelpTextFormatter(TestCase): - def test_remote_invoke_formatter(self): - self.formatter = RemoteInvokeCommandHelpTextFormatter() - self.assertTrue(self.formatter.left_justification_length <= get_terminal_size().columns // 2) - self.assertIsInstance(self.formatter.modifiers[0], BaseLineRowModifier) diff --git a/tests/unit/commands/remote/test_event/core/test_command.py b/tests/unit/commands/remote/test_event/core/test_command.py index bb90a972c5..846400def5 100644 --- a/tests/unit/commands/remote/test_event/core/test_command.py +++ b/tests/unit/commands/remote/test_event/core/test_command.py @@ -27,11 +27,13 @@ def test_get_options_remote_invoke_command_text(self, mock_get_params): # NOTE: One option per option section. mock_get_params.return_value = [ MockParams(rv=("--region", "Region"), name="region"), + MockParams(rv=("--profile", ""), name="profile"), MockParams(rv=("--stack-name", ""), name="stack_name"), MockParams(rv=("--parameter", ""), name="parameter"), MockParams(rv=("--name", ""), name="name"), + MockParams(rv=("--output-file", ""), name="output_file"), MockParams(rv=("--config-file", ""), name="config_file"), - MockParams(rv=("--beta-features", ""), name="beta_features"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), ] @@ -42,34 +44,36 @@ def test_get_options_remote_invoke_command_text(self, mock_get_params): "Description": [(cmd.description + cmd.description_addendum, "")], "Examples": [], "Get a test event from default Lambda function": [ - ("", ""), ("$ sam remote test-event get --stack-name hello-world --name MyEvent\x1b[0m", ""), ], "Get a test event for a named Lambda function in the stack": [ - ("", ""), ("$ sam remote test-event get --stack-name hello-world HelloWorldFunction --name MyEvent\x1b[0m", ""), ], "Get a test event for a named Lambda function in the stack and save the result to a file": [ - ("", ""), ( "$ sam remote test-event get --stack-name hello-world HelloWorldFunction --name MyEvent --output-file my-event.json\x1b[0m", "", ), ], "Get a test event for a function using the Lambda ARN": [ - ("", ""), ( "$ sam remote test-event get arn:aws:lambda:us-west-2:123456789012:function:my-function --name MyEvent\x1b[0m", "", ), ], "Acronyms": [("ARN", "")], - "Infrastructure Options": [("", ""), ("--stack-name", ""), ("", "")], - "Test Event Options": [("", ""), ("--name", ""), ("", "")], - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "Infrastructure Options": [("--stack-name", "")], + "Test Event Options": [("--name", ""), ("--output-file", "")], + "AWS Credential Options": [("--region", ""), ("--profile", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) @@ -86,11 +90,13 @@ def test_put_options_remote_invoke_command_text(self, mock_get_params): # NOTE: One option per option section. mock_get_params.return_value = [ MockParams(rv=("--region", "Region"), name="region"), + MockParams(rv=("--profile", ""), name="profile"), MockParams(rv=("--stack-name", ""), name="stack_name"), MockParams(rv=("--parameter", ""), name="parameter"), MockParams(rv=("--name", ""), name="name"), + MockParams(rv=("--file", ""), name="file"), MockParams(rv=("--config-file", ""), name="config_file"), - MockParams(rv=("--beta-features", ""), name="beta_features"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), ] @@ -101,40 +107,42 @@ def test_put_options_remote_invoke_command_text(self, mock_get_params): "Description": [(cmd.description + cmd.description_addendum, "")], "Examples": [], "Put a remote test event for default Lambda function using the contents of a file": [ - ("", ""), ( "$ sam remote test-event put --stack-name hello-world --name MyEvent --file /path/to/event.json\x1b[0m", "", ), ], "Put a remote test event for a named Lambda function using the contents of a file": [ - ("", ""), ( "$ sam remote test-event put --stack-name hello-world HelloWorldFunction --name MyEvent --file /path/to/event.json\x1b[0m", "", ), ], "Put a remote test event for a named Lambda function with stdin input": [ - ("", ""), ( '$ echo \'{"message": "hello!"}\' | sam remote test-event put --stack-name hello-world HelloWorldFunction --name MyEvent --file -\x1b[0m', "", ), ], "Put a test event for a function using the Lambda ARN using the contents of a file": [ - ("", ""), ( "$ sam remote test-event put arn:aws:lambda:us-west-2:123456789012:function:my-function --name MyEvent --file /path/to/event.json\x1b[0m", "", ), ], "Acronyms": [("ARN", "")], - "Infrastructure Options": [("", ""), ("--stack-name", ""), ("", "")], - "Test Event Options": [("", ""), ("--name", ""), ("", "")], - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "Infrastructure Options": [("--stack-name", "")], + "Test Event Options": [("--name", ""), ("--file", "")], + "AWS Credential Options": [("--region", ""), ("--profile", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) @@ -151,10 +159,11 @@ def test_get_options_remote_invoke_command_text(self, mock_get_params): # NOTE: One option per option section. mock_get_params.return_value = [ MockParams(rv=("--region", "Region"), name="region"), + MockParams(rv=("--profile", ""), name="profile"), MockParams(rv=("--stack-name", ""), name="stack_name"), MockParams(rv=("--parameter", ""), name="parameter"), MockParams(rv=("--config-file", ""), name="config_file"), - MockParams(rv=("--beta-features", ""), name="beta_features"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), ] @@ -165,26 +174,29 @@ def test_get_options_remote_invoke_command_text(self, mock_get_params): "Description": [(cmd.description + cmd.description_addendum, "")], "Examples": [], "List remote test events for default Lambda function": [ - ("", ""), ("$ sam remote test-event list --stack-name hello-world\x1b[0m", ""), ], "List remote test events for a named Lambda function in the stack": [ - ("", ""), ("$ sam remote test-event list --stack-name hello-world HelloWorldFunction\x1b[0m", ""), ], "List remote test events for a function using Lambda ARN": [ - ("", ""), ( "$ sam remote test-event list arn:aws:lambda:us-west-2:123456789012:function:my-function\x1b[0m", "", ), ], "Acronyms": [("ARN", "")], - "Infrastructure Options": [("", ""), ("--stack-name", ""), ("", "")], - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "Infrastructure Options": [("--stack-name", "")], + "AWS Credential Options": [("--region", ""), ("--profile", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) @@ -201,11 +213,12 @@ def test_get_options_remote_invoke_command_text(self, mock_get_params): # NOTE: One option per option section. mock_get_params.return_value = [ MockParams(rv=("--region", "Region"), name="region"), + MockParams(rv=("--profile", ""), name="profile"), MockParams(rv=("--stack-name", ""), name="stack_name"), MockParams(rv=("--parameter", ""), name="parameter"), MockParams(rv=("--name", ""), name="name"), MockParams(rv=("--config-file", ""), name="config_file"), - MockParams(rv=("--beta-features", ""), name="beta_features"), + MockParams(rv=("--beta-features / --no-beta-features", ""), name="beta_features"), MockParams(rv=("--debug", ""), name="debug"), ] @@ -216,30 +229,33 @@ def test_get_options_remote_invoke_command_text(self, mock_get_params): "Description": [(cmd.description + cmd.description_addendum, "")], "Examples": [], "Delete a test event from default Lambda function": [ - ("", ""), ("$ sam remote test-event delete --stack-name hello-world --name MyEvent\x1b[0m", ""), ], "Delete a test event for a named Lambda function in the stack": [ - ("", ""), ( "$ sam remote test-event delete --stack-name hello-world HelloWorldFunction --name MyEvent\x1b[0m", "", ), ], "Delete a test event for a function using the Lambda ARN": [ - ("", ""), ( "$ sam remote test-event delete arn:aws:lambda:us-west-2:123456789012:function:my-function --name MyEvent\x1b[0m", "", ), ], "Acronyms": [("ARN", "")], - "Infrastructure Options": [("", ""), ("--stack-name", ""), ("", "")], - "Test Event Options": [("", ""), ("--name", ""), ("", "")], - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], + "Infrastructure Options": [("--stack-name", "")], + "Test Event Options": [("--name", "")], + "AWS Credential Options": [("--region", ""), ("--profile", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], + "Beta Options": [("--beta-features / --no-beta-features", "")], + "Other Options": [("--debug", "")], } cmd.format_options(ctx, formatter) diff --git a/tests/unit/commands/remote/test_event/core/test_formatter.py b/tests/unit/commands/remote/test_event/core/test_formatter.py deleted file mode 100644 index 09a1a38001..0000000000 --- a/tests/unit/commands/remote/test_event/core/test_formatter.py +++ /dev/null @@ -1,24 +0,0 @@ -from shutil import get_terminal_size -from unittest import TestCase -from parameterized import parameterized - -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.remote.test_event.delete.core.formatters import RemoteTestEventDeleteCommandHelpTextFormatter -from samcli.commands.remote.test_event.get.core.formatters import RemoteTestEventGetCommandHelpTextFormatter -from samcli.commands.remote.test_event.list.core.formatters import RemoteTestEventListCommandHelpTextFormatter -from samcli.commands.remote.test_event.put.core.formatters import RemoteTestEventPutCommandHelpTextFormatter - - -class TestRemoteInvokeCommandHelpTextFormatter(TestCase): - @parameterized.expand( - [ - (RemoteTestEventDeleteCommandHelpTextFormatter,), - (RemoteTestEventGetCommandHelpTextFormatter,), - (RemoteTestEventListCommandHelpTextFormatter,), - (RemoteTestEventPutCommandHelpTextFormatter,), - ] - ) - def test_remote_invoke_formatter(self, FormatterClass): - self.formatter = FormatterClass() - self.assertTrue(self.formatter.left_justification_length <= get_terminal_size().columns // 2) - self.assertIsInstance(self.formatter.modifiers[0], BaseLineRowModifier) diff --git a/tests/unit/commands/sync/core/test_command.py b/tests/unit/commands/sync/core/test_command.py index 19e1c5d436..710a547359 100644 --- a/tests/unit/commands/sync/core/test_command.py +++ b/tests/unit/commands/sync/core/test_command.py @@ -33,21 +33,31 @@ def test_get_options_sync_command_text(self, mock_get_params): cmd = SyncCommand(name="sync", requires_credentials=True, description=DESCRIPTION) expected_output = { - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], + "AWS Credential Options": [("--region", "")], "Acronyms": [("IAM", ""), ("ARN", ""), ("S3", ""), ("SNS", ""), ("ECR", ""), ("KMS", "")], - "Additional Options": [("", ""), ("--resource", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], + "Additional Options": [("--resource", "")], + "Beta Options": [("--beta-features", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], "Description": [(cmd.description + cmd.description_addendum, "")], - "Examples": [ - ("", ""), + "Examples": [], + "Sync with watch mode": [ ("$ sam sync --watch --stack-name {stack}\x1b[0m", ""), + ], + "Sync code changes with watch mode": [ ("$ sam sync --code --watch --stack-name {stack}\x1b[0m", ""), + ], + "Sync code changes for specific resource": [ ("$ sam sync --code --stack-name {stack} --resource-id " "{ChildStack}/{ResourceId}\x1b[0m", ""), ], - "Infrastructure Options": [("", ""), ("--s3-bucket", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], - "Required Options": [("", ""), ("--stack-name", ""), ("", "")], + "Infrastructure Options": [("--s3-bucket", "")], + "Other Options": [("--debug", "")], + "Required Options": [("--stack-name", "")], } cmd.format_options(ctx, formatter) diff --git a/tests/unit/commands/sync/core/test_formatter.py b/tests/unit/commands/sync/core/test_formatter.py deleted file mode 100644 index 73e781401c..0000000000 --- a/tests/unit/commands/sync/core/test_formatter.py +++ /dev/null @@ -1,12 +0,0 @@ -from shutil import get_terminal_size -from unittest import TestCase - -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.sync.core.formatters import SyncCommandHelpTextFormatter - - -class TestSyncCommandHelpTextFormatter(TestCase): - def test_sync_formatter(self): - self.formatter = SyncCommandHelpTextFormatter() - self.assertTrue(self.formatter.left_justification_length <= get_terminal_size().columns // 2) - self.assertIsInstance(self.formatter.modifiers[0], BaseLineRowModifier) diff --git a/tests/unit/commands/traces/__init__.py b/tests/unit/commands/traces/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/unit/commands/traces/core/__init__.py b/tests/unit/commands/traces/core/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/unit/commands/traces/core/test_command.py b/tests/unit/commands/traces/core/test_command.py new file mode 100644 index 0000000000..20085c29b4 --- /dev/null +++ b/tests/unit/commands/traces/core/test_command.py @@ -0,0 +1,40 @@ +""" +Unit tests for traces command class +""" + +from unittest import TestCase +from unittest.mock import Mock, patch + +from samcli.commands.traces.core.command import TracesCommand + + +class TestTracesCommand(TestCase): + def test_get_options_traces_command_text(self): + ctx = Mock() + ctx.command_path = "sam traces" + formatter = Mock() + formatter.write_text_rows = Mock() + formatter.indented_section = Mock() + + # Set up the mock to track indented_section calls + indented_sections = {} + + def mock_indented_section(name, extra_indents=0): + mock_context = Mock() + mock_context.__enter__ = Mock(return_value=mock_context) + mock_context.__exit__ = Mock(return_value=False) + indented_sections[name] = True + return mock_context + + formatter.indented_section.side_effect = mock_indented_section + + # Call format_examples + TracesCommand.format_examples(ctx, formatter) + + # Verify that the expected sections were created + self.assertIn("Examples", indented_sections) + self.assertIn("Fetch traces by ID", indented_sections) + self.assertIn("Tail traces as they become available", indented_sections) + + # Verify write_text_rows was called (once for each example subsection) + self.assertEqual(formatter.write_text_rows.call_count, 2) diff --git a/tests/unit/commands/validate/core/test_command.py b/tests/unit/commands/validate/core/test_command.py index 79f8242dee..34c9e8622e 100644 --- a/tests/unit/commands/validate/core/test_command.py +++ b/tests/unit/commands/validate/core/test_command.py @@ -33,15 +33,21 @@ def test_get_options_validate_command_text(self, mock_get_params): cmd = ValidateCommand(name="validate", requires_credentials=False, description=DESCRIPTION) expected_output = { - "AWS Credential Options": [("", ""), ("--region", ""), ("", "")], - "Configuration Options": [("", ""), ("--config-file", ""), ("", "")], - "Other Options": [("", ""), ("--debug", ""), ("", "")], - "Required Options": [("", ""), ("--template-file", ""), ("", "")], - "Lint Options": [("", ""), ("--lint", ""), ("", "")], - "Beta Options": [("", ""), ("--beta-features", ""), ("", "")], + "AWS Credential Options": [("--region", "")], + "Configuration Options": [ + ( + "Learn more about configuration files at: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html.", + "", + ), + ("--config-file", ""), + ], + "Other Options": [("--debug", "")], + "Required Options": [("--template-file", "")], + "Lint Options": [("--lint", "")], + "Beta Options": [("--beta-features", "")], "Description": [(cmd.description + cmd.description_addendum, "")], "Examples": [], - "Validate and Lint": [("", ""), ("$ sam validate --lint\x1b[0m", "")], + "Validate and Lint": [("$ sam validate --lint\x1b[0m", "")], } cmd.format_options(ctx, formatter) diff --git a/tests/unit/commands/validate/core/test_formatter.py b/tests/unit/commands/validate/core/test_formatter.py deleted file mode 100644 index 952e5d3b8f..0000000000 --- a/tests/unit/commands/validate/core/test_formatter.py +++ /dev/null @@ -1,12 +0,0 @@ -from shutil import get_terminal_size -from unittest import TestCase - -from samcli.cli.row_modifiers import BaseLineRowModifier -from samcli.commands.validate.core.formatters import ValidateCommandHelpTextFormatter - - -class TestValidateCommandHelpTextFormatter(TestCase): - def test_validate_formatter(self): - self.formatter = ValidateCommandHelpTextFormatter() - self.assertTrue(self.formatter.left_justification_length <= get_terminal_size().columns // 2) - self.assertIsInstance(self.formatter.modifiers[0], BaseLineRowModifier)