@gidw/aws-lambda-deploy
Advanced tools
Comparing version 1.0.3 to 1.0.4
# Changelog | ||
## [1.0.4] - 2017-07-01 | ||
#### Changes | ||
- Bug fixes | ||
- Split library code in modules | ||
- Support TypeScript 2.4 | ||
- Added default value for `archiveName` | ||
- Added default value for `Handler` | ||
#### Build | ||
- Added test environment | ||
- Added clean install script | ||
## [1.0.3] - 2017-06-30 | ||
@@ -4,0 +19,0 @@ |
339
lib/main.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// Node JS dependencies | ||
const fs = require("fs"); | ||
const os = require("os"); | ||
const path = require("path"); | ||
// AWS SDK dependencies | ||
const aws_sdk_1 = require("aws-sdk"); | ||
const Lambda = require("aws-sdk/clients/lambda"); | ||
function isLambdaConfig(obj) { | ||
return (typeof obj === 'object' && | ||
obj !== null && | ||
obj.hasOwnProperty('archiveName') && | ||
obj.hasOwnProperty('FunctionName') && | ||
obj.hasOwnProperty('Description') && | ||
obj.hasOwnProperty('Handler') && | ||
obj.hasOwnProperty('Publish') && | ||
obj.hasOwnProperty('Runtime') && | ||
obj.hasOwnProperty('MemorySize') && | ||
obj.hasOwnProperty('Timeout')); | ||
} | ||
function isLambdaSecrets(obj) { | ||
return (typeof obj === 'object' && | ||
obj !== null && | ||
obj.hasOwnProperty('region') && | ||
obj.hasOwnProperty('profile') && | ||
obj.hasOwnProperty('accessKeyId') && | ||
obj.hasOwnProperty('secretAccessKey') && | ||
obj.hasOwnProperty('Role') && | ||
obj.hasOwnProperty('Environment')); | ||
} | ||
function isLambdaTest(obj) { | ||
return (typeof obj === 'object' && | ||
obj !== null && | ||
obj.hasOwnProperty('context') && | ||
obj.hasOwnProperty('events')); | ||
} | ||
function isLambdaTests(obj) { | ||
if (Array.isArray(obj)) { | ||
let i, length; | ||
length = obj.length; | ||
for (i = 0; i < length; i++) { | ||
if (!isLambdaTest(obj[i])) | ||
return false; | ||
} | ||
return true; | ||
} | ||
return false; | ||
} | ||
/** | ||
* Checks whether a given variable is null, undefined, an empty object | ||
* or an empty Array | ||
* | ||
* @param {*} obj | ||
* @returns {boolean} | ||
*/ | ||
function isEmpty(obj) { | ||
return (obj === undefined || | ||
obj === null || | ||
(isObject(obj) && Object.keys(obj).length === 0) || | ||
(Array.isArray(obj) && obj.length === 0)); | ||
} | ||
/** | ||
* Checks for non-empty string | ||
* | ||
* @param {string} value | ||
* @returns {boolean} | ||
*/ | ||
function isNEString(value) { | ||
return (typeof value === 'string' && | ||
value.length > 0); | ||
} | ||
/** | ||
* Checks for non-null object | ||
* | ||
* @param {Object} obj | ||
* @returns {boolean} | ||
*/ | ||
function isObject(obj) { | ||
return (typeof obj === 'object' && | ||
obj !== undefined && | ||
obj !== null); | ||
} | ||
// Local dependencies | ||
const Util_1 = require("./Util"); | ||
const types_1 = require("./types"); | ||
class GdwAwsLambda { | ||
//region Entry methods | ||
init() { | ||
@@ -97,3 +29,3 @@ return Promise.all([ | ||
if (result === GdwAwsLambda.ERR_LAMBDA_NOT_FOUND) { | ||
return this.createFunction(); | ||
return this.createLambdaFunction(); | ||
} | ||
@@ -103,3 +35,3 @@ else { | ||
if (options && options.updateConfig) { | ||
promises.push(this.updateConfig()); | ||
promises.push(this.updateLambdaConfig()); | ||
} | ||
@@ -112,3 +44,3 @@ else { | ||
} | ||
promises.push(this.updateFunctionCode()); | ||
promises.push(this.updateLambdaFunctionCode()); | ||
return Promise.all(promises) | ||
@@ -123,3 +55,3 @@ .then(() => { | ||
let testFile = GdwAwsLambda.FILE_LAMBDA_TESTS; | ||
if (testFileName && isNEString(testFileName)) { | ||
if (Util_1.default.isNEString(testFileName)) { | ||
testFile = testFileName; | ||
@@ -129,5 +61,5 @@ } | ||
this.readObject(GdwAwsLambda.FILE_LAMBDA_CONFIG, GdwAwsLambda.FILE_LAMBDA_CONFIG).then((cfg) => { | ||
if (isLambdaConfig(cfg) && | ||
isNEString(cfg.FunctionName) && | ||
isNEString(cfg.Handler)) { | ||
if (types_1.default.isLambdaConfig(cfg) && | ||
Util_1.default.isNEString(cfg.FunctionName) && | ||
Util_1.default.isNEString(cfg.Handler)) { | ||
this.lambdaCfg = cfg; | ||
@@ -142,3 +74,3 @@ return this.lambdaCfg; | ||
this.readObject(testFile, GdwAwsLambda.FILE_LAMBDA_TESTS).then((obj) => { | ||
if (isLambdaTests(obj)) { | ||
if (types_1.default.isLambdaTests(obj)) { | ||
this.lambdaTests = obj; | ||
@@ -156,2 +88,3 @@ return this.lambdaTests; | ||
} | ||
//endregion | ||
createLambdaService() { | ||
@@ -165,3 +98,3 @@ return this.readConfig() | ||
// Authentication | ||
if (isNEString(this.lambdaSecrets.profile)) { | ||
if (Util_1.default.isNEString(this.lambdaSecrets.profile)) { | ||
lambdaOptions.credentials = new aws_sdk_1.SharedIniFileCredentials({ | ||
@@ -171,4 +104,4 @@ profile: this.lambdaSecrets.profile | ||
} | ||
else if (isNEString(this.lambdaSecrets.accessKeyId) && | ||
isNEString(this.lambdaSecrets.secretAccessKey)) { | ||
else if (Util_1.default.isNEString(this.lambdaSecrets.accessKeyId) && | ||
Util_1.default.isNEString(this.lambdaSecrets.secretAccessKey)) { | ||
lambdaOptions.accessKeyId = | ||
@@ -231,26 +164,24 @@ this.lambdaSecrets.accessKeyId; | ||
static compareEnvironment(env1, env2) { | ||
if ((isEmpty(env1) || isObject(env1) && env1 && | ||
isEmpty(env1.Variables)) && | ||
(isEmpty(env2) || isObject(env2) && env2 && | ||
isEmpty(env2.Variables))) { | ||
if ((Util_1.default.isEmpty(env1) || Util_1.default.isObject(env1) && | ||
Util_1.default.isEmpty(env1.Variables)) && | ||
(Util_1.default.isEmpty(env2) || Util_1.default.isObject(env2) && | ||
Util_1.default.isEmpty(env2.Variables))) { | ||
return true; | ||
} | ||
else if (isObject(env2) && env2 && | ||
isObject(env2.Variables) && | ||
else if (Util_1.default.isObject(env2) && | ||
Util_1.default.isObject(env2.Variables) && | ||
Object.keys(env2.Variables).length > 0 && | ||
(isEmpty(env1) || isObject(env1) && env1 && | ||
isEmpty(env1.Variables))) { | ||
(Util_1.default.isEmpty(env1) || Util_1.default.isObject(env1) && | ||
Util_1.default.isEmpty(env1.Variables))) { | ||
return false; | ||
} | ||
else if (isObject(env1) && env1 && | ||
isObject(env1.Variables) && | ||
else if (Util_1.default.isObject(env1) && | ||
Util_1.default.isObject(env1.Variables) && | ||
Object.keys(env1.Variables).length > 0 && | ||
(isEmpty(env2) || isObject(env2) && env2 && | ||
isEmpty(env2.Variables))) { | ||
(Util_1.default.isEmpty(env2) || Util_1.default.isObject(env2) && | ||
Util_1.default.isEmpty(env2.Variables))) { | ||
return false; | ||
} | ||
else if (isObject(env1) && env1 && isObject(env1.Variables) && | ||
env1.Variables && | ||
isObject(env2) && env2 && isObject(env2.Variables) && | ||
env2.Variables) { | ||
else if (Util_1.default.isObject(env1) && Util_1.default.isObject(env1.Variables) && | ||
Util_1.default.isObject(env2) && Util_1.default.isObject(env2.Variables)) { | ||
let k1 = Object.keys(env1.Variables); | ||
@@ -277,3 +208,3 @@ let k2 = Object.keys(env2.Variables); | ||
} | ||
createFunction() { | ||
createLambdaFunction() { | ||
return this.readArchive() | ||
@@ -294,7 +225,4 @@ .then((result) => { | ||
}; | ||
this.lambda.createFunction(params, (err) => { | ||
if (err) { | ||
return Promise | ||
.reject('Error creating Lambda function'); | ||
} | ||
return this.createFunction(params) | ||
.then(() => { | ||
return 'Lambda function (' + | ||
@@ -305,6 +233,24 @@ this.lambdaCfg.FunctionName + ') created'; | ||
} | ||
updateFunctionCode() { | ||
updateLambdaConfig() { | ||
let params = { | ||
FunctionName: this.lambdaCfg.FunctionName, | ||
Description: this.lambdaCfg.Description, | ||
Handler: this.lambdaCfg.Handler, | ||
Runtime: this.lambdaCfg.Runtime, | ||
MemorySize: this.lambdaCfg.MemorySize, | ||
Timeout: this.lambdaCfg.Timeout, | ||
Role: this.lambdaSecrets.Role, | ||
Environment: this.lambdaSecrets.Environment | ||
}; | ||
return this.updateConfig(params) | ||
.then(() => { | ||
return 'Lambda function (' + | ||
this.lambdaCfg.FunctionName + | ||
') configuration updated'; | ||
}); | ||
} | ||
updateLambdaFunctionCode() { | ||
return this.readArchive() | ||
.then(() => { | ||
return this.updateCode({ | ||
return this.updateFunctionCode({ | ||
FunctionName: this.lambdaCfg.FunctionName, | ||
@@ -320,3 +266,3 @@ Publish: this.lambdaCfg.Publish, | ||
this.lambdaGetInfo.Configuration.CodeSha256) { | ||
return this.updateCode({ | ||
return this.updateFunctionCode({ | ||
FunctionName: this.lambdaCfg.FunctionName, | ||
@@ -326,2 +272,7 @@ Publish: this.lambdaCfg.Publish, | ||
DryRun: false | ||
}) | ||
.then(() => { | ||
return 'Lambda function (' + | ||
this.lambdaCfg.FunctionName + | ||
') code has been updated'; | ||
}); | ||
@@ -340,15 +291,7 @@ } | ||
} | ||
updateConfig() { | ||
//region AWS Lambda Promise wrappers | ||
createFunction(params) { | ||
return new Promise((resolve, reject) => { | ||
this.lambda.updateFunctionConfiguration({ | ||
FunctionName: this.lambdaCfg.FunctionName, | ||
Description: this.lambdaCfg.Description, | ||
Handler: this.lambdaCfg.Handler, | ||
Runtime: this.lambdaCfg.Runtime, | ||
MemorySize: this.lambdaCfg.MemorySize, | ||
Timeout: this.lambdaCfg.Timeout, | ||
Role: this.lambdaSecrets.Role, | ||
Environment: this.lambdaSecrets.Environment | ||
}, (err, data) => { | ||
err ? reject('Error updating function configuration') | ||
this.lambda.createFunction(params, (err, data) => { | ||
err ? reject(err) | ||
: resolve(data); | ||
@@ -358,17 +301,80 @@ }); | ||
} | ||
updateCode(config) { | ||
updateConfig(params) { | ||
return new Promise((resolve, reject) => { | ||
this.lambda.updateFunctionCode(config, (err, data) => { | ||
if (err) { | ||
reject(err); | ||
} | ||
else { | ||
resolve(data); | ||
} | ||
// this.lambda.updateFunctionConfiguration({ | ||
// FunctionName: this.lambdaCfg.FunctionName, | ||
// Description: this.lambdaCfg.Description, | ||
// Handler: this.lambdaCfg.Handler, | ||
// Runtime: this.lambdaCfg.Runtime, | ||
// MemorySize: this.lambdaCfg.MemorySize, | ||
// Timeout: this.lambdaCfg.Timeout, | ||
// Role: this.lambdaSecrets.Role, | ||
// Environment: this.lambdaSecrets.Environment | ||
// }, (err, data) => { | ||
// | ||
// err ? reject('Error updating function configuration') | ||
// : resolve(data); | ||
// | ||
// }) | ||
this.lambda.updateFunctionConfiguration(params, (err, data) => { | ||
err ? reject(err) | ||
: resolve(data); | ||
}); | ||
}); | ||
} | ||
updateFunctionCode(params) { | ||
return new Promise((resolve, reject) => { | ||
this.lambda.updateFunctionCode(params, (err, data) => { | ||
err ? reject(err) | ||
: resolve(data); | ||
}); | ||
}); | ||
} | ||
//endregion | ||
//region Lambda tests | ||
runTests() { | ||
let splits; | ||
let module; | ||
let eventHandler; | ||
let filePath; | ||
// Extract module and handler name | ||
splits = this.lambdaCfg.Handler.split('.'); | ||
if (splits.length !== 2) | ||
throw 'Invalid handler'; | ||
module = splits[0]; | ||
eventHandler = splits[1]; | ||
filePath = path.join(process.cwd(), module + '.js'); | ||
const handler = require(filePath)[eventHandler]; | ||
if (!handler) | ||
throw 'invalid handler object'; | ||
let promises = []; | ||
let i, length; | ||
length = this.lambdaTests.length; | ||
for (i = 0; i < length; i++) { | ||
promises.push(GdwAwsLambda.executeContextTest(handler, this.lambdaTests[i])); | ||
} | ||
return Promise.all(promises); | ||
} | ||
static executeContextTest(handler, test) { | ||
let promises = []; | ||
let i, length; | ||
length = test.events.length; | ||
for (i = 0; i < length; i++) { | ||
promises.push(GdwAwsLambda.executeEventTest(handler, test.context, test.events[i])); | ||
} | ||
return Promise.all(promises); | ||
} | ||
static executeEventTest(handler, context, event) { | ||
return new Promise((resolve, reject) => { | ||
handler(event, context, (err, data) => { | ||
err ? reject(err) | ||
: resolve(data); | ||
}); | ||
}); | ||
} | ||
//endregion | ||
//region File methods | ||
readArchive() { | ||
return new Promise((resolve, reject) => { | ||
if (isNEString(this.lambdaCfg.archiveName)) { | ||
if (Util_1.default.isNEString(this.lambdaCfg.archiveName)) { | ||
fs.readFile(this.lambdaCfg.archiveName, (err, data) => { | ||
@@ -393,5 +399,5 @@ if (err) { | ||
this.readObject(GdwAwsLambda.FILE_LAMBDA_CONFIG, GdwAwsLambda.FILE_LAMBDA_CONFIG).then((cfg) => { | ||
if (isLambdaConfig(cfg) && | ||
isNEString(cfg.FunctionName) && | ||
isNEString(cfg.Handler)) { | ||
if (types_1.default.isLambdaConfig(cfg) && | ||
Util_1.default.isNEString(cfg.FunctionName) && | ||
Util_1.default.isNEString(cfg.Handler)) { | ||
this.lambdaCfg = cfg; | ||
@@ -406,5 +412,5 @@ return this.lambdaCfg; | ||
this.readObject(GdwAwsLambda.FILE_LAMBDA_SECRETS, GdwAwsLambda.FILE_LAMBDA_SECRETS).then((cfg) => { | ||
if (isLambdaSecrets(cfg) && | ||
isNEString(cfg.region) && | ||
isNEString(cfg.Role)) { | ||
if (types_1.default.isLambdaSecrets(cfg) && | ||
Util_1.default.isNEString(cfg.region) && | ||
Util_1.default.isNEString(cfg.Role)) { | ||
this.lambdaSecrets = cfg; | ||
@@ -422,3 +428,5 @@ return this.lambdaSecrets; | ||
return this.readObject(file, type) | ||
.catch(() => { | ||
.then(() => { | ||
return `File ${file} exists already`; | ||
}, () => { | ||
return this.initFile(file); | ||
@@ -434,45 +442,6 @@ }); | ||
else { | ||
return Promise.reject(`Unable to create object for ${file}`); | ||
// return Promise.reject(`Unable to create object for ${file}`); | ||
throw `Unable to create object for ${file}`; | ||
} | ||
} | ||
runTests() { | ||
let splits; | ||
let module; | ||
let eventHandler; | ||
let filePath; | ||
// Extract module and handler name | ||
splits = this.lambdaCfg.Handler.split('.'); | ||
if (splits.length !== 2) | ||
throw 'Invalid handler'; | ||
module = splits[0]; | ||
eventHandler = splits[1]; | ||
filePath = path.join(process.cwd(), module + '.js'); | ||
const handler = require(filePath)[eventHandler]; | ||
if (!handler) | ||
throw 'invalid handler object'; | ||
let promises = []; | ||
let i, length; | ||
length = this.lambdaTests.length; | ||
for (i = 0; i < length; i++) { | ||
promises.push(GdwAwsLambda.executeContextTest(handler, this.lambdaTests[i])); | ||
} | ||
return Promise.all(promises); | ||
} | ||
static executeContextTest(handler, test) { | ||
let promises = []; | ||
let i, length; | ||
length = test.events.length; | ||
for (i = 0; i < length; i++) { | ||
promises.push(GdwAwsLambda.executeEventTest(handler, test.context, test.events[i])); | ||
} | ||
return Promise.all(promises); | ||
} | ||
static executeEventTest(handler, context, event) { | ||
return new Promise((resolve, reject) => { | ||
handler(event, context, (err, data) => { | ||
err ? reject(err) | ||
: resolve(data); | ||
}); | ||
}); | ||
} | ||
readObject(file, checkType) { | ||
@@ -516,6 +485,8 @@ return new Promise((resolve, reject) => { | ||
} | ||
//endregion | ||
//region Static methods | ||
static checkObject(object, checkType) { | ||
switch (checkType) { | ||
case GdwAwsLambda.FILE_LAMBDA_CONFIG: | ||
if (isLambdaConfig(object)) { | ||
if (types_1.default.isLambdaConfig(object)) { | ||
return ''; | ||
@@ -527,3 +498,3 @@ } | ||
case GdwAwsLambda.FILE_LAMBDA_SECRETS: | ||
if (isLambdaSecrets(object)) { | ||
if (types_1.default.isLambdaSecrets(object)) { | ||
return ''; | ||
@@ -539,3 +510,3 @@ } | ||
for (i = 0; i < length; i++) { | ||
if (!isLambdaTest(object[i])) { | ||
if (!types_1.default.isLambdaTest(object[i])) { | ||
return 'Invalid lambda tests'; | ||
@@ -557,6 +528,6 @@ } | ||
return { | ||
archiveName: '', | ||
archiveName: 'archive.zip', | ||
FunctionName: '', | ||
Description: '', | ||
Handler: '', | ||
Handler: 'index.handler', | ||
Publish: false, | ||
@@ -563,0 +534,0 @@ Runtime: 'nodejs6.10', |
{ | ||
"name": "@gidw/aws-lambda-deploy", | ||
"version": "1.0.3", | ||
"version": "1.0.4", | ||
"description": "Helper module for deploying AWS Lambda functions in Node.js.", | ||
@@ -22,7 +22,7 @@ "author": "Gilles De Waele", | ||
"dependencies": { | ||
"aws-sdk": "^2.79.0" | ||
"aws-sdk": "^2.80.0" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "~8.0.6", | ||
"typescript": "2.3.4" | ||
"typescript": "~2.4.1" | ||
}, | ||
@@ -38,4 +38,6 @@ "repository": { | ||
"scripts": { | ||
"clean-install": "rm -rf node_modules && rm -f package-lock.json && npm i && npm i", | ||
"build-debug": "tsc --sourceMap true", | ||
"build": "tsc", | ||
"create-test": "npm pack && mv *.tgz test/", | ||
"publish": "tsc && npm publish", | ||
@@ -42,0 +44,0 @@ "clean": "rm -rf lib/*" |
36234
9
848
Updatedaws-sdk@^2.80.0