mirror of
https://github.com/serverless/serverless.git
synced 2026-01-25 15:07:39 +00:00
Merge branch 'master' into window-env-path
This commit is contained in:
commit
6e05ce8f9c
47
README.md
47
README.md
@ -22,6 +22,8 @@ Serverless is an MIT open-source project, actively maintained by a full-time, ve
|
||||
|
||||
## Contents
|
||||
|
||||
<img align="right" width="400" src="https://s3-us-west-2.amazonaws.com/assets.site.serverless.com/email/sls-getting-started.gif" />
|
||||
|
||||
* [Quick Start](#quick-start)
|
||||
* [Examples](https://github.com/serverless/examples)
|
||||
* [Services](#services)
|
||||
@ -129,7 +131,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.
|
||||
* Supports Node.js, Python, Java, Scala, C#, F#, 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.
|
||||
@ -152,40 +154,60 @@ This table is generated from https://github.com/serverless/plugins/blob/master/p
|
||||
-->
|
||||
| Plugin | Author |
|
||||
|:-------|:------:|
|
||||
| **[API GW binary support](https://github.com/maciejtreder/serverless-apigw-binary)** <br/> Serverless plugin to enable binary support in AWS API Gateway. | [Maciej Treder](https://github.com/maciejtreder) |
|
||||
| **[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 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) |
|
||||
| **[Serverless Aws Alias](https://github.com/HyperBrain/serverless-aws-alias)** <br/> This plugin enables use of AWS aliases on Lambda functions. | [HyperBrain](http://github.com/HyperBrain) |
|
||||
| **[Serverless Aws Documentation](https://github.com/9cookies/serverless-aws-documentation)** <br/> Serverless plugin to add documentation and models to the serverless generated API Gateway | [9cookies](http://github.com/9cookies) |
|
||||
| **[Serverless Build Plugin](https://github.com/nfour/serverless-build-plugin)** <br/> A Node.js focused build plugin for serverless. | [nfour](http://github.com/nfour) |
|
||||
| **[Serverless Cf Vars](https://gitlab.com/kabo/serverless-cf-vars)** <br/> Enables use of AWS pseudo functions and Fn::Sub string substitution | [kabo](http://github.com/kabo) |
|
||||
| **[Serverless Cljs Plugin](https://github.com/nervous-systems/serverless-cljs-plugin)** <br/> Enables Clojurescript as an implementation language for Lambda handlers | [nervous-systems](http://github.com/nervous-systems) |
|
||||
| **[Serverless Coffeescript](https://github.com/duanefields/serverless-coffeescript)** <br/> A Serverless plugin to compile your CoffeeScript into JavaScript at deployment | [duanefields](http://github.com/duanefields) |
|
||||
| **[Serverless Command Line Event Args](https://github.com/horike37/serverless-command-line-event-args)** <br/> This module is Serverless Framework plugin. Event JSON passes to your Lambda function in commandline. | [horike37](http://github.com/horike37) |
|
||||
| **[Serverless Crypt](https://github.com/marcy-terui/serverless-crypt)** <br/> Securing the secrets on Serverless Framework by AWS KMS encryption. | [marcy-terui](http://github.com/marcy-terui) |
|
||||
| **[Serverless Custom Packaging Plugin](https://github.com/hypoport/serverless-custom-packaging-plugin)** <br/> Plugin to package your sourcecode using a custom target path inside the zip. | [hypoport](http://github.com/hypoport) |
|
||||
| **[Serverless Dir Config Plugin](https://github.com/economysizegeek/serverless-dir-config-plugin)** <br/> EXPERIMENTAL - Serverless plugin to load function and resource definitions from a directory. | [economysizegeek](http://github.com/economysizegeek) |
|
||||
| **[Serverless Domain Manager](https://github.com/amplify-education/serverless-domain-manager)** <br/> Serverless plugin for managing custom domains with API Gateways. | [amplify-education](http://github.com/amplify-education) |
|
||||
| **[Serverless Dotenv](https://github.com/Jimdo/serverless-dotenv)** <br/> Fetch environment variables and write it to a .env file | [Jimdo](http://github.com/Jimdo) |
|
||||
| **[Serverless Dotnet](https://github.com/fruffin/serverless-dotnet)** <br/> A serverless plugin to run 'dotnet' commands as part of the deploy process | [fruffin](http://github.com/fruffin) |
|
||||
| **[Serverless Dynalite](https://github.com/sdd/serverless-dynalite)** <br/> Run dynalite locally (no JVM, all JS) to simulate DynamoDB. Watch serverless.yml for table config updates. | [sdd](http://github.com/sdd) |
|
||||
| **[Serverless Dynamodb Autoscaling](https://github.com/sbstjn/serverless-dynamodb-autoscaling)** <br/> Configure Amazon DynamoDB's native Auto Scaling for your table capacities. | [sbstjn](http://github.com/sbstjn) |
|
||||
| **[Serverless Dynamodb Local](https://github.com/99xt/serverless-dynamodb-local)** <br/> Serverless Dynamodb Local Plugin - Allows to run dynamodb locally for serverless | [99xt](http://github.com/99xt) |
|
||||
| **[Serverless Dynamodb Ttl](https://github.com/Jimdo/serverless-dynamodb-ttl)** <br/> Configure DynamoDB TTL in serverless.yml (until CloudFormation supports this). | [Jimdo](http://github.com/Jimdo) |
|
||||
| **[Serverless Enable Api Logs](https://github.com/paulSambolin/serverless-enable-api-logs)** <br/> Enables Coudwatch logging for API Gateway events | [paulSambolin](http://github.com/paulSambolin) |
|
||||
| **[Serverless Env Generator](https://github.com/DieProduktMacher/serverless-env-generator)** <br/> Manage environment variables with YAML and load them with dotenv. Supports variable encryption with KMS, multiple stages and custom profiles. | [DieProduktMacher](http://github.com/DieProduktMacher) |
|
||||
| **[Serverless Event Constant Inputs](https://github.com/dittto/serverless-event-constant-inputs)** <br/> Allows you to add constant inputs to events in Serverless 1.0. For more info see [constant values in Cloudwatch](https://aws.amazon.com/blogs/compute/simply-serverless-use-constant-values-in-cloudwatch-event-triggered-lambda-functions/) | [dittto](http://github.com/dittto) |
|
||||
| **[Serverless Export Env](https://github.com/arabold/serverless-export-env)** <br/> Export environment variables into a .env file with automatic AWS CloudFormation reference resolution. | [arabold](http://github.com/arabold) |
|
||||
| **[Serverless Gulp](https://github.com/rhythminme/serverless-gulp)** <br/> A thin task wrapper around @goserverless that allows you to automate build, test and deploy tasks using gulp | [rhythminme](http://github.com/rhythminme) |
|
||||
| **[Serverless Hooks Plugin](https://github.com/uswitch/serverless-hooks-plugin)** <br/> Run arbitrary commands on any lifecycle event in serverless | [uswitch](http://github.com/uswitch) |
|
||||
| **[Serverless Jest Plugin](https://github.com/SC5/serverless-jest-plugin)** <br/> A Serverless Plugin for the Serverless Framework which adds support for test-driven development using Jest | [SC5](http://github.com/SC5) |
|
||||
| **[Serverless Kms Secrets](https://github.com/SC5/serverless-kms-secrets)** <br/> Allows to easily encrypt and decrypt secrets using KMS from the serverless CLI | [SC5](http://github.com/SC5) |
|
||||
| **[Serverless Kubeless](https://github.com/serverless/serverless-kubeless)** <br/> Serverless plugin for deploying functions to Kubeless. | [serverless](http://github.com/serverless) |
|
||||
| **[Serverless Local Dev Server](https://github.com/DieProduktMacher/serverless-local-dev-server)** <br/> Speeds up development of Alexa Skills, Chatbots and APIs by exposing your functions as local HTTP endpoints and mapping received events. | [DieProduktMacher](http://github.com/DieProduktMacher) |
|
||||
| **[Serverless Log Forwarding](https://github.com/amplify-education/serverless-log-forwarding)** <br/> Serverless plugin for forwarding CloudWatch logs to another Lambda function. | [amplify-education](http://github.com/amplify-education) |
|
||||
| **[Serverless Mocha Plugin](https://github.com/SC5/serverless-mocha-plugin)** <br/> A Serverless Plugin for the Serverless Framework which adds support for test-driven development using Mocha | [SC5](http://github.com/SC5) |
|
||||
| **[Serverless Nested Stack](https://github.com/jagdish-176/serverless-nested-stack)** <br/> A plugin to Workaround for Cloudformation 200 resource limit | [jagdish-176](http://github.com/jagdish-176) |
|
||||
| **[Serverless Offline](https://github.com/dherault/serverless-offline)** <br/> Emulate AWS λ and API Gateway locally when developing your Serverless project | [dherault](http://github.com/dherault) |
|
||||
| **[Serverless Offline Scheduler](https://github.com/ajmath/serverless-offline-scheduler)** <br/> Runs scheduled functions offline while integrating with serverless-offline | [ajmath](http://github.com/ajmath) |
|
||||
| **[Serverless Package Python Functions](https://github.com/ubaniabalogun/serverless-package-python-functions)** <br/> Packaging Python Lambda functions with only the dependencies/requirements they need. | [ubaniabalogun](http://github.com/ubaniabalogun) |
|
||||
| **[Serverless Parameters](https://github.com/svdgraaf/serverless-parameters)** <br/> Add parameters to the generated cloudformation templates | [svdgraaf](http://github.com/svdgraaf) |
|
||||
| **[Serverless Plugin Aws Alerts](https://github.com/ACloudGuru/serverless-plugin-aws-alerts)** <br/> A Serverless plugin to easily add CloudWatch alarms to functions | [ACloudGuru](http://github.com/ACloudGuru) |
|
||||
| **[Serverless Plugin Aws Resolvers](https://github.com/DopplerLabs/serverless-plugin-aws-resolvers)** <br/> Resolves variables from ESS, RDS, or Kinesis for serverless services | [DopplerLabs](http://github.com/DopplerLabs) |
|
||||
| **[Serverless Plugin Bespoken](https://github.com/bespoken/serverless-plugin-bespoken)** <br/> Creates a local server and a proxy so you don't have to deploy anytime you want to test your code | [bespoken](http://github.com/bespoken) |
|
||||
| **[Serverless Plugin Bind Deployment Id](https://github.com/jacob-meacham/serverless-plugin-bind-deployment-id)** <br/> A Serverless plugin to bind the randomly generated deployment resource to your custom resources | [jacob-meacham](http://github.com/jacob-meacham) |
|
||||
| **[Serverless Plugin Browserifier](https://github.com/digitalmaas/serverless-plugin-browserifier)** <br/> Reduce the size and speed up your Node.js based lambda's using browserify. | [digitalmaas](http://github.com/digitalmaas) |
|
||||
| **[Serverless Plugin Browserify](https://github.com/doapp-ryanp/serverless-plugin-browserify)** <br/> Speed up your node based lambda's | [doapp-ryanp](http://github.com/doapp-ryanp) |
|
||||
| **[Serverless Plugin Cfauthorizer](https://github.com/SC5/serverless-plugin-cfauthorizer)** <br/> This plugin allows you to define your own API Gateway Authorizers as the Serverless CloudFormation resources and apply them to HTTP endpoints. | [SC5](http://github.com/SC5) |
|
||||
| **[Serverless Plugin Cloudwatch Sumologic](https://github.com/ACloudGuru/serverless-plugin-cloudwatch-sumologic)** <br/> Plugin which auto-subscribes a log delivery lambda function to lambda log groups created by serverless | [ACloudGuru](http://github.com/ACloudGuru) |
|
||||
| **[Serverless Plugin Common Excludes](https://github.com/dougmoscrop/serverless-plugin-common-excludes)** <br/> Adds commonly excluded files to package.excludes | [dougmoscrop](http://github.com/dougmoscrop) |
|
||||
| **[Serverless Plugin Custom Domain](https://github.com/dougmoscrop/serverless-plugin-custom-domain)** <br/> Reliably sets a BasePathMapping to an API Gateway Custom Domain | [dougmoscrop](http://github.com/dougmoscrop) |
|
||||
| **[Serverless Plugin Deploy Environment](https://github.com/DopplerLabs/serverless-plugin-deploy-environment)** <br/> Plugin to manage deployment environment across stages | [DopplerLabs](http://github.com/DopplerLabs) |
|
||||
| **[Serverless Plugin Diff](https://github.com/nicka/serverless-plugin-diff)** <br/> Compares your local AWS CloudFormation templates against deployed ones. | [nicka](http://github.com/nicka) |
|
||||
| **[Serverless Plugin Elastic Beanstalk](https://github.com/rawphp/serverless-plugin-elastic-beanstalk)** <br/> A serverless plugin to deploy applications to AWS ElasticBeanstalk. | [rawphp](http://github.com/rawphp) |
|
||||
| **[Serverless Plugin Encode Env Var Objects](https://github.com/yonomi/serverless-plugin-encode-env-var-objects)** <br/> Serverless plugin to encode any environment variable objects. | [yonomi](http://github.com/yonomi) |
|
||||
| **[Serverless Plugin External Sns Events](https://github.com/silvermine/serverless-plugin-external-sns-events)** <br/> Add ability for functions to use existing or external SNS topics as an event source | [silvermine](http://github.com/silvermine) |
|
||||
| **[Serverless Plugin Git Variables](https://github.com/jacob-meacham/serverless-plugin-git-variables)** <br/> A Serverless plugin to expose git variables (branch name, HEAD description, full commit hash) to your serverless services | [jacob-meacham](http://github.com/jacob-meacham) |
|
||||
@ -193,12 +215,16 @@ This table is generated from https://github.com/serverless/plugins/blob/master/p
|
||||
| **[Serverless Plugin Include Dependencies](https://github.com/dougmoscrop/serverless-plugin-include-dependencies)** <br/> This is a Serverless plugin that should make your deployed functions smaller. | [dougmoscrop](http://github.com/dougmoscrop) |
|
||||
| **[Serverless Plugin Iopipe](https://github.com/iopipe/serverless-plugin-iopipe)** <br/> See inside your Lambda functions with high fidelity metrics and monitoring. | [iopipe](http://github.com/iopipe) |
|
||||
| **[Serverless Plugin Lambda Dead Letter](https://github.com/gmetzker/serverless-plugin-lambda-dead-letter)** <br/> A Serverless plugin that can configure a lambda with a dead letter queue or topic | [gmetzker](http://github.com/gmetzker) |
|
||||
| **[Serverless Plugin Log Subscription](https://github.com/dougmoscrop/serverless-plugin-log-subscription)** <br/> Adds a CloudWatch LogSubscription for functions | [dougmoscrop](http://github.com/dougmoscrop) |
|
||||
| **[Serverless Plugin Multiple Responses](https://github.com/silvermine/serverless-plugin-multiple-responses)** <br/> Enable multiple content-types for Response template | [silvermine](http://github.com/silvermine) |
|
||||
| **[Serverless Plugin Offline Kinesis Events](https://github.com/DopplerLabs/serverless-plugin-offline-kinesis-events)** <br/> Plugin that works with serverless-offline to allow offline testing of serverless functions that are triggered by Kinesis events. | [DopplerLabs](http://github.com/DopplerLabs) |
|
||||
| **[Serverless Plugin Optimize](https://github.com/FidelLimited/serverless-plugin-optimize)** <br/> Bundle with Browserify, transpile with Babel to ES5 and minify with Uglify your Serverless functions. | [FidelLimited](http://github.com/FidelLimited) |
|
||||
| **[Serverless Plugin Package Dotenv File](https://github.com/ACloudGuru/serverless-plugin-package-dotenv-file)** <br/> A Serverless plugin to copy a .env file into the serverless package | [ACloudGuru](http://github.com/ACloudGuru) |
|
||||
| **[Serverless Plugin Scripts](https://github.com/mvila/serverless-plugin-scripts)** <br/> Add scripting capabilities to the Serverless Framework | [mvila](http://github.com/mvila) |
|
||||
| **[Serverless Plugin Select](https://github.com/FidelLimited/serverless-plugin-select)** <br/> Select which functions are to be deployed based on region and stage. | [FidelLimited](http://github.com/FidelLimited) |
|
||||
| **[Serverless Plugin Simulate](https://github.com/gertjvr/serverless-plugin-simulate)** <br/> Simulate AWS Lambda and API Gateway locally using Docker | [gertjvr](http://github.com/gertjvr) |
|
||||
| **[Serverless Plugin Split Stacks](https://github.com/dougmoscrop/serverless-plugin-split-stacks)** <br/> Migrate certain resources to nested stacks | [dougmoscrop](http://github.com/dougmoscrop) |
|
||||
| **[Serverless Plugin Stack Config](https://github.com/rawphp/serverless-plugin-stack-config)** <br/> A serverless plugin to manage configurations for a stack across micro-services. | [rawphp](http://github.com/rawphp) |
|
||||
| **[Serverless Plugin Stack Outputs](https://github.com/svdgraaf/serverless-plugin-stack-outputs)** <br/> Displays stack outputs for your serverless stacks when `sls info` is ran | [svdgraaf](http://github.com/svdgraaf) |
|
||||
| **[Serverless Plugin Stage Variables](https://github.com/svdgraaf/serverless-plugin-stage-variables)** <br/> Add stage variables for Serverless 1.x to ApiGateway, so you can use variables in your Lambda's | [svdgraaf](http://github.com/svdgraaf) |
|
||||
| **[Serverless Plugin Subscription Filter](https://github.com/tsub/serverless-plugin-subscription-filter)** <br/> A serverless plugin to register AWS CloudWatchLogs subscription filter | [tsub](http://github.com/tsub) |
|
||||
@ -212,14 +238,20 @@ This table is generated from https://github.com/serverless/plugins/blob/master/p
|
||||
| **[Serverless Python Requirements](https://github.com/UnitedIncome/serverless-python-requirements)** <br/> Serverless plugin to bundle Python packages | [UnitedIncome](http://github.com/UnitedIncome) |
|
||||
| **[Serverless Resources Env](https://github.com/rurri/serverless-resources-env)** <br/> After Deploy, this plugin fetches cloudformation resource identifiers and sets them on AWS lambdas, and creates local .<state>-env file | [rurri](http://github.com/rurri) |
|
||||
| **[Serverless Run Function Plugin](https://github.com/lithin/serverless-run-function-plugin)** <br/> Run serverless function locally | [lithin](http://github.com/lithin) |
|
||||
| **[Serverless S3 Remover](https://github.com/sinofseven/serverless-s3-remover)** <br/> A serverless plugin to make s3 buckets empty before deleting cloudformation stack when ```sls remove``` | [sinofseven](http://github.com/sinofseven) |
|
||||
| **[Serverless S3 Sync](https://github.com/k1LoW/serverless-s3-sync)** <br/> A plugin to sync local directories and S3 prefixes for Serverless Framework, | [k1LoW](http://github.com/k1LoW) |
|
||||
| **[Serverless S3bucket Sync](https://github.com/sbstjn/serverless-s3bucket-sync)** <br/> Sync a local folder with a S3 bucket after sls deploy | [sbstjn](http://github.com/sbstjn) |
|
||||
| **[Serverless Sam](https://github.com/SAPessi/serverless-sam)** <br/> Exports an AWS SAM template for a service created with the Serverless Framework. | [SAPessi](http://github.com/SAPessi) |
|
||||
| **[Serverless Scriptable Plugin](https://github.com/weixu365/serverless-scriptable-plugin)** <br/> Customize Serverless behavior without writing a plugin. | [weixu365](http://github.com/weixu365) |
|
||||
| **[Serverless Sentry](https://github.com/arabold/serverless-sentry-plugin)** <br/> Automatic monitoring of memory usage, execution timeouts and forwarding of Lambda errors to Sentry (https://sentry.io). | [arabold](http://github.com/arabold) |
|
||||
| **[Serverless Shell](https://github.com/UnitedIncome/serverless-shell)** <br/> Drop to a runtime shell with all the environment variables set that you'd have in lambda. | [UnitedIncome](http://github.com/UnitedIncome) |
|
||||
| **[Serverless Sqs Alarms Plugin](https://github.com/sbstjn/serverless-sqs-alarms-plugin)** <br/> Wrapper to setup CloudWatch Alarms on SQS queue length | [sbstjn](http://github.com/sbstjn) |
|
||||
| **[Serverless Sqs Fifo](https://github.com/vortarian/serverless-sqs-fifo)** <br/> A serverless plugin to handle creation of sqs fifo queue's in aws (stop-gap) | [vortarian](http://github.com/vortarian) |
|
||||
| **[Serverless Stack Output](https://github.com/sbstjn/serverless-stack-output)** <br/> Store output from your AWS CloudFormation Stack in JSON/YAML/TOML files, or to pass it to a JavaScript function for further processing. | [sbstjn](http://github.com/sbstjn) |
|
||||
| **[Serverless Step Functions](https://github.com/horike37/serverless-step-functions)** <br/> AWS Step Functions with Serverless Framework. | [horike37](http://github.com/horike37) |
|
||||
| **[Serverless Subscription Filter](https://github.com/blackevil245/serverless-subscription-filter)** <br/> Serverless plugin to register subscription filter for Lambda logs. Register and pipe the logs of one lambda to another to process. | [blackevil245](http://github.com/blackevil245) |
|
||||
| **[Serverless Vpc Discovery](https://github.com/amplify-education/serverless-vpc-discovery)** <br/> Serverless plugin for discovering VPC / Subnet / Security Group configuration by name. | [amplify-education](http://github.com/amplify-education) |
|
||||
| **[Serverless Webpack](https://github.com/elastic-coders/serverless-webpack)** <br/> Serverless plugin to bundle your lambdas with Webpack | [elastic-coders](http://github.com/elastic-coders) |
|
||||
| **[Serverless Webpack](https://github.com/serverless-heaven/serverless-webpack)** <br/> Serverless plugin to bundle your lambdas with Webpack | [serverless-heaven](http://github.com/serverless-heaven) |
|
||||
| **[Serverless Wsgi](https://github.com/logandk/serverless-wsgi)** <br/> Serverless plugin to deploy WSGI applications (Flask/Django/Pyramid etc.) and bundle Python packages | [logandk](http://github.com/logandk) |
|
||||
<!-- AUTO-GENERATED-CONTENT:END This table is generated from https://github.com/serverless/plugins/blob/master/plugins.json please make additions there -->
|
||||
|
||||
@ -230,6 +262,7 @@ This table is generated from https://github.com/serverless/examples/blob/master/
|
||||
-->
|
||||
| Project Name | Author |
|
||||
|:-------------|:------:|
|
||||
| **[Jwtauthorizr](https://github.com/serverlessbuch/jwtAuthorizr)** <br/> Custom JWT Authorizer Lambda function for Amazon API Gateway with Bearer JWT | [serverlessbuch](http://github.com/serverlessbuch) |
|
||||
| **[Serverless Graphql Api](https://github.com/boazdejong/serverless-graphql-api)** <br/> Serverless GraphQL API using Lambda and DynamoDB | [boazdejong](http://github.com/boazdejong) |
|
||||
| **[Serverless Screenshot](https://github.com/svdgraaf/serverless-screenshot)** <br/> Serverless Screenshot Service using PhantomJS | [svdgraaf](http://github.com/svdgraaf) |
|
||||
| **[Serverless Postgraphql](https://github.com/rentrop/serverless-postgraphql)** <br/> GraphQL endpoint for PostgreSQL using postgraphql | [rentrop](http://github.com/rentrop) |
|
||||
@ -275,6 +308,14 @@ This table is generated from https://github.com/serverless/examples/blob/master/
|
||||
| **[Aws Api Gateway Serverless Project Written In Go](https://github.com/yunspace/serverless-golang)** <br/> A serverless project that contains an API Gateway endpoint powered by a Lambda function written in golang and built using [eawsy/aws-lambda-go-shim](https://github.com/eawsy/aws-lambda-go-shim). | [yunspace](http://github.com/yunspace) |
|
||||
| **[Video Preview And Analysis Service](https://github.com/laardee/video-preview-and-analysis-service)** <br/> An event-driven service that generates labels using Amazon Rekognition and creates preview GIF animation from a video file. | [laardee](http://github.com/laardee) |
|
||||
| **[Serverless Es6/7 Crud Api](https://github.com/AnomalyInnovations/serverless-stack-demo-api)** <br/> [Serverless Stack](http://serverless-stack.com) examples of backend CRUD APIs (DynamoDB + Lambda + API Gateway + Cognito User Pool authorizer) for [React.js single-page app](http://demo.serverless-stack.com) | [AnomalyInnovations](http://github.com/AnomalyInnovations) |
|
||||
| **[Sqs Worker With Aws Lambda And Cloudwatch Alarms](https://github.com/sbstjn/sqs-worker-serverless)** <br/> Process messages stored in SQS with an [auto-scaled AWS Lambda worker](https://sbstjn.com/serverless-sqs-worker-with-aws-lambda.html) function. | [sbstjn](http://github.com/sbstjn) |
|
||||
| **[Aws Lambda Power Tuning (Powered By Step Functions)](https://github.com/alexcasalboni/aws-lambda-power-tuning)** <br/> Build a [Step Functions](https://aws.amazon.com/step-functions/) state machine to optimize your AWS Lambda Function memory/power configuration. | [alexcasalboni](http://github.com/alexcasalboni) |
|
||||
| **[Amazon Kinesis Streams Fan Out Via Kinesis Analytics](https://github.com/alexcasalboni/kinesis-streams-fan-out-kinesis-analytics)** <br/> Use [Amazon Kinesis Analytics](https://aws.amazon.com/kinesis/analytics/) to fan-out your Kinesis Streams and avoid read throttling. | [alexcasalboni](http://github.com/alexcasalboni) |
|
||||
| **[Grants Api Serverless](https://github.com/comicrelief/grants-api-serverless)** <br/> ES6 API to consume data from an external API, ingest into Elasticsearch and return a queryable endpoint on top of Elasticsearch | [comicrelief](http://github.com/comicrelief) |
|
||||
| **[Honeylambda](https://github.com/0x4D31/honeyLambda)** <br/> a simple, serverless application designed to create and monitor URL {honey}tokens, on top of AWS Lambda and Amazon API Gateway | [0x4D31](http://github.com/0x4D31) |
|
||||
| **[Stack Overflow Monitor](https://github.com/picsoung/stackoverflowmonitor)** <br/> Monitor Stack Overflow questions and post them in a Slack channel | [picsoung](http://github.com/picsoung) |
|
||||
| **[React & Stripe Serverless Ecommerce](https://github.com/patrick-michelberger/serverless-shop)** <br/> Serverless E-Commerce App with AWS Lambda, Stripe and React | [patrick-michelberger](http://github.com/patrick-michelberger) |
|
||||
| **[Serverless + Medium Text To Speech](https://github.com/RafalWilinski/serverless-medium-text-to-speech)** <br/> Serverless-based, text-to-speech service for Medium articles | [RafalWilinski](http://github.com/RafalWilinski) |
|
||||
<!-- AUTO-GENERATED-CONTENT:END This table is generated from https://github.com/serverless/examples/blob/master/community-examples.json please make additions there -->
|
||||
|
||||
## <a name="contributing"></a>Contributing
|
||||
|
||||
@ -39,6 +39,10 @@ services:
|
||||
image: maven:3-jdk-8
|
||||
volumes:
|
||||
- ./tmp/serverless-integration-test-aws-kotlin-jvm-maven:/app
|
||||
aws-kotlin-nodejs-gradle:
|
||||
image: pgoudreau/docker-maven-node
|
||||
volumes:
|
||||
- ./tmp/serverless-integration-test-aws-kotlin-nodejs-gradle:/app
|
||||
aws-groovy-gradle:
|
||||
image: java:8
|
||||
volumes:
|
||||
|
||||
@ -23,7 +23,7 @@ npm install -g serverless
|
||||
serverless login
|
||||
```
|
||||
|
||||
*Serverless follows the [Semantic Versioning](http://semver.org) schema. You can read more about that in our dedicated [versioning file](http://bit.ly/2eP05Iw).*
|
||||
Next up, it's time to choose where you'd like your serverless service to run.
|
||||
|
||||
## Choose your compute provider
|
||||
|
||||
|
||||
@ -46,6 +46,7 @@ Most commonly used templates:
|
||||
- aws-python
|
||||
- aws-python3
|
||||
- aws-kotlin-jvm-maven
|
||||
- aws-kotlin-nodejs-gradle
|
||||
- aws-groovy-gradle
|
||||
- aws-java-maven
|
||||
- aws-java-gradle
|
||||
|
||||
@ -18,16 +18,16 @@ The `sls deploy function` command deploys an individual function without AWS Clo
|
||||
serverless deploy function -f functionName
|
||||
```
|
||||
|
||||
**Note:** Because this command is only deploying the function code, function
|
||||
properties such as environment variables and events will **not** be deployed.
|
||||
Those properties are deployed via CloudFormation, which does not execute with
|
||||
this command.
|
||||
**Note:** This command **now** deploys both function configuration and code by
|
||||
default. Just as before, this puts your function in an inconsistent state that
|
||||
is out of sync with your CloudFormation stack. Use this for faster development
|
||||
cycles and not production deployments
|
||||
|
||||
## Options
|
||||
- `--function` or `-f` The name of the function which should be deployed
|
||||
- `--stage` or `-s` The stage in your service that you want to deploy to.
|
||||
- `--region` or `-r` The region in that stage that you want to deploy to.
|
||||
- `--update-config` or `-u` Pushes Lambda-level configuration changes e.g. timeout or memorySize
|
||||
- `--update-config` or `-u` Pushes ONLY Lambda-level configuration changes e.g. timeout or memorySize
|
||||
|
||||
## Examples
|
||||
|
||||
@ -43,8 +43,8 @@ serverless deploy function --function helloWorld
|
||||
serverless deploy function --function helloWorld --stage dev --region us-east-1
|
||||
```
|
||||
|
||||
### Deployment with configuration change
|
||||
### Deploy only configuration changes
|
||||
|
||||
```bash
|
||||
serverless deploy function --function helloWorld --update-config
|
||||
```
|
||||
```
|
||||
|
||||
@ -96,7 +96,9 @@ This example will pass the json context in the `lib/context.json` file (relative
|
||||
|
||||
### Limitations
|
||||
|
||||
Currently, `invoke local` only supports the NodeJs and Python runtimes.
|
||||
Currently, `invoke local` only supports the NodeJs, Python & Java runtimes.
|
||||
|
||||
**Note:** In order to get correct output when using Java runtime, your Response class must implement `toString()` method.
|
||||
|
||||
## Resource permissions
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ serverless invoke [local] --function functionName
|
||||
|
||||
# Invoke Local
|
||||
|
||||
Invokes a function locally for testing and logs the output. You can only invoke Node.js runtime locally at the moment. Keep in mind that we mock the `context` with simple mock data.
|
||||
Invokes a function locally for testing and logs the output. Keep in mind that we mock the `context` with simple mock data.
|
||||
|
||||
```bash
|
||||
serverless invoke local --function functionName
|
||||
|
||||
@ -56,6 +56,7 @@ Here are the available runtimes for AWS Lambda:
|
||||
* aws-python
|
||||
* aws-python3
|
||||
* aws-kotlin-jvm-maven
|
||||
* aws-kotlin-nodejs-gradle
|
||||
* aws-groovy-gradle
|
||||
* aws-java-gradle
|
||||
* aws-java-maven
|
||||
|
||||
@ -13,8 +13,9 @@ layout: Doc
|
||||
1. Node.js `v6.5.0` or later. *(this is the runtime version supported by Azure Functions)*
|
||||
2. Serverless CLI `v1.9.0` or later. You can run
|
||||
`npm install -g serverless` to install it.
|
||||
3. An Azure account. If you don't already have one, you can sign up for a [free trial](https://azure.microsoft.com/en-us/free/) that includes $200 of free credit.
|
||||
4. **Set-up your [Provider Credentials](./credentials.md)**.
|
||||
3. Azure plugin that allows you to work with Azure Functions `npm install -g serverless-azure-functions`
|
||||
4. An Azure account. If you don't already have one, you can sign up for a [free trial](https://azure.microsoft.com/en-us/free/) that includes $200 of free credit.
|
||||
5. **Set-up your [Provider Credentials](./credentials.md)**.
|
||||
|
||||
## Create a new service
|
||||
|
||||
|
||||
@ -140,6 +140,7 @@ class CLI {
|
||||
this.consoleLog(chalk.yellow.underline('Commands'));
|
||||
this.consoleLog(chalk.dim('* You can run commands with "serverless" or the shortcut "sls"'));
|
||||
this.consoleLog(chalk.dim('* Pass "--verbose" to this command to get in-depth plugin info'));
|
||||
this.consoleLog(chalk.dim('* Pass "--no-color" to disable CLI colors'));
|
||||
this.consoleLog(chalk.dim('* Pass "--help" after any <command> for contextual help'));
|
||||
|
||||
this.consoleLog('');
|
||||
|
||||
@ -67,8 +67,10 @@ class PluginManager {
|
||||
}
|
||||
|
||||
// don't load plugins twice
|
||||
const loadedPlugins = this.plugins.map(plugin => plugin.constructor.name);
|
||||
if (_.includes(loadedPlugins, Plugin.name)) return;
|
||||
if (this.plugins.some(plugin => plugin instanceof Plugin)) {
|
||||
this.serverless.cli.log(`WARNING: duplicate plugin ${Plugin.name} was not loaded\n`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadCommands(pluginInstance);
|
||||
this.loadHooks(pluginInstance);
|
||||
|
||||
@ -546,6 +546,28 @@ describe('PluginManager', () => {
|
||||
expect(pluginManager.plugins.length).to.equal(1);
|
||||
});
|
||||
|
||||
it('should load two plugins that happen to have the same class name', () => {
|
||||
function getFirst() {
|
||||
return class PluginMock {
|
||||
};
|
||||
}
|
||||
|
||||
function getSecond() {
|
||||
return class PluginMock {
|
||||
};
|
||||
}
|
||||
|
||||
const first = getFirst();
|
||||
const second = getSecond();
|
||||
|
||||
pluginManager.addPlugin(first);
|
||||
pluginManager.addPlugin(second);
|
||||
|
||||
expect(pluginManager.plugins[0]).to.be.instanceof(first);
|
||||
expect(pluginManager.plugins[1]).to.be.instanceof(second);
|
||||
expect(pluginManager.plugins.length).to.equal(2);
|
||||
});
|
||||
|
||||
it('should load the plugin commands', () => {
|
||||
pluginManager.addPlugin(SynchronousPluginMock);
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ class Variables {
|
||||
this.cfRefSyntax = RegExp(/^cf:/g);
|
||||
this.s3RefSyntax = RegExp(/^s3:(.+?)\/(.+)$/);
|
||||
this.stringRefSynax = RegExp(/('.*')|(".*")/g);
|
||||
this.ssmRefSyntax = RegExp(/^ssm:([a-zA-Z0-9_.-/]+)[~]?(true|false)?/);
|
||||
this.ssmRefSyntax = RegExp(/^ssm:([a-zA-Z0-9_.\-/]+)[~]?(true|false)?/);
|
||||
}
|
||||
|
||||
loadVariableSyntax() {
|
||||
|
||||
@ -946,21 +946,23 @@ describe('Variables', () => {
|
||||
});
|
||||
|
||||
it('should get variable from Ssm using regular-style param', () => {
|
||||
const param = 'Param-01_valid.chars';
|
||||
const value = 'MockValue';
|
||||
const awsResponseMock = {
|
||||
Parameter: {
|
||||
Value: 'MockValue',
|
||||
Value: value,
|
||||
},
|
||||
};
|
||||
const ssmStub = sinon.stub(awsProvider, 'request').resolves(awsResponseMock);
|
||||
|
||||
return serverless.variables.getValueFromSsm('ssm:param').then(value => {
|
||||
expect(value).to.be.equal('MockValue');
|
||||
return serverless.variables.getValueFromSsm(`ssm:${param}`).then(resolved => {
|
||||
expect(resolved).to.be.equal(value);
|
||||
expect(ssmStub.calledOnce).to.be.equal(true);
|
||||
expect(ssmStub.calledWithExactly(
|
||||
'SSM',
|
||||
'getParameter',
|
||||
{
|
||||
Name: 'param',
|
||||
Name: param,
|
||||
WithDecryption: false,
|
||||
},
|
||||
serverless.variables.options.stage,
|
||||
@ -970,21 +972,23 @@ describe('Variables', () => {
|
||||
});
|
||||
|
||||
it('should get variable from Ssm using path-style param', () => {
|
||||
const param = '/path/to/Param-01_valid.chars';
|
||||
const value = 'MockValue';
|
||||
const awsResponseMock = {
|
||||
Parameter: {
|
||||
Value: 'MockValue',
|
||||
Value: value,
|
||||
},
|
||||
};
|
||||
const ssmStub = sinon.stub(awsProvider, 'request').resolves(awsResponseMock);
|
||||
|
||||
return serverless.variables.getValueFromSsm('ssm:/some/path/to/param').then(value => {
|
||||
expect(value).to.be.equal('MockValue');
|
||||
return serverless.variables.getValueFromSsm(`ssm:${param}`).then(resolved => {
|
||||
expect(resolved).to.be.equal(value);
|
||||
expect(ssmStub.calledOnce).to.be.equal(true);
|
||||
expect(ssmStub.calledWithExactly(
|
||||
'SSM',
|
||||
'getParameter',
|
||||
{
|
||||
Name: '/some/path/to/param',
|
||||
Name: param,
|
||||
WithDecryption: false,
|
||||
},
|
||||
serverless.variables.options.stage,
|
||||
@ -994,21 +998,23 @@ describe('Variables', () => {
|
||||
});
|
||||
|
||||
it('should get encrypted variable from Ssm using extended syntax', () => {
|
||||
const param = '/path/to/Param-01_valid.chars';
|
||||
const value = 'MockValue';
|
||||
const awsResponseMock = {
|
||||
Parameter: {
|
||||
Value: 'MockValue',
|
||||
Value: value,
|
||||
},
|
||||
};
|
||||
const ssmStub = sinon.stub(awsProvider, 'request').resolves(awsResponseMock);
|
||||
|
||||
return serverless.variables.getValueFromSsm('ssm:/some/path/to/param~true').then(value => {
|
||||
expect(value).to.be.equal('MockValue');
|
||||
return serverless.variables.getValueFromSsm(`ssm:${param}~true`).then(resolved => {
|
||||
expect(resolved).to.be.equal(value);
|
||||
expect(ssmStub.calledOnce).to.be.equal(true);
|
||||
expect(ssmStub.calledWithExactly(
|
||||
'SSM',
|
||||
'getParameter',
|
||||
{
|
||||
Name: '/some/path/to/param',
|
||||
Name: param,
|
||||
WithDecryption: true,
|
||||
},
|
||||
serverless.variables.options.stage,
|
||||
@ -1018,21 +1024,23 @@ describe('Variables', () => {
|
||||
});
|
||||
|
||||
it('should get unencrypted variable from Ssm using extended syntax', () => {
|
||||
const param = '/path/to/Param-01_valid.chars';
|
||||
const value = 'MockValue';
|
||||
const awsResponseMock = {
|
||||
Parameter: {
|
||||
Value: 'MockValue',
|
||||
Value: value,
|
||||
},
|
||||
};
|
||||
const ssmStub = sinon.stub(awsProvider, 'request').resolves(awsResponseMock);
|
||||
|
||||
return serverless.variables.getValueFromSsm('ssm:/some/path/to/param~false').then(value => {
|
||||
expect(value).to.be.equal('MockValue');
|
||||
return serverless.variables.getValueFromSsm(`ssm:${param}~false`).then(resolved => {
|
||||
expect(resolved).to.be.equal(value);
|
||||
expect(ssmStub.calledOnce).to.be.equal(true);
|
||||
expect(ssmStub.calledWithExactly(
|
||||
'SSM',
|
||||
'getParameter',
|
||||
{
|
||||
Name: '/some/path/to/param',
|
||||
Name: param,
|
||||
WithDecryption: false,
|
||||
},
|
||||
serverless.variables.options.stage,
|
||||
@ -1042,28 +1050,29 @@ describe('Variables', () => {
|
||||
});
|
||||
|
||||
it('should ignore bad values for extended syntax', () => {
|
||||
const param = '/path/to/Param-01_valid.chars';
|
||||
const value = 'MockValue';
|
||||
const awsResponseMock = {
|
||||
Parameter: {
|
||||
Value: 'MockValue',
|
||||
Value: value,
|
||||
},
|
||||
};
|
||||
const ssmStub = sinon.stub(awsProvider, 'request').resolves(awsResponseMock);
|
||||
|
||||
return serverless.variables.getValueFromSsm('ssm:/some/path/to/param~badvalue')
|
||||
.then(value => {
|
||||
expect(value).to.be.equal('MockValue');
|
||||
expect(ssmStub.calledOnce).to.be.equal(true);
|
||||
expect(ssmStub.calledWithExactly(
|
||||
'SSM',
|
||||
'getParameter',
|
||||
{
|
||||
Name: '/some/path/to/param',
|
||||
WithDecryption: false,
|
||||
},
|
||||
serverless.variables.options.stage,
|
||||
serverless.variables.options.region
|
||||
)).to.be.equal(true);
|
||||
});
|
||||
return serverless.variables.getValueFromSsm(`ssm:${param}~badvalue`).then(resolved => {
|
||||
expect(resolved).to.be.equal(value);
|
||||
expect(ssmStub.calledOnce).to.be.equal(true);
|
||||
expect(ssmStub.calledWithExactly(
|
||||
'SSM',
|
||||
'getParameter',
|
||||
{
|
||||
Name: param,
|
||||
WithDecryption: false,
|
||||
},
|
||||
serverless.variables.options.stage,
|
||||
serverless.variables.options.region
|
||||
)).to.be.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined if SSM parameter does not exist', () => {
|
||||
|
||||
@ -44,7 +44,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
return this.provider.request('S3',
|
||||
'putObject',
|
||||
'upload',
|
||||
params,
|
||||
this.options.stage,
|
||||
this.options.region);
|
||||
@ -73,7 +73,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
return this.provider.request('S3',
|
||||
'putObject',
|
||||
'upload',
|
||||
params,
|
||||
this.options.stage,
|
||||
this.options.region);
|
||||
@ -83,7 +83,7 @@ module.exports = {
|
||||
let shouldUploadService = false;
|
||||
this.serverless.cli.log('Uploading artifacts...');
|
||||
const functionNames = this.serverless.service.getAllFunctions();
|
||||
const uploadPromises = functionNames.map(name => {
|
||||
return BbPromise.map(functionNames, (name) => {
|
||||
const functionArtifactFileName = this.provider.naming.getFunctionArtifactName(name);
|
||||
const functionObject = this.serverless.service.getFunction(name);
|
||||
functionObject.package = functionObject.package || {};
|
||||
@ -100,9 +100,7 @@ module.exports = {
|
||||
return BbPromise.resolve();
|
||||
}
|
||||
return this.uploadZipFile(artifactFilePath);
|
||||
});
|
||||
|
||||
return BbPromise.all(uploadPromises).then(() => {
|
||||
}, { concurrency: 3 }).then(() => {
|
||||
if (shouldUploadService) {
|
||||
const artifactFileName = this.provider.naming.getServiceArtifactName();
|
||||
const artifactFilePath = path.join(this.packagePath, artifactFileName);
|
||||
|
||||
@ -70,13 +70,13 @@ describe('uploadArtifacts', () => {
|
||||
|
||||
describe('#uploadCloudFormationFile()', () => {
|
||||
let normalizeCloudFormationTemplateStub;
|
||||
let putObjectStub;
|
||||
let uploadStub;
|
||||
|
||||
beforeEach(() => {
|
||||
normalizeCloudFormationTemplateStub = sinon
|
||||
.stub(normalizeFiles, 'normalizeCloudFormationTemplate')
|
||||
.returns();
|
||||
putObjectStub = sinon
|
||||
uploadStub = sinon
|
||||
.stub(awsDeploy.provider, 'request')
|
||||
.resolves();
|
||||
});
|
||||
@ -91,10 +91,10 @@ describe('uploadArtifacts', () => {
|
||||
|
||||
return awsDeploy.uploadCloudFormationFile().then(() => {
|
||||
expect(normalizeCloudFormationTemplateStub.calledOnce).to.equal(true);
|
||||
expect(putObjectStub.calledOnce).to.equal(true);
|
||||
expect(putObjectStub.calledWithExactly(
|
||||
expect(uploadStub.calledOnce).to.equal(true);
|
||||
expect(uploadStub.calledWithExactly(
|
||||
'S3',
|
||||
'putObject',
|
||||
'upload',
|
||||
{
|
||||
Bucket: awsDeploy.bucketName,
|
||||
Key: `${awsDeploy.serverless.service.package
|
||||
@ -121,10 +121,10 @@ describe('uploadArtifacts', () => {
|
||||
|
||||
return awsDeploy.uploadCloudFormationFile().then(() => {
|
||||
expect(normalizeCloudFormationTemplateStub.calledOnce).to.equal(true);
|
||||
expect(putObjectStub.calledOnce).to.be.equal(true);
|
||||
expect(putObjectStub.calledWithExactly(
|
||||
expect(uploadStub.calledOnce).to.be.equal(true);
|
||||
expect(uploadStub.calledWithExactly(
|
||||
'S3',
|
||||
'putObject',
|
||||
'upload',
|
||||
{
|
||||
Bucket: awsDeploy.bucketName,
|
||||
Key: `${awsDeploy.serverless.service.package
|
||||
@ -147,13 +147,13 @@ describe('uploadArtifacts', () => {
|
||||
|
||||
describe('#uploadZipFile()', () => {
|
||||
let readFileSyncStub;
|
||||
let putObjectStub;
|
||||
let uploadStub;
|
||||
|
||||
beforeEach(() => {
|
||||
readFileSyncStub = sinon
|
||||
.stub(fs, 'readFileSync')
|
||||
.returns();
|
||||
putObjectStub = sinon
|
||||
uploadStub = sinon
|
||||
.stub(awsDeploy.provider, 'request')
|
||||
.resolves();
|
||||
});
|
||||
@ -175,11 +175,11 @@ describe('uploadArtifacts', () => {
|
||||
serverless.utils.writeFileSync(artifactFilePath, 'artifact.zip file content');
|
||||
|
||||
return awsDeploy.uploadZipFile(artifactFilePath).then(() => {
|
||||
expect(putObjectStub.calledOnce).to.be.equal(true);
|
||||
expect(uploadStub.calledOnce).to.be.equal(true);
|
||||
expect(readFileSyncStub.calledOnce).to.equal(true);
|
||||
expect(putObjectStub.calledWithExactly(
|
||||
expect(uploadStub.calledWithExactly(
|
||||
'S3',
|
||||
'putObject',
|
||||
'upload',
|
||||
{
|
||||
Bucket: awsDeploy.bucketName,
|
||||
Key: `${awsDeploy.serverless.service.package.artifactDirectoryName}/artifact.zip`,
|
||||
@ -207,11 +207,11 @@ describe('uploadArtifacts', () => {
|
||||
};
|
||||
|
||||
return awsDeploy.uploadZipFile(artifactFilePath).then(() => {
|
||||
expect(putObjectStub.calledOnce).to.be.equal(true);
|
||||
expect(uploadStub.calledOnce).to.be.equal(true);
|
||||
expect(readFileSyncStub.calledOnce).to.equal(true);
|
||||
expect(putObjectStub.calledWithExactly(
|
||||
expect(uploadStub.calledWithExactly(
|
||||
'S3',
|
||||
'putObject',
|
||||
'upload',
|
||||
{
|
||||
Bucket: awsDeploy.bucketName,
|
||||
Key: `${awsDeploy.serverless.service.package.artifactDirectoryName}/artifact.zip`,
|
||||
|
||||
4
lib/plugins/aws/invokeLocal/.gitignore
vendored
4
lib/plugins/aws/invokeLocal/.gitignore
vendored
@ -1 +1,5 @@
|
||||
*.pyc
|
||||
java/target
|
||||
java/.project
|
||||
java/.settings
|
||||
java/.classpath
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
const BbPromise = require('bluebird');
|
||||
const _ = require('lodash');
|
||||
const os = require('os');
|
||||
const fs = BbPromise.promisifyAll(require('fs'));
|
||||
const path = require('path');
|
||||
const validate = require('../lib/validate');
|
||||
const chalk = require('chalk');
|
||||
@ -137,8 +138,17 @@ class AwsInvokeLocal {
|
||||
this.options.context);
|
||||
}
|
||||
|
||||
if (runtime === 'java8') {
|
||||
return this.invokeLocalJava(
|
||||
'java',
|
||||
handler,
|
||||
this.serverless.service.package.artifact,
|
||||
this.options.data,
|
||||
this.options.context);
|
||||
}
|
||||
|
||||
throw new this.serverless.classes
|
||||
.Error('You can only invoke Node.js & Python functions locally.');
|
||||
.Error('You can only invoke Node.js, Python & Java functions locally.');
|
||||
}
|
||||
|
||||
invokeLocalPython(runtime, handlerPath, handlerName, event, context) {
|
||||
@ -163,6 +173,68 @@ class AwsInvokeLocal {
|
||||
});
|
||||
}
|
||||
|
||||
callJavaBridge(artifactPath, className, input) {
|
||||
return new BbPromise((resolve) => fs.statAsync(artifactPath).then(() => {
|
||||
const java = spawn('java', [
|
||||
`-DartifactPath=${artifactPath}`,
|
||||
`-DclassName=${className}`,
|
||||
'-jar',
|
||||
path.join(__dirname, 'java', 'target', 'invoke-bridge-1.0.jar'),
|
||||
]);
|
||||
|
||||
this.serverless.cli.log([
|
||||
'In order to get human-readable output,',
|
||||
' please implement "toString()" method of your "ApiGatewayResponse" object.',
|
||||
].join(''));
|
||||
|
||||
java.stdout.on('data', (buf) => this.serverless.cli.consoleLog(buf.toString()));
|
||||
java.stderr.on('data', (buf) => this.serverless.cli.consoleLog(buf.toString()));
|
||||
java.stdin.write(input);
|
||||
java.stdin.end();
|
||||
java.on('close', () => resolve());
|
||||
}).catch(() => {
|
||||
throw new Error(`Artifact ${artifactPath} doesn't exists, please compile it first.`);
|
||||
}));
|
||||
}
|
||||
|
||||
invokeLocalJava(runtime, className, artifactPath, event, customContext) {
|
||||
const timeout = Number(this.options.functionObj.timeout)
|
||||
|| Number(this.serverless.service.provider.timeout)
|
||||
|| 6;
|
||||
const context = {
|
||||
name: this.options.functionObj.name,
|
||||
version: 'LATEST',
|
||||
logGroupName: this.provider.naming.getLogGroupName(this.options.functionObj.name),
|
||||
timeout,
|
||||
};
|
||||
const input = JSON.stringify({
|
||||
event: event || {},
|
||||
context: customContext || context,
|
||||
});
|
||||
|
||||
const javaBridgePath = path.join(__dirname, 'java');
|
||||
const executablePath = path.join(javaBridgePath, 'target');
|
||||
|
||||
return new BbPromise(resolve => fs.statAsync(executablePath)
|
||||
.then(() => this.callJavaBridge(artifactPath, className, input))
|
||||
.then(resolve)
|
||||
.catch(() => {
|
||||
const mvn = spawn('mvn', [
|
||||
'package',
|
||||
'-f',
|
||||
path.join(javaBridgePath, 'pom.xml'),
|
||||
]);
|
||||
|
||||
this.serverless.cli
|
||||
.log('Building Java bridge, first invocation might take a bit longer.');
|
||||
|
||||
mvn.stderr.on('data', (buf) => this.serverless.cli.consoleLog(`mvn - ${buf.toString()}`));
|
||||
mvn.stdin.end();
|
||||
|
||||
mvn.on('close', () => this.callJavaBridge(artifactPath, className, input).then(resolve));
|
||||
}));
|
||||
}
|
||||
|
||||
invokeLocalNodeJs(handlerPath, handlerName, event, customContext) {
|
||||
let lambda;
|
||||
|
||||
|
||||
@ -3,6 +3,9 @@
|
||||
const expect = require('chai').expect;
|
||||
const sinon = require('sinon');
|
||||
const path = require('path');
|
||||
const mockRequire = require('mock-require');
|
||||
const EventEmitter = require('events');
|
||||
const fse = require('fs-extra');
|
||||
const AwsInvokeLocal = require('./index');
|
||||
const AwsProvider = require('../provider/awsProvider');
|
||||
const Serverless = require('../../../Serverless');
|
||||
@ -276,12 +279,15 @@ describe('AwsInvokeLocal', () => {
|
||||
describe('#invokeLocal()', () => {
|
||||
let invokeLocalNodeJsStub;
|
||||
let invokeLocalPythonStub;
|
||||
let invokeLocalJavaStub;
|
||||
|
||||
beforeEach(() => {
|
||||
invokeLocalNodeJsStub =
|
||||
sinon.stub(awsInvokeLocal, 'invokeLocalNodeJs').resolves();
|
||||
invokeLocalPythonStub =
|
||||
sinon.stub(awsInvokeLocal, 'invokeLocalPython').resolves();
|
||||
invokeLocalJavaStub =
|
||||
sinon.stub(awsInvokeLocal, 'invokeLocalJava').resolves();
|
||||
|
||||
awsInvokeLocal.serverless.service.service = 'new-service';
|
||||
awsInvokeLocal.options = {
|
||||
@ -298,6 +304,7 @@ describe('AwsInvokeLocal', () => {
|
||||
afterEach(() => {
|
||||
awsInvokeLocal.invokeLocalNodeJs.restore();
|
||||
awsInvokeLocal.invokeLocalPython.restore();
|
||||
awsInvokeLocal.invokeLocalJava.restore();
|
||||
});
|
||||
|
||||
it('should call invokeLocalNodeJs when no runtime is set', () => awsInvokeLocal.invokeLocal()
|
||||
@ -352,12 +359,26 @@ describe('AwsInvokeLocal', () => {
|
||||
{},
|
||||
undefined
|
||||
)).to.be.equal(true);
|
||||
delete awsInvokeLocal.options.functionObj.runtime;
|
||||
});
|
||||
});
|
||||
|
||||
it('throw error when using runtime other than Node.js or Python', () => {
|
||||
it('should call invokeLocalJava when java8 runtime is set', () => {
|
||||
awsInvokeLocal.options.functionObj.runtime = 'java8';
|
||||
return awsInvokeLocal.invokeLocal()
|
||||
.then(() => {
|
||||
expect(invokeLocalJavaStub.calledOnce).to.be.equal(true);
|
||||
expect(invokeLocalJavaStub.calledWithExactly(
|
||||
'java',
|
||||
'handler.hello',
|
||||
undefined,
|
||||
{},
|
||||
undefined
|
||||
)).to.be.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('throw error when using runtime other than Node.js or Python', () => {
|
||||
awsInvokeLocal.options.functionObj.runtime = 'invalid-runtime';
|
||||
expect(() => awsInvokeLocal.invokeLocal()).to.throw(Error);
|
||||
delete awsInvokeLocal.options.functionObj.runtime;
|
||||
});
|
||||
@ -507,4 +528,183 @@ describe('AwsInvokeLocal', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#callJavaBridge()', () => {
|
||||
let awsInvokeLocalMocked;
|
||||
let writeChildStub;
|
||||
let endChildStub;
|
||||
|
||||
beforeEach(() => {
|
||||
writeChildStub = sinon.stub();
|
||||
endChildStub = sinon.stub();
|
||||
|
||||
mockRequire('child_process', {
|
||||
spawn: () => ({
|
||||
stderr: new EventEmitter().on('data', () => {}),
|
||||
stdout: new EventEmitter().on('data', () => {}),
|
||||
stdin: {
|
||||
write: writeChildStub,
|
||||
end: endChildStub,
|
||||
},
|
||||
on: (key, callback) => callback(),
|
||||
}),
|
||||
});
|
||||
|
||||
// Remove Node.js internal "require cache" contents and re-require ./index.js
|
||||
delete require.cache[require.resolve('./index')];
|
||||
delete require.cache[require.resolve('child_process')];
|
||||
|
||||
const AwsInvokeLocalMocked = require('./index'); // eslint-disable-line global-require
|
||||
|
||||
serverless.setProvider('aws', new AwsProvider(serverless));
|
||||
awsInvokeLocalMocked = new AwsInvokeLocalMocked(serverless, options);
|
||||
|
||||
awsInvokeLocalMocked.options = {
|
||||
stage: 'dev',
|
||||
function: 'first',
|
||||
functionObj: {
|
||||
handler: 'handler.hello',
|
||||
name: 'hello',
|
||||
timeout: 4,
|
||||
},
|
||||
data: {},
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
delete require.cache[require.resolve('./index')];
|
||||
delete require.cache[require.resolve('child_process')];
|
||||
});
|
||||
|
||||
it('spawns java process with correct arguments', () =>
|
||||
awsInvokeLocalMocked.callJavaBridge(
|
||||
__dirname,
|
||||
'com.serverless.Handler',
|
||||
'{}'
|
||||
).then(() => {
|
||||
expect(writeChildStub.calledOnce).to.be.equal(true);
|
||||
expect(endChildStub.calledOnce).to.be.equal(true);
|
||||
expect(writeChildStub.calledWithExactly('{}')).to.be.equal(true);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
describe('#invokeLocalJava()', () => {
|
||||
const bridgePath = path.join(__dirname, 'java', 'target');
|
||||
let callJavaBridgeStub;
|
||||
|
||||
beforeEach(() => {
|
||||
fse.mkdirsSync(bridgePath);
|
||||
callJavaBridgeStub = sinon.stub(awsInvokeLocal, 'callJavaBridge').resolves();
|
||||
awsInvokeLocal.options = {
|
||||
stage: 'dev',
|
||||
function: 'first',
|
||||
functionObj: {
|
||||
handler: 'handler.hello',
|
||||
name: 'hello',
|
||||
timeout: 4,
|
||||
},
|
||||
data: {},
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
awsInvokeLocal.callJavaBridge.restore();
|
||||
fse.removeSync(bridgePath);
|
||||
});
|
||||
|
||||
it('should invoke callJavaBridge when bridge is built', () =>
|
||||
awsInvokeLocal.invokeLocalJava(
|
||||
'java',
|
||||
'com.serverless.Handler',
|
||||
__dirname,
|
||||
{}
|
||||
).then(() => {
|
||||
expect(callJavaBridgeStub.calledOnce).to.be.equal(true);
|
||||
expect(callJavaBridgeStub.calledWithExactly(
|
||||
__dirname,
|
||||
'com.serverless.Handler',
|
||||
JSON.stringify({
|
||||
event: {},
|
||||
context: {
|
||||
name: 'hello',
|
||||
version: 'LATEST',
|
||||
logGroupName: '/aws/lambda/hello',
|
||||
timeout: 4,
|
||||
},
|
||||
})
|
||||
)).to.be.equal(true);
|
||||
})
|
||||
);
|
||||
|
||||
describe('when attempting to build the Java bridge', () => {
|
||||
let awsInvokeLocalMocked;
|
||||
let callJavaBridgeMockedStub;
|
||||
|
||||
beforeEach(() => {
|
||||
mockRequire('child_process', {
|
||||
spawn: () => ({
|
||||
stderr: new EventEmitter().on('data', () => {}),
|
||||
stdout: new EventEmitter().on('data', () => {}),
|
||||
stdin: {
|
||||
write: () => {},
|
||||
end: () => {},
|
||||
},
|
||||
on: (key, callback) => callback(),
|
||||
}),
|
||||
});
|
||||
|
||||
// Remove Node.js internal "require cache" contents and re-require ./index.js
|
||||
delete require.cache[require.resolve('./index')];
|
||||
delete require.cache[require.resolve('child_process')];
|
||||
|
||||
const AwsInvokeLocalMocked = require('./index'); // eslint-disable-line global-require
|
||||
|
||||
serverless.setProvider('aws', new AwsProvider(serverless));
|
||||
awsInvokeLocalMocked = new AwsInvokeLocalMocked(serverless, options);
|
||||
callJavaBridgeMockedStub = sinon.stub(awsInvokeLocalMocked, 'callJavaBridge').resolves();
|
||||
|
||||
awsInvokeLocalMocked.options = {
|
||||
stage: 'dev',
|
||||
function: 'first',
|
||||
functionObj: {
|
||||
handler: 'handler.hello',
|
||||
name: 'hello',
|
||||
timeout: 4,
|
||||
},
|
||||
data: {},
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
awsInvokeLocalMocked.callJavaBridge.restore();
|
||||
delete require.cache[require.resolve('./index')];
|
||||
delete require.cache[require.resolve('child_process')];
|
||||
});
|
||||
|
||||
it('if it\'s not present yet', () =>
|
||||
awsInvokeLocalMocked.invokeLocalJava(
|
||||
'java',
|
||||
'com.serverless.Handler',
|
||||
__dirname,
|
||||
{}
|
||||
).then(() => {
|
||||
expect(callJavaBridgeMockedStub.calledOnce).to.be.equal(true);
|
||||
expect(callJavaBridgeMockedStub.calledWithExactly(
|
||||
__dirname,
|
||||
'com.serverless.Handler',
|
||||
JSON.stringify({
|
||||
event: {},
|
||||
context: {
|
||||
name: 'hello',
|
||||
version: 'LATEST',
|
||||
logGroupName: '/aws/lambda/hello',
|
||||
timeout: 4,
|
||||
},
|
||||
})
|
||||
)).to.be.equal(true);
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
2
lib/plugins/aws/invokeLocal/java/MANIFEST.mf
Normal file
2
lib/plugins/aws/invokeLocal/java/MANIFEST.mf
Normal file
@ -0,0 +1,2 @@
|
||||
Manifest-version: 1.0
|
||||
Main-Class: com.serverless.InvokeBridge
|
||||
71
lib/plugins/aws/invokeLocal/java/pom.xml
Normal file
71
lib/plugins/aws/invokeLocal/java/pom.xml
Normal file
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.serverless</groupId>
|
||||
<artifactId>invoke-bridge</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-lambda-java-core</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-lambda-java-log4j</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.3</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>com.serverless.InvokeBridge</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -0,0 +1,86 @@
|
||||
package com.serverless;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Client;
|
||||
import com.amazonaws.services.lambda.runtime.ClientContext;
|
||||
import com.amazonaws.services.lambda.runtime.CognitoIdentity;
|
||||
import com.amazonaws.services.lambda.runtime.LambdaLogger;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class Context implements com.amazonaws.services.lambda.runtime.Context {
|
||||
private String name;
|
||||
private String version;
|
||||
private String logGroupName;
|
||||
private long endTime;
|
||||
|
||||
Context(String name, String version, String logGroupName, int timeout) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.logGroupName = logGroupName;
|
||||
this.endTime = System.currentTimeMillis() + (timeout * 1000);
|
||||
}
|
||||
|
||||
public String getAwsRequestId() {
|
||||
return "1234567890";
|
||||
}
|
||||
|
||||
public String getLogGroupName() {
|
||||
return this.logGroupName;
|
||||
}
|
||||
|
||||
public String getLogStreamName() {
|
||||
return "LogStream_" + this.name;
|
||||
}
|
||||
|
||||
public String getFunctionName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getFunctionVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public String getInvokedFunctionArn() {
|
||||
return "arn:aws:lambda:serverless:" + this.name;
|
||||
}
|
||||
|
||||
public CognitoIdentity getIdentity() {
|
||||
return new CognitoIdentity() {
|
||||
public String getIdentityId() {
|
||||
return "1";
|
||||
}
|
||||
|
||||
public String getIdentityPoolId() {
|
||||
return "1";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public ClientContext getClientContext() {
|
||||
return new ClientContext() {
|
||||
public Client getClient() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<String, String> getCustom() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<String, String> getEnvironment() {
|
||||
return System.getenv();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public int getRemainingTimeInMillis() {
|
||||
return Math.max(0, (int) (this.endTime - System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
public int getMemoryLimitInMB() {
|
||||
return 1024;
|
||||
}
|
||||
|
||||
public LambdaLogger getLogger() {
|
||||
return System.out::println;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
package com.serverless;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class InvokeBridge {
|
||||
private File artifact;
|
||||
private String className;
|
||||
private Object instance;
|
||||
private Class clazz;
|
||||
|
||||
private InvokeBridge() {
|
||||
this.artifact = new File(new File("."), System.getProperty("artifactPath"));
|
||||
this.className = System.getProperty("className");
|
||||
|
||||
try {
|
||||
HashMap<String, Object> parsedInput = parseInput(getInput());
|
||||
HashMap<String, Object> eventMap = (HashMap<String, Object>) parsedInput.get("event");
|
||||
|
||||
this.instance = this.getInstance();
|
||||
|
||||
System.out.println(this.invoke(eventMap, this.getContext(parsedInput)).toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Context getContext(HashMap<String, Object> parsedInput) {
|
||||
HashMap<String, Object> contextMap = (HashMap<String, Object>) parsedInput.get("context");
|
||||
|
||||
String name = (String) contextMap.getOrDefault("name", "functionName");
|
||||
String version = (String) contextMap.getOrDefault("version", "LATEST");
|
||||
String logGroupName = (String) contextMap.getOrDefault("logGroupName", "logGroup");
|
||||
int timeout = Integer.parseInt(String.valueOf(contextMap.getOrDefault("timeout", 5)));
|
||||
|
||||
return new Context(name, version, logGroupName, timeout);
|
||||
}
|
||||
|
||||
private Object getInstance() throws Exception {
|
||||
URL[] urls = {this.artifact.toURI().toURL()};
|
||||
URLClassLoader child = new URLClassLoader(urls, this.getClass().getClassLoader());
|
||||
|
||||
this.clazz = Class.forName(this.className, true, child);
|
||||
|
||||
return this.clazz.newInstance();
|
||||
}
|
||||
|
||||
private Object invoke(HashMap<String, Object> event, Context context) throws Exception {
|
||||
Method[] methods = this.clazz.getDeclaredMethods();
|
||||
|
||||
return methods[1].invoke(this.instance, event, context);
|
||||
}
|
||||
|
||||
private HashMap<String, Object> parseInput(String input) throws IOException {
|
||||
TypeReference<HashMap<String,Object>> typeRef = new TypeReference<HashMap<String,Object>>() {};
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
JsonNode jsonNode = mapper.readTree(input);
|
||||
|
||||
return mapper.convertValue(jsonNode, typeRef);
|
||||
}
|
||||
|
||||
private String getInput() throws IOException {
|
||||
BufferedReader streamReader = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
|
||||
StringBuilder inputStringBuilder = new StringBuilder();
|
||||
String inputStr;
|
||||
|
||||
while ((inputStr = streamReader.readLine()) != null) {
|
||||
inputStringBuilder.append(inputStr);
|
||||
}
|
||||
|
||||
return inputStringBuilder.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new InvokeBridge();
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@ const validTemplates = [
|
||||
'aws-java-maven',
|
||||
'aws-java-gradle',
|
||||
'aws-kotlin-jvm-maven',
|
||||
'aws-kotlin-nodejs-gradle',
|
||||
'aws-scala-sbt',
|
||||
'aws-csharp',
|
||||
'aws-fsharp',
|
||||
|
||||
@ -228,6 +228,34 @@ describe('Create', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate scaffolding for "aws-kotlin-nodejs-gradle" template', () => {
|
||||
process.chdir(tmpDir);
|
||||
create.options.template = 'aws-kotlin-nodejs-gradle';
|
||||
|
||||
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('build.gradle');
|
||||
expect(dirContent).to.include('gradlew');
|
||||
expect(dirContent).to.include('gradlew.bat');
|
||||
expect(dirContent).to.include('package.json');
|
||||
expect(dirContent).to.include(path.join('gradle', 'wrapper',
|
||||
'gradle-wrapper.jar'));
|
||||
expect(dirContent).to.include(path.join('gradle', 'wrapper',
|
||||
'gradle-wrapper.properties'));
|
||||
expect(dirContent).to.include(path.join('src', 'main', 'kotlin', 'com', 'serverless',
|
||||
'Handler.kt'));
|
||||
expect(dirContent).to.include(path.join('src', 'main', 'kotlin', 'com', 'serverless',
|
||||
'ApiGatewayResponse.kt'));
|
||||
expect(dirContent).to.include(path.join('src', 'main', 'kotlin', 'com', 'serverless',
|
||||
'Response.kt'));
|
||||
expect(dirContent).to.include(path.join('src', 'test', 'kotlin', '.gitkeep'));
|
||||
expect(dirContent).to.include(path.join('.gitignore'));
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate scaffolding for "aws-java-gradle" template', () => {
|
||||
process.chdir(tmpDir);
|
||||
create.options.template = 'aws-java-gradle';
|
||||
|
||||
@ -3,6 +3,7 @@ package com.serverless;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.log4j.BasicConfigurator;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
@ -14,6 +15,8 @@ public class Handler implements RequestHandler<Map<String, Object>, ApiGatewayRe
|
||||
|
||||
@Override
|
||||
public ApiGatewayResponse handleRequest(Map<String, Object> input, Context context) {
|
||||
BasicConfigurator.configure();
|
||||
|
||||
LOG.info("received: " + input);
|
||||
Response responseBody = new Response("Go Serverless v1.x! Your function executed successfully!", input);
|
||||
return ApiGatewayResponse.builder()
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
group 'serverless-kotlin-node'
|
||||
version '1.0-SNAPSHOT'
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.1.1'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin2js'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile (
|
||||
"org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
compileKotlin2Js.kotlinOptions {
|
||||
moduleKind = "commonjs"
|
||||
outputFile = "build/index.js"
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
*.class
|
||||
target
|
||||
/bin/
|
||||
/.settings/
|
||||
.project
|
||||
.classpath
|
||||
.gradle
|
||||
build/
|
||||
|
||||
# Serverless directories
|
||||
.serverless%
|
||||
|
||||
# package directories
|
||||
node_modules
|
||||
jspm_packages
|
||||
BIN
lib/plugins/create/templates/aws-kotlin-nodejs-gradle/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
lib/plugins/create/templates/aws-kotlin-nodejs-gradle/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
#Sat Sep 09 11:10:27 CEST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip
|
||||
172
lib/plugins/create/templates/aws-kotlin-nodejs-gradle/gradlew
vendored
Executable file
172
lib/plugins/create/templates/aws-kotlin-nodejs-gradle/gradlew
vendored
Executable file
@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save ( ) {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
84
lib/plugins/create/templates/aws-kotlin-nodejs-gradle/gradlew.bat
vendored
Executable file
84
lib/plugins/create/templates/aws-kotlin-nodejs-gradle/gradlew.bat
vendored
Executable file
@ -0,0 +1,84 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"kotlin": "^1.1.4"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
# 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-kotlin-nodejs-gradle # 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: nodejs6.10
|
||||
|
||||
# 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
|
||||
|
||||
functions:
|
||||
hello:
|
||||
handler: build/index.Handler
|
||||
|
||||
# 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:
|
||||
# - 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
|
||||
# - 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"
|
||||
@ -0,0 +1,31 @@
|
||||
class ApiGatewayResponse(
|
||||
val statusCode: Int = 200,
|
||||
var body: String? = null,
|
||||
val headers: dynamic,
|
||||
val isBase64Encoded: Boolean = false
|
||||
) {
|
||||
companion object {
|
||||
inline fun build(block: Builder.() -> Unit) = Builder().apply(block).build()
|
||||
}
|
||||
|
||||
class Builder {
|
||||
var statusCode: Int = 200
|
||||
var rawBody: String? = null
|
||||
var headers: dynamic = object{}
|
||||
var objectBody: Response? = null
|
||||
var binaryBody: ByteArray? = null
|
||||
var base64Encoded: Boolean = false
|
||||
|
||||
fun build(): ApiGatewayResponse {
|
||||
var body: String? = null
|
||||
|
||||
when {
|
||||
rawBody != null -> body = rawBody as String
|
||||
objectBody != null -> body = objectBody.toString()
|
||||
binaryBody != null -> body = binaryBody.toString()
|
||||
}
|
||||
|
||||
return ApiGatewayResponse(statusCode, body, headers, base64Encoded)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
@JsName("Handler")
|
||||
public fun Handler(input: dynamic = {}, context: Any, callback: (Any?, ApiGatewayResponse) -> ApiGatewayResponse): Any {
|
||||
println("Received: " + js("JSON.stringify(input)"));
|
||||
|
||||
val responseBody: Response = Response("Go Serverless v1.x! Your Kotlin function executed successfully!", input);
|
||||
val responseHeaders: dynamic = object{}
|
||||
responseHeaders["X-Powered-By"] = "AWS Lambda & serverless"
|
||||
|
||||
return callback(null, ApiGatewayResponse.build {
|
||||
statusCode = 201
|
||||
objectBody = responseBody
|
||||
headers = responseHeaders
|
||||
})
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
class Response(message: String, input: dynamic) {
|
||||
val message: String = message
|
||||
get
|
||||
val input: dynamic = input
|
||||
get
|
||||
|
||||
override fun toString(): String {
|
||||
val stringified = js("JSON.stringify(this.input)")
|
||||
|
||||
return "{\"$message\": ${stringified} }";
|
||||
}
|
||||
}
|
||||
@ -24,4 +24,3 @@ functions:
|
||||
- http:
|
||||
method: get
|
||||
path: second
|
||||
integration: lambda
|
||||
|
||||
@ -1,3 +1,11 @@
|
||||
export const hello = (event, context, cb) => cb(null,
|
||||
{ message: 'Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!', event }
|
||||
);
|
||||
export const hello = (event, context, cb) => {
|
||||
const response = {
|
||||
statusCode: 200,
|
||||
body: JSON.stringify({
|
||||
message: 'Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!',
|
||||
input: event,
|
||||
}),
|
||||
};
|
||||
|
||||
cb(null, response);
|
||||
}
|
||||
|
||||
@ -7,10 +7,10 @@
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"serverless-webpack": "^2.2.0",
|
||||
"ts-loader": "^2.3.1",
|
||||
"typescript": "^2.4.2",
|
||||
"webpack": "^3.3.0"
|
||||
"serverless-webpack": "^3.0.0",
|
||||
"ts-loader": "^2.3.7",
|
||||
"typescript": "^2.5.2",
|
||||
"webpack": "^3.6.0"
|
||||
},
|
||||
"author": "The serverless webpack authors (https://github.com/elastic-coders/serverless-webpack)",
|
||||
"license": "MIT"
|
||||
|
||||
@ -10,13 +10,9 @@ provider:
|
||||
runtime: nodejs6.10
|
||||
|
||||
functions:
|
||||
# Example with LAMBDA-PROXY integration
|
||||
# Invoking locally:
|
||||
# sls webpack invoke -f hello
|
||||
hello:
|
||||
handler: handler.hello
|
||||
events:
|
||||
- http:
|
||||
method: get
|
||||
path: hello
|
||||
integration: lambda
|
||||
|
||||
@ -1,9 +1,17 @@
|
||||
const path = require('path');
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
const slsw = require('serverless-webpack');
|
||||
|
||||
module.exports = {
|
||||
entry: slsw.lib.entries,
|
||||
resolve: {
|
||||
extensions: [
|
||||
'.js',
|
||||
'.jsx',
|
||||
'.json',
|
||||
'.ts',
|
||||
'.tsx'
|
||||
]
|
||||
},
|
||||
output: {
|
||||
libraryTarget: 'commonjs',
|
||||
path: path.join(__dirname, '.webpack'),
|
||||
|
||||
11
lib/utils/log/serverlessLog.js
Normal file
11
lib/utils/log/serverlessLog.js
Normal file
@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const chalk = require('chalk');
|
||||
|
||||
const log = function (message) {
|
||||
console.log(`Serverless: ${chalk.yellow(message)}`);
|
||||
};
|
||||
|
||||
module.exports = log;
|
||||
@ -5,6 +5,8 @@ const BbPromise = require('bluebird');
|
||||
const fs = BbPromise.promisifyAll(require('fs'));
|
||||
const _ = require('lodash');
|
||||
const os = require('os');
|
||||
const chalk = require('chalk');
|
||||
const log = require('./log/serverlessLog');
|
||||
|
||||
const findKeyChain = (astContent) => {
|
||||
let content = astContent;
|
||||
@ -24,6 +26,16 @@ const parseAST = (ymlAstContent, astObject) => {
|
||||
let newAstObject = astObject || {};
|
||||
if (ymlAstContent.mappings && _.isArray(ymlAstContent.mappings)) {
|
||||
_.forEach(ymlAstContent.mappings, (v) => {
|
||||
if (!v.value) {
|
||||
const errorMessage = [
|
||||
'Serverless: ',
|
||||
`${chalk.red('Your serverless.yml has an invalid value with key:')} `,
|
||||
`${chalk.red(`"${v.key.value}"`)}`,
|
||||
].join('');
|
||||
log(errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (v.key.kind === 0 && v.value.kind === 0) {
|
||||
newAstObject[findKeyChain(v)] = v.value;
|
||||
} else if (v.key.kind === 0 && v.value.kind === 2) {
|
||||
|
||||
@ -20,7 +20,7 @@ describe('#yamlAstParser', () => {
|
||||
it('should add a top level object and item into the yaml file', () => {
|
||||
const yamlFilePath = path.join(tmpDirPath, 'test.yaml');
|
||||
|
||||
writeFileSync(yamlFilePath, 'serveice: test-service');
|
||||
writeFileSync(yamlFilePath, 'service: test-service');
|
||||
return expect(yamlAstParser.addNewArrayItem(yamlFilePath, 'toplevel', 'foo'))
|
||||
.to.be.fulfilled.then(() => {
|
||||
const yaml = readFileSync(yamlFilePath, 'utf8');
|
||||
@ -44,7 +44,7 @@ describe('#yamlAstParser', () => {
|
||||
it('should add a multiple level object and item into the yaml file', () => {
|
||||
const yamlFilePath = path.join(tmpDirPath, 'test.yaml');
|
||||
|
||||
writeFileSync(yamlFilePath, 'serveice: test-service');
|
||||
writeFileSync(yamlFilePath, 'service: test-service');
|
||||
return expect(yamlAstParser.addNewArrayItem(yamlFilePath, 'toplevel.second.third', 'foo'))
|
||||
.to.be.fulfilled.then(() => {
|
||||
const yaml = readFileSync(yamlFilePath, 'utf8');
|
||||
@ -90,6 +90,18 @@ describe('#yamlAstParser', () => {
|
||||
expect(yaml.toplevel).to.be.deep.equal(['foo']);
|
||||
});
|
||||
});
|
||||
|
||||
it('should survive with invalid yaml', () => {
|
||||
const yamlFilePath = path.join(tmpDirPath, 'test.yaml');
|
||||
|
||||
writeFileSync(yamlFilePath, 'service:');
|
||||
return expect(yamlAstParser.addNewArrayItem(yamlFilePath, 'toplevel', 'foo'))
|
||||
.to.be.fulfilled.then(() => {
|
||||
const yaml = readFileSync(yamlFilePath, 'utf8');
|
||||
expect(yaml).to.have.property('toplevel');
|
||||
expect(yaml.toplevel).to.be.deep.equal(['foo']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#removeExistingArrayItem()', () => {
|
||||
|
||||
@ -18,6 +18,7 @@ integration-test aws-nodejs
|
||||
integration-test aws-python
|
||||
integration-test aws-python3
|
||||
integration-test aws-kotlin-jvm-maven
|
||||
integration-test aws-kotlin-nodejs-gradle
|
||||
integration-test aws-nodejs-typescript
|
||||
integration-test aws-nodejs-ecma-script
|
||||
integration-test google-nodejs
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user