Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v0.31.0 #1511

Merged
merged 9 commits into from
Nov 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ notes=FIXME,XXX
[SIMILARITIES]

# Minimum lines number of a similarity.
min-similarity-lines=6
min-similarity-lines=12

# Ignore comments when computing similarities.
ignore-comments=yes
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Read the [SAM Documentation Contribution Guide](https://github.com/awsdocs/aws-s
started.

### Join the SAM Community on Slack
[Join the SAM developers channel (#samdev)](https://join.slack.com/t/awsdevelopers/shared_invite/enQtMzg3NTc5OTM2MzcxLTdjYTdhYWE3OTQyYTU4Njk1ZWY4Y2ZjYjBhMTUxNGYzNDg5MWQ1ZTc5MTRlOGY0OTI4NTdlZTMwNmI5YTgwOGM/) on Slack to collaborate with fellow community members and the AWS SAM team.
[Join the SAM developers channel (#samdev)](https://join.slack.com/t/awsdevelopers/shared_invite/enQtMzg3NTc5OTM2MzcxLTIxNjc0ZTJkNmYyNWY3OWE4NTFiNzU1ZTM2Y2VkNmFlNjQ2YjI3YTE1ZDA5YjE5NDE2MjVmYWFlYWIxNjE2NjU) on Slack to collaborate with fellow community members and the AWS SAM team.



4 changes: 4 additions & 0 deletions appveyor-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ install:
# Upgrade setuptools, wheel and virtualenv
- "python -m pip install --upgrade setuptools wheel virtualenv"

# Install AWS CLI Globally via pip3
- "pip install awscli"

# Create new virtual environment with chosen python version and activate it
- "python -m virtualenv venv"
- "venv\\Scripts\\activate"
Expand All @@ -72,6 +75,7 @@ test_script:
- "venv\\Scripts\\activate"
- "docker system prune -a -f"
- "pytest -vv tests/integration"
- "pytest -vv tests/regression"

# Uncomment for RDP
# on_finish:
Expand Down
9 changes: 9 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ for:
- "echo %PATH%"
- "python -m pip install --upgrade setuptools wheel virtualenv"

# Install AWS CLI Globally outside of a venv.
- "pip install awscli"

# Create new virtual environment and activate it
- "rm -rf venv"
- "python -m virtualenv venv"
Expand Down Expand Up @@ -90,6 +93,11 @@ for:
- sh: "chmod +x /tmp/black"
- sh: "/tmp/black --version"

# Install AWS CLI
- sh: "virtualenv aws_cli"
- sh: "./aws_cli/bin/python -m pip install awscli"
- sh: "PATH=$(echo $PWD'/aws_cli/bin'):$PATH"

build_script:
- "python -c \"import sys; print(sys.executable)\""
- "pip install -e \".[dev]\""
Expand All @@ -103,6 +111,7 @@ for:

# Runs only in Linux
- sh: "pytest -vv tests/integration"
- sh: "pytest -vv -n 4 tests/regression"
- sh: "/tmp/black --check setup.py tests samcli scripts"
- sh: "python scripts/check-isolated-needs-update.py"

Expand Down
3 changes: 2 additions & 1 deletion requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ chevron~=0.12
click~=7.0
Flask~=1.0.2
boto3~=1.9, >=1.9.56
jmespath~=0.9.4
PyYAML~=5.1
cookiecutter~=1.6.0
aws-sam-translator==1.15.1
docker~=4.0
dateparser~=0.7
python-dateutil~=2.6
python-dateutil~=2.6, <2.8.1
requests==2.22.0
serverlessrepo==0.1.9
aws_lambda_builders==0.5.0
2 changes: 1 addition & 1 deletion samcli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
SAM CLI version
"""

__version__ = "0.30.0"
__version__ = "0.31.0"
8 changes: 7 additions & 1 deletion samcli/cli/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
import uuid
import logging
import boto3
import botocore
import click

from samcli.commands.exceptions import CredentialsError


class Context:
"""
Expand Down Expand Up @@ -139,4 +142,7 @@ def _refresh_session(self):
the Boto3's session object are read-only. Therefore when Click parses new AWS session related properties (like
region & profile), it will call this method to create a new session with latest values for these properties.
"""
boto3.setup_default_session(region_name=self._aws_region, profile_name=self._aws_profile)
try:
boto3.setup_default_session(region_name=self._aws_region, profile_name=self._aws_profile)
except botocore.exceptions.ProfileNotFound as ex:
raise CredentialsError(str(ex))
49 changes: 49 additions & 0 deletions samcli/cli/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"""

import re
import json
from json import JSONDecodeError

import click


Expand Down Expand Up @@ -64,3 +67,49 @@ def _unquote(value):
value = value.strip('"')

return value.replace("\\ ", " ").replace('\\"', '"')


class CfnMetadataType(click.ParamType):
"""
Custom Click options type to accept values for metadata parameters.
metadata parameters can be of the type KeyName1=string,KeyName2=string or {"string":"string"}
"""

_EXAMPLE = 'KeyName1=string,KeyName2=string or {"string":"string"}'

_pattern = r"([A-Za-z0-9\"]+)=([A-Za-z0-9\"]+)"

# NOTE(TheSriram): name needs to be added to click.ParamType requires it.
name = "CfnMetadata"

def convert(self, value, param, ctx):
result = {}
fail = False
if not value:
return result
try:
# Look to load the value into json if we can.
result = json.loads(value)
for val in result.values():
if isinstance(val, (dict, list)):
# Need a non nested dictionary or a dictionary with non list values,
# If either is found, fail the conversion.
fail = True
except JSONDecodeError:
# if looking for a json format failed, look at if the specified value follows
# KeyName1=string,KeyName2=string format
groups = re.findall(self._pattern, value)

if not groups:
fail = True
for group in groups:
key, value = group
# assign to result['KeyName1'] = string and so on.
result[key] = value

if fail:
return self.fail(
"{} is not in valid format. It must look something like '{}'".format(value, self._EXAMPLE), param, ctx
)

return result
14 changes: 13 additions & 1 deletion samcli/commands/_utils/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from functools import partial

import click
from samcli.cli.types import CfnParameterOverridesType
from samcli.cli.types import CfnParameterOverridesType, CfnMetadataType

_TEMPLATE_OPTION_DEFAULT_VALUE = "template.[yaml|yml]"

Expand Down Expand Up @@ -122,3 +122,15 @@ def parameter_override_click_option():

def parameter_override_option(f):
return parameter_override_click_option()(f)


def metadata_click_option():
return click.option(
"--metadata",
type=CfnMetadataType(),
help="Optional. A map of metadata to attach to ALL the artifacts that are referenced in your template.",
)


def metadata_override_option(f):
return metadata_click_option()(f)
46 changes: 46 additions & 0 deletions samcli/commands/_utils/resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""
Enums for Resources and thier Location Properties, along with utlity functions
"""

AWS_SERVERLESSREPO_APPLICATION = "AWS::ServerlessRepo::Application"
AWS_SERVERLESS_FUNCTION = "AWS::Serverless::Function"
AWS_SERVERLESS_API = "AWS::Serverless::Api"
AWS_APPSYNC_GRAPHQLSCHEMA = "AWS::AppSync::GraphQLSchema"
AWS_APPSYNC_RESOLVER = "AWS::AppSync::Resolver"
AWS_APPSYNC_FUNCTIONCONFIGURATION = "AWS::AppSync::FunctionConfiguration"
AWS_LAMBDA_FUNCTION = "AWS::Lambda::Function"
AWS_APIGATEWAY_RESTAPI = "AWS::ApiGateway::RestApi"
AWS_ELASTICBEANSTALK_APPLICATIONVERSION = "AWS::ElasticBeanstalk::ApplicationVersion"
AWS_CLOUDFORMATION_STACK = "AWS::CloudFormation::Stack"
AWS_SERVERLESS_APPLICATION = "AWS::Serverless::Application"
AWS_LAMBDA_LAYERVERSION = "AWS::Lambda::LayerVersion"
AWS_SERVERLESS_LAYERVERSION = "AWS::Serverless::LayerVersion"
AWS_GLUE_JOB = "AWS::Glue::Job"

METADATA_WITH_LOCAL_PATHS = {AWS_SERVERLESSREPO_APPLICATION: ["LicenseUrl", "ReadmeUrl"]}

RESOURCES_WITH_LOCAL_PATHS = {
AWS_SERVERLESS_FUNCTION: ["CodeUri"],
AWS_SERVERLESS_API: ["DefinitionUri"],
AWS_APPSYNC_GRAPHQLSCHEMA: ["DefinitionS3Location"],
AWS_APPSYNC_RESOLVER: ["RequestMappingTemplateS3Location", "ResponseMappingTemplateS3Location"],
AWS_APPSYNC_FUNCTIONCONFIGURATION: ["RequestMappingTemplateS3Location", "ResponseMappingTemplateS3Location"],
AWS_LAMBDA_FUNCTION: ["Code"],
AWS_APIGATEWAY_RESTAPI: ["BodyS3Location"],
AWS_ELASTICBEANSTALK_APPLICATIONVERSION: ["SourceBundle"],
AWS_CLOUDFORMATION_STACK: ["TemplateURL"],
AWS_SERVERLESS_APPLICATION: ["Location"],
AWS_LAMBDA_LAYERVERSION: ["Content"],
AWS_SERVERLESS_LAYERVERSION: ["ContentUri"],
AWS_GLUE_JOB: ["Command.ScriptLocation"],
}


def resources_generator():
"""
Generator to yield set of resources and their locations that are supported for package operations
:return:
"""
for resource, locations in dict({**METADATA_WITH_LOCAL_PATHS, **RESOURCES_WITH_LOCAL_PATHS}).items():
for location in locations:
yield resource, location
27 changes: 5 additions & 22 deletions samcli/commands/_utils/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,7 @@
import yaml

from samcli.yamlhelper import yaml_parse, yaml_dump


_METADATA_WITH_LOCAL_PATHS = {"AWS::ServerlessRepo::Application": ["LicenseUrl", "ReadmeUrl"]}

_RESOURCES_WITH_LOCAL_PATHS = {
"AWS::Serverless::Function": ["CodeUri"],
"AWS::Serverless::Api": ["DefinitionUri"],
"AWS::AppSync::GraphQLSchema": ["DefinitionS3Location"],
"AWS::AppSync::Resolver": ["RequestMappingTemplateS3Location", "ResponseMappingTemplateS3Location"],
"AWS::AppSync::FunctionConfiguration": ["RequestMappingTemplateS3Location", "ResponseMappingTemplateS3Location"],
"AWS::Lambda::Function": ["Code"],
"AWS::ApiGateway::RestApi": ["BodyS3Location"],
"AWS::ElasticBeanstalk::ApplicationVersion": ["SourceBundle"],
"AWS::CloudFormation::Stack": ["TemplateURL"],
"AWS::Serverless::Application": ["Location"],
"AWS::Lambda::LayerVersion": ["Content"],
"AWS::Serverless::LayerVersion": ["ContentUri"],
}
from samcli.commands._utils.resources import METADATA_WITH_LOCAL_PATHS, RESOURCES_WITH_LOCAL_PATHS


def get_template_data(template_file):
Expand Down Expand Up @@ -126,11 +109,11 @@ def _update_relative_paths(template_dict, original_root, new_root):

for resource_type, properties in template_dict.get("Metadata", {}).items():

if resource_type not in _METADATA_WITH_LOCAL_PATHS:
if resource_type not in METADATA_WITH_LOCAL_PATHS:
# Unknown resource. Skipping
continue

for path_prop_name in _METADATA_WITH_LOCAL_PATHS[resource_type]:
for path_prop_name in METADATA_WITH_LOCAL_PATHS[resource_type]:
path = properties.get(path_prop_name)

updated_path = _resolve_relative_to(path, original_root, new_root)
Expand All @@ -143,11 +126,11 @@ def _update_relative_paths(template_dict, original_root, new_root):
for _, resource in template_dict.get("Resources", {}).items():
resource_type = resource.get("Type")

if resource_type not in _RESOURCES_WITH_LOCAL_PATHS:
if resource_type not in RESOURCES_WITH_LOCAL_PATHS:
# Unknown resource. Skipping
continue

for path_prop_name in _RESOURCES_WITH_LOCAL_PATHS[resource_type]:
for path_prop_name in RESOURCES_WITH_LOCAL_PATHS[resource_type]:
properties = resource.get("Properties", {})
path = properties.get(path_prop_name)

Expand Down
6 changes: 6 additions & 0 deletions samcli/commands/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,9 @@ class UserException(click.ClickException):
"""

exit_code = 1


class CredentialsError(UserException):
"""
Exception class when credentials that have been passed are invalid.
"""
2 changes: 1 addition & 1 deletion samcli/commands/init/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
help="Dependency manager of your Lambda runtime",
required=False,
)
@click.option("-o", "--output-dir", type=click.Path(), help="Where to output the initialized app into")
@click.option("-o", "--output-dir", type=click.Path(), help="Where to output the initialized app into", default=".")
@click.option("-n", "--name", help="Name of your project to be generated as a folder")
@click.option(
"--app-template",
Expand Down
40 changes: 0 additions & 40 deletions samcli/commands/init/init_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,7 @@


def do_generate(location, runtime, dependency_manager, output_dir, name, no_input, extra_context):
no_build_msg = """
Project generated: {output_dir}/{name}

Steps you can take next within the project folder
===================================================
[*] Invoke Function: sam local invoke HelloWorldFunction --event event.json
[*] Start API Gateway locally: sam local start-api
""".format(
output_dir=output_dir, name=name
)

build_msg = """
Project generated: {output_dir}/{name}

Steps you can take next within the project folder
===================================================
[*] Install dependencies
[*] Invoke Function: sam local invoke HelloWorldFunction --event event.json
[*] Start API Gateway locally: sam local start-api
""".format(
output_dir=output_dir, name=name
)

no_build_step_required = (
"python",
"python3.7",
"python3.6",
"python2.7",
"nodejs",
"nodejs4.3",
"nodejs6.10",
"nodejs8.10",
"nodejs10.x",
"ruby2.5",
)
next_step_msg = no_build_msg if runtime in no_build_step_required else build_msg
try:
generate_project(location, runtime, dependency_manager, output_dir, name, no_input, extra_context)
if not location:
click.secho(next_step_msg, bold=True)
click.secho("Read {name}/README.md for further instructions\n".format(name=name), bold=True)
click.secho("[*] Project initialization is now complete", fg="green")
except GenerateProjectFailedError as e:
raise UserException(str(e))
Loading