|
| 1 | +"""CLI command for "publish" command.""" |
| 2 | + |
| 3 | +import json |
| 4 | + |
| 5 | +import click |
| 6 | +import boto3 |
| 7 | +from botocore.exceptions import ClientError |
| 8 | +from serverlessrepo import publish_application |
| 9 | +from serverlessrepo.publish import CREATE_APPLICATION |
| 10 | +from serverlessrepo.exceptions import ServerlessRepoError |
| 11 | + |
| 12 | +from samcli.cli.main import pass_context, common_options as cli_framework_options, aws_creds_options |
| 13 | +from samcli.commands._utils.options import template_common_option |
| 14 | +from samcli.commands._utils.template import get_template_data |
| 15 | +from samcli.commands.exceptions import UserException |
| 16 | + |
| 17 | +HELP_TEXT = """ |
| 18 | +Use this command to publish a packaged AWS SAM template to |
| 19 | +the AWS Serverless Application Repository to share within your team, |
| 20 | +across your organization, or with the community at large.\n |
| 21 | +\b |
| 22 | +This command expects the template's Metadata section to contain an |
| 23 | +AWS::ServerlessRepo::Application section with application metadata |
| 24 | +for publishing. For more details on this metadata section, see |
| 25 | +https://docs.aws.amazon.com/serverlessrepo/latest/devguide/serverless-app-publishing-applications.html |
| 26 | +\b |
| 27 | +Examples |
| 28 | +-------- |
| 29 | +To publish an application |
| 30 | +$ sam publish -t packaged.yaml --region <region> |
| 31 | +""" |
| 32 | +SHORT_HELP = "Publish a packaged AWS SAM template to the AWS Serverless Application Repository." |
| 33 | +SERVERLESSREPO_CONSOLE_URL = "https://console.aws.amazon.com/serverlessrepo/home?region={}#/published-applications/{}" |
| 34 | + |
| 35 | + |
| 36 | +@click.command("publish", help=HELP_TEXT, short_help=SHORT_HELP) |
| 37 | +@template_common_option |
| 38 | +@aws_creds_options |
| 39 | +@cli_framework_options |
| 40 | +@pass_context |
| 41 | +def cli(ctx, template): |
| 42 | + # All logic must be implemented in the ``do_cli`` method. This helps with easy unit testing |
| 43 | + |
| 44 | + do_cli(ctx, template) # pragma: no cover |
| 45 | + |
| 46 | + |
| 47 | +def do_cli(ctx, template): |
| 48 | + """Publish the application based on command line inputs.""" |
| 49 | + try: |
| 50 | + template_data = get_template_data(template) |
| 51 | + except ValueError as ex: |
| 52 | + click.secho("Publish Failed", fg='red') |
| 53 | + raise UserException(str(ex)) |
| 54 | + |
| 55 | + try: |
| 56 | + publish_output = publish_application(template_data) |
| 57 | + click.secho("Publish Succeeded", fg="green") |
| 58 | + click.secho(_gen_success_message(publish_output), fg="yellow") |
| 59 | + except ServerlessRepoError as ex: |
| 60 | + click.secho("Publish Failed", fg='red') |
| 61 | + raise UserException(str(ex)) |
| 62 | + except ClientError as ex: |
| 63 | + click.secho("Publish Failed", fg='red') |
| 64 | + raise _wrap_s3_uri_exception(ex) |
| 65 | + |
| 66 | + application_id = publish_output.get('application_id') |
| 67 | + _print_console_link(ctx.region, application_id) |
| 68 | + |
| 69 | + |
| 70 | +def _gen_success_message(publish_output): |
| 71 | + """ |
| 72 | + Generate detailed success message for published applications. |
| 73 | +
|
| 74 | + Parameters |
| 75 | + ---------- |
| 76 | + publish_output : dict |
| 77 | + Output from serverlessrepo publish_application |
| 78 | +
|
| 79 | + Returns |
| 80 | + ------- |
| 81 | + str |
| 82 | + Detailed success message |
| 83 | + """ |
| 84 | + application_id = publish_output.get('application_id') |
| 85 | + details = json.dumps(publish_output.get('details'), indent=2) |
| 86 | + |
| 87 | + if CREATE_APPLICATION in publish_output.get('actions'): |
| 88 | + return "Created new application with the following metadata:\n{}".format(details) |
| 89 | + |
| 90 | + return 'The following metadata of application "{}" has been updated:\n{}'.format(application_id, details) |
| 91 | + |
| 92 | + |
| 93 | +def _print_console_link(region, application_id): |
| 94 | + """ |
| 95 | + Print link for the application in AWS Serverless Application Repository console. |
| 96 | +
|
| 97 | + Parameters |
| 98 | + ---------- |
| 99 | + region : str |
| 100 | + AWS region name |
| 101 | + application_id : str |
| 102 | + The Amazon Resource Name (ARN) of the application |
| 103 | +
|
| 104 | + """ |
| 105 | + if not region: |
| 106 | + region = boto3.Session().region_name |
| 107 | + |
| 108 | + console_link = SERVERLESSREPO_CONSOLE_URL.format(region, application_id.replace('/', '~')) |
| 109 | + msg = "Click the link below to view your application in AWS console:\n{}".format(console_link) |
| 110 | + click.secho(msg, fg="yellow") |
| 111 | + |
| 112 | + |
| 113 | +def _wrap_s3_uri_exception(ex): |
| 114 | + """ |
| 115 | + Wrap invalid S3 URI exception with a better error message. |
| 116 | +
|
| 117 | + Parameters |
| 118 | + ---------- |
| 119 | + ex : ClientError |
| 120 | + boto3 exception |
| 121 | +
|
| 122 | + Returns |
| 123 | + ------- |
| 124 | + Exception |
| 125 | + UserException if found invalid S3 URI or ClientError |
| 126 | + """ |
| 127 | + error_code = ex.response.get('Error').get('Code') |
| 128 | + message = ex.response.get('Error').get('Message') |
| 129 | + |
| 130 | + if error_code == 'BadRequestException' and "Invalid S3 URI" in message: |
| 131 | + return UserException( |
| 132 | + "Your SAM template contains invalid S3 URIs. Please make sure that you have uploaded application " |
| 133 | + "artifacts to S3 by packaging the template: 'sam package --template-file <file-path>'.") |
| 134 | + |
| 135 | + return ex |
0 commit comments