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.
@@ -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 ${{ matrix.os }}
8
- runs-on: ${{ matrix.os }}
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: [10.x, 12.x, 14.x, 16.x]
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: 'nodejs14.x')
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
- -h, --help output usage information
120
- -H, --handler [index.handler] Lambda Handler {index.handler}
121
- -j, --eventFile [event.json] Event JSON File
122
- -u, --runtime [nodejs14.x] Lambda Runtime
123
- -t, --timeout [3] Lambda Timeout
124
- -f, --configFile [] Path to file holding secret environment variables (e.g. "deploy.env")
125
- -x, --contextFile [context.json] Context JSON File
126
- -M, --enableRunMultipleEvents [true] Enable run multiple events
127
- -y, --proxy [] Proxy server
128
- --apiGateway Convert to API Gateway events
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
- -h, --help output usage information
145
- -A, --packageDirectory [build] Local Package Directory
146
- -I, --dockerImage [] Docker image for npm install
147
- -n, --functionName [node-lambda] Lambda FunctionName
148
- -H, --handler [index.handler] Lambda Handler {index.handler}
149
- -e, --environment [development] Choose environment {dev, staging, production}
150
- -x, --excludeGlobs [event.json] Space-separated glob pattern(s) for additional exclude files (e.g. "event.json dotenv.sample")
151
- -D, --prebuiltDirectory [] Prebuilt directory
152
- -m, --keepNodeModules [false] Keep the current node_modules and skip the npm install step
153
- -v, --dockerVolumes [] Additional docker volumes to mount. Each volume definition has to be separated by a space (e.g. "$HOME/.gitconfig:/etc/gitconfig $HOME/.ssh:/root/.ssh"
154
- --no-optionalDependencies Run `npm install` with `--no-optional`
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
- -h, --help output usage information
171
- -e, --environment [development] Choose environment {dev, staging, production}
172
- -E, --endpoint [AWS_ENDPOINT] Choose endpoint (e.g. localstack, "http://127.0.0.1:4574") (default: "")
173
- -a, --accessKey [your_key] AWS Access Key
174
- -s, --secretKey [your_secret] AWS Secret Key
175
- -P, --profile [] AWS Profile
176
- -k, --sessionToken [] AWS Session Token
177
- -r, --region [us-east-1] AWS Region
178
- -n, --functionName [node-lambda] Lambda FunctionName
179
- -H, --handler [index.handler] Lambda Handler {index.handler}
180
- -o, --role [your_amazon_role] Amazon Role ARN
181
- -m, --memorySize [128] Lambda Memory Size
182
- -t, --timeout [3] Lambda Timeout
183
- -d, --description [missing] Lambda Description
184
- -u, --runtime [nodejs14.x] Lambda Runtime
185
- -p, --publish [false] Lambda Publish
186
- -L, --lambdaVersion [] Lambda Function Version
187
- -b, --vpcSubnets [] Lambda Function VPC Subnet IDs (comma delimited)
188
- -g, --vpcSecurityGroups [] Lambda VPC Security Group IDs (comma delimited)
189
- -K, --kmsKeyArn [] Lambda KMS Key ARN
190
- -Q, --deadLetterConfigTargetArn [] Lambda DLQ resource
191
- -c, --tracingConfig [] Lambda tracing settings
192
- -l, --layers [] Lambda Layers settings (e.g. "ARN1,ARN2[,..])" (default: "")
193
- -R, --retentionInDays [] CloudWatchLogs retentionInDays settings
194
- -G, --sourceDirectory [] Path to lambda source Directory (e.g. "./some-lambda")
195
- -I, --dockerImage [] Docker image for npm install
196
- -f, --configFile [] Path to file holding secret environment variables (e.g. "deploy.env")
197
- -S, --eventSourceFile [] Path to file holding event source mapping variables (e.g. "event_sources.json")
198
- -x, --excludeGlobs [event.json] Space-separated glob pattern(s) for additional exclude files (e.g. "event.json dotenv.sample")
199
- -D, --prebuiltDirectory [] Prebuilt directory
200
- -T, --deployTimeout [120000] Deploy Timeout
201
- -z, --deployZipfile [] Deploy zipfile
202
- -B, --deployUseS3 [] Use S3 to deploy.
203
- -i, --imageUri [] URI of a container image in the Amazon ECR registry. (default: "")
204
- -y, --proxy [] Proxy server
205
- -A, --tags [] Tags as key value pairs (e.g. "tagname1=tagvalue1,tagname2=tagvalue2") (default: "")
206
- --silent Silent or quiet mode (default: false)
207
- --no-optionalDependencies Run `npm install` with `--no-optional`
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.js14 and Node.js 12. Please also check the [Lambda runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html) page.
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 || 'nodejs14.x'
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=nodejs14.x
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: region }
9
+ const awsSecurity = { region }
10
10
 
11
11
  if (config.profile) {
12
12
  aws.config.credentials = new aws.SharedIniFileCredentials({
@@ -4,7 +4,7 @@ class CloudWatchLogs {
4
4
  constructor (aws, region) {
5
5
  // Authenticated `aws` object in `lib/main.js`
6
6
  this.lambda = new aws.Lambda({
7
- region: region,
7
+ region,
8
8
  apiVersion: '2015-03-31'
9
9
  })
10
10
  this.cloudwatchlogs = new aws.CloudWatchLogs({
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
- _npmInstall (program, codeDirectory) {
389
- // Run on windows:
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
- installCommand,
394
+ this._shouldUseNpmCi(codeDirectory) ? 'ci' : 'install',
398
395
  '--production',
399
396
  '--no-audit'
400
397
  ]
401
398
 
402
399
  if (program.optionalDependencies === false) {
403
- npmInstallBaseOptions.push('--no-optional')
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, 'npm'].concat(npmInstallBaseOptions)
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 npm install
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', 'npm'].concat(options)
481
+ options: ['/c', packageManager].concat(installOptions)
438
482
  }
439
483
  }
440
484
  return {
441
- command: 'npm',
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._npmInstall()` may not work properly.
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(`=> Running npm ${this._shouldUseNpmCi(codeDirectory) ? 'ci' : 'install'} --production`)
695
- await this._npmInstall(program, codeDirectory)
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: 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: 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: region }, params)
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: region,
11
+ region,
12
12
  apiVersion: '2015-03-31'
13
13
  })
14
14
  this.s3 = new aws.S3({
15
- region: region,
15
+ region,
16
16
  apiVersion: '2006-03-01'
17
17
  })
18
18
  }
@@ -4,7 +4,7 @@ class ScheduleEvents {
4
4
  constructor (aws, region) {
5
5
  // Authenticated `aws` object in `lib/main.js`
6
6
  this.lambda = new aws.Lambda({
7
- region: region,
7
+ region,
8
8
  apiVersion: '2015-03-31'
9
9
  })
10
10
  this.cloudwatchevents = new aws.CloudWatchEvents({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-lambda",
3
- "version": "0.20.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.936.0",
47
- "aws-xray-sdk-core": "^3.3.3",
48
- "commander": "^8.2.0",
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": "^10.0.0",
43
+ "dotenv": "^16.0.0",
51
44
  "fs-extra": "^10.0.0",
52
- "klaw": "^3.0.0",
53
- "minimatch": "^3.0.4",
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: 'nodejs14.x',
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(60000)` for the whole test.
136
- this.timeout(60000)
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.20.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
- ['build', 'fuga', '__unittest'].forEach((path) => {
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('_npmInstall', function () {
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('when package-lock.json does exist', () => {
606
- it('should use "npm ci"', () => {
607
- const beforeAwsSdkStat = fs.statSync(path.join(codeDirectory, 'node_modules', 'aws-sdk'))
608
- return lambda._npmInstall(program, codeDirectory).then(() => {
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
- // Not installed with the `--production` option.
618
- assert.isFalse(fs.existsSync(nodeModulesMocha))
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
- describe('when package-lock.json does not exist', () => {
624
- beforeEach(() => {
625
- return fs.removeSync(path.join(codeDirectory, 'package-lock.json'))
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
- it('should use "npm install"', () => {
629
- const beforeAwsSdkStat = fs.statSync(path.join(codeDirectory, 'node_modules', 'aws-sdk'))
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
- // Installed packages will remain intact.
635
- // beforeAwsSdkStat.ctimeMs === afterAwsSdkStat.ctimeMs
636
- const afterAwsSdkStat = fs.statSync(path.join(codeDirectory, 'node_modules', 'aws-sdk'))
637
- assert.equal(beforeAwsSdkStat.ctimeMs, afterAwsSdkStat.ctimeMs)
812
+ describe('No `--no-optionalDependencies`', () => {
813
+ it('optionalDependencies is installed', () => testOptionalDependenciesIsInstalled('npm'))
814
+ })
638
815
 
639
- // Not installed with the `--production` option.
640
- assert.isFalse(fs.existsSync(nodeModulesMocha))
816
+ describe('With `--no-optionalDependencies`', () => {
817
+ it('optionalDependency is NOT installed', () => testOptionalDependenciesIsNotInstalled('npm'))
641
818
  })
642
819
  })
643
820
  })
644
821
 
645
- describe('optionalDependencies', () => {
646
- beforeEach(() => {
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('No `--no-optionalDependencies`', () => {
654
- it('optionalDependencies is installed', () => {
655
- return lambda._npmInstall(program, codeDirectory).then(() => {
656
- const contents = fs.readdirSync(path.join(codeDirectory, 'node_modules'))
657
- assert.include(contents, 'npm')
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
- describe('With `--no-optionalDependencies`', () => {
663
- it('optionalDependency is NOT installed', () => {
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('_npmInstall (When codeDirectory contains characters to be escaped)', () => {
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
- it('_npm adds node_modules', function () {
695
- _timeout({ this: this, sec: 30 }) // give it time to build the node modules
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
- return lambda._npmInstall(program, codeDirectory).then(() => {
698
- const contents = fs.readdirSync(codeDirectory)
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
- beforeEach(function () {
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
- it('Compress the file. `index.js` and `bin/node-lambda` are included and the permission is also preserved.', function () {
791
- _timeout({ this: this, sec: 30 }) // give it time to zip
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
- return lambda._zip(program, codeDirectory).then((data) => {
794
- const archive = new Zip(data)
795
- assert.include(archive.files['index.js'].name, 'index.js')
796
- assert.include(archive.files['bin/node-lambda'].name, 'bin/node-lambda')
797
-
798
- if (process.platform !== 'win32') {
799
- const indexJsStat = fs.lstatSync('index.js')
800
- const binNodeLambdaStat = fs.lstatSync(path.join('bin', 'node-lambda'))
801
- assert.equal(
802
- archive.files['index.js'].unixPermissions,
803
- indexJsStat.mode
804
- )
805
- assert.equal(
806
- archive.files['bin/node-lambda'].unixPermissions,
807
- binNodeLambdaStat.mode
808
- )
809
-
810
- // isSymbolicLink
811
- assert.include(archive.files['node-lambda-link'].name, 'node-lambda-link')
812
- assert.equal(
813
- archive.files['node-lambda-link'].unixPermissions & fs.constants.S_IFMT,
814
- fs.constants.S_IFLNK
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
 
@@ -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 = 'nodejs14.x'
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
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { assert } = require('chai')
4
+ const process = require('process')
4
5
  const path = require('path')
5
6
  const aws = require('aws-sdk-mock')
6
7
  aws.setSDK(path.resolve('node_modules/aws-sdk'))
package/test/s3_events.js CHANGED
@@ -60,7 +60,7 @@ describe('lib/s3_events', () => {
60
60
  describe('_statementId', () => {
61
61
  it('StatementId that matches /[a-zA-Z0-9-_]+/.', () => {
62
62
  [{
63
- params: params,
63
+ params,
64
64
  expected: 'node-lambda-test-bucket'
65
65
  }, {
66
66
  params: { Bucket: 'example.com' },