node-lambda 0.20.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/workflow.yml +23 -5
- package/CHANGELOG.md +16 -0
- package/README.md +97 -70
- package/bin/node-lambda +7 -3
- package/lib/.env.example +2 -2
- package/lib/aws.js +1 -1
- package/lib/cloudwatch_logs.js +1 -1
- package/lib/main.js +75 -27
- package/lib/s3_deploy.js +3 -2
- package/lib/s3_events.js +2 -2
- package/lib/schedule_events.js +1 -1
- package/package.json +14 -14
- package/test/main.js +301 -113
- package/test/node-lambda.js +2 -1
- package/test/s3_deploy.js +1 -0
- package/test/s3_events.js +1 -1
|
@@ -3,14 +3,13 @@ name: Node CI
|
|
|
3
3
|
on: [push, pull_request]
|
|
4
4
|
|
|
5
5
|
jobs:
|
|
6
|
-
test:
|
|
7
|
-
name: Test on node ${{ matrix.node-version }} and
|
|
8
|
-
runs-on:
|
|
6
|
+
ubuntu-test:
|
|
7
|
+
name: Test on node ${{ matrix.node-version }} and Ubuntu
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
9
|
strategy:
|
|
10
10
|
fail-fast: false
|
|
11
11
|
matrix:
|
|
12
|
-
node-version: [
|
|
13
|
-
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
12
|
+
node-version: [14.x, 16.x, 18.x]
|
|
14
13
|
steps:
|
|
15
14
|
- uses: actions/checkout@v2
|
|
16
15
|
- uses: actions/setup-node@v2
|
|
@@ -22,3 +21,22 @@ jobs:
|
|
|
22
21
|
- run: npm -v
|
|
23
22
|
- run: npm ci
|
|
24
23
|
- run: npm test
|
|
24
|
+
|
|
25
|
+
mac-and-windows-test:
|
|
26
|
+
name: Test on node latest and ${{ matrix.os }}
|
|
27
|
+
runs-on: ${{ matrix.os }}
|
|
28
|
+
strategy:
|
|
29
|
+
fail-fast: false
|
|
30
|
+
matrix:
|
|
31
|
+
os: [windows-latest, macos-latest]
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v2
|
|
34
|
+
- uses: actions/setup-node@v2
|
|
35
|
+
with:
|
|
36
|
+
node-version: 18.x
|
|
37
|
+
cache: 'npm'
|
|
38
|
+
- run: npm i -g npm
|
|
39
|
+
- run: node -v
|
|
40
|
+
- run: npm -v
|
|
41
|
+
- run: npm ci
|
|
42
|
+
- run: npm test
|
package/CHANGELOG.md
CHANGED
|
@@ -440,3 +440,19 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
440
440
|
- fix(_uploadExisting): fix function update errors [#575](https://github.com/motdotla/node-lambda/pull/575)
|
|
441
441
|
- test: fix npm install test failing in some cases [#569](https://github.com/motdotla/node-lambda/pull/569)
|
|
442
442
|
- Clean the tmp dir during `_archivePrebuilt` to match `_buildAndArchive` behavior [#518](https://github.com/motdotla/node-lambda/pull/518)
|
|
443
|
+
|
|
444
|
+
## [0.21.0] - 2021-11-10
|
|
445
|
+
### Features
|
|
446
|
+
- feat: support for yarn [#581](https://github.com/motdotla/node-lambda/pull/581)
|
|
447
|
+
|
|
448
|
+
## [0.22.0] - 2022-02-17
|
|
449
|
+
### Features
|
|
450
|
+
- Support for Architectures parameter [#591](https://github.com/motdotla/node-lambda/pull/591)
|
|
451
|
+
### Bugfixes
|
|
452
|
+
- fix: skip installing the package, when there is no `package.json` [#589](https://github.com/motdotla/node-lambda/pull/589)
|
|
453
|
+
|
|
454
|
+
## [1.0.0] - 2022-05-19
|
|
455
|
+
### Features
|
|
456
|
+
- feat: remove BUILD from the exclusion list [#607](https://github.com/motdotla/node-lambda/pull/607)
|
|
457
|
+
- BREAKING CHANGES
|
|
458
|
+
- add nodejs16.x to runtime [#605](https://github.com/motdotla/node-lambda/pull/605)
|
package/README.md
CHANGED
|
@@ -64,6 +64,7 @@ $ echo -e ".env\ndeploy.env\nevent.json\n.lambda" >> .gitignore
|
|
|
64
64
|
##### Deploy env variables
|
|
65
65
|
|
|
66
66
|
```
|
|
67
|
+
PACKAGE_MANAGER // (default: 'npm')
|
|
67
68
|
AWS_ENVIRONMENT // (default: '')
|
|
68
69
|
AWS_ENDPOINT // (default: '')
|
|
69
70
|
CONFIG_FILE // (default: '')
|
|
@@ -80,8 +81,9 @@ AWS_ROLE_ARN || AWS_ROLE // (default: 'missing')
|
|
|
80
81
|
AWS_MEMORY_SIZE // (default: 128)
|
|
81
82
|
AWS_TIMEOUT // (default: 60)
|
|
82
83
|
AWS_RUN_TIMEOUT // (default: 3)
|
|
84
|
+
AWS_ARCHITECTURE // (default: 'x86_64')
|
|
83
85
|
AWS_DESCRIPTION // (default: package.json.description or '')
|
|
84
|
-
AWS_RUNTIME // (default: '
|
|
86
|
+
AWS_RUNTIME // (default: 'nodejs16.x')
|
|
85
87
|
AWS_PUBLISH // (default: false)
|
|
86
88
|
AWS_FUNCTION_VERSION // (default: '')
|
|
87
89
|
AWS_VPC_SUBNETS // (default: '')
|
|
@@ -109,23 +111,21 @@ Runs your Amazon Lambda index.js file locally. Passes `event.json` data to the A
|
|
|
109
111
|
|
|
110
112
|
```
|
|
111
113
|
$ node-lambda run --help
|
|
112
|
-
|
|
113
|
-
Usage: run|execute [options]
|
|
114
|
+
Usage: node-lambda run|execute [options]
|
|
114
115
|
|
|
115
116
|
Run your Amazon Lambda application locally
|
|
116
117
|
|
|
117
|
-
|
|
118
118
|
Options:
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
-
|
|
125
|
-
-
|
|
126
|
-
-
|
|
127
|
-
|
|
128
|
-
--
|
|
119
|
+
-H, --handler [AWS_HANDLER] Lambda Handler {index.handler} (default: "index.handler")
|
|
120
|
+
-j, --eventFile [EVENT_FILE] Event JSON File (default: "event.json")
|
|
121
|
+
-u, --runtime [AWS_RUNTIME] Lambda Runtime (default: "nodejs16.x")
|
|
122
|
+
-t, --timeout [AWS_RUN_TIMEOUT] Lambda Timeout (default: 3)
|
|
123
|
+
-f, --configFile [CONFIG_FILE] Path to file holding secret environment variables (e.g. "deploy.env") (default: "")
|
|
124
|
+
-x, --contextFile [CONTEXT_FILE] Context JSON File (default: "context.json")
|
|
125
|
+
-M, --enableRunMultipleEvents [ENABLE_RUN_MULTIPLE_EVENTS] Enable run multiple events (default: true)
|
|
126
|
+
-y, --proxy [PROXY] Proxy server (default: "")
|
|
127
|
+
--apiGateway Convert to API Gateway events (default: false)
|
|
128
|
+
-h, --help display help for command
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
#### package
|
|
@@ -134,24 +134,26 @@ Bundles your application into a local zip file.
|
|
|
134
134
|
|
|
135
135
|
```
|
|
136
136
|
$ node-lambda package --help
|
|
137
|
-
|
|
138
|
-
Usage: package|zip [options]
|
|
137
|
+
Usage: node-lambda package|zip [options]
|
|
139
138
|
|
|
140
139
|
Create zipped package for Amazon Lambda deployment
|
|
141
140
|
|
|
142
|
-
|
|
143
141
|
Options:
|
|
144
|
-
|
|
145
|
-
-A, --packageDirectory [
|
|
146
|
-
-I, --dockerImage [] Docker image for npm
|
|
147
|
-
-n, --functionName [
|
|
148
|
-
-H, --handler [
|
|
149
|
-
-e, --environment [
|
|
150
|
-
-x, --excludeGlobs [
|
|
151
|
-
|
|
152
|
-
-
|
|
153
|
-
-
|
|
154
|
-
|
|
142
|
+
--packageManager [PACKAGE_MANAGER] Package manager used to install dependencies (default: "npm", options: "npm", "yarn")
|
|
143
|
+
-A, --packageDirectory [PACKAGE_DIRECTORY] Local Package Directory
|
|
144
|
+
-I, --dockerImage [DOCKER_IMAGE] Docker image for npm ci (default: "")
|
|
145
|
+
-n, --functionName [AWS_FUNCTION_NAME] Lambda FunctionName (default: "node-lambda")
|
|
146
|
+
-H, --handler [AWS_HANDLER] Lambda Handler {index.handler} (default: "index.handler")
|
|
147
|
+
-e, --environment [AWS_ENVIRONMENT] Choose environment {dev, staging, production} (default: "")
|
|
148
|
+
-x, --excludeGlobs [EXCLUDE_GLOBS] Space-separated glob pattern(s) for additional exclude files (e.g.
|
|
149
|
+
"event.json dotenv.sample") (default: "")
|
|
150
|
+
-D, --prebuiltDirectory [PREBUILT_DIRECTORY] Prebuilt directory (default: "")
|
|
151
|
+
-m, --keepNodeModules [KEEP_NODE_MODULES] Keep the current node_modules directory. (default: false)
|
|
152
|
+
-v, --dockerVolumes [DOCKER_VOLUMES] Additional docker volumes to mount. Each volume definition has to be
|
|
153
|
+
separated by a space (e.g. "$HOME/.gitconfig:/etc/gitconfig
|
|
154
|
+
$HOME/.ssh:/root/.ssh") (default: "")
|
|
155
|
+
--no-optionalDependencies Run `npm install` with `--no-optional`
|
|
156
|
+
-h, --help display help for command
|
|
155
157
|
```
|
|
156
158
|
|
|
157
159
|
#### deploy
|
|
@@ -160,51 +162,51 @@ Bundles and deploys your application up to Amazon Lambda.
|
|
|
160
162
|
|
|
161
163
|
```
|
|
162
164
|
$ node-lambda deploy --help
|
|
163
|
-
|
|
164
|
-
Usage: deploy [options]
|
|
165
|
+
Usage: node-lambda deploy [options]
|
|
165
166
|
|
|
166
167
|
Deploy your application to Amazon Lambda
|
|
167
168
|
|
|
168
|
-
|
|
169
169
|
Options:
|
|
170
|
-
|
|
171
|
-
-e, --environment [
|
|
172
|
-
-E, --endpoint [AWS_ENDPOINT]
|
|
173
|
-
-a, --accessKey [
|
|
174
|
-
-s, --secretKey [
|
|
175
|
-
-P, --profile []
|
|
176
|
-
-k, --sessionToken []
|
|
177
|
-
-r, --region [us-east-1
|
|
178
|
-
-n, --functionName [
|
|
179
|
-
-H, --handler [
|
|
180
|
-
-o, --role [
|
|
181
|
-
-m, --memorySize [
|
|
182
|
-
-t, --timeout [
|
|
183
|
-
|
|
184
|
-
-
|
|
185
|
-
-
|
|
186
|
-
-
|
|
187
|
-
-
|
|
188
|
-
-
|
|
189
|
-
-
|
|
190
|
-
-
|
|
191
|
-
-
|
|
192
|
-
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
195
|
-
-
|
|
196
|
-
-
|
|
197
|
-
-
|
|
198
|
-
-
|
|
199
|
-
-
|
|
200
|
-
-
|
|
201
|
-
-
|
|
202
|
-
-
|
|
203
|
-
-
|
|
204
|
-
-
|
|
205
|
-
-
|
|
206
|
-
--
|
|
207
|
-
--
|
|
170
|
+
--packageManager [PACKAGE_MANAGER] Package manager used to install dependencies (default: "npm", options: "npm", "yarn")
|
|
171
|
+
-e, --environment [AWS_ENVIRONMENT] Choose environment {dev, staging, production} (default: "")
|
|
172
|
+
-E, --endpoint [AWS_ENDPOINT] Choose endpoint (e.g. localstack, "http://127.0.0.1:4574") (default: "")
|
|
173
|
+
-a, --accessKey [AWS_ACCESS_KEY_ID] AWS Access Key
|
|
174
|
+
-s, --secretKey [AWS_SECRET_ACCESS_KEY] AWS Secret Key
|
|
175
|
+
-P, --profile [AWS_PROFILE] AWS Profile (default: "")
|
|
176
|
+
-k, --sessionToken [AWS_SESSION_TOKEN] AWS Session Token (default: "")
|
|
177
|
+
-r, --region [AWS_REGION] AWS Region (default: "us-east-1,us-west-2,eu-west-1")
|
|
178
|
+
-n, --functionName [AWS_FUNCTION_NAME] Lambda FunctionName (default: "node-lambda")
|
|
179
|
+
-H, --handler [AWS_HANDLER] Lambda Handler {index.handler} (default: "index.handler")
|
|
180
|
+
-o, --role [AWS_ROLE] Amazon Role ARN (default: "missing")
|
|
181
|
+
-m, --memorySize [AWS_MEMORY_SIZE] Lambda Memory Size (default: 128)
|
|
182
|
+
-t, --timeout [AWS_TIMEOUT] Lambda Timeout (default: 60)
|
|
183
|
+
--architecture [AWS_ARCHITECTURE] The instruction set architecture that the function supports. (x86_64|arm64) (default: "x86_64")
|
|
184
|
+
-d, --description [AWS_DESCRIPTION] Lambda Description (default: "Command line tool for locally running and remotely deploying your node.js applications to Amazon Lambda.")
|
|
185
|
+
-u, --runtime [AWS_RUNTIME] Lambda Runtime (default: "nodejs16.x")
|
|
186
|
+
-p, --publish [AWS_PUBLISH] Lambda Publish (default: false)
|
|
187
|
+
-L, --lambdaVersion [AWS_FUNCTION_VERSION] Lambda Function Version (default: "")
|
|
188
|
+
-b, --vpcSubnets [AWS_VPC_SUBNETS] Lambda Function VPC Subnet IDs (comma delimited) (default: "")
|
|
189
|
+
-g, --vpcSecurityGroups [AWS_VPC_SECURITY_GROUPS] Lambda VPC Security Group IDs (comma delimited) (default: "")
|
|
190
|
+
-K, --kmsKeyArn [AWS_KMS_KEY_ARN] Lambda KMS Key ARN (default: "")
|
|
191
|
+
-Q, --deadLetterConfigTargetArn [AWS_DLQ_TARGET_ARN] Lambda DLQ resource
|
|
192
|
+
-c, --tracingConfig [AWS_TRACING_CONFIG] Lambda tracing settings (default: "")
|
|
193
|
+
-l, --layers [AWS_LAYERS] Lambda Layers settings (e.g. "ARN1,ARN2[,..])" (default: "")
|
|
194
|
+
-R, --retentionInDays [AWS_LOGS_RETENTION_IN_DAYS] CloudWatchLogs retentionInDays settings (default: "")
|
|
195
|
+
-G, --sourceDirectory [SRC_DIRECTORY] Path to lambda source Directory (e.g. "./some-lambda") (default: "")
|
|
196
|
+
-I, --dockerImage [DOCKER_IMAGE] Docker image for npm ci (default: "")
|
|
197
|
+
-f, --configFile [CONFIG_FILE] Path to file holding secret environment variables (e.g. "deploy.env") (default: "")
|
|
198
|
+
-S, --eventSourceFile [EVENT_SOURCE_FILE] Path to file holding event source mapping variables (e.g. "event_sources.json") (default: "")
|
|
199
|
+
-x, --excludeGlobs [EXCLUDE_GLOBS] Space-separated glob pattern(s) for additional exclude files (e.g. "event.json dotenv.sample") (default: "")
|
|
200
|
+
-D, --prebuiltDirectory [PREBUILT_DIRECTORY] Prebuilt directory (default: "")
|
|
201
|
+
-T, --deployTimeout [DEPLOY_TIMEOUT] Deploy Timeout (default: 120000)
|
|
202
|
+
-z, --deployZipfile [DEPLOY_ZIPFILE] Deploy zipfile (default: "")
|
|
203
|
+
-B, --deployUseS3 [DEPLOY_USE_S3] Use S3 to deploy. (default: false)
|
|
204
|
+
-i, --imageUri [IMAGE_URI] URI of a container image in the Amazon ECR registry. (default: "")
|
|
205
|
+
-y, --proxy [PROXY] Proxy server (default: "")
|
|
206
|
+
-A, --tags [AWS_TAGS] Tags as key value pairs (e.g. "tagname1=tagvalue1,tagname2=tagvalue2)" (default: "")
|
|
207
|
+
--silent Silent or quiet mode (default: false)
|
|
208
|
+
--no-optionalDependencies Run `npm install` with `--no-optional`
|
|
209
|
+
-h, --help display help for command
|
|
208
210
|
```
|
|
209
211
|
|
|
210
212
|
If you are deploying to a custom endpoint you may also need to pass in an access key/secret. For localstack these can be anything, but cannot be blank:
|
|
@@ -219,7 +221,32 @@ AWS Lambda will let you set environment variables for your function. Use the sam
|
|
|
219
221
|
|
|
220
222
|
## Node.js Runtime Configuration
|
|
221
223
|
|
|
222
|
-
AWS Lambda now supports Node.
|
|
224
|
+
AWS Lambda now supports Node.js 16, Node.js 14 and Node.js 12. Please also check the [Lambda runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html) page.
|
|
225
|
+
|
|
226
|
+
## Use S3 to deploy
|
|
227
|
+
|
|
228
|
+
Use the command line argument `--deployUseS3` or `-B`. (This option is true/false.)
|
|
229
|
+
Example: `% node-lambda deploy -B`
|
|
230
|
+
|
|
231
|
+
You can also set the environment variable `DEPLOY_USE_S3`.
|
|
232
|
+
Example: `DEPLOY_USE_S3=true`
|
|
233
|
+
|
|
234
|
+
Use the environment variable to set the bucket name or S3 key prefix.
|
|
235
|
+
The environment variable name is different for each region. Please set it to the environment variable you want to deploy.
|
|
236
|
+
It can be set in `.env`.
|
|
237
|
+
|
|
238
|
+
Example:
|
|
239
|
+
|
|
240
|
+
```sh
|
|
241
|
+
# S3_<region>_BUCKET
|
|
242
|
+
S3_US_WEST_1_BUCKET=test_aaa
|
|
243
|
+
|
|
244
|
+
# S3_<region>_PREFIX
|
|
245
|
+
S3_US_WEST_1_PREFIX=bbb
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
In this case, the S3 key:
|
|
249
|
+
`test_aaa/bbb/deploy-package-${FunctionName}.zip`
|
|
223
250
|
|
|
224
251
|
## To deploy a container image to Lambda
|
|
225
252
|
|
package/bin/node-lambda
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
'use strict'
|
|
4
4
|
|
|
5
5
|
require('dotenv').config()
|
|
6
|
+
const process = require('process')
|
|
6
7
|
const path = require('path')
|
|
7
8
|
|
|
8
9
|
const lambda = require(path.join(__dirname, '..', 'lib', 'main.js'))
|
|
@@ -11,6 +12,7 @@ const fs = require('fs')
|
|
|
11
12
|
const packageJson = fs.existsSync(path.join(process.cwd(), 'package.json')) ? require(path.join(process.cwd(), 'package.json')) : {}
|
|
12
13
|
const packageJsonName = packageJson.name || 'UnnamedFunction'
|
|
13
14
|
|
|
15
|
+
const PACKAGE_MANAGER = process.env.PACKAGE_MANAGER || 'npm'
|
|
14
16
|
const AWS_ENVIRONMENT = process.env.AWS_ENVIRONMENT || ''
|
|
15
17
|
const AWS_ENDPOINT = process.env.AWS_ENDPOINT || ''
|
|
16
18
|
const CONFIG_FILE = process.env.CONFIG_FILE || ''
|
|
@@ -27,8 +29,9 @@ const AWS_ROLE = process.env.AWS_ROLE_ARN || process.env.AWS_ROLE || 'missing'
|
|
|
27
29
|
const AWS_MEMORY_SIZE = process.env.AWS_MEMORY_SIZE || 128
|
|
28
30
|
const AWS_TIMEOUT = process.env.AWS_TIMEOUT || 60
|
|
29
31
|
const AWS_RUN_TIMEOUT = process.env.AWS_RUN_TIMEOUT || 3
|
|
32
|
+
const AWS_ARCHITECTURE = process.env.AWS_ARCHITECTURE || 'x86_64'
|
|
30
33
|
const AWS_DESCRIPTION = process.env.AWS_DESCRIPTION || packageJson.description || ''
|
|
31
|
-
const AWS_RUNTIME = process.env.AWS_RUNTIME || '
|
|
34
|
+
const AWS_RUNTIME = process.env.AWS_RUNTIME || 'nodejs16.x'
|
|
32
35
|
const AWS_PUBLISH = process.env.AWS_PUBLISH || false
|
|
33
36
|
const AWS_FUNCTION_VERSION = process.env.AWS_FUNCTION_VERSION || ''
|
|
34
37
|
const AWS_VPC_SUBNETS = process.env.AWS_VPC_SUBNETS || ''
|
|
@@ -61,11 +64,10 @@ const DOCKER_VOLUMES = process.env.DOCKER_VOLUMES || ''
|
|
|
61
64
|
const AWS_TAGS = process.env.AWS_TAGS || ''
|
|
62
65
|
const IMAGE_URI = process.env.IMAGE_URI || ''
|
|
63
66
|
|
|
64
|
-
program.showSuggestionAfterError()
|
|
65
|
-
|
|
66
67
|
program
|
|
67
68
|
.command('deploy')
|
|
68
69
|
.description('Deploy your application to Amazon Lambda')
|
|
70
|
+
.option('--packageManager [PACKAGE_MANAGER]', 'Package manager used to install dependencies', PACKAGE_MANAGER)
|
|
69
71
|
.option('-e, --environment [AWS_ENVIRONMENT]', 'Choose environment {dev, staging, production}',
|
|
70
72
|
AWS_ENVIRONMENT)
|
|
71
73
|
.option('-E, --endpoint [AWS_ENDPOINT]', 'Choose endpoint (e.g. localstack, "http://127.0.0.1:4574")',
|
|
@@ -80,6 +82,7 @@ program
|
|
|
80
82
|
.option('-o, --role [AWS_ROLE]', 'Amazon Role ARN', AWS_ROLE)
|
|
81
83
|
.option('-m, --memorySize [AWS_MEMORY_SIZE]', 'Lambda Memory Size', AWS_MEMORY_SIZE)
|
|
82
84
|
.option('-t, --timeout [AWS_TIMEOUT]', 'Lambda Timeout', AWS_TIMEOUT)
|
|
85
|
+
.option('--architecture [AWS_ARCHITECTURE]', 'The instruction set architecture that the function supports. (x86_64|arm64)', AWS_ARCHITECTURE)
|
|
83
86
|
.option('-d, --description [AWS_DESCRIPTION]', 'Lambda Description', AWS_DESCRIPTION)
|
|
84
87
|
.option('-u, --runtime [AWS_RUNTIME]', 'Lambda Runtime', AWS_RUNTIME)
|
|
85
88
|
.option('-p, --publish [AWS_PUBLISH]', 'Lambda Publish', AWS_PUBLISH)
|
|
@@ -123,6 +126,7 @@ program
|
|
|
123
126
|
.command('package')
|
|
124
127
|
.alias('zip')
|
|
125
128
|
.description('Create zipped package for Amazon Lambda deployment')
|
|
129
|
+
.option('--packageManager [PACKAGE_MANAGER]', 'Package manager used to install dependencies', PACKAGE_MANAGER)
|
|
126
130
|
.option('-A, --packageDirectory [PACKAGE_DIRECTORY]', 'Local Package Directory', PACKAGE_DIRECTORY)
|
|
127
131
|
.option('-I, --dockerImage [DOCKER_IMAGE]', 'Docker image for npm ci', DOCKER_IMAGE)
|
|
128
132
|
.option('-n, --functionName [AWS_FUNCTION_NAME]', 'Lambda FunctionName', AWS_FUNCTION_NAME)
|
package/lib/.env.example
CHANGED
|
@@ -10,10 +10,10 @@ AWS_HANDLER=index.handler
|
|
|
10
10
|
AWS_MEMORY_SIZE=128
|
|
11
11
|
AWS_TIMEOUT=3
|
|
12
12
|
AWS_DESCRIPTION=
|
|
13
|
-
AWS_RUNTIME=
|
|
13
|
+
AWS_RUNTIME=nodejs16.x
|
|
14
14
|
AWS_VPC_SUBNETS=
|
|
15
15
|
AWS_VPC_SECURITY_GROUPS=
|
|
16
16
|
AWS_TRACING_CONFIG=
|
|
17
17
|
AWS_LOGS_RETENTION_IN_DAYS=
|
|
18
|
-
EXCLUDE_GLOBS="event.json"
|
|
18
|
+
EXCLUDE_GLOBS="event.json build/"
|
|
19
19
|
PACKAGE_DIRECTORY=build
|
package/lib/aws.js
CHANGED
|
@@ -6,7 +6,7 @@ const proxy = require('proxy-agent')
|
|
|
6
6
|
module.exports = {
|
|
7
7
|
sdk: aws,
|
|
8
8
|
updateConfig (config, region) {
|
|
9
|
-
const awsSecurity = { region
|
|
9
|
+
const awsSecurity = { region }
|
|
10
10
|
|
|
11
11
|
if (config.profile) {
|
|
12
12
|
aws.config.credentials = new aws.SharedIniFileCredentials({
|
package/lib/cloudwatch_logs.js
CHANGED
package/lib/main.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const process = require('process')
|
|
3
4
|
const path = require('path')
|
|
4
5
|
const os = require('os')
|
|
5
6
|
const aws = require(path.join(__dirname, 'aws'))
|
|
@@ -51,7 +52,7 @@ event_sources.json and ${program.eventFile} files as needed.`)
|
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
run (program) {
|
|
54
|
-
if (!['nodejs12.x', 'nodejs14.x'].includes(program.runtime)) {
|
|
55
|
+
if (!['nodejs12.x', 'nodejs14.x', 'nodejs16.x'].includes(program.runtime)) {
|
|
55
56
|
console.error(`Runtime [${program.runtime}] is not supported.`)
|
|
56
57
|
process.exit(254)
|
|
57
58
|
}
|
|
@@ -215,6 +216,7 @@ Emulate only the body of the API Gateway event.
|
|
|
215
216
|
Description: program.description,
|
|
216
217
|
MemorySize: program.memorySize,
|
|
217
218
|
Timeout: program.timeout,
|
|
219
|
+
Architectures: program.architecture ? [program.architecture] : ['x86_64'],
|
|
218
220
|
Publish: (() => {
|
|
219
221
|
if (typeof program.publish === 'boolean') {
|
|
220
222
|
return program.publish
|
|
@@ -334,8 +336,7 @@ Emulate only the body of the API Gateway event.
|
|
|
334
336
|
'.editorconfig',
|
|
335
337
|
'.lambda',
|
|
336
338
|
'deploy.env',
|
|
337
|
-
'*.log'
|
|
338
|
-
path.join('build', path.sep)
|
|
339
|
+
'*.log'
|
|
339
340
|
]
|
|
340
341
|
.concat(program.excludeGlobs ? program.excludeGlobs.split(' ') : [])
|
|
341
342
|
.concat(excludeNodeModules ? [path.join('node_modules')] : [])
|
|
@@ -350,7 +351,7 @@ Emulate only the body of the API Gateway event.
|
|
|
350
351
|
}
|
|
351
352
|
return str
|
|
352
353
|
}).join(',') + '}'
|
|
353
|
-
const dirPatternRegExp = new RegExp(`(${dirBlobs.join('|')})$`)
|
|
354
|
+
const dirPatternRegExp = dirBlobs.length > 0 ? new RegExp(`(${dirBlobs.join('|')})$`) : null
|
|
354
355
|
|
|
355
356
|
return new Promise((resolve, reject) => {
|
|
356
357
|
fs.mkdirs(dest, (err) => {
|
|
@@ -366,10 +367,12 @@ Emulate only the body of the API Gateway event.
|
|
|
366
367
|
if (!minimatch(src, pattern, { matchBase: true })) {
|
|
367
368
|
return true
|
|
368
369
|
}
|
|
370
|
+
|
|
369
371
|
// Directory check. Even if `src` is a directory it will not end with '/'.
|
|
370
|
-
if (!dirPatternRegExp.test(src)) {
|
|
372
|
+
if (dirPatternRegExp === null || !dirPatternRegExp.test(src)) {
|
|
371
373
|
return false
|
|
372
374
|
}
|
|
375
|
+
|
|
373
376
|
return !fs.statSync(src).isDirectory()
|
|
374
377
|
}
|
|
375
378
|
}
|
|
@@ -385,31 +388,73 @@ Emulate only the body of the API Gateway event.
|
|
|
385
388
|
return fs.existsSync(path.join(codeDirectory, 'package-lock.json'))
|
|
386
389
|
}
|
|
387
390
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
// https://nodejs.org/api/child_process.html#child_process_spawning_bat_and_cmd_files_on_windows
|
|
391
|
-
|
|
392
|
-
const installCommand = this._shouldUseNpmCi(codeDirectory)
|
|
393
|
-
? 'ci'
|
|
394
|
-
: 'install'
|
|
395
|
-
const npmInstallBaseOptions = [
|
|
391
|
+
_getNpmInstallCommand (program, codeDirectory) {
|
|
392
|
+
const installOptions = [
|
|
396
393
|
'-s',
|
|
397
|
-
|
|
394
|
+
this._shouldUseNpmCi(codeDirectory) ? 'ci' : 'install',
|
|
398
395
|
'--production',
|
|
399
396
|
'--no-audit'
|
|
400
397
|
]
|
|
401
398
|
|
|
402
399
|
if (program.optionalDependencies === false) {
|
|
403
|
-
|
|
400
|
+
installOptions.push('--no-optional')
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (!program.dockerImage) {
|
|
404
|
+
installOptions.push('--prefix', codeDirectory)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return {
|
|
408
|
+
packageManager: 'npm',
|
|
409
|
+
installOptions
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
_getYarnInstallCommand (program, codeDirectory) {
|
|
414
|
+
const installOptions = [
|
|
415
|
+
'-s',
|
|
416
|
+
'install',
|
|
417
|
+
'--production'
|
|
418
|
+
]
|
|
419
|
+
|
|
420
|
+
if (program.optionalDependencies === false) {
|
|
421
|
+
installOptions.push('--ignore-optional')
|
|
404
422
|
}
|
|
405
423
|
|
|
424
|
+
if (!program.dockerImage) {
|
|
425
|
+
installOptions.push('--cwd', codeDirectory)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
packageManager: 'yarn',
|
|
430
|
+
installOptions
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
_packageInstall (program, codeDirectory) {
|
|
435
|
+
if (!fs.existsSync(path.join(codeDirectory, 'package.json'))) {
|
|
436
|
+
console.log('Skip the installation of the package. (Because package.json is not found.)')
|
|
437
|
+
return
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Run on windows:
|
|
441
|
+
// https://nodejs.org/api/child_process.html#child_process_spawning_bat_and_cmd_files_on_windows
|
|
442
|
+
|
|
443
|
+
const { packageManager, installOptions } = (() => {
|
|
444
|
+
// default npm
|
|
445
|
+
if (program.packageManager === 'yarn') {
|
|
446
|
+
return this._getYarnInstallCommand(program, codeDirectory)
|
|
447
|
+
}
|
|
448
|
+
return this._getNpmInstallCommand(program, codeDirectory)
|
|
449
|
+
})()
|
|
450
|
+
|
|
406
451
|
const paramsOnContainer = (() => {
|
|
407
452
|
// with docker
|
|
408
453
|
let dockerVolumesOptions = []
|
|
409
454
|
program.dockerVolumes && program.dockerVolumes.split(' ').forEach((volume) => {
|
|
410
455
|
dockerVolumesOptions = dockerVolumesOptions.concat(['-v', volume])
|
|
411
456
|
})
|
|
412
|
-
const dockerCommand = [program.dockerImage,
|
|
457
|
+
const dockerCommand = [program.dockerImage, packageManager].concat(installOptions)
|
|
413
458
|
const dockerBaseOptions = [
|
|
414
459
|
'run', '--rm',
|
|
415
460
|
'-v', `${fs.realpathSync(codeDirectory)}:/var/task`,
|
|
@@ -429,17 +474,16 @@ Emulate only the body of the API Gateway event.
|
|
|
429
474
|
})()
|
|
430
475
|
|
|
431
476
|
const paramsOnHost = (() => {
|
|
432
|
-
// simple
|
|
433
|
-
const options = npmInstallBaseOptions.concat(['--prefix', codeDirectory])
|
|
477
|
+
// simple install
|
|
434
478
|
if (process.platform === 'win32') {
|
|
435
479
|
return {
|
|
436
480
|
command: 'cmd.exe',
|
|
437
|
-
options: ['/c',
|
|
481
|
+
options: ['/c', packageManager].concat(installOptions)
|
|
438
482
|
}
|
|
439
483
|
}
|
|
440
484
|
return {
|
|
441
|
-
command:
|
|
442
|
-
options
|
|
485
|
+
command: packageManager,
|
|
486
|
+
options: installOptions
|
|
443
487
|
}
|
|
444
488
|
})()
|
|
445
489
|
|
|
@@ -450,7 +494,7 @@ Emulate only the body of the API Gateway event.
|
|
|
450
494
|
env: process.env
|
|
451
495
|
}, (err) => {
|
|
452
496
|
if (err) return reject(err)
|
|
453
|
-
resolve()
|
|
497
|
+
resolve(packageManager)
|
|
454
498
|
})
|
|
455
499
|
})
|
|
456
500
|
}
|
|
@@ -518,7 +562,7 @@ Emulate only the body of the API Gateway event.
|
|
|
518
562
|
|
|
519
563
|
_codeDirectory () {
|
|
520
564
|
// Why realpathSync?:
|
|
521
|
-
// If tmpdir is symbolic link and npm>=7, `this.
|
|
565
|
+
// If tmpdir is symbolic link and npm>=7, `this._packageInstall()` may not work properly.
|
|
522
566
|
return path.join(fs.realpathSync(os.tmpdir()), `${path.basename(path.resolve('.'))}-lambda`)
|
|
523
567
|
}
|
|
524
568
|
|
|
@@ -569,7 +613,8 @@ Emulate only the body of the API Gateway event.
|
|
|
569
613
|
async _uploadExisting (lambda, params) {
|
|
570
614
|
const functionCodeParams = Object.assign({
|
|
571
615
|
FunctionName: params.FunctionName,
|
|
572
|
-
Publish: params.Publish
|
|
616
|
+
Publish: params.Publish,
|
|
617
|
+
Architectures: params.Architectures
|
|
573
618
|
}, params.Code)
|
|
574
619
|
|
|
575
620
|
const functionConfigParams = {
|
|
@@ -691,8 +736,11 @@ they may not work as expected in the Lambda environment.
|
|
|
691
736
|
console.log('=> Moving files to temporary directory')
|
|
692
737
|
await this._fileCopy(program, lambdaSrcDirectory, codeDirectory, true)
|
|
693
738
|
if (!program.keepNodeModules) {
|
|
694
|
-
console.log(
|
|
695
|
-
await this.
|
|
739
|
+
console.log('=> Running package install')
|
|
740
|
+
const usedPackageManager = await this._packageInstall(program, codeDirectory)
|
|
741
|
+
if (usedPackageManager) {
|
|
742
|
+
console.log(`(Package manager used was '${usedPackageManager}'.)`)
|
|
743
|
+
}
|
|
696
744
|
}
|
|
697
745
|
await this._postInstallScript(program, codeDirectory)
|
|
698
746
|
console.log('=> Zipping deployment package')
|
|
@@ -926,7 +974,7 @@ they may not work as expected in the Lambda environment.
|
|
|
926
974
|
console.log(params)
|
|
927
975
|
|
|
928
976
|
const lambda = new aws.sdk.Lambda({
|
|
929
|
-
region
|
|
977
|
+
region,
|
|
930
978
|
apiVersion: '2015-03-31'
|
|
931
979
|
})
|
|
932
980
|
const scheduleEvents = new ScheduleEvents(aws.sdk, region)
|
package/lib/s3_deploy.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const process = require('process')
|
|
3
4
|
const crypto = require('crypto')
|
|
4
5
|
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#createBucket-property
|
|
5
6
|
const S3_LOCATION_POSSIBLE_VALUES = [
|
|
@@ -34,7 +35,7 @@ class S3Deploy {
|
|
|
34
35
|
constructor (aws, region) {
|
|
35
36
|
// Authenticated `aws` object in `lib/main.js`
|
|
36
37
|
this.s3 = new aws.S3({
|
|
37
|
-
region
|
|
38
|
+
region,
|
|
38
39
|
apiVersion: '2006-03-01'
|
|
39
40
|
})
|
|
40
41
|
}
|
|
@@ -132,7 +133,7 @@ class S3Deploy {
|
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
putPackage (params, region, buffer) {
|
|
135
|
-
const _params = Object.assign({ region
|
|
136
|
+
const _params = Object.assign({ region }, params)
|
|
136
137
|
_params.bucketName = this._bucketName(_params)
|
|
137
138
|
_params.s3Key = this._s3Key(_params)
|
|
138
139
|
|
package/lib/s3_events.js
CHANGED
|
@@ -8,11 +8,11 @@ class S3Events {
|
|
|
8
8
|
constructor (aws, region) {
|
|
9
9
|
// Authenticated `aws` object in `lib/main.js`
|
|
10
10
|
this.lambda = new aws.Lambda({
|
|
11
|
-
region
|
|
11
|
+
region,
|
|
12
12
|
apiVersion: '2015-03-31'
|
|
13
13
|
})
|
|
14
14
|
this.s3 = new aws.S3({
|
|
15
|
-
region
|
|
15
|
+
region,
|
|
16
16
|
apiVersion: '2006-03-01'
|
|
17
17
|
})
|
|
18
18
|
}
|
package/lib/schedule_events.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-lambda",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Command line tool for locally running and remotely deploying your node.js applications to Amazon Lambda.",
|
|
5
5
|
"main": "lib/main.js",
|
|
6
6
|
"directories": {
|
|
@@ -31,26 +31,26 @@
|
|
|
31
31
|
"readmeFilename": "README.md",
|
|
32
32
|
"author": "motdotla",
|
|
33
33
|
"license": "BSD-2-Clause",
|
|
34
|
-
"devDependencies": {
|
|
35
|
-
"aws-sdk-mock": "^5.2.1",
|
|
36
|
-
"chai": "^4.3.4",
|
|
37
|
-
"mocha": "^9.0.1",
|
|
38
|
-
"node-zip": "^1.1.1",
|
|
39
|
-
"standard": "^16.0.3"
|
|
40
|
-
},
|
|
41
34
|
"engines": {
|
|
42
35
|
"node": ">= 10.0.0"
|
|
43
36
|
},
|
|
44
37
|
"dependencies": {
|
|
45
38
|
"archiver": "^5.3.0",
|
|
46
|
-
"aws-sdk": "^2.
|
|
47
|
-
"aws-xray-sdk-core": "^3.3.
|
|
48
|
-
"commander": "^
|
|
39
|
+
"aws-sdk": "^2.1135.0",
|
|
40
|
+
"aws-xray-sdk-core": "^3.3.4",
|
|
41
|
+
"commander": "^9.0.0",
|
|
49
42
|
"continuation-local-storage": "^3.2.1",
|
|
50
|
-
"dotenv": "^
|
|
43
|
+
"dotenv": "^16.0.0",
|
|
51
44
|
"fs-extra": "^10.0.0",
|
|
52
|
-
"klaw": "^
|
|
53
|
-
"minimatch": "^
|
|
45
|
+
"klaw": "^4.0.1",
|
|
46
|
+
"minimatch": "^5.0.0",
|
|
54
47
|
"proxy-agent": "^5.0.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"aws-sdk-mock": "^5.6.2",
|
|
51
|
+
"chai": "^4.3.6",
|
|
52
|
+
"mocha": "^9.2.0",
|
|
53
|
+
"node-zip": "^1.1.1",
|
|
54
|
+
"standard": "^17.0.0"
|
|
55
55
|
}
|
|
56
56
|
}
|
package/test/main.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const process = require('process')
|
|
3
4
|
const path = require('path')
|
|
4
5
|
const os = require('os')
|
|
5
6
|
const fs = require('fs-extra')
|
|
@@ -10,6 +11,7 @@ const awsMock = require('aws-sdk-mock')
|
|
|
10
11
|
awsMock.setSDK(path.resolve('node_modules/aws-sdk'))
|
|
11
12
|
|
|
12
13
|
const originalProgram = {
|
|
14
|
+
packageManager: 'npm',
|
|
13
15
|
environment: 'development',
|
|
14
16
|
accessKey: 'key',
|
|
15
17
|
secretKey: 'secret',
|
|
@@ -20,7 +22,7 @@ const originalProgram = {
|
|
|
20
22
|
memorySize: 128,
|
|
21
23
|
timeout: 3,
|
|
22
24
|
description: '',
|
|
23
|
-
runtime: '
|
|
25
|
+
runtime: 'nodejs16.x',
|
|
24
26
|
deadLetterConfigTargetArn: '',
|
|
25
27
|
tracingConfig: '',
|
|
26
28
|
Layers: '',
|
|
@@ -132,8 +134,8 @@ const _awsRestore = () => {
|
|
|
132
134
|
describe('lib/main', function () {
|
|
133
135
|
if (['win32', 'darwin'].includes(process.platform)) {
|
|
134
136
|
// It seems that it takes time for file operation in Windows and Mac.
|
|
135
|
-
// So set `timeout(
|
|
136
|
-
this.timeout(
|
|
137
|
+
// So set `timeout(120000)` for the whole test.
|
|
138
|
+
this.timeout(120000)
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
let aws = null // mock
|
|
@@ -149,7 +151,7 @@ describe('lib/main', function () {
|
|
|
149
151
|
})
|
|
150
152
|
|
|
151
153
|
it('version should be set', () => {
|
|
152
|
-
assert.equal(lambda.version, '0.
|
|
154
|
+
assert.equal(lambda.version, '1.0.0')
|
|
153
155
|
})
|
|
154
156
|
|
|
155
157
|
describe('_codeDirectory', () => {
|
|
@@ -457,7 +459,6 @@ describe('lib/main', function () {
|
|
|
457
459
|
|
|
458
460
|
describe('_fileCopy', () => {
|
|
459
461
|
before(() => {
|
|
460
|
-
fs.mkdirSync('build')
|
|
461
462
|
fs.mkdirsSync(path.join('__unittest', 'hoge'))
|
|
462
463
|
fs.mkdirsSync(path.join('__unittest', 'fuga'))
|
|
463
464
|
fs.writeFileSync(path.join('__unittest', 'hoge', 'piyo'), '')
|
|
@@ -465,7 +466,7 @@ describe('lib/main', function () {
|
|
|
465
466
|
fs.writeFileSync('fuga', '')
|
|
466
467
|
})
|
|
467
468
|
after(() => {
|
|
468
|
-
['
|
|
469
|
+
['fuga', '__unittest'].forEach((path) => {
|
|
469
470
|
fs.removeSync(path)
|
|
470
471
|
})
|
|
471
472
|
})
|
|
@@ -590,91 +591,254 @@ describe('lib/main', function () {
|
|
|
590
591
|
})
|
|
591
592
|
})
|
|
592
593
|
|
|
593
|
-
describe('
|
|
594
|
+
describe('_getNpmInstallCommand', () => {
|
|
595
|
+
describe('when package-lock.json exists', () => {
|
|
596
|
+
const codeDirectory = '.'
|
|
597
|
+
|
|
598
|
+
it('npm ci', () => {
|
|
599
|
+
const { packageManager, installOptions } = lambda._getNpmInstallCommand(program, codeDirectory)
|
|
600
|
+
assert.equal(packageManager, 'npm')
|
|
601
|
+
assert.deepEqual(installOptions, ['-s', 'ci', '--production', '--no-audit', '--prefix', codeDirectory])
|
|
602
|
+
})
|
|
603
|
+
|
|
604
|
+
it('npm ci with "--no-optional"', () => {
|
|
605
|
+
const { packageManager, installOptions } = lambda._getNpmInstallCommand(
|
|
606
|
+
{
|
|
607
|
+
...program,
|
|
608
|
+
optionalDependencies: false
|
|
609
|
+
},
|
|
610
|
+
codeDirectory
|
|
611
|
+
)
|
|
612
|
+
assert.equal(packageManager, 'npm')
|
|
613
|
+
assert.deepEqual(
|
|
614
|
+
installOptions,
|
|
615
|
+
['-s', 'ci', '--production', '--no-audit', '--no-optional', '--prefix', codeDirectory]
|
|
616
|
+
)
|
|
617
|
+
})
|
|
618
|
+
|
|
619
|
+
it('npm ci on docker', () => {
|
|
620
|
+
const { packageManager, installOptions } = lambda._getNpmInstallCommand(
|
|
621
|
+
{
|
|
622
|
+
...program,
|
|
623
|
+
dockerImage: 'test'
|
|
624
|
+
},
|
|
625
|
+
codeDirectory
|
|
626
|
+
)
|
|
627
|
+
assert.equal(packageManager, 'npm')
|
|
628
|
+
assert.deepEqual(installOptions, ['-s', 'ci', '--production', '--no-audit'])
|
|
629
|
+
})
|
|
630
|
+
})
|
|
631
|
+
|
|
632
|
+
describe('when package-lock.json does not exist', () => {
|
|
633
|
+
const codeDirectory = './test'
|
|
634
|
+
|
|
635
|
+
it('npm install', () => {
|
|
636
|
+
const { packageManager, installOptions } = lambda._getNpmInstallCommand(program, './test')
|
|
637
|
+
assert.equal(packageManager, 'npm')
|
|
638
|
+
assert.deepEqual(installOptions, ['-s', 'install', '--production', '--no-audit', '--prefix', './test'])
|
|
639
|
+
})
|
|
640
|
+
|
|
641
|
+
it('npm install with "--no-optional"', () => {
|
|
642
|
+
const { packageManager, installOptions } = lambda._getNpmInstallCommand(
|
|
643
|
+
{
|
|
644
|
+
...program,
|
|
645
|
+
optionalDependencies: false
|
|
646
|
+
},
|
|
647
|
+
codeDirectory
|
|
648
|
+
)
|
|
649
|
+
assert.equal(packageManager, 'npm')
|
|
650
|
+
assert.deepEqual(
|
|
651
|
+
installOptions,
|
|
652
|
+
['-s', 'install', '--production', '--no-audit', '--no-optional', '--prefix', codeDirectory]
|
|
653
|
+
)
|
|
654
|
+
})
|
|
655
|
+
|
|
656
|
+
it('npm install on docker', () => {
|
|
657
|
+
const { packageManager, installOptions } = lambda._getNpmInstallCommand(
|
|
658
|
+
{
|
|
659
|
+
...program,
|
|
660
|
+
dockerImage: 'test'
|
|
661
|
+
},
|
|
662
|
+
codeDirectory
|
|
663
|
+
)
|
|
664
|
+
assert.equal(packageManager, 'npm')
|
|
665
|
+
assert.deepEqual(installOptions, ['-s', 'install', '--production', '--no-audit'])
|
|
666
|
+
})
|
|
667
|
+
})
|
|
668
|
+
})
|
|
669
|
+
|
|
670
|
+
describe('_getYarnInstallCommand', () => {
|
|
671
|
+
const codeDirectory = '.'
|
|
672
|
+
|
|
673
|
+
it('yarn install', () => {
|
|
674
|
+
const { packageManager, installOptions } = lambda._getYarnInstallCommand(program, codeDirectory)
|
|
675
|
+
assert.equal(packageManager, 'yarn')
|
|
676
|
+
assert.deepEqual(installOptions, ['-s', 'install', '--production', '--cwd', codeDirectory])
|
|
677
|
+
})
|
|
678
|
+
|
|
679
|
+
it('yarn install with "--no-optional"', () => {
|
|
680
|
+
const { packageManager, installOptions } = lambda._getYarnInstallCommand(
|
|
681
|
+
{
|
|
682
|
+
...program,
|
|
683
|
+
optionalDependencies: false
|
|
684
|
+
},
|
|
685
|
+
codeDirectory
|
|
686
|
+
)
|
|
687
|
+
assert.equal(packageManager, 'yarn')
|
|
688
|
+
assert.deepEqual(
|
|
689
|
+
installOptions,
|
|
690
|
+
['-s', 'install', '--production', '--ignore-optional', '--cwd', codeDirectory]
|
|
691
|
+
)
|
|
692
|
+
})
|
|
693
|
+
|
|
694
|
+
it('yarn install on docker', () => {
|
|
695
|
+
const { packageManager, installOptions } = lambda._getYarnInstallCommand(
|
|
696
|
+
{
|
|
697
|
+
...program,
|
|
698
|
+
dockerImage: 'test'
|
|
699
|
+
},
|
|
700
|
+
codeDirectory
|
|
701
|
+
)
|
|
702
|
+
assert.equal(packageManager, 'yarn')
|
|
703
|
+
assert.deepEqual(installOptions, ['-s', 'install', '--production'])
|
|
704
|
+
})
|
|
705
|
+
})
|
|
706
|
+
|
|
707
|
+
describe('_packageInstall', function () {
|
|
594
708
|
_timeout({ this: this, sec: 60 }) // ci should be faster than install
|
|
595
709
|
|
|
596
710
|
// npm treats files as packages when installing, and so removes them.
|
|
597
711
|
// Test with `devDependencies` packages that are not installed with the `--production` option.
|
|
598
712
|
const nodeModulesMocha = path.join(codeDirectory, 'node_modules', 'mocha')
|
|
599
713
|
|
|
714
|
+
const testCleanAndInstall = async (packageManager) => {
|
|
715
|
+
const beforeAwsSdkStat = fs.statSync(path.join(codeDirectory, 'node_modules', 'aws-sdk'))
|
|
716
|
+
|
|
717
|
+
const usedPackageManager = await lambda._packageInstall(
|
|
718
|
+
{
|
|
719
|
+
...program,
|
|
720
|
+
packageManager
|
|
721
|
+
},
|
|
722
|
+
codeDirectory
|
|
723
|
+
)
|
|
724
|
+
assert.equal(usedPackageManager, packageManager)
|
|
725
|
+
|
|
726
|
+
const contents = fs.readdirSync(path.join(codeDirectory, 'node_modules'))
|
|
727
|
+
assert.include(contents, 'dotenv')
|
|
728
|
+
|
|
729
|
+
// To remove and then install.
|
|
730
|
+
// beforeAwsSdkStat.ctimeMs < afterAwsSdkStat.ctimeMs
|
|
731
|
+
const afterAwsSdkStat = fs.statSync(path.join(codeDirectory, 'node_modules', 'aws-sdk'))
|
|
732
|
+
assert.isBelow(beforeAwsSdkStat.ctimeMs, afterAwsSdkStat.ctimeMs)
|
|
733
|
+
|
|
734
|
+
// Not installed with the `--production` option.
|
|
735
|
+
assert.isFalse(fs.existsSync(nodeModulesMocha))
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const beforeEachOptionalDependencies = () => {
|
|
739
|
+
const packageJsonPath = path.join(codeDirectory, 'package.json')
|
|
740
|
+
const packageJson = require(packageJsonPath)
|
|
741
|
+
packageJson.optionalDependencies = { npm: '*' }
|
|
742
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson))
|
|
743
|
+
|
|
744
|
+
// Remove package-lock.json because it does not match the package.json to which optionalDependencies was added.
|
|
745
|
+
fs.removeSync(path.join(codeDirectory, 'package-lock.json'))
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
const testOptionalDependenciesIsInstalled = async (packageManager) => {
|
|
749
|
+
const usedPackageManager = await lambda._packageInstall(
|
|
750
|
+
{
|
|
751
|
+
...program,
|
|
752
|
+
packageManager
|
|
753
|
+
},
|
|
754
|
+
codeDirectory
|
|
755
|
+
)
|
|
756
|
+
assert.equal(usedPackageManager, packageManager)
|
|
757
|
+
|
|
758
|
+
const contents = fs.readdirSync(path.join(codeDirectory, 'node_modules'))
|
|
759
|
+
assert.include(contents, 'npm')
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
const testOptionalDependenciesIsNotInstalled = async (packageManager) => {
|
|
763
|
+
const params = {
|
|
764
|
+
...program,
|
|
765
|
+
packageManager,
|
|
766
|
+
optionalDependencies: false
|
|
767
|
+
}
|
|
768
|
+
const usedPackageManager = await lambda._packageInstall(params, codeDirectory)
|
|
769
|
+
assert.equal(usedPackageManager, packageManager)
|
|
770
|
+
|
|
771
|
+
const contents = fs.readdirSync(path.join(codeDirectory, 'node_modules'))
|
|
772
|
+
assert.notInclude(contents, 'npm')
|
|
773
|
+
}
|
|
774
|
+
|
|
600
775
|
beforeEach(async () => {
|
|
601
776
|
await lambda._cleanDirectory(codeDirectory)
|
|
602
777
|
await lambda._fileCopy(program, '.', codeDirectory, false)
|
|
603
778
|
})
|
|
604
779
|
|
|
605
|
-
describe('
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
const contents = fs.readdirSync(path.join(codeDirectory, 'node_modules'))
|
|
610
|
-
assert.include(contents, 'dotenv')
|
|
611
|
-
|
|
612
|
-
// To remove and then install.
|
|
613
|
-
// beforeAwsSdkStat.ctimeMs < afterAwsSdkStat.ctimeMs
|
|
614
|
-
const afterAwsSdkStat = fs.statSync(path.join(codeDirectory, 'node_modules', 'aws-sdk'))
|
|
615
|
-
assert.isBelow(beforeAwsSdkStat.ctimeMs, afterAwsSdkStat.ctimeMs)
|
|
780
|
+
describe('Use npm', () => {
|
|
781
|
+
describe('when package-lock.json does exist', () => {
|
|
782
|
+
it('should use "npm ci"', () => testCleanAndInstall('npm'))
|
|
783
|
+
})
|
|
616
784
|
|
|
617
|
-
|
|
618
|
-
|
|
785
|
+
describe('when package-lock.json does not exist', () => {
|
|
786
|
+
beforeEach(() => {
|
|
787
|
+
return fs.removeSync(path.join(codeDirectory, 'package-lock.json'))
|
|
619
788
|
})
|
|
620
|
-
})
|
|
621
|
-
})
|
|
622
789
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
790
|
+
it('should use "npm install"', () => {
|
|
791
|
+
const beforeAwsSdkStat = fs.statSync(path.join(codeDirectory, 'node_modules', 'aws-sdk'))
|
|
792
|
+
return lambda._packageInstall(program, codeDirectory).then((usedPackageManager) => {
|
|
793
|
+
assert.equal(usedPackageManager, 'npm')
|
|
794
|
+
|
|
795
|
+
const contents = fs.readdirSync(path.join(codeDirectory, 'node_modules'))
|
|
796
|
+
assert.include(contents, 'dotenv')
|
|
797
|
+
|
|
798
|
+
// Installed packages will remain intact.
|
|
799
|
+
// beforeAwsSdkStat.ctimeMs === afterAwsSdkStat.ctimeMs
|
|
800
|
+
const afterAwsSdkStat = fs.statSync(path.join(codeDirectory, 'node_modules', 'aws-sdk'))
|
|
801
|
+
assert.equal(beforeAwsSdkStat.ctimeMs, afterAwsSdkStat.ctimeMs)
|
|
802
|
+
|
|
803
|
+
// Not installed with the `--production` option.
|
|
804
|
+
assert.isFalse(fs.existsSync(nodeModulesMocha))
|
|
805
|
+
})
|
|
806
|
+
})
|
|
626
807
|
})
|
|
627
808
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
return lambda._npmInstall(program, codeDirectory).then(() => {
|
|
631
|
-
const contents = fs.readdirSync(path.join(codeDirectory, 'node_modules'))
|
|
632
|
-
assert.include(contents, 'dotenv')
|
|
809
|
+
describe('optionalDependencies', () => {
|
|
810
|
+
beforeEach(beforeEachOptionalDependencies)
|
|
633
811
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
assert.equal(beforeAwsSdkStat.ctimeMs, afterAwsSdkStat.ctimeMs)
|
|
812
|
+
describe('No `--no-optionalDependencies`', () => {
|
|
813
|
+
it('optionalDependencies is installed', () => testOptionalDependenciesIsInstalled('npm'))
|
|
814
|
+
})
|
|
638
815
|
|
|
639
|
-
|
|
640
|
-
|
|
816
|
+
describe('With `--no-optionalDependencies`', () => {
|
|
817
|
+
it('optionalDependency is NOT installed', () => testOptionalDependenciesIsNotInstalled('npm'))
|
|
641
818
|
})
|
|
642
819
|
})
|
|
643
820
|
})
|
|
644
821
|
|
|
645
|
-
describe('
|
|
646
|
-
|
|
647
|
-
const packageJsonPath = path.join(codeDirectory, 'package.json')
|
|
648
|
-
const packageJson = require(packageJsonPath)
|
|
649
|
-
packageJson.optionalDependencies = { npm: '*' }
|
|
650
|
-
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson))
|
|
651
|
-
})
|
|
822
|
+
describe('Use yarn', () => {
|
|
823
|
+
it('should use "yarn install"', () => testCleanAndInstall('yarn'))
|
|
652
824
|
|
|
653
|
-
describe('
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
})
|
|
825
|
+
describe('optionalDependencies', () => {
|
|
826
|
+
beforeEach(beforeEachOptionalDependencies)
|
|
827
|
+
|
|
828
|
+
describe('No `--ignore-optionalDependencies`', () => {
|
|
829
|
+
it('optionalDependencies is installed', () => testOptionalDependenciesIsInstalled('yarn'))
|
|
659
830
|
})
|
|
660
|
-
})
|
|
661
831
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
const params = {
|
|
665
|
-
...program,
|
|
666
|
-
optionalDependencies: false
|
|
667
|
-
}
|
|
668
|
-
return lambda._npmInstall(params, codeDirectory).then(() => {
|
|
669
|
-
const contents = fs.readdirSync(path.join(codeDirectory, 'node_modules'))
|
|
670
|
-
assert.notInclude(contents, 'npm')
|
|
671
|
-
})
|
|
832
|
+
describe('With `--ignore-optionalDependencies`', () => {
|
|
833
|
+
it('optionalDependency is NOT installed', () => testOptionalDependenciesIsNotInstalled('yarn'))
|
|
672
834
|
})
|
|
673
835
|
})
|
|
674
836
|
})
|
|
675
837
|
})
|
|
676
838
|
|
|
677
|
-
describe('
|
|
839
|
+
describe('_packageInstall (When codeDirectory contains characters to be escaped)', function () {
|
|
840
|
+
_timeout({ this: this, sec: 30 }) // give it time to build the node modules
|
|
841
|
+
|
|
678
842
|
beforeEach(() => {
|
|
679
843
|
// Since '\' can not be included in the file or directory name in Windows
|
|
680
844
|
const directoryName = process.platform === 'win32'
|
|
@@ -691,14 +855,21 @@ describe('lib/main', function () {
|
|
|
691
855
|
codeDirectory = lambda._codeDirectory()
|
|
692
856
|
})
|
|
693
857
|
|
|
694
|
-
|
|
695
|
-
|
|
858
|
+
const testFunc = async (packageManager) => {
|
|
859
|
+
const usedPackageManager = await lambda._packageInstall(
|
|
860
|
+
{
|
|
861
|
+
...program,
|
|
862
|
+
packageManager
|
|
863
|
+
},
|
|
864
|
+
codeDirectory
|
|
865
|
+
)
|
|
866
|
+
assert.equal(usedPackageManager, packageManager)
|
|
867
|
+
const contents = fs.readdirSync(codeDirectory)
|
|
868
|
+
assert.include(contents, 'node_modules')
|
|
869
|
+
}
|
|
696
870
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
assert.include(contents, 'node_modules')
|
|
700
|
-
})
|
|
701
|
-
})
|
|
871
|
+
it('npm adds node_modules', () => testFunc('npm'))
|
|
872
|
+
it('yarn adds node_modules', () => testFunc('yarn'))
|
|
702
873
|
})
|
|
703
874
|
|
|
704
875
|
describe('_postInstallScript', () => {
|
|
@@ -768,53 +939,70 @@ describe('lib/main', function () {
|
|
|
768
939
|
})
|
|
769
940
|
})
|
|
770
941
|
|
|
771
|
-
describe('_zip', ()
|
|
772
|
-
|
|
773
|
-
_timeout({ this: this, sec: 30 }) // give it time to build the node modules
|
|
774
|
-
return Promise.resolve().then(() => {
|
|
775
|
-
return lambda._cleanDirectory(codeDirectory)
|
|
776
|
-
}).then(() => {
|
|
777
|
-
return lambda._fileCopy(program, '.', codeDirectory, true)
|
|
778
|
-
}).then(() => {
|
|
779
|
-
return lambda._npmInstall(program, codeDirectory)
|
|
780
|
-
}).then(() => {
|
|
781
|
-
if (process.platform !== 'win32') {
|
|
782
|
-
fs.symlinkSync(
|
|
783
|
-
path.join(__dirname, '..', 'bin', 'node-lambda'),
|
|
784
|
-
path.join(codeDirectory, 'node-lambda-link')
|
|
785
|
-
)
|
|
786
|
-
}
|
|
787
|
-
})
|
|
788
|
-
})
|
|
942
|
+
describe('_zip', function () {
|
|
943
|
+
_timeout({ this: this, sec: 60 }) // give it time to zip
|
|
789
944
|
|
|
790
|
-
|
|
791
|
-
|
|
945
|
+
const beforeTask = async (packageManager) => {
|
|
946
|
+
await lambda._cleanDirectory(codeDirectory)
|
|
947
|
+
await lambda._fileCopy(program, '.', codeDirectory, true)
|
|
948
|
+
const usedPackageManager = await lambda._packageInstall(
|
|
949
|
+
{
|
|
950
|
+
...program,
|
|
951
|
+
packageManager
|
|
952
|
+
},
|
|
953
|
+
codeDirectory
|
|
954
|
+
)
|
|
955
|
+
assert.equal(usedPackageManager, packageManager)
|
|
956
|
+
if (process.platform !== 'win32') {
|
|
957
|
+
fs.symlinkSync(
|
|
958
|
+
path.join(__dirname, '..', 'bin', 'node-lambda'),
|
|
959
|
+
path.join(codeDirectory, 'node-lambda-link')
|
|
960
|
+
)
|
|
961
|
+
}
|
|
962
|
+
}
|
|
792
963
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
964
|
+
const testFunc = async (packageManager) => {
|
|
965
|
+
// setup
|
|
966
|
+
await beforeTask(packageManager)
|
|
967
|
+
|
|
968
|
+
// tests
|
|
969
|
+
const data = await lambda._zip(program, codeDirectory)
|
|
970
|
+
const archive = new Zip(data)
|
|
971
|
+
assert.include(archive.files['index.js'].name, 'index.js')
|
|
972
|
+
assert.include(archive.files['bin/node-lambda'].name, 'bin/node-lambda')
|
|
973
|
+
|
|
974
|
+
if (process.platform !== 'win32') {
|
|
975
|
+
const indexJsStat = fs.lstatSync('index.js')
|
|
976
|
+
const binNodeLambdaStat = fs.lstatSync(path.join('bin', 'node-lambda'))
|
|
977
|
+
assert.equal(
|
|
978
|
+
archive.files['index.js'].unixPermissions,
|
|
979
|
+
indexJsStat.mode
|
|
980
|
+
)
|
|
981
|
+
assert.equal(
|
|
982
|
+
archive.files['bin/node-lambda'].unixPermissions,
|
|
983
|
+
binNodeLambdaStat.mode
|
|
984
|
+
)
|
|
985
|
+
|
|
986
|
+
// isSymbolicLink
|
|
987
|
+
assert.include(archive.files['node-lambda-link'].name, 'node-lambda-link')
|
|
988
|
+
assert.equal(
|
|
989
|
+
archive.files['node-lambda-link'].unixPermissions & fs.constants.S_IFMT,
|
|
990
|
+
fs.constants.S_IFLNK
|
|
991
|
+
)
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
describe('Use npm', () => {
|
|
996
|
+
it(
|
|
997
|
+
'Compress the file. `index.js` and `bin/node-lambda` are included and the permission is also preserved.',
|
|
998
|
+
() => testFunc('npm')
|
|
999
|
+
)
|
|
1000
|
+
})
|
|
1001
|
+
describe('Use yarn', () => {
|
|
1002
|
+
it(
|
|
1003
|
+
'Compress the file. `index.js` and `bin/node-lambda` are included and the permission is also preserved.',
|
|
1004
|
+
() => testFunc('yarn')
|
|
1005
|
+
)
|
|
818
1006
|
})
|
|
819
1007
|
})
|
|
820
1008
|
|
package/test/node-lambda.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const assert = require('chai').assert
|
|
4
|
+
const process = require('process')
|
|
4
5
|
const path = require('path')
|
|
5
6
|
const fs = require('fs-extra')
|
|
6
7
|
const spawn = require('child_process').spawn
|
|
@@ -156,7 +157,7 @@ describe('bin/node-lambda', () => {
|
|
|
156
157
|
process.env.AWS_RUNTIME = 'test'
|
|
157
158
|
})
|
|
158
159
|
after(() => {
|
|
159
|
-
process.env.AWS_RUNTIME = '
|
|
160
|
+
process.env.AWS_RUNTIME = 'nodejs16.x'
|
|
160
161
|
})
|
|
161
162
|
|
|
162
163
|
it('`node-lambda run` exitCode is `254` (callback(null))', (done) => {
|
package/test/s3_deploy.js
CHANGED
package/test/s3_events.js
CHANGED