Merge pull request #1 from serverless/master

update fork
This commit is contained in:
Alex Gaesser 2018-02-05 15:10:09 -08:00 committed by GitHub
commit 8dde4c7e22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 1809 additions and 294 deletions

View File

@ -1,3 +1,16 @@
# 1.26.0 (29.01.2018)
- [AWS Go support](https://github.com/serverless/serverless/pull/4669)
- [Support for using an existing ApiGateway and Resources](https://github.com/serverless/serverless/pull/4247)
- [Add logRetentionInDays config](https://github.com/serverless/serverless/pull/4591)
- [Add support of `serverless.js` configuration file](https://github.com/serverless/serverless/pull/4590)
- [Add "did you mean..." CLI suggestions](https://github.com/serverless/serverless/pull/4586)
- [Add `--template-path` option to `serverless create`](https://github.com/serverless/serverless/pull/4576)
- [Add support POJO input support for Java invoke local](https://github.com/serverless/serverless/pull/4596)
## Meta
- [Comparison since last release](https://github.com/serverless/serverless/compare/v1.25.0...v1.26.0)
# 1.25.0 (20.12.2017)
- [Improve Stage and Region Usage](https://github.com/serverless/serverless/pull/4560)
- [Add API Gateway endpoint configuration](https://github.com/serverless/serverless/pull/4531)

View File

@ -132,7 +132,7 @@ The following are services you can instantly install and use by running `serverl
## <a name="features"></a>Features
* Supports Node.js, Python, Java, Scala, C#, F#, Groovy, Kotlin, PHP & Swift.
* Supports Node.js, Python, Java, Scala, C#, F#, Go, Groovy, Kotlin, PHP & Swift.
* Manages the lifecycle of your serverless architecture (build, deploy, update, delete).
* Safely deploy functions, events and their required resources together via provider resource managers (e.g., AWS CloudFormation).
* Functions can be grouped ("serverless services") for easy management of code, resources & processes, across large projects & teams.
@ -158,7 +158,7 @@ This table is generated from https://github.com/serverless/plugins/blob/master/p
| **[Raml Serverless](https://github.com/andrewcurioso/raml-serverless)** <br/> Serverless plugin to work with RAML API spec documents | [andrewcurioso](http://github.com/andrewcurioso) |
| **[Serverless Alexa Plugin](https://github.com/rajington/serverless-alexa-plugin)** <br/> Serverless plugin to support Alexa Lambda events | [rajington](http://github.com/rajington) |
| **[Serverless Api Stage](https://github.com/leftclickben/serverless-api-stage)** <br/> Serverless API Stage plugin, enables stage variables and logging for AWS API Gateway. | [leftclickben](http://github.com/leftclickben) |
| **[Serverless Apig S3](https://github.com/sdd/serverless-apig-s3)** <br/> Serve static front-end content from S3 via the API Gatewy and deploy client bundle to S3. | [sdd](http://github.com/sdd) |
| **[Serverless Apig S3](https://github.com/sdd/serverless-apig-s3)** <br/> Serve static front-end content from S3 via the API Gateway and deploy client bundle to S3. | [sdd](http://github.com/sdd) |
| **[Serverless Apigateway Plugin](https://github.com/GFG/serverless-apigateway-plugin)** <br/> Configure the AWS api gateway: Binary support, Headers and Body template mappings | [GFG](http://github.com/GFG) |
| **[Serverless Apigw Binary](https://github.com/maciejtreder/serverless-apigw-binary)** <br/> Plugin to enable binary support in AWS API Gateway. | [maciejtreder](http://github.com/maciejtreder) |
| **[Serverless Apigwy Binary](https://github.com/ryanmurakami/serverless-apigwy-binary)** <br/> Serverless plugin for configuring API Gateway to return binary responses | [ryanmurakami](http://github.com/ryanmurakami) |

View File

@ -63,6 +63,16 @@ services:
image: microsoft/dotnet:1.0.4-sdk
volumes:
- ./tmp/serverless-integration-test-aws-fsharp:/app
aws-go:
image: golang:1.9
volumes:
- ./tmp/serverless-integration-test-aws-go:/app
- ./tmp/serverless-integration-test-aws-go:/go/src/app
aws-go-dep:
image: yunspace/golang:1.9
volumes:
- ./tmp/serverless-integration-test-aws-go-dep:/app
- ./tmp/serverless-integration-test-aws-go-dep:/go/src/app
aws-nodejs-typescript:
image: node:6.10.3
volumes:

View File

@ -14,14 +14,41 @@ layout: Doc
## Event definition
This will enable your Lambda function to be called by an Alexa skill kit.
This will enable your Lambda function to be called by an Alexa Skill kit.
`amzn1.ask.skill.xx-xx-xx-xx-xx` is a skill ID for Alexa Skills kit. You receive a skill ID once you register and create a skill in [Amazon Developer Console](https://developer.amazon.com/).
After deploying, add your deployed Lambda function ARN to which this event is attached to the Service Endpoint under Configuration on Amazon Developer Console.
```yml
functions:
mySkill:
handler: mySkill.handler
events:
- alexaSkill
- alexaSkill: amzn1.ask.skill.xx-xx-xx-xx-xx
```
You can find detailed guides on how to create an Alexa Skill with Serverless using NodeJS [here](https://github.com/serverless/examples/tree/master/aws-node-alexa-skill) as well as in combination with Python [here](https://github.com/serverless/examples/tree/master/aws-python-alexa-skill).
## Enabling / Disabling
**Note:** `alexaSkill` events are enabled by default.
This will create and attach a alexaSkill event for the `mySkill` function which is disabled. If enabled it will call
the `mySkill` function by an Alexa Skill.
```yaml
functions:
mySkill:
handler: mySkill.handler
events:
- alexaSkill:
appId: amzn1.ask.skill.xx-xx-xx-xx
enabled: false
```
## Backwards compatability
Previous syntax of this event didn't require a skill ID as parameter, but according to [Amazon's documentation](https://developer.amazon.com/docs/custom-skills/host-a-custom-skill-as-an-aws-lambda-function.html#configuring-the-alexa-skills-kit-trigger) you should restrict your lambda function to be executed only by your skill.
Omitting the skill id will make your Lambda function available for the public, allowing any other skill developer to invoke it.
(This is important, as [opposing to custom HTTPS endpoints](https://developer.amazon.com/docs/custom-skills/handle-requests-sent-by-alexa.html#request-verify), there's no way to validate the request was sent by your skill.)

View File

@ -872,7 +872,7 @@ functions:
```
In case the application has many chilren and grandchildren paths, you also want to break them out into smaller services.
In case the application has many children and grandchildren paths, you also want to break them out into smaller services.
```yml
service: service-a

View File

@ -14,7 +14,7 @@ layout: Doc
## Simple event definition
This will enable your Lambda function to be called by an Log Stream.
This will enable your Lambda function to be called by a Log Stream.
```yml
functions:

View File

@ -17,6 +17,8 @@ Pick your language of choice:
* [JavaScript](./node)
* [Python](./python)
* [csharp](./csharp)
* [C#](./csharp)
* [F#](./fsharp)
* [Go](./go)
[View all examples](https://www.serverless.com/framework/docs/providers/aws/examples/)

View File

@ -13,13 +13,32 @@ layout: Doc
Make sure `serverless` is installed. [See installation guide](../../../guide/installation.md).
Once installed the Serverless CLI can be called with `serverless` or the shorthand `sls` command.
```
$ sls
Commands
* You can run commands with "serverless" or the shortcut "sls"
* Pass "--verbose" to this command to get in-depth plugin info
* Pass "--no-color" to disable CLI colors
* Pass "--help" after any <command> for contextual help
```
## 1. Create a service
`serverless create --template aws-csharp --path myService` or `sls create --template aws-csharp --path myService`, where 'myService' is a new folder to be created with template service files. Change directories into this new folder.
```
sls create --template aws-csharp --path myService
```
Using the `create` command we can specify one of the available [templates](https://serverless.com/framework/docs/providers/aws/cli-reference/create#available-templates). For this example use aws-csharp with the `--template` or shorthand `-t` flag.
The `--path` or shorthand `-p` is the location to be created with the template service files. Change directories into this new folder.
## 2. Build using .NET CLI tools and create zip package
```
# Linux or OSX
# Linux or Mac OS
./build.sh
```
@ -29,14 +48,23 @@ Make sure `serverless` is installed. [See installation guide](../../../guide/ins
```
## 3. Deploy
`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command
```
sls deploy
```
This will deploy your function to AWS Lambda based on the settings in `serverless.yml`.
## 4. Invoke deployed function
`serverless invoke --function hello` or `serverless invoke -f hello`
`-f` is shorthand for `--function`
```
sls invoke -f hello
```
In your terminal window you should see the response from AWS Lambda
Invoke deployed function with command `invoke` and `--function` or shorthand `-f`.
In your terminal window you should see the response from AWS Lambda.
```bash
{
@ -49,4 +77,4 @@ In your terminal window you should see the response from AWS Lambda
}
```
Congrats you have just deployed and run your Hello World function!
Congrats you have deployed and ran your Hello World function!

View File

@ -7,31 +7,69 @@ layout: Doc
# Hello World F# Example
## Prerequisites
Make sure `serverless` is installed. [See installation guide](../../../guide/installation.md).
* Make sure `serverless` is installed. [See installation guide](../../../guide/installation.md).
* [.Net Core 1.0.1 SDK](https://www.microsoft.com/net/download/core)
* 1.1 isn't currently supported by AWS Lambda
* [NodeJS v4 or higher](https://nodejs.org/en/)
* An AWS Account
## Build and Package
From the root of this directory, run `build.cmd`, or `build.sh` if on Linux / Mac.
This will produce your deployment package at `bin/release/netcoreapp1.0/deploy-package.zip`.
## Deployment and Invocation
Once packaged, you can follow [these instructions](https://github.com/serverless/serverless#quick-start) to deploy and remotely invoke the function on AWS Lambda.
In short the commands you will need to run are (from the root of this directory):
Once installed the Serverless CLI can be called with `serverless` or the shorthand `sls` command.
```
serverless config credentials --provider aws --key {YourAwsAccessKey} --secret {YourAwsSecret}
serverless deploy -v
serverless invoke -f hello -l
serverless remove
$ sls
Commands
* You can run commands with "serverless" or the shortcut "sls"
* Pass "--verbose" to this command to get in-depth plugin info
* Pass "--no-color" to disable CLI colors
* Pass "--help" after any <command> for contextual help
```
By default this template deploys to us-east-1, you can change that in "serverless.yml" under the `region: us-east-1` key.
## 1. Create a service
```
sls create --template aws-fsharp --path myService
```
Using the `create` command we can specify one of the available [templates](https://serverless.com/framework/docs/providers/aws/cli-reference/create#available-templates). For this example use aws-fsharp with the `--template` or shorthand `-t` flag.
The `--path` or shorthand `-p` is the location to be created with the template service files. Change directories into this new folder.
## 2. Build using .NET CLI tools and create zip package
```
# Linux or Mac OS
./build.sh
```
```
# Windows PowerShell
./build.cmd
```
## 3. Deploy
```
sls deploy
```
This will deploy your function to AWS Lambda based on the settings in `serverless.yml`.
## 4. Invoke deployed function
```
sls invoke -f hello
```
Invoke deployed function with command `invoke` and `--function` or shorthand `-f`.
In your terminal window you should see the response from AWS Lambda.
```bash
{
"Message": "Go Serverless v1.0! Your function executed successfully!",
"Request": {
"Key1": null,
"Key2": null,
"Key3": null
}
}
```
Congrats you have deployed and ran your Hello World function!

View File

@ -66,7 +66,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -0,0 +1,116 @@
<!--
title: Hello World Go Example
menuText: Hello World Go Example
description: Create a Go Hello World Lambda function
layout: Doc
-->
<!-- DOCS-SITE-LINK:START automatically geneated -->
### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/aws/examples/hello-world/go/)
<!-- DOCS-SITE-LINK:END -->
# Hello World Go Example
Make sure `serverless` is installed. [See installation guide](../../../guide/installation.md).
Once installed the Serverless CLI can be called with `serverless` or the shorthand `sls` command.
```
$ sls
Commands
* You can run commands with "serverless" or the shortcut "sls"
* Pass "--verbose" to this command to get in-depth plugin info
* Pass "--no-color" to disable CLI colors
* Pass "--help" after any <command> for contextual help
```
You should also have [go](https://golang.org/doc/install) and [make](https://www.gnu.org/software/make/)
It is always good practice to organize your `go` projects within [GOPATH](https://golang.org/doc/code.html#GOPATH), to maximize the benefits of go tooling.
## 1. Create a service
There are two templates for `go`:
The Serverless Framework includes starter templates for various languages and providers. There are two templates for `go`.
#### [aws-go](https://github.com/serverless/serverless/tree/master/lib/plugins/create/templates/aws-go)
`aws-go` fetches dependencies using standard `go get`.
```
sls create --template aws-go --path myService
```
#### [aws-go-dep](https://github.com/serverless/serverless/tree/master/lib/plugins/create/templates/aws-go-dep)
`aws-go-dep` uses [go dep](https://github.com/golang/dep) and requires your project to be in `$GOPATH/src`
```
sls create --template aws-go-dep --path myService
```
Using the `create` command we can specify one of the available [templates](https://serverless.com/framework/docs/providers/aws/cli-reference/create#available-templates). For this example use aws-nodejs with the `--template` or shorthand `-t` flag.
The `--path` or shorthand `-p` is the location to be created with the template service files.
Change directories into 'myService' folder and you can see this project has 2 handler functions: `hello` and `world` split into 2 separate go packages (folders):
```
.
├── hello/
│ └── main.go
├── world/
│ └── main.go
```
This because a `main()` function is required as entry point for each handler executable.
## 2. Build using go build to create static binaries
Run `make build` to build both functions. Successful build should generate the following binaries:
```
.
├── bin/
│ |── hello
│ └── world
```
## 3. Deploy
```
sls deploy
```
This will deploy your function to AWS Lambda based on the settings in `serverless.yml`.
## 4. Invoke deployed function
```
sls invoke -f hello
```
```
sls invoke -f world
```
Invoke either deployed function with command `invoke` and `--function` or shorthand `-f`.
In your terminal window you should see the response from AWS Lambda.
```bash
serverless invoke -f hello
{
"message": "Go Serverless v1.0! Your function executed successfully!"
}
serverless invoke -f world
{
"message": "Okay so your other function also executed successfully!"
}
```
Congrats you have deployed and ran your Hello World function!

View File

@ -13,18 +13,45 @@ layout: Doc
Make sure `serverless` is installed. [See installation guide](../../../guide/installation.md).
Once installed the Serverless CLI can be called with `serverless` or the shorthand `sls` command.
```
$ sls
Commands
* You can run commands with "serverless" or the shortcut "sls"
* Pass "--verbose" to this command to get in-depth plugin info
* Pass "--no-color" to disable CLI colors
* Pass "--help" after any <command> for contextual help
```
## 1. Create a service
`serverless create --template aws-nodejs --path myService` or `sls create --template aws-nodejs --path myService`, where 'myService' is a new folder to be created with template service files. Change directories into this new folder.
```
sls create --template aws-nodejs --path myService
```
Using the `create` command we can specify one of the available [templates](https://serverless.com/framework/docs/providers/aws/cli-reference/create#available-templates). For this example use aws-nodejs with the `--template` or shorthand `-t` flag.
The `--path` or shorthand `-p` is the location to be created with the template service files. Change directories into this new folder.
## 2. Deploy
`serverless deploy` or `sls deploy`. `sls` is shorthand for the Serverless CLI command
```
sls deploy
```
This will deploy your function to AWS Lambda based on the settings in `serverless.yml`.
## 3. Invoke deployed function
`serverless invoke --function hello` or `serverless invoke -f hello`
`-f` is shorthand for `--function`
```
sls invoke -f hello
```
In your terminal window you should see the response from AWS Lambda
Invoke deployed function with command `invoke` and `--function` or shorthand `-f`.
In your terminal window you should see the response from AWS Lambda.
```bash
{
@ -33,4 +60,4 @@ In your terminal window you should see the response from AWS Lambda
}
```
Congrats you have just deployed and run your Hello World function!
Congrats you have deployed and ran your Hello World function!

View File

@ -13,18 +13,45 @@ layout: Doc
Make sure `serverless` is installed. [See installation guide](../../../guide/installation.md).
Once installed the Serverless CLI can be called with `serverless` or the shorthand `sls` command.
```
$ sls
Commands
* You can run commands with "serverless" or the shortcut "sls"
* Pass "--verbose" to this command to get in-depth plugin info
* Pass "--no-color" to disable CLI colors
* Pass "--help" after any <command> for contextual help
```
## 1. Create a service
`serverless create --template aws-python --path myService` or `sls create --template aws-python --path myService`, where 'myService' is a new folder to be created with template service files. Change directories into this new folder.
```
sls create --template aws-python --path myService
```
Using the `create` command we can specify one of the available [templates](https://serverless.com/framework/docs/providers/aws/cli-reference/create#available-templates). For this example use aws-python with the `--template` or shorthand `-t` flag.
The `--path` or shorthand `-p` is the location to be created with the template service files. Change directories into this new folder.
## 2. Deploy
`serverless deploy` or `sls deploy`. `sls` is shorthand for the serverless CLI command
```
sls deploy
```
This will deploy your function to AWS Lambda based on the settings in `serverless.yml`.
## 3. Invoke deployed function
`serverless invoke --function hello` or `serverless invoke -f hello`
`-f` is shorthand for `--function`
```
sls invoke -f hello
```
In your terminal window you should see the response from AWS Lambda
Invoke deployed function with command `invoke` and `--function` or shorthand `-f`.
In your terminal window you should see the response from AWS Lambda.
```bash
{
@ -33,4 +60,4 @@ In your terminal window you should see the response from AWS Lambda
}
```
Congrats you have just deployed and ran your Hello World function!
Congrats you have deployed and ran your Hello World function!

View File

@ -37,6 +37,7 @@ functions:
runtime: python2.7 # optional overwrite, default is provider runtime
memorySize: 512 # optional, in MB, default is 1024
timeout: 10 # optional, in seconds, default is 6
reservedConcurrency: 5 # optional, reserved concurrency limit for this function. By default, AWS uses account concurrency limit
```
The `handler` property points to the file and module containing the code you want to run in your function.

View File

@ -159,7 +159,9 @@ functions:
batchSize: 100
startingPosition: LATEST
enabled: false
- alexaSkill
- alexaSkill:
appId: amzn1.ask.skill.xx-xx-xx-xx
enabled: true
- alexaSmartHome:
appId: amzn1.ask.skill.xx-xx-xx-xx
enabled: true

View File

@ -63,6 +63,7 @@ Here are the available runtimes for AWS Lambda:
* aws-scala-sbt
* aws-csharp
* aws-fsharp
* aws-go
Check out the [create command docs](../cli-reference/create) for all the details and options.

View File

@ -39,4 +39,4 @@ In your terminal window you should see the response from azure
}
```
Congrats you have just deployed and run your Hello World function!
Congrats you have deployed and ran your Hello World function!

View File

@ -0,0 +1,56 @@
<!--
title: Serverless Framework Commands - Google Cloud Functions - Invoke Local
menuText: invoke local
menuOrder: 7
description: Emulate an invocation of your Google Cloud function locally using the Serverless Framework
layout: Doc
-->
<!-- DOCS-SITE-LINK:START automatically generated -->
### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/google/cli-reference/invoke-local)
<!-- DOCS-SITE-LINK:END -->
# Google - Invoke Local
Invokes deployed function locally. It allows to send event data to the function, read logs and display other important information of the function invocation.
```bash
serverless invoke -f functionName
```
## Options
* `--function` or `-f` The name of the function in your service that you want to invoke. **Required**.
\_ `--data` or `-d` Data you want to pass into the function
* `--path` or `-p` Path to JSON or YAML file holding input data. This path is relative to the root directory of the service.
* `--raw` Pass data as a raw string even if it is JSON. If not set, JSON data are parsed and passed as an object.
* `--contextPath` or `-x`, The path to a json file holding input context to be passed to the invoked function. This path is relative to the root directory of the service.
* `--context` or `-c`, String data to be passed as a context to your function. Same like with `--data`, context included in `--contextPath` will overwrite the context you passed with `--context` flag.
> Keep in mind that if you pass both `--path` and `--data`, the data included in the `--path` file will overwrite the data you passed with the `--data` flag.
## Examples
### Local function invocation
```bash
serverless invoke local -f functionName
```
### Local function invocation with data
```bash
serverless invoke local -f functionName -d '{ "data": "hello world" }'
```
### Local function invocation with data passing
```bash
serverless invoke local -f functionName -p path/to/file.json
# OR
serverless invoke local -f functionName -p path/to/file.yaml
```

View File

@ -31,8 +31,8 @@ Update the `credentials` and your `project` property in the `serverless.yml` fil
## 5. Invoke deployed function
`serverless invoke --function helloWorld`
`serverless invoke --function first`
In your terminal window you should see a response from the Google Cloud
Congrats you have just deployed and run your Hello World function!
Congrats you have deployed and ran your Hello World function!

View File

@ -30,6 +30,7 @@ If you have questions, join the [chat in gitter](https://gitter.im/serverless/se
<li><a href="./guide/functions.md">Functions</a></li>
<li><a href="./guide/events.md">Events</a></li>
<li><a href="./guide/deploying.md">Deploying</a></li>
<li><a href="./guide/packaging.md">Packaging</a></li>
<li><a href="./guide/debugging.md">Debugging</a></li>
<li><a href="./guide/workflow.md">Workflow</a></li>
</ul>

View File

@ -25,6 +25,9 @@ service: my-service
provider:
name: kubeless
runtime: python2.7
memorySize: 512M # optional, maximum memory
timeout: 10 # optional, in seconds, default is 180
namespace: funcions # optional, deployment namespace if not specified it uses "default"
plugins:
- serverless-kubeless
@ -34,7 +37,12 @@ functions:
# and the K8s service object to get a request to call the function
hello:
# The function to call as a response to the HTTP event
handler: handler.hello
handler: handler.hello # required, handler set
description: Description of what the function does # optional, to set the description as an annotation
memorySize: 512M # optional, maximum memory
timeout: 10 # optional, in seconds, default is 180
namespace: funcions # optional, deployment namespace, if not specified "default" will be used
port: 8081 # optional, deploy http-based function with a custom port, default is 8080
```
The `handler` property points to the file and module containing the code you want to run in your function.
@ -88,3 +96,139 @@ The Kubeless provider plugin supports the following runtimes.
Please see the following repository for sample projects using those runtimes:
[https://github.com/serverless/serverless-kubeless/tree/master/examples](https://github.com/serverless/serverless-kubeless/tree/master/examples)
## Installing dependencies
For installing dependencies the standard dependency file should be placed in the function folder:
- For Python functions, it will use the file `requirements.txt`
- For Nodejs functions, `dependencies` in the `package.json` file will be installed
- For Ruby functions, it will use the file `Gemfile.rb`
If one of the above files is found, the depencies will be installed using a [`Init Container`](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).
## Environment Variables
You can add environment variable configuration to a specific function in `serverless.yml` by adding an `environment` object property in the function configuration. This object should contain a key/value collection of strings:
```yml
# serverless.yml
service: service-name
provider: kubeless
plugins:
- serverless-kubeless
functions:
hello:
handler: handler.hello
environment:
TABLE_NAME: tableName
```
Or if you want to apply environment variable configuration to all functions in your service, you can add the configuration to the higher level `provider` object. Environment variables configured at the function level are merged with those at the provider level, so your function with specific environment variables will also have access to the environment variables defined at the provider level. If an environment variable with the same key is defined at both the function and provider levels, the function-specific value overrides the provider-level default value. For example:
```yml
# serverless.yml
service: service-name
provider:
name: kubeless
environment:
SYSTEM_NAME: mySystem
TABLE_NAME: tableName1
plugins:
- serverless-kubeless
functions:
hello:
# this function will have SYSTEM_NAME=mySystem and TABLE_NAME=tableName1 from the provider-level environment config above
handler: handler.hello
users:
# this function will have SYSTEM_NAME=mySystem from the provider-level environment config above
# but TABLE_NAME will be tableName2 because this more specific config will override the default above
handler: handler.users
environment:
TABLE_NAME: tableName2
```
## Labels
Using the `labels` configuration makes it possible to add `key` / `value` labels to your functions.
Those labels will appear in deployments, services and pods and will make it easier to group functions by label or find functions with a common label.
```yml
provider:
name: kubeless
plugins:
- serverless-kubeless
functions:
hello:
handler: handler.hello
labels:
foo: bar
```
## Custom hostname and path
It is possible to define a custom hostname and path that will be used to serve a function in a specific endpoint. For doing this, it is necessary to have an [Ingress Controller](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-controllers) available in the cluster.
```yml
provider:
name: kubeless
hostname: myhostname.io
plugins:
- serverless-kubeless
functions:
hello:
handler: handler.hello
events:
- http:
path: /hello
```
In the example above, once the Ingress Rule has been processed by the Ingress controller, you can call the function using as endpoing `myhostname.io/hello`.
If no hostname is given but a function specifies a `path`, the plugin will use the IP of the cluster followed by a DNS mapping service. By default [nip.io](http://nip.io) will be used but this can be configured with the property `defaultDNSResolution`.
```yml
provider:
name: kubeless
defaultDNSResolution: 'xip.io'
plugins:
- serverless-kubeless
functions:
hello:
handler: handler.hello
events:
- http:
path: /hello
```
The above will result in an endpoint like `1.2.3.4.xip.io/hello` where `1.2.3.4` is the IP of the cluster server.
The final URL in which the function will be listening can be retrieved executing `serverless info`.
## Custom images (alpha feature)
It is possible to skip the Kubeless build system and specify a prebuilt image to run a function. This feature is useful for using Kubeless with languages that are still not supported or if the function package [is over 1MB](./packaging.md#package-maximum-size). To get more information about how to use custom images visit the [upstream documentation](https://github.com/kubeless/kubeless/blob/master/docs/runtimes.md#custom-runtime-alpha).
```yml
service: hello
provider:
name: kubeless
runtime: python2.7
plugins:
- serverless-kubeless
functions:
hello:
handler: handler.hello
image: tuna/kubeless-python:0.0.6
```

View File

@ -0,0 +1,144 @@
<!--
title: Serverless Framework - Kubeless Guide - Packaging
menuText: Packaging
menuOrder: 10
description: How the Serverless Framework packages your Kubeless functions and other available options
layout: Doc
-->
<!-- DOCS-SITE-LINK:START automatically generated -->
### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/kubeless/guide/packaging)
<!-- DOCS-SITE-LINK:END -->
# Kubeless - Packaging
## Package CLI Command
Using the Serverless CLI tool, you can package your project without deploying with Kubeless. This is best used with CI / CD workflows to ensure consistent deployable artifacts.
Running the following command will build and save all of the deployment artifacts in the service's .serverless directory:
```bash
serverless package
```
However, you can also use the --package option to add a destination path and Serverless will store your deployment artifacts there (./my-artifacts in the following case):
```bash
serverless package --package my-artifacts
```
## Package Maximum Size
Kubeless uses [Kubernetes ConfigMaps](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/) to store functions configuration and code. These ConfigMaps have a limitation in size of one MB since they are stored as a single entry in a `etcd` database. Due to this limitation, the maximum possible size for a Kubeless function package is no more than one MB. Note that only code and configuration files should be included in this package, dependencies will be installed during the build process. If your function package size is over one MB please [exclude some directories](#exclude-include) or create a [custom image](./functions#custom-images-alpha-feature) with your function. By default, files under the `node_modules` folder will be excluded.
## Package Configuration
Sometimes you might like to have more control over your function artifacts and how they are packaged.
You can use the `package` and `exclude` configuration for more control over the packaging process.
### Exclude / include
Exclude and include allows you to define globs that will be excluded / included from the resulting artifact. If you wish to
include files you can use a glob pattern prefixed with `!` such as `!re-include-me/**` in `exclude` or the dedicated `include` config.
Serverless will run the glob patterns in order.
At first it will apply the globs defined in `exclude`. After that it'll add all the globs from `include`. This way you can always re-include
previously excluded files and directories.
### Examples
Exclude all node_modules but then re-include a specific modules (in this case node-fetch) using `exclude` exclusively
``` yml
package:
exclude:
- node_modules/**
- '!node_modules/node-fetch/**'
```
Exclude all files but `handler.js` using `exclude` and `include`
``` yml
package:
exclude:
- src/**
include:
- src/function/handler.js
```
**Note:** Don't forget to use the correct glob syntax if you want to exclude directories
```
exclude:
- tmp/**
- .git/**
```
### Artifact
For complete control over the packaging process you can specify your own artifact zip file.
Serverless won't zip your service if this is configured and therefore `exclude` and `include` will be ignored. Either you use artifact or include / exclude.
The artifact option is especially useful in case your development environment allows you to generate a deployable artifact like Maven does for Java.
### Example
```yml
service: my-service
package:
artifact: path/to/my-artifact.zip
```
### Packaging functions separately
If you want even more controls over your functions for deployment you can configure them to be packaged independently. This allows you more control for optimizing your deployment. To enable individual packaging set `individually` to true in the service or function wide packaging settings.
Then for every function you can use the same `exclude`, `include` or `artifact` config options as you can service wide. The `exclude` and `include` option will be merged with the service wide options to create one `exclude` and `include` config per function during packaging.
```yml
service: my-service
package:
individually: true
exclude:
- excluded-by-default.json
functions:
hello:
handler: handler.hello
package:
# We're including this file so it will be in the final package of this function only
include:
- excluded-by-default.json
world:
handler: handler.hello
package:
exclude:
- some-file.js
```
You can also select which functions to be packaged separately, and have the rest use the service package by setting the `individually` flag at the function level:
```yml
service: my-service
functions:
hello:
handler: handler.hello
world:
handler: handler.hello
package:
individually: true
```
### Development dependencies
Serverless will auto-detect and exclude development dependencies based on the runtime your service is using.
This ensures that only the production relevant packages and modules are included in your zip file. Doing this drastically reduces the overall size of the deployment package which will be uploaded to the cloud provider.
You can opt-out of automatic dev dependency exclusion by setting the `excludeDevDependencies` package config to `false`:
```yml
package:
excludeDevDependencies: false
```

View File

@ -35,4 +35,4 @@ In your terminal window you should see the response from Apache OpenWhisk
}
```
Congrats you have just deployed and run your Hello World function!
Congrats you have deployed and ran your Hello World function!

View File

@ -35,4 +35,4 @@ In your terminal window you should see the response from Apache OpenWhisk
}
```
Congrats you have just deployed and run your Hello World function!
Congrats you have deployed and ran your Hello World function!

View File

@ -35,4 +35,4 @@ In your terminal window you should see the response from Apache OpenWhisk
}
```
Congrats you have just deployed and run your Hello World function!
Congrats you have deployed and ran your Hello World function!

View File

@ -35,4 +35,4 @@ In your terminal window you should see the response from Apache OpenWhisk
}
```
Congrats you have just deployed and run your Hello World function!
Congrats you have deployed and ran your Hello World function!

View File

@ -32,7 +32,7 @@ In your terminal window you should see the response
{"hello":"null"}
```
Congrats you have just deployed and ran your Hello World function!
Congrats you have deployed and ran your Hello World function!
## Short Hand Guide

View File

@ -32,7 +32,7 @@ In your terminal window you should see the response
{"hello":"from NodeJS8.3 function"}
```
Congrats you have just deployed and ran your Hello World function!
Congrats you have deployed and ran your Hello World function!
## Short Hand Guide

View File

@ -34,7 +34,7 @@ In your terminal window you should see the response
'{"hello":"from Python2.7 function"}'
```
Congrats you have just deployed and ran your Hello World function!
Congrats you have deployed and ran your Hello World function!
## Short Hand Guide

View File

@ -11,21 +11,21 @@ layout: Doc
# Hello World Ruby Example
Make sure `serverless` is installed.
Make sure `serverless` is installed.
## 1. Create a service
`serverless create --template spotinst-ruby --path serviceName` `serviceName` is going to be a new directory there the Ruby template will be loaded. Once the download is complete change into that directory. Next you will need to install the Spotinst Serverless Functions plugin by running `npm install` in the root directory. You will need to go into the serverless.yml file and add in the environment variable that you want to deploy into.
## 2. Deploy
```bash
```bash
serverless deploy
```
## 3. Invoke deployed function
```bash
serverless invoke --function hello
```
```
In your terminal window you should see the response
@ -33,14 +33,14 @@ In your terminal window you should see the response
'{"hello":"from Ruby2.4.1 function"}'
```
Congrats you have just deployed and ran your Hello World function!
Congrats you have deployed and ran your Hello World function!
## Short Hand Guide
`sls` is short hand for serverless cli commands
`sls` is short hand for serverless cli commands
`-f` is short hand for `--function`
`-t` is short hand for `--template`
`-p` is short hang for `--path`
`-p` is short hang for `--path`

View File

@ -19,7 +19,7 @@ const writeMessage = (messageType, message) => {
consoleLog(' ');
if (message) {
consoleLog(chalk.white(` ${message}`));
consoleLog(` ${message}`);
}
consoleLog(' ');
@ -61,17 +61,16 @@ module.exports.logError = (e) => {
consoleLog(' ');
}
const platform = chalk.white(process.platform);
const nodeVersion = chalk.white(process.version.replace(/^[v|V]/, ''));
const slsVersion = chalk.white(version);
const platform = process.platform;
const nodeVersion = process.version.replace(/^[v|V]/, '');
const slsVersion = version;
consoleLog(chalk.yellow(' Get Support --------------------------------------------'));
consoleLog(`${chalk.yellow(' Docs: ')}${chalk.white('docs.serverless.com')}`);
consoleLog(`${chalk.yellow(' Bugs: ')}${chalk
.white('github.com/serverless/serverless/issues')}`);
consoleLog(`${chalk.yellow(' Forums: ')}${chalk.white('forum.serverless.com')}`);
consoleLog(`${chalk.yellow(' Chat: ')}${chalk
.white('gitter.im/serverless/serverless')}`);
consoleLog(`${chalk.yellow(' Docs: ')}${'docs.serverless.com'}`);
consoleLog(`${chalk.yellow(' Bugs: ')}${
'github.com/serverless/serverless/issues'}`);
consoleLog(`${chalk.yellow(' Forums: ')}${'forum.serverless.com'}`);
consoleLog(`${chalk.yellow(' Chat: ')}${'gitter.im/serverless/serverless'}`);
consoleLog(' ');
consoleLog(chalk.yellow(' Your Environment Information -----------------------------'));

View File

@ -6,7 +6,6 @@ const path = require('path');
const AwsProvider = require('../../provider/awsProvider');
const AwsDeploy = require('../index');
const Serverless = require('../../../../Serverless');
const BbPromise = require('bluebird');
const testUtils = require('../../../../../tests/utils');
describe('createStack', () => {
@ -98,8 +97,7 @@ describe('createStack', () => {
it('should set the createLater flag and resolve if deployment bucket is provided', () => {
awsDeploy.serverless.service.provider.deploymentBucket = 'serverless';
sandbox.stub(awsDeploy.provider, 'request')
.returns(BbPromise.reject({ message: 'does not exist' }));
sandbox.stub(awsDeploy.provider, 'request').rejects(new Error('does not exist'));
return awsDeploy.createStack().then(() => {
expect(awsDeploy.createLater).to.equal(true);

View File

@ -1,6 +1,6 @@
'use strict';
const expect = require('chai').expect;
const chai = require('chai');
const sinon = require('sinon');
const path = require('path');
const AwsProvider = require('../../provider/awsProvider');
@ -8,6 +8,10 @@ const AwsDeploy = require('../index');
const Serverless = require('../../../../Serverless');
const testUtils = require('../../../../../tests/utils');
chai.use(require('sinon-chai'));
const expect = chai.expect;
describe('extendedValidate', () => {
let awsDeploy;
const tmpDirPath = testUtils.getTmpDirPath();
@ -60,8 +64,8 @@ describe('extendedValidate', () => {
});
afterEach(() => {
awsDeploy.serverless.utils.fileExistsSync.restore();
awsDeploy.serverless.utils.readFileSync.restore();
fileExistsSyncStub.restore();
readFileSyncStub.restore();
});
it('should throw error if state file does not exist', () => {

View File

@ -90,8 +90,8 @@ describe('uploadArtifacts', () => {
});
afterEach(() => {
normalizeFiles.normalizeCloudFormationTemplate.restore();
awsDeploy.provider.request.restore();
normalizeCloudFormationTemplateStub.restore();
uploadStub.restore();
});
it('should upload the CloudFormation file to the S3 bucket', () => {
@ -159,8 +159,8 @@ describe('uploadArtifacts', () => {
});
afterEach(() => {
fs.readFileSync.restore();
awsDeploy.provider.request.restore();
readFileSyncStub.restore();
uploadStub.restore();
});
it('should throw for null artifact paths', () => {
@ -265,7 +265,7 @@ describe('uploadArtifacts', () => {
.to.be.equal(awsDeploy.serverless.service.functions.first.package.artifact);
expect(uploadZipFileStub.args[1][0])
.to.be.equal(awsDeploy.serverless.service.functions.second.package.artifact);
awsDeploy.uploadZipFile.restore();
uploadZipFileStub.restore();
});
});
@ -286,7 +286,7 @@ describe('uploadArtifacts', () => {
const uploadZipFileStub = sinon
.stub(awsDeploy, 'uploadZipFile').resolves();
sinon.stub(fs, 'statSync').returns({ size: 1024 });
const statSyncStub = sinon.stub(fs, 'statSync').returns({ size: 1024 });
return awsDeploy.uploadFunctions().then(() => {
expect(uploadZipFileStub.calledTwice).to.be.equal(true);
@ -294,8 +294,9 @@ describe('uploadArtifacts', () => {
.to.be.equal(awsDeploy.serverless.service.functions.first.package.artifact);
expect(uploadZipFileStub.args[1][0])
.to.be.equal(awsDeploy.serverless.service.package.artifact);
awsDeploy.uploadZipFile.restore();
fs.statSync.restore();
}).finally(() => {
uploadZipFileStub.restore();
statSyncStub.restore();
});
});
@ -303,16 +304,16 @@ describe('uploadArtifacts', () => {
awsDeploy.serverless.config.servicePath = 'some/path';
awsDeploy.serverless.service.service = 'new-service';
sinon.stub(fs, 'statSync').returns({ size: 1024 });
sinon.stub(awsDeploy, 'uploadZipFile').resolves();
const statSyncStub = sinon.stub(fs, 'statSync').returns({ size: 1024 });
const uploadZipFileStub = sinon.stub(awsDeploy, 'uploadZipFile').resolves();
sinon.spy(awsDeploy.serverless.cli, 'log');
return awsDeploy.uploadFunctions().then(() => {
const expected = 'Uploading service .zip file to S3 (1 KB)...';
expect(awsDeploy.serverless.cli.log.calledWithExactly(expected)).to.be.equal(true);
fs.statSync.restore();
awsDeploy.uploadZipFile.restore();
}).finally(() => {
statSyncStub.restore();
uploadZipFileStub.restore();
});
});
});

View File

@ -83,12 +83,12 @@ class AwsInvoke {
}
log(invocationReply) {
const color = !invocationReply.FunctionError ? 'white' : 'red';
const color = !invocationReply.FunctionError ? (x => x) : chalk.red;
if (invocationReply.Payload) {
const response = JSON.parse(invocationReply.Payload);
this.consoleLog(chalk[color](JSON.stringify(response, null, 4)));
this.consoleLog(color(JSON.stringify(response, null, 4)));
}
if (invocationReply.LogResult) {

View File

@ -6,7 +6,6 @@ const path = require('path');
const AwsInvoke = require('./index');
const AwsProvider = require('../provider/awsProvider');
const Serverless = require('../../../Serverless');
const chalk = require('chalk');
const testUtils = require('../../../../tests/utils');
describe('AwsInvoke', () => {
@ -271,7 +270,7 @@ describe('AwsInvoke', () => {
};
return awsInvoke.log(invocationReplyMock).then(() => {
const expectedPayloadMessage = `${chalk.white('{\n "testProp": "testValue"\n}')}`;
const expectedPayloadMessage = '{\n "testProp": "testValue"\n}';
expect(consoleLogStub.calledWith(expectedPayloadMessage)).to.equal(true);
});

View File

@ -282,8 +282,9 @@ module.exports = {
getLambdaApiGatewayPermissionLogicalId(functionName) {
return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionApiGateway`;
},
getLambdaAlexaSkillPermissionLogicalId(functionName) {
return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionAlexaSkill`;
getLambdaAlexaSkillPermissionLogicalId(functionName, alexaSkillIndex) {
return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionAlexaSkill${
alexaSkillIndex || '0'}`;
},
getLambdaAlexaSmartHomePermissionLogicalId(functionName, alexaSmartHomeIndex) {
return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionAlexaSmartHome${

View File

@ -464,9 +464,15 @@ describe('#naming()', () => {
describe('#getLambdaAlexaSkillPermissionLogicalId()', () => {
it('should normalize the function name and append the standard suffix',
() => {
expect(sdk.naming.getLambdaAlexaSkillPermissionLogicalId('functionName', 2))
.to.equal('FunctionNameLambdaPermissionAlexaSkill2');
});
it('should normalize the function name and append a default suffix if not defined',
() => {
expect(sdk.naming.getLambdaAlexaSkillPermissionLogicalId('functionName'))
.to.equal('FunctionNameLambdaPermissionAlexaSkill');
.to.equal('FunctionNameLambdaPermissionAlexaSkill0');
});
});

View File

@ -15,10 +15,45 @@ class AwsCompileAlexaSkillEvents {
compileAlexaSkillEvents() {
this.serverless.service.getAllFunctions().forEach((functionName) => {
const functionObj = this.serverless.service.getFunction(functionName);
let alexaSkillNumberInFunction = 0;
if (functionObj.events) {
functionObj.events.forEach(event => {
if (event === 'alexaSkill') {
if (event === 'alexaSkill' || event.alexaSkill) {
let enabled = true;
let appId;
if (event === 'alexaSkill') {
const warningMessage = [
'Warning! You are using an old syntax for alexaSkill which doesn\'t',
' restrict the invocation solely to your skill.',
' Please refer to the documentation for additional information.',
].join('');
this.serverless.cli.log(warningMessage);
} else if (_.isString(event.alexaSkill)) {
appId = event.alexaSkill;
} else if (_.isPlainObject(event.alexaSkill)) {
if (!_.isString(event.alexaSkill.appId)) {
const errorMessage = [
`Missing "appId" property for alexaSkill event in function ${functionName}`,
' The correct syntax is: appId: amzn1.ask.skill.xx-xx-xx-xx-xx',
' OR an object with "appId" property.',
' Please check the docs for more info.',
].join('');
throw new this.serverless.classes.Error(errorMessage);
}
appId = event.alexaSkill.appId;
// Parameter `enabled` is optional, hence the explicit non-equal check for false.
enabled = event.alexaSkill.enabled !== false;
} else {
const errorMessage = [
`Alexa Skill event of function "${functionName}" is not an object or string.`,
' The correct syntax is: alexaSkill.',
' Please check the docs for more info.',
].join('');
throw new this.serverless.classes.Error(errorMessage);
}
alexaSkillNumberInFunction++;
const lambdaLogicalId = this.provider.naming
.getLambdaLogicalId(functionName);
@ -31,13 +66,18 @@ class AwsCompileAlexaSkillEvents {
'Arn',
],
},
Action: 'lambda:InvokeFunction',
Action: enabled ? 'lambda:InvokeFunction' : 'lambda:DisableInvokeFunction',
Principal: 'alexa-appkit.amazon.com',
},
};
if (appId) {
permissionTemplate.Properties.EventSourceToken = appId.replace(/\\n|\\r/g, '');
}
const lambdaPermissionLogicalId = this.provider.naming
.getLambdaAlexaSkillPermissionLogicalId(functionName);
.getLambdaAlexaSkillPermissionLogicalId(functionName,
alexaSkillNumberInFunction);
const permissionCloudForamtionResource = {
[lambdaPermissionLogicalId]: permissionTemplate,
@ -45,13 +85,6 @@ class AwsCompileAlexaSkillEvents {
_.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources,
permissionCloudForamtionResource);
} else if (event.alexaSkill) {
const errorMessage = [
`Alexa Skill event of function "${functionName}" is not an object or string.`,
' The correct syntax is: alexaSkill.',
' Please check the docs for more info.',
].join('');
throw new this.serverless.classes.Error(errorMessage);
}
});
}

View File

@ -1,5 +1,7 @@
'use strict';
/* eslint-disable no-unused-expressions */
const expect = require('chai').expect;
const AwsProvider = require('../../../../provider/awsProvider');
const AwsCompileAlexaSkillEvents = require('./index');
@ -8,11 +10,19 @@ const Serverless = require('../../../../../../Serverless');
describe('AwsCompileAlexaSkillEvents', () => {
let serverless;
let awsCompileAlexaSkillEvents;
let consolePrinted;
beforeEach(() => {
serverless = new Serverless();
serverless.service.provider.compiledCloudFormationTemplate = { Resources: {} };
serverless.setProvider('aws', new AwsProvider(serverless));
consolePrinted = '';
serverless.cli = {
// serverless.cli isn't available in tests, so we will mimic it.
log: txt => {
consolePrinted += `${txt}\r\n`;
},
};
awsCompileAlexaSkillEvents = new AwsCompileAlexaSkillEvents(serverless);
});
@ -25,7 +35,42 @@ describe('AwsCompileAlexaSkillEvents', () => {
});
describe('#compileAlexaSkillEvents()', () => {
it('should throw an error if alexaSkill event is not an string', () => {
it('should show a warning if alexaSkill appId is not specified', () => {
awsCompileAlexaSkillEvents.serverless.service.functions = {
first: {
events: [
'alexaSkill',
],
},
};
awsCompileAlexaSkillEvents.compileAlexaSkillEvents();
expect(consolePrinted).to.contain.string('old syntax for alexaSkill');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill1.Type
).to.equal('AWS::Lambda::Permission');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill1.Properties.FunctionName
).to.deep.equal({ 'Fn::GetAtt': ['FirstLambdaFunction', 'Arn'] });
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill1.Properties.Action
).to.equal('lambda:InvokeFunction');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill1.Properties.Principal
).to.equal('alexa-appkit.amazon.com');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill1.Properties.EventSourceToken
).to.be.undefined;
});
it('should throw an error if alexaSkill event is not a string or an object', () => {
awsCompileAlexaSkillEvents.serverless.service.functions = {
first: {
events: [
@ -39,11 +84,36 @@ describe('AwsCompileAlexaSkillEvents', () => {
expect(() => awsCompileAlexaSkillEvents.compileAlexaSkillEvents()).to.throw(Error);
});
it('should create corresponding resources when a alexaSkill event is provided', () => {
it('should throw an error if alexaSkill event appId is not a string', () => {
awsCompileAlexaSkillEvents.serverless.service.functions = {
first: {
events: [
'alexaSkill',
{
alexaSkill: {
appId: 42,
},
},
],
},
};
expect(() => awsCompileAlexaSkillEvents.compileAlexaSkillEvents()).to.throw(Error);
});
it('should create corresponding resources when multiple alexaSkill events are provided', () => {
const skillId1 = 'amzn1.ask.skill.xx-xx-xx-xx';
const skillId2 = 'amzn1.ask.skill.yy-yy-yy-yy';
awsCompileAlexaSkillEvents.serverless.service.functions = {
first: {
events: [
{
alexaSkill: skillId1,
},
{
alexaSkill: {
appId: skillId2,
},
},
],
},
};
@ -52,20 +122,84 @@ describe('AwsCompileAlexaSkillEvents', () => {
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill.Type
.FirstLambdaPermissionAlexaSkill1.Type
).to.equal('AWS::Lambda::Permission');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill.Properties.FunctionName
.FirstLambdaPermissionAlexaSkill1.Properties.FunctionName
).to.deep.equal({ 'Fn::GetAtt': ['FirstLambdaFunction', 'Arn'] });
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill.Properties.Action
.FirstLambdaPermissionAlexaSkill1.Properties.Action
).to.equal('lambda:InvokeFunction');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill.Properties.Principal
.FirstLambdaPermissionAlexaSkill1.Properties.Principal
).to.equal('alexa-appkit.amazon.com');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill1.Properties.EventSourceToken
).to.equal(skillId1);
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill2.Type
).to.equal('AWS::Lambda::Permission');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill2.Properties.FunctionName
).to.deep.equal({ 'Fn::GetAtt': ['FirstLambdaFunction', 'Arn'] });
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill2.Properties.Action
).to.equal('lambda:InvokeFunction');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill2.Properties.Principal
).to.equal('alexa-appkit.amazon.com');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill2.Properties.EventSourceToken
).to.equal(skillId2);
});
it('should create corresponding resources when a disabled alexaSkill event is provided', () => {
const skillId1 = 'amzn1.ask.skill.xx-xx-xx-xx';
awsCompileAlexaSkillEvents.serverless.service.functions = {
first: {
events: [
{
alexaSkill: {
appId: skillId1,
enabled: false,
},
},
],
},
};
awsCompileAlexaSkillEvents.compileAlexaSkillEvents();
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill1.Type
).to.equal('AWS::Lambda::Permission');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill1.Properties.FunctionName
).to.deep.equal({ 'Fn::GetAtt': ['FirstLambdaFunction', 'Arn'] });
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill1.Properties.Action
).to.equal('lambda:DisableInvokeFunction');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill1.Properties.Principal
).to.equal('alexa-appkit.amazon.com');
expect(awsCompileAlexaSkillEvents.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionAlexaSkill1.Properties.EventSourceToken
).to.equal(skillId1);
});
it('should not create corresponding resources when alexaSkill event is not given', () => {
@ -82,5 +216,22 @@ describe('AwsCompileAlexaSkillEvents', () => {
.compiledCloudFormationTemplate.Resources
).to.deep.equal({});
});
it('should not not throw error when other events are present', () => {
awsCompileAlexaSkillEvents.serverless.service.functions = {
first: {
events: [
{
http: {
method: 'get',
path: '/',
},
},
],
},
};
expect(() => awsCompileAlexaSkillEvents.compileAlexaSkillEvents()).to.not.throw();
});
});
});

View File

@ -20,19 +20,20 @@ class AwsCompileCognitoUserPoolEvents {
this.hooks = {
'package:compileEvents': this.compileCognitoUserPoolEvents.bind(this),
'after:package:finalize': this.mergeWithCustomResources.bind(this),
};
}
compileCognitoUserPoolEvents() {
findUserPoolsAndFunctions() {
const userPools = [];
const cognitoUserPoolTriggerFunctions = [];
// Iterate through all functions declared in `serverless.yml`
this.serverless.service.getAllFunctions().forEach((functionName) => {
_.forEach(this.serverless.service.getAllFunctions(), (functionName) => {
const functionObj = this.serverless.service.getFunction(functionName);
if (functionObj.events) {
functionObj.events.forEach(event => {
_.forEach(functionObj.events, (event) => {
if (event.cognitoUserPool) {
// Check event definition for `cognitoUserPool` object
if (typeof event.cognitoUserPool === 'object') {
@ -80,51 +81,61 @@ class AwsCompileCognitoUserPoolEvents {
}
});
// Generate CloudFormation templates for Cognito User Pool changes
_.forEach(userPools, (poolName) => {
// Create a `LambdaConfig` object for the CloudFormation template
const currentPoolTriggerFunctions = _.filter(cognitoUserPoolTriggerFunctions, {
poolName,
return { cognitoUserPoolTriggerFunctions, userPools };
}
generateTemplateForPool(poolName, currentPoolTriggerFunctions) {
const lambdaConfig = _.reduce(currentPoolTriggerFunctions, (result, value) => {
const lambdaLogicalId = this.provider.naming.getLambdaLogicalId(value.functionName);
// Return a new object to avoid lint errors
return Object.assign({}, result, {
[value.triggerSource]: {
'Fn::GetAtt': [
lambdaLogicalId,
'Arn',
],
},
});
}, {});
const lambdaConfig = _.reduce(currentPoolTriggerFunctions, (result, value) => {
const lambdaLogicalId = this.provider.naming.getLambdaLogicalId(value.functionName);
const userPoolLogicalId = this.provider.naming.getCognitoUserPoolLogicalId(poolName);
// Return a new object to avoid lint errors
return Object.assign({}, result, {
[value.triggerSource]: {
'Fn::GetAtt': [
lambdaLogicalId,
'Arn',
],
},
});
}, {});
// Attach `DependsOn` for any relevant Lambdas
const DependsOn = _.map(currentPoolTriggerFunctions, (value) => this
.provider.naming.getLambdaLogicalId(value.functionName));
const userPoolLogicalId = this.provider.naming.getCognitoUserPoolLogicalId(poolName);
const DependsOn = _.map(currentPoolTriggerFunctions, (value) => this
.provider.naming.getLambdaLogicalId(value.functionName));
const userPoolTemplate = {
return {
[userPoolLogicalId]: {
Type: 'AWS::Cognito::UserPool',
Properties: {
UserPoolName: poolName,
LambdaConfig: lambdaConfig,
},
DependsOn,
};
},
};
}
const userPoolCFResource = {
[userPoolLogicalId]: userPoolTemplate,
};
compileCognitoUserPoolEvents() {
const result = this.findUserPoolsAndFunctions();
const cognitoUserPoolTriggerFunctions = result.cognitoUserPoolTriggerFunctions;
const userPools = result.userPools;
// Generate CloudFormation templates for Cognito User Pool changes
_.forEach(userPools, (poolName) => {
const currentPoolTriggerFunctions = _.filter(cognitoUserPoolTriggerFunctions, { poolName });
const userPoolCFResource = this.generateTemplateForPool(
poolName,
currentPoolTriggerFunctions
);
_.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources,
userPoolCFResource);
});
// Generate CloudFormation templates for IAM permissions to allow Cognito to trigger Lambda
cognitoUserPoolTriggerFunctions.forEach((cognitoUserPoolTriggerFunction) => {
_.forEach(cognitoUserPoolTriggerFunctions, (cognitoUserPoolTriggerFunction) => {
const userPoolLogicalId = this.provider.naming
.getCognitoUserPoolLogicalId(cognitoUserPoolTriggerFunction.poolName);
const lambdaLogicalId = this.provider.naming
@ -159,6 +170,43 @@ class AwsCompileCognitoUserPoolEvents {
permissionCFResource);
});
}
mergeWithCustomResources() {
const result = this.findUserPoolsAndFunctions();
const cognitoUserPoolTriggerFunctions = result.cognitoUserPoolTriggerFunctions;
const userPools = result.userPools;
_.forEach(userPools, (poolName) => {
const currentPoolTriggerFunctions = _.filter(cognitoUserPoolTriggerFunctions, { poolName });
const userPoolLogicalId = this.provider.naming.getCognitoUserPoolLogicalId(poolName);
// If overrides exist in `Resources`, merge them in
if (_.has(this.serverless.service.resources, userPoolLogicalId)) {
const customUserPool = this.serverless.service.resources[userPoolLogicalId];
const generatedUserPool = this.generateTemplateForPool(
poolName,
currentPoolTriggerFunctions
)[userPoolLogicalId];
// Merge `DependsOn` clauses
const customUserPoolDependsOn = _.get(customUserPool, 'DependsOn', []);
const DependsOn = generatedUserPool.DependsOn.concat(customUserPoolDependsOn);
// Merge default and custom resources, and `DependsOn` clause
const mergedTemplate = Object.assign(
{},
_.merge(generatedUserPool, customUserPool),
{ DependsOn }
);
// Merge resource back into `Resources`
_.merge(
this.serverless.service.provider.compiledCloudFormationTemplate.Resources,
{ [userPoolLogicalId]: mergedTemplate }
);
}
});
}
}
module.exports = AwsCompileCognitoUserPoolEvents;

View File

@ -1,5 +1,6 @@
'use strict';
const _ = require('lodash');
const expect = require('chai').expect;
const AwsProvider = require('../../../../provider/awsProvider');
const AwsCompileCognitoUserPoolEvents = require('./index');
@ -115,9 +116,15 @@ describe('AwsCompileCognitoUserPoolEvents', () => {
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool1.Type
).to.equal('AWS::Cognito::UserPool');
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool1.DependsOn
).to.have.lengthOf(1);
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool2.Type
).to.equal('AWS::Cognito::UserPool');
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool2.DependsOn
).to.have.lengthOf(1);
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionCognitoUserPoolMyUserPool1TriggerSourcePreSignUp.Type
@ -153,9 +160,15 @@ describe('AwsCompileCognitoUserPoolEvents', () => {
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool1.Type
).to.equal('AWS::Cognito::UserPool');
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool1.DependsOn
).to.have.lengthOf(1);
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool2.Type
).to.equal('AWS::Cognito::UserPool');
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool2.DependsOn
).to.have.lengthOf(1);
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionCognitoUserPoolMyUserPool1TriggerSourcePreSignUp.Type
@ -195,6 +208,9 @@ describe('AwsCompileCognitoUserPoolEvents', () => {
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool1.Type
).to.equal('AWS::Cognito::UserPool');
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool1.DependsOn
).to.have.lengthOf(1);
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool1
.Properties.LambdaConfig.PreSignUp['Fn::GetAtt'][0]
@ -204,6 +220,9 @@ describe('AwsCompileCognitoUserPoolEvents', () => {
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool2.Type
).to.equal('AWS::Cognito::UserPool');
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool2.DependsOn
).to.have.lengthOf(1);
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources.CognitoUserPoolMyUserPool2
.Properties.LambdaConfig.PreSignUp['Fn::GetAtt'][0]
@ -250,10 +269,14 @@ describe('AwsCompileCognitoUserPoolEvents', () => {
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.Type
).to.equal('AWS::Cognito::UserPool');
expect(Object.keys(awsCompileCognitoUserPoolEvents.serverless.service.provider
expect(_.keys(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.Properties.LambdaConfig).length
).to.equal(2);
.CognitoUserPoolMyUserPool.Properties.LambdaConfig)
).to.have.lengthOf(2);
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.DependsOn
).to.have.lengthOf(2);
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionCognitoUserPoolMyUserPoolTriggerSourcePreSignUp.Type
@ -279,4 +302,145 @@ describe('AwsCompileCognitoUserPoolEvents', () => {
).to.deep.equal({});
});
});
describe('#mergeWithCustomResources()', () => {
it('does not merge if no custom resource is found in Resources', () => {
awsCompileCognitoUserPoolEvents.serverless.service.functions = {
first: {
events: [
{
cognitoUserPool: {
pool: 'MyUserPool',
trigger: 'PreSignUp',
},
},
],
},
};
awsCompileCognitoUserPoolEvents.serverless.service.resources = {};
awsCompileCognitoUserPoolEvents.compileCognitoUserPoolEvents();
awsCompileCognitoUserPoolEvents.mergeWithCustomResources();
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.Type
).to.equal('AWS::Cognito::UserPool');
expect(_.keys(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.Properties)
).to.have.lengthOf(2);
expect(_.keys(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.Properties.LambdaConfig)
).to.have.lengthOf(1);
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionCognitoUserPoolMyUserPoolTriggerSourcePreSignUp.Type
).to.equal('AWS::Lambda::Permission');
});
it('should merge custom resources found in Resources', () => {
awsCompileCognitoUserPoolEvents.serverless.service.functions = {
first: {
events: [
{
cognitoUserPool: {
pool: 'MyUserPool',
trigger: 'PreSignUp',
},
},
],
},
};
awsCompileCognitoUserPoolEvents.serverless.service.resources = {
CognitoUserPoolMyUserPool: {
Type: 'AWS::Cognito::UserPool',
Properties: {
UserPoolName: 'ProdMyUserPool',
MfaConfiguration: 'OFF',
EmailVerificationSubject: 'Your verification code',
EmailVerificationMessage: 'Your verification code is {####}.',
SmsVerificationMessage: 'Your verification code is {####}.',
},
},
};
awsCompileCognitoUserPoolEvents.compileCognitoUserPoolEvents();
awsCompileCognitoUserPoolEvents.mergeWithCustomResources();
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.Type
).to.equal('AWS::Cognito::UserPool');
expect(_.keys(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.Properties)
).to.have.lengthOf(6);
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.DependsOn
).to.have.lengthOf(1);
expect(_.keys(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.Properties.LambdaConfig)
).to.have.lengthOf(1);
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionCognitoUserPoolMyUserPoolTriggerSourcePreSignUp.Type
).to.equal('AWS::Lambda::Permission');
});
it('should merge `DependsOn` clauses correctly if being overridden from Resources', () => {
awsCompileCognitoUserPoolEvents.serverless.service.functions = {
first: {
events: [
{
cognitoUserPool: {
pool: 'MyUserPool',
trigger: 'PreSignUp',
},
},
],
},
};
awsCompileCognitoUserPoolEvents.serverless.service.resources = {
CognitoUserPoolMyUserPool: {
DependsOn: ['Something', 'SomethingElse', ['Nothing', 'NothingAtAll']],
Type: 'AWS::Cognito::UserPool',
Properties: {
UserPoolName: 'ProdMyUserPool',
MfaConfiguration: 'OFF',
EmailVerificationSubject: 'Your verification code',
EmailVerificationMessage: 'Your verification code is {####}.',
SmsVerificationMessage: 'Your verification code is {####}.',
},
},
};
awsCompileCognitoUserPoolEvents.compileCognitoUserPoolEvents();
awsCompileCognitoUserPoolEvents.mergeWithCustomResources();
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.Type
).to.equal('AWS::Cognito::UserPool');
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.DependsOn
).to.have.lengthOf(4);
expect(_.keys(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.Properties)
).to.have.lengthOf(6);
expect(_.keys(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.CognitoUserPoolMyUserPool.Properties.LambdaConfig)
).to.have.lengthOf(1);
expect(awsCompileCognitoUserPoolEvents.serverless.service.provider
.compiledCloudFormationTemplate.Resources
.FirstLambdaPermissionCognitoUserPoolMyUserPoolTriggerSourcePreSignUp.Type
).to.equal('AWS::Lambda::Permission');
});
});
});

View File

@ -279,6 +279,19 @@ class AwsCompileFunctions {
delete newFunction.Properties.VpcConfig;
}
if (functionObject.reservedConcurrency) {
if (_.isInteger(functionObject.reservedConcurrency)) {
newFunction.Properties.ReservedConcurrentExecutions = functionObject.reservedConcurrency;
} else {
const errorMessage = [
'You should use integer as reservedConcurrency value on function: ',
`${newFunction.Properties.FunctionName}`,
].join('');
return BbPromise.reject(new this.serverless.classes.Error(errorMessage));
}
}
newFunction.DependsOn = [this.provider.naming.getLogGroupLogicalId(functionName)]
.concat(newFunction.DependsOn || []);

View File

@ -25,6 +25,7 @@ describe('AwsCompileFunctions', () => {
};
serverless = new Serverless(options);
serverless.setProvider('aws', new AwsProvider(serverless, options));
serverless.cli = new serverless.classes.CLI();
awsCompileFunctions = new AwsCompileFunctions(serverless, options);
awsCompileFunctions.serverless.service.provider.compiledCloudFormationTemplate = {
Resources: {},
@ -1730,6 +1731,65 @@ describe('AwsCompileFunctions', () => {
);
});
});
it('should set function declared reserved concurrency limit', () => {
const s3Folder = awsCompileFunctions.serverless.service.package.artifactDirectoryName;
const s3FileName = awsCompileFunctions.serverless.service.package.artifact
.split(path.sep).pop();
awsCompileFunctions.serverless.service.functions = {
func: {
handler: 'func.function.handler',
name: 'new-service-dev-func',
reservedConcurrency: 5,
},
};
const compiledFunction = {
Type: 'AWS::Lambda::Function',
DependsOn: [
'FuncLogGroup',
'IamRoleLambdaExecution',
],
Properties: {
Code: {
S3Key: `${s3Folder}/${s3FileName}`,
S3Bucket: { Ref: 'ServerlessDeploymentBucket' },
},
FunctionName: 'new-service-dev-func',
Handler: 'func.function.handler',
MemorySize: 1024,
ReservedConcurrentExecutions: 5,
Role: { 'Fn::GetAtt': ['IamRoleLambdaExecution', 'Arn'] },
Runtime: 'nodejs4.3',
Timeout: 6,
},
};
return expect(awsCompileFunctions.compileFunctions()).to.be.fulfilled
.then(() => {
expect(
awsCompileFunctions.serverless.service.provider.compiledCloudFormationTemplate
.Resources.FuncLambdaFunction
).to.deep.equal(compiledFunction);
});
});
it('should throw an informative error message if non-integer reserved concurrency limit set ' +
'on function', () => {
awsCompileFunctions.serverless.service.functions = {
func: {
handler: 'func.function.handler',
name: 'new-service-dev-func',
reservedConcurrency: '1',
},
};
const errorMessage = [
'You should use integer as reservedConcurrency value on function: ',
'new-service-dev-func',
].join('');
return expect(awsCompileFunctions.compileFunctions()).to.be.rejectedWith(errorMessage);
});
});
describe('#compileRole()', () => {

View File

@ -328,8 +328,6 @@ class AwsProvider {
enableS3TransferAcceleration(credentials) {
this.serverless.cli.log('Using S3 Transfer Acceleration Endpoint...');
credentials.useAccelerateEndpoint = true; // eslint-disable-line no-param-reassign
credentials.signatureVersion = 'v2'; // eslint-disable-line no-param-reassign
// see https://github.com/aws/aws-sdk-js/issues/281
}
getRegion() {

View File

@ -34,7 +34,7 @@ module.exports = (msgParam) => {
} else if (!isNaN((new Date(splitted[1])).getTime())) {
date = splitted[1];
reqId = splitted[2];
level = `${chalk.white(splitted[0])}\t`;
level = `${splitted[0]}\t`;
} else {
return msg;
}

View File

@ -37,7 +37,7 @@ describe('#formatLambdaLogEvent()', () => {
const momentDate = moment('2016-01-01T12:00:00Z').format('YYYY-MM-DD HH:mm:ss.SSS (Z)');
expectedLogMessage += `${chalk.green(momentDate)}\t`;
expectedLogMessage += `${chalk.yellow('99c30000-b01a-11e5-93f7-b8e85631a00e')}\t`;
expectedLogMessage += `${chalk.white('[INFO]')}\t`;
expectedLogMessage += `${'[INFO]'}\t`;
expectedLogMessage += 'test';
expect(formatLambdaLogEvent(pythonLoggerLine)).to.equal(expectedLogMessage);

View File

@ -28,6 +28,8 @@ const validTemplates = [
'aws-scala-sbt',
'aws-csharp',
'aws-fsharp',
'aws-go',
'aws-go-dep',
'azure-nodejs',
'google-nodejs',
'kubeless-python',

View File

@ -726,5 +726,39 @@ describe('Create', () => {
expect((/service: my-awesome-service/).test(serverlessYmlfileContent)).to.equal(true);
});
});
it('should generate scaffolding for "aws-go" template', () => {
process.chdir(tmpDir);
create.options.template = 'aws-go';
return create.create().then(() => {
const dirContent = walkDirSync(tmpDir)
.map(elem => elem.replace(path.join(tmpDir, path.sep), ''));
expect(dirContent).to.include('serverless.yml');
expect(dirContent).to.include(path.join('hello', 'main.go'));
expect(dirContent).to.include(path.join('world', 'main.go'));
expect(dirContent).to.include('Makefile');
expect(dirContent).to.include('.gitignore');
});
});
it('should generate scaffolding for "aws-go-dep" template', () => {
process.chdir(tmpDir);
create.options.template = 'aws-go-dep';
return create.create().then(() => {
const dirContent = walkDirSync(tmpDir)
.map(elem => elem.replace(path.join(tmpDir, path.sep), ''));
expect(dirContent).to.include('serverless.yml');
expect(dirContent).to.include(path.join('hello', 'main.go'));
expect(dirContent).to.include(path.join('world', 'main.go'));
expect(dirContent).to.include('Gopkg.toml');
expect(dirContent).to.include('Gopkg.lock');
expect(dirContent).to.include('Makefile');
expect(dirContent).to.include('.gitignore');
});
});
});
});

View File

@ -67,7 +67,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -67,7 +67,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -0,0 +1,19 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/aws/aws-lambda-go"
packages = [
"lambda",
"lambda/messages",
"lambdacontext"
]
revision = "6e2e37798efbb1dfd8e9c6681702e683a6046517"
version = "v1.0.1"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "85fa166cc59d0fa113a1517ffbb5dee0f1fa4a6795239936afb18c64364af759"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -0,0 +1,25 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
name = "github.com/aws/aws-lambda-go"
version = "^1.0.1"

View File

@ -0,0 +1,4 @@
build:
dep ensure
env GOOS=linux go build -ldflags="-s -w" -o bin/hello hello/main.go
env GOOS=linux go build -ldflags="-s -w" -o bin/world world/main.go

View File

@ -0,0 +1,8 @@
# Serverless directories
.serverless
# golang output binary directory
bin
# golang vendor (dependencies) directory
vendor

View File

@ -0,0 +1,19 @@
package main
import (
"github.com/aws/aws-lambda-go/lambda"
)
type Response struct {
Message string `json:"message"`
}
func Handler() (Response, error) {
return Response{
Message: "Go Serverless v1.0! Your function executed successfully!",
}, nil
}
func main() {
lambda.Start(Handler)
}

View File

@ -0,0 +1,104 @@
# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
# docs.serverless.com
#
# Happy Coding!
service: aws-go-dep # NOTE: update this with your service name
# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"
provider:
name: aws
runtime: go1.x
# you can overwrite defaults here
# stage: dev
# region: us-east-1
# you can add statements to the Lambda function's IAM Role here
# iamRoleStatements:
# - Effect: "Allow"
# Action:
# - "s3:ListBucket"
# Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] }
# - Effect: "Allow"
# Action:
# - "s3:PutObject"
# Resource:
# Fn::Join:
# - ""
# - - "arn:aws:s3:::"
# - "Ref" : "ServerlessDeploymentBucket"
# - "/*"
# you can define service wide environment variables here
# environment:
# variable1: value1
package:
exclude:
- ./**
include:
- ./bin/**
functions:
hello:
handler: bin/hello
world:
handler: bin/world
# The following are a few example events you can configure
# NOTE: Please make sure to change your handler code to work with those events
# Check the event documentation for details
# events:
# events:
# - http:
# path: users/create
# method: get
# - s3: ${env:BUCKET}
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"
# - cloudwatchEvent:
# event:
# source:
# - "aws.ec2"
# detail-type:
# - "EC2 Instance State-change Notification"
# detail:
# state:
# - pending
# - cloudwatchLog: '/aws/lambda/hello'
# - cognitoUserPool:
# pool: MyUserPool
# trigger: PreSignUp
# Define function environment variables here
# environment:
# variable2: value2
# you can add CloudFormation resource templates here
#resources:
# Resources:
# NewResource:
# Type: AWS::S3::Bucket
# Properties:
# BucketName: my-new-bucket
# Outputs:
# NewOutput:
# Description: "Description for the output"
# Value: "Some output value"

View File

@ -0,0 +1,19 @@
package main
import (
"github.com/aws/aws-lambda-go/lambda"
)
type Response struct {
Message string `json:"message"`
}
func Handler() (Response, error) {
return Response{
Message: "Okay so your other function also executed successfully!",
}, nil
}
func main() {
lambda.Start(Handler)
}

View File

@ -0,0 +1,4 @@
build:
go get github.com/aws/aws-lambda-go/lambda
env GOOS=linux go build -ldflags="-s -w" -o bin/hello hello/main.go
env GOOS=linux go build -ldflags="-s -w" -o bin/world world/main.go

View File

@ -0,0 +1,5 @@
# Serverless directories
.serverless
# golang output binary directory
bin

View File

@ -0,0 +1,19 @@
package main
import (
"github.com/aws/aws-lambda-go/lambda"
)
type Response struct {
Message string `json:"message"`
}
func Handler() (Response, error) {
return Response{
Message: "Go Serverless v1.0! Your function executed successfully!",
}, nil
}
func main() {
lambda.Start(Handler)
}

View File

@ -0,0 +1,104 @@
# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
# docs.serverless.com
#
# Happy Coding!
service: aws-go # NOTE: update this with your service name
# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"
provider:
name: aws
runtime: go1.x
# you can overwrite defaults here
# stage: dev
# region: us-east-1
# you can add statements to the Lambda function's IAM Role here
# iamRoleStatements:
# - Effect: "Allow"
# Action:
# - "s3:ListBucket"
# Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] }
# - Effect: "Allow"
# Action:
# - "s3:PutObject"
# Resource:
# Fn::Join:
# - ""
# - - "arn:aws:s3:::"
# - "Ref" : "ServerlessDeploymentBucket"
# - "/*"
# you can define service wide environment variables here
# environment:
# variable1: value1
package:
exclude:
- ./**
include:
- ./bin/**
functions:
hello:
handler: bin/hello
world:
handler: bin/world
# The following are a few example events you can configure
# NOTE: Please make sure to change your handler code to work with those events
# Check the event documentation for details
# events:
# events:
# - http:
# path: users/create
# method: get
# - s3: ${env:BUCKET}
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"
# - cloudwatchEvent:
# event:
# source:
# - "aws.ec2"
# detail-type:
# - "EC2 Instance State-change Notification"
# detail:
# state:
# - pending
# - cloudwatchLog: '/aws/lambda/hello'
# - cognitoUserPool:
# pool: MyUserPool
# trigger: PreSignUp
# Define function environment variables here
# environment:
# variable2: value2
# you can add CloudFormation resource templates here
#resources:
# Resources:
# NewResource:
# Type: AWS::S3::Bucket
# Properties:
# BucketName: my-new-bucket
# Outputs:
# NewOutput:
# Description: "Description for the output"
# Value: "Some output value"

View File

@ -0,0 +1,19 @@
package main
import (
"github.com/aws/aws-lambda-go/lambda"
)
type Response struct {
Message string `json:"message"`
}
func Handler() (Response, error) {
return Response{
Message: "Okay so your other function also executed successfully!",
}, nil
}
func main() {
lambda.Start(Handler)
}

View File

@ -64,7 +64,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -64,7 +64,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -64,7 +64,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -64,7 +64,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -64,7 +64,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -60,7 +60,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -3,6 +3,7 @@ const slsw = require('serverless-webpack');
module.exports = {
entry: slsw.lib.entries,
devtool: 'source-map',
resolve: {
extensions: [
'.js',

View File

@ -69,7 +69,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -69,7 +69,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -69,7 +69,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -66,7 +66,7 @@ functions:
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
# - iot:
# sql: "SELECT * FROM 'some_topic'"

View File

@ -3,7 +3,7 @@
"version": "1.0.0",
"description": "Example function for serverless kubeless",
"dependencies": {
"serverless-kubeless": "^0.2.4",
"serverless-kubeless": "^0.3.1",
"lodash": "^4.1.0"
},
"devDependencies": {},

View File

@ -3,7 +3,7 @@
"version": "1.0.0",
"description": "Sample Kubeless Python serverless framework service.",
"dependencies": {
"serverless-kubeless": "^0.2.4"
"serverless-kubeless": "^0.3.1"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"

250
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "serverless",
"version": "1.25.0",
"version": "1.26.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -33,9 +33,9 @@
"dev": true
},
"acorn": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz",
"integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==",
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.3.0.tgz",
"integrity": "sha512-Yej+zOJ1Dm/IMZzzj78OntP/r3zHEaKcyNoU2lAaxPtrseM6rF0xwqoz5Q5ysAiED9hTjI2hgtvLXitlCN1/Ug==",
"dev": true
},
"acorn-globals": {
@ -213,7 +213,7 @@
"graphql-anywhere": "3.1.0",
"graphql-tag": "2.6.1",
"redux": "3.7.2",
"symbol-observable": "1.1.0",
"symbol-observable": "1.2.0",
"whatwg-fetch": "2.0.3"
}
},
@ -367,9 +367,9 @@
"dev": true
},
"assertion-error": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz",
"integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true
},
"async": {
@ -389,12 +389,11 @@
"dev": true
},
"aws-sdk": {
"version": "2.172.0",
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.172.0.tgz",
"integrity": "sha1-R9+3mQeXbrvVOFYupaJYNbWz810=",
"version": "2.188.0",
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.188.0.tgz",
"integrity": "sha1-kGKrx9umOTRZ+i80I89dKU8ARhE=",
"requires": {
"buffer": "4.9.1",
"crypto-browserify": "1.0.9",
"events": "1.1.1",
"jmespath": "0.15.0",
"querystring": "0.2.0",
@ -887,7 +886,7 @@
"integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=",
"dev": true,
"requires": {
"assertion-error": "1.0.2",
"assertion-error": "1.1.0",
"deep-eql": "0.1.3",
"type-detect": "1.0.0"
}
@ -951,13 +950,13 @@
}
},
"cli-usage": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/cli-usage/-/cli-usage-0.1.4.tgz",
"integrity": "sha1-fAHg3HBsI0s5yTODjI4gshdXduI=",
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/cli-usage/-/cli-usage-0.1.7.tgz",
"integrity": "sha512-x/Q52iLSZsRrRb2ePmTsVYXrGcrPQ8G4yRAY7QpMlumxAfPVrnDOH2X6Z5s8qsAX7AA7YuIi8AXFrvH0wWEesA==",
"dev": true,
"requires": {
"marked": "0.3.7",
"marked-terminal": "1.7.0"
"marked": "0.3.12",
"marked-terminal": "2.0.0"
}
},
"cli-width": {
@ -1202,11 +1201,6 @@
"boom": "2.10.1"
}
},
"crypto-browserify": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz",
"integrity": "sha1-zFRJaF37hesRyYKKzHy4erW7/MA="
},
"crypto-random-string": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz",
@ -1233,7 +1227,7 @@
"integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
"dev": true,
"requires": {
"es5-ext": "0.10.37"
"es5-ext": "0.10.38"
}
},
"damerau-levenshtein": {
@ -1481,9 +1475,9 @@
"dev": true
},
"doctrine": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.2.tgz",
"integrity": "sha512-y0tm5Pq6ywp3qSTZ1vPgVdAnbDEoeoc5wlOHXoY1c4Wug/a7JvqHIl7BTvwodaHmejWkK/9dSb3sCYfyo/om8A==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
"requires": {
"esutils": "2.0.2"
@ -1535,9 +1529,9 @@
}
},
"end-of-stream": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz",
"integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=",
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
"requires": {
"once": "1.4.0"
}
@ -1585,9 +1579,9 @@
}
},
"es5-ext": {
"version": "0.10.37",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.37.tgz",
"integrity": "sha1-DudB0Ui4AGm6J9AgOTdWryV978M=",
"version": "0.10.38",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.38.tgz",
"integrity": "sha512-jCMyePo7AXbUESwbl8Qi01VSH2piY9s/a3rSU/5w/MlTIx8HPL1xn2InGN8ejt/xulcJgnTO7vqNtOAxzYd2Kg==",
"dev": true,
"requires": {
"es6-iterator": "2.0.3",
@ -1601,7 +1595,7 @@
"dev": true,
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.37",
"es5-ext": "0.10.38",
"es6-symbol": "3.1.1"
}
},
@ -1612,7 +1606,7 @@
"dev": true,
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.37",
"es5-ext": "0.10.38",
"es6-iterator": "2.0.3",
"es6-set": "0.1.5",
"es6-symbol": "3.1.1",
@ -1632,7 +1626,7 @@
"dev": true,
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.37",
"es5-ext": "0.10.38",
"es6-iterator": "2.0.3",
"es6-symbol": "3.1.1",
"event-emitter": "0.3.5"
@ -1645,7 +1639,7 @@
"dev": true,
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.37"
"es5-ext": "0.10.38"
}
},
"es6-weak-map": {
@ -1655,7 +1649,7 @@
"dev": true,
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.37",
"es5-ext": "0.10.38",
"es6-iterator": "2.0.3",
"es6-symbol": "3.1.1"
}
@ -1714,7 +1708,7 @@
"chalk": "1.1.3",
"concat-stream": "1.6.0",
"debug": "2.6.9",
"doctrine": "2.0.2",
"doctrine": "2.1.0",
"escope": "3.6.0",
"espree": "3.5.2",
"esquery": "1.0.0",
@ -1727,7 +1721,7 @@
"imurmurhash": "0.1.4",
"inquirer": "0.12.0",
"is-my-json-valid": "2.17.1",
"is-resolvable": "1.0.1",
"is-resolvable": "1.1.0",
"js-yaml": "3.10.0",
"json-stable-stringify": "1.0.1",
"levn": "0.3.0",
@ -1887,7 +1881,7 @@
"doctrine": "1.5.0",
"has": "1.0.1",
"jsx-ast-utils": "1.4.1",
"object.assign": "4.0.4"
"object.assign": "4.1.0"
},
"dependencies": {
"doctrine": {
@ -1908,7 +1902,7 @@
"integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==",
"dev": true,
"requires": {
"acorn": "5.2.1",
"acorn": "5.3.0",
"acorn-jsx": "3.0.1"
}
},
@ -1955,7 +1949,7 @@
"dev": true,
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.37"
"es5-ext": "0.10.38"
}
},
"events": {
@ -2404,9 +2398,9 @@
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
},
"graphlib": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.1.tgz",
"integrity": "sha1-QjUsUrovTQNctWbrkfc5X3bryVE=",
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.5.tgz",
"integrity": "sha512-XvtbqCcw+EM5SqQrIetIKKD+uZVNQtDPD1goIg7K73RuRZtVI5rYMdcCVSHm/AS1sCBZ7vt0p5WgXouucHQaOA==",
"requires": {
"lodash": "4.17.4"
}
@ -2416,7 +2410,7 @@
"resolved": "https://registry.npmjs.org/graphql/-/graphql-0.10.5.tgz",
"integrity": "sha512-Q7cx22DiLhwHsEfUnUip1Ww/Vfx7FS0w6+iHItNuN61+XpegHSa3k5U0+6M5BcpavQImBwFiy0z3uYwY7cXMLQ==",
"requires": {
"iterall": "1.1.3"
"iterall": "1.1.4"
}
},
"graphql-anywhere": {
@ -2484,7 +2478,7 @@
"dev": true,
"requires": {
"chalk": "1.1.3",
"commander": "2.12.2",
"commander": "2.13.0",
"is-my-json-valid": "2.17.1",
"pinkie-promise": "2.0.1"
},
@ -2509,9 +2503,9 @@
}
},
"commander": {
"version": "2.12.2",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
"integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==",
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
"integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==",
"dev": true
},
"supports-color": {
@ -2549,6 +2543,12 @@
"resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.1.tgz",
"integrity": "sha512-JkaetveU7hFbqnAC1EV1sF4rlojU2D4Usc5CmS69l6NfmPDnpnFUegzFg33eDkkpNCxZ0mQp65HwUDrNFS/8MA=="
},
"has-symbols": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
"integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
"dev": true
},
"has-to-string-tag-x": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz",
@ -2794,9 +2794,9 @@
"dev": true
},
"is-ci": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.0.10.tgz",
"integrity": "sha1-9zkzayYyNlBhqdSCcM1WrjNpMY4=",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.1.0.tgz",
"integrity": "sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg==",
"dev": true,
"requires": {
"ci-info": "1.1.2"
@ -3000,9 +3000,9 @@
}
},
"is-resolvable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.1.tgz",
"integrity": "sha512-y5CXYbzvB3jTnWAZH1Nl7ykUWb6T3BcTs56HUruwBf8MhF56n1HWqhDWnVFo8GHrUPDgvUUNVhrc2U8W7iqz5g==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
"integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
"dev": true
},
"is-retry-allowed": {
@ -3193,7 +3193,7 @@
"babel-types": "6.26.0",
"babylon": "6.18.0",
"istanbul-lib-coverage": "1.1.1",
"semver": "5.4.1"
"semver": "5.5.0"
}
},
"istanbul-lib-report": {
@ -3274,9 +3274,9 @@
}
},
"iterall": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.1.3.tgz",
"integrity": "sha512-Cu/kb+4HiNSejAPhSaN1VukdNTTi/r4/e+yykqjlG/IW+1gZH5b4+Bq3whDX4tvbYugta3r8KTMUiqT3fIGxuQ=="
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.1.4.tgz",
"integrity": "sha512-eaDsM/PY8D/X5mYQhecVc5/9xvSHED7yPON+ffQroBeTuqUVm7dfphMkK8NksXuImqZlVRoKtrNfMIVCYIqaUQ=="
},
"jest-changed-files": {
"version": "17.0.2",
@ -3294,7 +3294,7 @@
"callsites": "2.0.0",
"chalk": "1.1.3",
"graceful-fs": "4.1.11",
"is-ci": "1.0.10",
"is-ci": "1.1.0",
"istanbul-api": "1.2.1",
"istanbul-lib-coverage": "1.1.1",
"istanbul-lib-instrument": "1.9.1",
@ -3823,8 +3823,8 @@
"resolved": "https://registry.npmjs.org/json-refs/-/json-refs-2.1.7.tgz",
"integrity": "sha1-uesB/in16j6Sh48VrqEK04taz4k=",
"requires": {
"commander": "2.12.2",
"graphlib": "2.1.1",
"commander": "2.13.0",
"graphlib": "2.1.5",
"js-yaml": "3.10.0",
"native-promise-only": "0.8.1",
"path-loader": "1.0.4",
@ -3833,9 +3833,9 @@
},
"dependencies": {
"commander": {
"version": "2.12.2",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
"integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA=="
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
"integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA=="
}
}
},
@ -4354,12 +4354,12 @@
"dev": true
},
"markdown-magic": {
"version": "0.1.19",
"resolved": "https://registry.npmjs.org/markdown-magic/-/markdown-magic-0.1.19.tgz",
"integrity": "sha1-IKnWWdqgx7DOt64DCVxuLK41KgM=",
"version": "0.1.20",
"resolved": "https://registry.npmjs.org/markdown-magic/-/markdown-magic-0.1.20.tgz",
"integrity": "sha1-Xw73k0L6G0O7pCr+Y9MCMobj7sM=",
"dev": true,
"requires": {
"commander": "2.12.2",
"commander": "2.13.0",
"deepmerge": "1.5.2",
"find-up": "2.1.0",
"fs-extra": "1.0.0",
@ -4370,9 +4370,9 @@
},
"dependencies": {
"commander": {
"version": "2.12.2",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
"integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==",
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
"integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==",
"dev": true
},
"find-up": {
@ -4435,15 +4435,15 @@
}
},
"marked": {
"version": "0.3.7",
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.7.tgz",
"integrity": "sha512-zBEP4qO1YQp5aXHt8S5wTiOv9i2X74V/LQL0zhUNvVaklt6Ywa6lChxIvS+ibYlCGgADwKwZFhjC3+XfpsvQvQ==",
"version": "0.3.12",
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.12.tgz",
"integrity": "sha512-k4NaW+vS7ytQn6MgJn3fYpQt20/mOgYM5Ft9BYMfQJDz2QT6yEeS9XJ8k2Nw8JTeWK/znPPW2n3UJGzyYEiMoA==",
"dev": true
},
"marked-terminal": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-1.7.0.tgz",
"integrity": "sha1-yMRgiBx3LHYEtkNnAH7l938SWQQ=",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-2.0.0.tgz",
"integrity": "sha1-Xq9Wi+ZvaGVBr6UqVYKAMQox3i0=",
"dev": true,
"requires": {
"cardinal": "1.0.0",
@ -4742,11 +4742,11 @@
"integrity": "sha1-BW0UJE89zBzq3+aK+c/wxUc6M/M=",
"dev": true,
"requires": {
"cli-usage": "0.1.4",
"cli-usage": "0.1.7",
"growly": "1.3.0",
"lodash.clonedeep": "3.0.2",
"minimist": "1.2.0",
"semver": "5.4.1",
"semver": "5.5.0",
"shellwords": "0.1.1",
"which": "1.3.0"
}
@ -4768,7 +4768,7 @@
"requires": {
"hosted-git-info": "2.5.0",
"is-builtin-module": "1.0.0",
"semver": "5.4.1",
"semver": "5.5.0",
"validate-npm-package-license": "3.0.1"
}
},
@ -4848,13 +4848,14 @@
"dev": true
},
"object.assign": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz",
"integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
"integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
"dev": true,
"requires": {
"define-properties": "1.1.2",
"function-bind": "1.1.1",
"has-symbols": "1.0.0",
"object-keys": "1.0.11"
}
},
@ -4899,9 +4900,9 @@
"integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k="
},
"opn": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz",
"integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==",
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/opn/-/opn-5.2.0.tgz",
"integrity": "sha512-Jd/GpzPyHF4P2/aNOVmS3lfMSWV9J7cOhCG1s08XCEAsPkB7lp6ddiU0J7XzyQRDUh8BqJ7PchfINjR8jyofRQ==",
"requires": {
"is-wsl": "1.1.0"
}
@ -4975,10 +4976,13 @@
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
},
"p-limit": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz",
"integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=",
"dev": true
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz",
"integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==",
"dev": true,
"requires": {
"p-try": "1.0.0"
}
},
"p-locate": {
"version": "2.0.0",
@ -4986,18 +4990,24 @@
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
"dev": true,
"requires": {
"p-limit": "1.1.0"
"p-limit": "1.2.0"
}
},
"p-try": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
"dev": true
},
"package-json": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz",
"integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=",
"requires": {
"got": "6.7.1",
"registry-auth-token": "3.3.1",
"registry-auth-token": "3.3.2",
"registry-url": "3.1.0",
"semver": "5.4.1"
"semver": "5.5.0"
}
},
"pako": {
@ -5197,9 +5207,9 @@
}
},
"promise-queue": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.3.tgz",
"integrity": "sha1-hTTXa/RnPDuqOoK7oBvSlcww8U8="
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz",
"integrity": "sha1-L29ffA9tCBCelnZZx5uIqe1ek7Q="
},
"proto-list": {
"version": "1.2.4",
@ -5322,9 +5332,9 @@
}
},
"rc": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.2.tgz",
"integrity": "sha1-2M6ctX6NZNnHut2YdsfDTL48cHc=",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.4.tgz",
"integrity": "sha1-oPYGyq4qO4YrvQ74VILAElsxX6M=",
"requires": {
"deep-extend": "0.4.2",
"ini": "1.3.5",
@ -5420,7 +5430,7 @@
"lodash": "4.17.4",
"lodash-es": "4.17.4",
"loose-envify": "1.3.1",
"symbol-observable": "1.1.0"
"symbol-observable": "1.2.0"
}
},
"regenerator-runtime": {
@ -5439,11 +5449,11 @@
}
},
"registry-auth-token": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.1.tgz",
"integrity": "sha1-+w0yie4Nmtosu1KvXf5mywcNMAY=",
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz",
"integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==",
"requires": {
"rc": "1.2.2",
"rc": "1.2.4",
"safe-buffer": "5.1.1"
}
},
@ -5452,7 +5462,7 @@
"resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
"integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
"requires": {
"rc": "1.2.2"
"rc": "1.2.4"
}
},
"remarkable": {
@ -5533,7 +5543,7 @@
"stringstream": "0.0.5",
"tough-cookie": "2.3.3",
"tunnel-agent": "0.4.3",
"uuid": "3.1.0"
"uuid": "3.2.1"
},
"dependencies": {
"form-data": {
@ -5560,9 +5570,9 @@
"dev": true
},
"uuid": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz",
"integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==",
"dev": true
}
}
@ -5694,16 +5704,16 @@
}
},
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
},
"semver-diff": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz",
"integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=",
"requires": {
"semver": "5.4.1"
"semver": "5.5.0"
}
},
"semver-regex": {
@ -6002,9 +6012,9 @@
}
},
"symbol-observable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.1.0.tgz",
"integrity": "sha512-dQoid9tqQ+uotGhuTKEY11X4xhyYePVnqGSoSm3OGKh2E8LZ6RPULp1uXTctk33IeERlrRJYoVSBglsL05F5Uw=="
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
},
"symbol-tree": {
"version": "3.2.2",
@ -6118,7 +6128,7 @@
"integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==",
"requires": {
"bl": "1.2.1",
"end-of-stream": "1.4.0",
"end-of-stream": "1.4.1",
"readable-stream": "2.3.3",
"xtend": "4.0.1"
}

View File

@ -1,6 +1,6 @@
{
"name": "serverless",
"version": "1.25.0",
"version": "1.26.0",
"engines": {
"node": ">=4.0"
},

View File

@ -37,5 +37,10 @@ serverless deploy -v
echo "Invoking Service"
serverless invoke --function hello
if [ $template == "aws-go" ] || [ $template == "aws-go-dep" ]
then
serverless invoke --function world
fi
echo "Removing Service"
serverless remove -v

View File

@ -10,6 +10,8 @@ function integration-test {
integration-test aws-csharp 'apt-get -qq update && apt-get -qq -y install zip && dotnet restore && dotnet lambda package --configuration release --framework netcoreapp1.0 --output-package bin/release/netcoreapp1.0/deploy-package.zip'
integration-test aws-fsharp 'apt-get -qq update && apt-get -qq -y install zip && dotnet restore && dotnet lambda package --configuration release --framework netcoreapp1.0 --output-package bin/release/netcoreapp1.0/deploy-package.zip'
integration-test aws-go 'cd /go/src/app && make build'
integration-test aws-go-dep 'cd /go/src/app && make build'
integration-test aws-groovy-gradle ./gradlew build
integration-test aws-java-gradle ./gradlew build
integration-test aws-java-maven mvn package