mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
seperated packaging and deployment
This commit is contained in:
parent
4d7eeb0119
commit
e38f22585f
@ -103,6 +103,7 @@ class Service {
|
||||
|
||||
if (serverlessFile.package) {
|
||||
that.package.individually = serverlessFile.package.individually;
|
||||
that.package.path = serverlessFile.package.path;
|
||||
that.package.artifact = serverlessFile.package.artifact;
|
||||
that.package.exclude = serverlessFile.package.exclude;
|
||||
that.package.include = serverlessFile.package.include;
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"./config/config.js",
|
||||
"./create/create.js",
|
||||
"./install/install.js",
|
||||
"./package/index.js",
|
||||
"./package/package.js",
|
||||
"./deploy/deploy.js",
|
||||
"./invoke/invoke.js",
|
||||
"./info/info.js",
|
||||
@ -15,22 +15,23 @@
|
||||
"./aws/configCredentials/awsConfigCredentials.js",
|
||||
"./aws/provider/awsProvider.js",
|
||||
"./aws/deploy/index.js",
|
||||
"./aws/package/index.js",
|
||||
"./aws/invoke/index.js",
|
||||
"./aws/info/index.js",
|
||||
"./aws/logs/index.js",
|
||||
"./aws/metrics/awsMetrics.js",
|
||||
"./aws/remove/index.js",
|
||||
"./aws/rollback/index.js",
|
||||
"./aws/deploy/compile/functions/index.js",
|
||||
"./aws/deploy/compile/events/schedule/index.js",
|
||||
"./aws/deploy/compile/events/s3/index.js",
|
||||
"./aws/deploy/compile/events/apiGateway/index.js",
|
||||
"./aws/deploy/compile/events/sns/index.js",
|
||||
"./aws/deploy/compile/events/stream/index.js",
|
||||
"./aws/deploy/compile/events/alexaSkill/index.js",
|
||||
"./aws/deploy/compile/events/iot/index.js",
|
||||
"./aws/deploy/compile/events/cloudWatchEvent/index.js",
|
||||
"./aws/deploy/compile/events/cloudWatchLog/index.js",
|
||||
"./aws/package/compile/functions/index.js",
|
||||
"./aws/package/compile/events/schedule/index.js",
|
||||
"./aws/package/compile/events/s3/index.js",
|
||||
"./aws/package/compile/events/apiGateway/index.js",
|
||||
"./aws/package/compile/events/sns/index.js",
|
||||
"./aws/package/compile/events/stream/index.js",
|
||||
"./aws/package/compile/events/alexaSkill/index.js",
|
||||
"./aws/package/compile/events/iot/index.js",
|
||||
"./aws/package/compile/events/cloudWatchEvent/index.js",
|
||||
"./aws/package/compile/events/cloudWatchLog/index.js",
|
||||
"./aws/deployFunction/index.js",
|
||||
"./aws/deployList/index.js",
|
||||
"./aws/invokeLocal/index.js"
|
||||
|
||||
@ -1,17 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* serverless package => package in default .serverless dir
|
||||
* serverless package --package => package in custom path
|
||||
*
|
||||
* serverless deploy => package in default .serverless & deploy from default .serverless
|
||||
* serverless deploy --package => deploy from custom path
|
||||
*/
|
||||
|
||||
const BbPromise = require('bluebird');
|
||||
const validate = require('../lib/validate');
|
||||
const runPackage = require('./lib/runPackage');
|
||||
const extendedValidate = require('./lib/extendedValidate');
|
||||
const monitorStack = require('../lib/monitorStack');
|
||||
const createStack = require('./lib/createStack');
|
||||
const mergeCustomProviderResources = require('./lib/mergeCustomProviderResources');
|
||||
const generateArtifactDirectoryName = require('./lib/generateArtifactDirectoryName');
|
||||
const setBucketName = require('../lib/setBucketName');
|
||||
const cleanupS3Bucket = require('./lib/cleanupS3Bucket');
|
||||
const uploadArtifacts = require('./lib/uploadArtifacts');
|
||||
const updateStack = require('../lib/updateStack');
|
||||
const configureStack = require('./lib/configureStack');
|
||||
const mergeIamTemplates = require('./lib/mergeIamTemplates');
|
||||
|
||||
class AwsDeploy {
|
||||
constructor(serverless, options) {
|
||||
@ -22,41 +28,30 @@ class AwsDeploy {
|
||||
Object.assign(
|
||||
this,
|
||||
validate,
|
||||
runPackage,
|
||||
extendedValidate,
|
||||
createStack,
|
||||
generateArtifactDirectoryName,
|
||||
mergeCustomProviderResources,
|
||||
setBucketName,
|
||||
cleanupS3Bucket,
|
||||
uploadArtifacts,
|
||||
updateStack,
|
||||
monitorStack,
|
||||
configureStack,
|
||||
mergeIamTemplates
|
||||
monitorStack
|
||||
);
|
||||
|
||||
this.hooks = {
|
||||
'before:deploy:initialize': () => BbPromise.bind(this)
|
||||
.then(this.validate),
|
||||
|
||||
'deploy:initialize': () => BbPromise.bind(this)
|
||||
.then(this.configureStack),
|
||||
|
||||
'deploy:setupProviderConfiguration': () => BbPromise.bind(this)
|
||||
.then(this.createStack)
|
||||
.then(this.mergeIamTemplates),
|
||||
|
||||
'before:deploy:compileFunctions': () => BbPromise.bind(this)
|
||||
.then(this.generateArtifactDirectoryName),
|
||||
.then(this.validate)
|
||||
.then(this.runPackage)
|
||||
.then(this.extendedValidate),
|
||||
|
||||
'deploy:deploy': () => BbPromise.bind(this)
|
||||
.then(this.mergeCustomProviderResources)
|
||||
.then(this.createStack)
|
||||
.then(this.setBucketName)
|
||||
.then(this.uploadArtifacts)
|
||||
.then(this.updateStack)
|
||||
.then(this.cleanupS3Bucket)
|
||||
.then(() => {
|
||||
if (this.options.noDeploy) this.serverless.cli.log('Did not deploy due to --noDeploy');
|
||||
}),
|
||||
.then(this.updateStack),
|
||||
|
||||
'deploy:finalize': () => BbPromise.bind(this)
|
||||
.then(this.cleanupS3Bucket),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,10 +51,6 @@ module.exports = {
|
||||
},
|
||||
|
||||
cleanupS3Bucket() {
|
||||
if (this.options.noDeploy) {
|
||||
return BbPromise.resolve();
|
||||
}
|
||||
|
||||
return BbPromise.bind(this)
|
||||
.then(this.getObjectsToRemove)
|
||||
.then(this.removeObjects);
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const path = require('path');
|
||||
const BbPromise = require('bluebird');
|
||||
|
||||
module.exports = {
|
||||
@ -9,6 +8,7 @@ module.exports = {
|
||||
// Note: using three dots instead of ellipsis to support non uni-code consoles.
|
||||
this.serverless.cli.log('Creating Stack...');
|
||||
const stackName = this.provider.naming.getStackName();
|
||||
|
||||
let stackTags = { STAGE: this.options.stage };
|
||||
|
||||
// Merge additional stack tags
|
||||
@ -24,8 +24,7 @@ module.exports = {
|
||||
'CAPABILITY_NAMED_IAM',
|
||||
],
|
||||
Parameters: [],
|
||||
TemplateBody: JSON.stringify(this.serverless.service.provider
|
||||
.compiledCloudFormationTemplate),
|
||||
TemplateBody: JSON.stringify(this.coreTemplateFileBody),
|
||||
Tags: Object.keys(stackTags).map((key) => ({ Key: key, Value: stackTags[key] })),
|
||||
};
|
||||
|
||||
@ -56,19 +55,12 @@ module.exports = {
|
||||
}
|
||||
|
||||
return BbPromise.bind(this)
|
||||
// always write the template to disk, whether we are deploying or not
|
||||
.then(this.writeCreateTemplateToDisk)
|
||||
.then(() => {
|
||||
if (this.options.noDeploy) {
|
||||
return BbPromise.resolve();
|
||||
}
|
||||
return this.provider.request('CloudFormation',
|
||||
.then(() => this.provider.request('CloudFormation',
|
||||
'describeStackResources',
|
||||
{ StackName: stackName },
|
||||
this.options.stage,
|
||||
this.options.region)
|
||||
.then(() => BbPromise.resolve('alreadyCreated'));
|
||||
})
|
||||
.then(() => BbPromise.resolve('alreadyCreated')))
|
||||
.catch((e) => {
|
||||
if (e.message.indexOf('does not exist') > -1) {
|
||||
if (this.serverless.service.provider.deploymentBucket) {
|
||||
@ -82,18 +74,4 @@ module.exports = {
|
||||
throw new this.serverless.classes.Error(e);
|
||||
});
|
||||
},
|
||||
|
||||
// helper methods
|
||||
writeCreateTemplateToDisk() {
|
||||
if (this.serverless.service.provider.deploymentBucket) {
|
||||
return BbPromise.resolve();
|
||||
}
|
||||
const cfTemplateFilePath = path.join(this.serverless.config.servicePath,
|
||||
'.serverless', 'cloudformation-template-create-stack.json');
|
||||
|
||||
this.serverless.utils.writeFileSync(cfTemplateFilePath,
|
||||
this.serverless.service.provider.compiledCloudFormationTemplate);
|
||||
|
||||
return BbPromise.resolve();
|
||||
},
|
||||
};
|
||||
|
||||
75
lib/plugins/aws/deploy/lib/extendedValidate.js
Normal file
75
lib/plugins/aws/deploy/lib/extendedValidate.js
Normal file
@ -0,0 +1,75 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const BbPromise = require('bluebird');
|
||||
const _ = require('lodash');
|
||||
|
||||
module.exports = {
|
||||
getArtifactS3Key() {
|
||||
const getArtifactS3KeysArray = function (obj, key) {
|
||||
if (_.has(obj, key)) {
|
||||
return obj[key];
|
||||
}
|
||||
|
||||
return _.flatten(_
|
||||
.map(obj, (v) => typeof v === 'object' ? getArtifactS3KeysArray(v, key) : false), true);
|
||||
};
|
||||
|
||||
return getArtifactS3KeysArray(this.compiledTemplateFileBody, 'S3Key')
|
||||
.find(item => item !== false);
|
||||
},
|
||||
|
||||
extendedValidate() {
|
||||
this.packagePath = this.options.package ||
|
||||
this.serverless.service.package.path ||
|
||||
path.join(this.serverless.config.servicePath, '.serverless');
|
||||
|
||||
if (this.serverless.service.package.individually) {
|
||||
// artifact file validation (multiple function artifacts)
|
||||
this.serverless.service.getAllFunctions().forEach(functionName => {
|
||||
const artifactFileName = this.provider.naming.getFunctionArtifactName(functionName);
|
||||
const artifactFilePath = path.join(this.packagePath, artifactFileName);
|
||||
if (!this.serverless.utils.fileExistsSync(artifactFilePath)) {
|
||||
throw new this.serverless.classes
|
||||
.Error(`No ${artifactFileName} file found in the package path you provided.`);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// artifact file validation (single service artifact)
|
||||
const artifactFileName = this.provider.naming.getServiceArtifactName();
|
||||
const artifactFilePath = path.join(this.packagePath, artifactFileName);
|
||||
if (!this.serverless.utils.fileExistsSync(artifactFilePath)) {
|
||||
throw new this.serverless.classes
|
||||
.Error(`No ${artifactFileName} file found in the package path you provided.`);
|
||||
}
|
||||
}
|
||||
|
||||
// compiled template file validation
|
||||
const compiledTemplateFileName = this.provider.naming.getCompiledTemplateFileName();
|
||||
this.compiledTemplateFilePath = path.join(this.packagePath, compiledTemplateFileName);
|
||||
if (!this.serverless.utils.fileExistsSync(this.compiledTemplateFilePath)) {
|
||||
throw new this.serverless.classes
|
||||
.Error(`No ${compiledTemplateFileName} file found in the package path you provided.`);
|
||||
}
|
||||
this.compiledTemplateFileBody = this.serverless
|
||||
.utils.readFileSync(this.compiledTemplateFilePath);
|
||||
|
||||
if (!this.serverless.service.deploymentBucket) {
|
||||
// core template file validation
|
||||
const coreTemplateFileName = this.provider.naming.getCoreTemplateFileName();
|
||||
this.coreTemplateFilePath = path.join(this.packagePath, coreTemplateFileName);
|
||||
if (!this.serverless.utils.fileExistsSync(this.coreTemplateFilePath)) {
|
||||
throw new this.serverless.classes
|
||||
.Error(`No ${coreTemplateFileName} file found in the package path you provided.`);
|
||||
}
|
||||
this.coreTemplateFileBody = this.serverless
|
||||
.utils.readFileSync(this.coreTemplateFilePath);
|
||||
}
|
||||
|
||||
this.packageS3DirKey = this.getArtifactS3Key().split(path.sep);
|
||||
this.packageS3DirKey.pop();
|
||||
this.packageS3DirKey = this.packageS3DirKey.join(path.sep);
|
||||
|
||||
return BbPromise.resolve();
|
||||
},
|
||||
};
|
||||
18
lib/plugins/aws/deploy/lib/runPackage.js
Normal file
18
lib/plugins/aws/deploy/lib/runPackage.js
Normal file
@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const BbPromise = require('bluebird');
|
||||
const execSync = require('child_process').execSync;
|
||||
|
||||
module.exports = {
|
||||
runPackage() {
|
||||
const serverlessExec = path.join(this.serverless.config
|
||||
.serverlessPath, '..', 'bin', 'serverless');
|
||||
|
||||
if (!this.options.package) {
|
||||
execSync(`${serverlessExec} package`, { stdio: 'inherit' });
|
||||
}
|
||||
|
||||
return BbPromise.resolve();
|
||||
},
|
||||
};
|
||||
@ -1,21 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const BbPromise = require('bluebird');
|
||||
const filesize = require('filesize');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
uploadCloudFormationFile() {
|
||||
this.serverless.cli.log('Uploading CloudFormation file to S3...');
|
||||
|
||||
const body = JSON.stringify(this.serverless.service.provider.compiledCloudFormationTemplate);
|
||||
const compiledTemplateFileName = this.provider.naming.getCompiledTemplateFileName();
|
||||
|
||||
const fileName = 'compiled-cloudformation-template.json';
|
||||
const body = JSON.stringify(this.compiledTemplateFileBody);
|
||||
|
||||
const params = {
|
||||
Bucket: this.bucketName,
|
||||
Key: `${this.serverless.service.package.artifactDirectoryName}/${fileName}`,
|
||||
Key: `${this.packageS3DirKey}/${compiledTemplateFileName}`,
|
||||
Body: body,
|
||||
ContentType: 'application/json',
|
||||
};
|
||||
@ -27,17 +27,17 @@ module.exports = {
|
||||
this.options.region);
|
||||
},
|
||||
|
||||
uploadZipFile(artifactFilePath) {
|
||||
if (!artifactFilePath) {
|
||||
throw new this.serverless.classes.Error('artifactFilePath was not supplied');
|
||||
uploadZipFile(functionName) {
|
||||
let fileName = this.provider.naming.getServiceArtifactName();
|
||||
|
||||
if (functionName) {
|
||||
fileName = this.provider.naming.getFunctionArtifactName(functionName);
|
||||
}
|
||||
|
||||
|
||||
const fileName = artifactFilePath.split(path.sep).pop();
|
||||
const artifactFilePath = path.join(this.packagePath, fileName);
|
||||
|
||||
const params = {
|
||||
Bucket: this.bucketName,
|
||||
Key: `${this.serverless.service.package.artifactDirectoryName}/${fileName}`,
|
||||
Key: `${this.packageS3DirKey}/${fileName}`,
|
||||
Body: fs.createReadStream(artifactFilePath),
|
||||
ContentType: 'application/zip',
|
||||
};
|
||||
@ -72,13 +72,24 @@ module.exports = {
|
||||
}
|
||||
return BbPromise.resolve();
|
||||
});
|
||||
if (this.serverless.service.package.individually) {
|
||||
this.serverless.cli.log('Uploading function .zip files to S3...');
|
||||
|
||||
const functionNames = this.serverless.service.getAllFunctions();
|
||||
const uploadPromises = functionNames.map(name => this.uploadZipFile(name));
|
||||
|
||||
return BbPromise.all(uploadPromises);
|
||||
}
|
||||
|
||||
const fileName = this.provider.naming.getServiceArtifactName();
|
||||
const artifactFilePath = path.join(this.packagePath, fileName);
|
||||
|
||||
const stats = fs.statSync(artifactFilePath);
|
||||
this.serverless.cli.log(`Uploading service .zip file to S3 (${filesize(stats.size)})...`);
|
||||
return this.uploadZipFile();
|
||||
},
|
||||
|
||||
uploadArtifacts() {
|
||||
if (this.options.noDeploy) {
|
||||
return BbPromise.resolve();
|
||||
}
|
||||
|
||||
return BbPromise.bind(this)
|
||||
.then(this.uploadCloudFormationFile)
|
||||
.then(this.uploadFunctions);
|
||||
|
||||
@ -1,17 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
const BbPromise = require('bluebird');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const validate = require('../lib/validate');
|
||||
const filesize = require('filesize');
|
||||
|
||||
// The Package plugin which is used to zip the service
|
||||
const Package = require('../../package');
|
||||
const Package = require('../package');
|
||||
|
||||
class AwsDeployFunction {
|
||||
constructor(serverless, options) {
|
||||
this.serverless = serverless;
|
||||
this.options = options || {};
|
||||
this.packagePath = this.options.package ||
|
||||
this.serverless.service.package.path ||
|
||||
path.join(this.serverless.config.servicePath, '.serverless');
|
||||
this.provider = this.serverless.getProvider('aws');
|
||||
|
||||
this.pkg = new Package(this.serverless, this.options);
|
||||
@ -72,7 +76,10 @@ class AwsDeployFunction {
|
||||
}
|
||||
|
||||
deployFunction() {
|
||||
const data = fs.readFileSync(this.options.functionObj.artifact);
|
||||
const artifactFileName = this.provider.naming
|
||||
.getFunctionArtifactName(this.options.function);
|
||||
const artifactFilePath = path.join(this.packagePath, artifactFileName);
|
||||
const data = fs.readFileSync(artifactFilePath);
|
||||
|
||||
const params = {
|
||||
FunctionName: this.options.functionObj.name,
|
||||
@ -80,7 +87,7 @@ class AwsDeployFunction {
|
||||
};
|
||||
|
||||
// Get function stats
|
||||
const stats = fs.statSync(this.options.functionObj.artifact);
|
||||
const stats = fs.statSync(artifactFilePath);
|
||||
this.serverless.cli.log(
|
||||
`Uploading function: ${this.options.function} (${filesize(stats.size)})...`
|
||||
);
|
||||
|
||||
@ -6,8 +6,6 @@ const chalk = require('chalk');
|
||||
|
||||
module.exports = {
|
||||
monitorStack(action, cfData, frequency) {
|
||||
// Skip monitoring if a deployment should not be performed
|
||||
if (this.options.noDeploy) return BbPromise.bind(this).then(BbPromise.resolve());
|
||||
|
||||
// Skip monitoring if stack was already created
|
||||
if (cfData === 'alreadyCreated') return BbPromise.bind(this).then(BbPromise.resolve());
|
||||
|
||||
@ -49,6 +49,22 @@ module.exports = {
|
||||
return `${this.provider.serverless.service.service}-${this.provider.getStage()}`;
|
||||
},
|
||||
|
||||
getServiceArtifactName() {
|
||||
return `${this.provider.serverless.service.service}.zip`;
|
||||
},
|
||||
|
||||
getFunctionArtifactName(functionName) {
|
||||
return `${functionName}.zip`;
|
||||
},
|
||||
|
||||
getCompiledTemplateFileName() {
|
||||
return 'cf-compiled-template.json';
|
||||
},
|
||||
|
||||
getCoreTemplateFileName() {
|
||||
return 'cf-core-template.json';
|
||||
},
|
||||
|
||||
// Role
|
||||
getRolePath() {
|
||||
return '/';
|
||||
|
||||
@ -8,10 +8,6 @@ module.exports = {
|
||||
return BbPromise.resolve(this.bucketName);
|
||||
}
|
||||
|
||||
if (this.options.noDeploy) {
|
||||
return BbPromise.resolve();
|
||||
}
|
||||
|
||||
return this.provider.getServerlessDeploymentBucketName(this.options.stage, this.options.region)
|
||||
.then((bucketName) => {
|
||||
this.bucketName = bucketName;
|
||||
|
||||
@ -13,11 +13,9 @@ module.exports = {
|
||||
|
||||
const stackName = this.provider.naming.getStackName();
|
||||
let stackTags = { STAGE: this.options.stage };
|
||||
const templateUrl = `https://s3.amazonaws.com/${
|
||||
this.bucketName
|
||||
}/${
|
||||
this.serverless.service.package.artifactDirectoryName
|
||||
}/compiled-cloudformation-template.json`;
|
||||
const compiledTemplateFileName = this.provider.naming.getCompiledTemplateFileName();
|
||||
const templateUrl = `https://s3.amazonaws.com/${this.bucketName}/${this.packageS3DirKey}/${compiledTemplateFileName}`;
|
||||
|
||||
// Merge additional stack tags
|
||||
if (typeof this.serverless.service.provider.stackTags === 'object') {
|
||||
stackTags = _.extend(stackTags, this.serverless.service.provider.stackTags);
|
||||
@ -44,11 +42,8 @@ module.exports = {
|
||||
},
|
||||
|
||||
update() {
|
||||
const templateUrl = `https://s3.amazonaws.com/${
|
||||
this.bucketName
|
||||
}/${
|
||||
this.serverless.service.package.artifactDirectoryName
|
||||
}/compiled-cloudformation-template.json`;
|
||||
const compiledTemplateFileName = this.provider.naming.getCompiledTemplateFileName();
|
||||
const templateUrl = `https://s3.amazonaws.com/${this.bucketName}/${this.packageS3DirKey}/${compiledTemplateFileName}`;
|
||||
|
||||
this.serverless.cli.log('Updating Stack...');
|
||||
const stackName = this.provider.naming.getStackName();
|
||||
@ -97,13 +92,9 @@ module.exports = {
|
||||
},
|
||||
|
||||
updateStack() {
|
||||
// just write the template to disk if a deployment should not be performed
|
||||
return BbPromise.bind(this)
|
||||
.then(this.writeUpdateTemplateToDisk)
|
||||
.then(() => {
|
||||
if (this.options.noDeploy) {
|
||||
return BbPromise.resolve();
|
||||
} else if (this.createLater) {
|
||||
if (this.createLater) {
|
||||
return BbPromise.bind(this)
|
||||
.then(this.createFallback);
|
||||
}
|
||||
@ -111,16 +102,4 @@ module.exports = {
|
||||
.then(this.update);
|
||||
});
|
||||
},
|
||||
|
||||
// helper methods
|
||||
writeUpdateTemplateToDisk() {
|
||||
const updateOrCreate = this.createLater ? 'create' : 'update';
|
||||
const cfTemplateFilePath = path.join(this.serverless.config.servicePath,
|
||||
'.serverless', `cloudformation-template-${updateOrCreate}-stack.json`);
|
||||
|
||||
this.serverless.utils.writeFileSync(cfTemplateFilePath,
|
||||
this.serverless.service.provider.compiledCloudFormationTemplate);
|
||||
|
||||
return BbPromise.resolve();
|
||||
},
|
||||
};
|
||||
|
||||
@ -8,7 +8,7 @@ class AwsCompileAlexaSkillEvents {
|
||||
this.provider = this.serverless.getProvider('aws');
|
||||
|
||||
this.hooks = {
|
||||
'deploy:compileEvents': this.compileAlexaSkillEvents.bind(this),
|
||||
'package:compileEvents': this.compileAlexaSkillEvents.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ class AwsCompileApigEvents {
|
||||
);
|
||||
|
||||
this.hooks = {
|
||||
'deploy:compileEvents': () => {
|
||||
'package:compileEvents': () => {
|
||||
this.validated = this.validate();
|
||||
|
||||
if (this.validated.events.length === 0) {
|
||||
@ -8,7 +8,7 @@ class AwsCompileCloudWatchEventEvents {
|
||||
this.provider = this.serverless.getProvider('aws');
|
||||
|
||||
this.hooks = {
|
||||
'deploy:compileEvents': this.compileCloudWatchEventEvents.bind(this),
|
||||
'package:compileEvents': this.compileCloudWatchEventEvents.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ class AwsCompileIoTEvents {
|
||||
this.provider = this.serverless.getProvider('aws');
|
||||
|
||||
this.hooks = {
|
||||
'deploy:compileEvents': this.compileIoTEvents.bind(this),
|
||||
'package:compileEvents': this.compileIoTEvents.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ class AwsCompileS3Events {
|
||||
this.provider = this.serverless.getProvider('aws');
|
||||
|
||||
this.hooks = {
|
||||
'deploy:compileEvents': this.compileS3Events.bind(this),
|
||||
'package:compileEvents': this.compileS3Events.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ class AwsCompileScheduledEvents {
|
||||
this.provider = this.serverless.getProvider('aws');
|
||||
|
||||
this.hooks = {
|
||||
'deploy:compileEvents': this.compileScheduledEvents.bind(this),
|
||||
'package:compileEvents': this.compileScheduledEvents.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ class AwsCompileSNSEvents {
|
||||
this.provider = this.serverless.getProvider('aws');
|
||||
|
||||
this.hooks = {
|
||||
'deploy:compileEvents': this.compileSNSEvents.bind(this),
|
||||
'package:compileEvents': this.compileSNSEvents.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ class AwsCompileStreamEvents {
|
||||
this.provider = this.serverless.getProvider('aws');
|
||||
|
||||
this.hooks = {
|
||||
'deploy:compileEvents': this.compileStreamEvents.bind(this),
|
||||
'package:compileEvents': this.compileStreamEvents.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
@ -9,6 +9,11 @@ class AwsCompileFunctions {
|
||||
constructor(serverless, options) {
|
||||
this.serverless = serverless;
|
||||
this.options = options;
|
||||
|
||||
this.packagePath = this.options.package ||
|
||||
this.serverless.service.package.path ||
|
||||
path.join(this.serverless.config.servicePath, '.serverless');
|
||||
|
||||
this.provider = this.serverless.getProvider('aws');
|
||||
|
||||
this.compileFunctions = this.compileFunctions.bind(this);
|
||||
@ -20,7 +25,7 @@ class AwsCompileFunctions {
|
||||
}
|
||||
|
||||
this.hooks = {
|
||||
'deploy:compileFunctions': this.compileFunctions,
|
||||
'package:compileFunctions': this.compileFunctions,
|
||||
};
|
||||
}
|
||||
|
||||
@ -74,6 +79,14 @@ class AwsCompileFunctions {
|
||||
} else {
|
||||
artifactFilePath = this.serverless.service.package.artifact;
|
||||
}
|
||||
const serviceArtifactFileName = this.provider.naming.getServiceArtifactName();
|
||||
const functionArtifactFileName = this.provider.naming.getFunctionArtifactName(functionName);
|
||||
|
||||
const artifactFileName = this.serverless.service.package.individually ?
|
||||
functionArtifactFileName :
|
||||
serviceArtifactFileName;
|
||||
|
||||
const artifactFilePath = path.join(this.packagePath, artifactFileName);
|
||||
|
||||
if (!artifactFilePath) {
|
||||
throw new Error(`No artifact path is set for function: "${functionName}"`);
|
||||
57
lib/plugins/aws/package/index.js
Normal file
57
lib/plugins/aws/package/index.js
Normal file
@ -0,0 +1,57 @@
|
||||
'use strict';
|
||||
|
||||
const BbPromise = require('bluebird');
|
||||
const path = require('path');
|
||||
const validate = require('../lib/validate');
|
||||
const mergeCustomProviderResources = require('./lib/mergeCustomProviderResources');
|
||||
const generateArtifactDirectoryName = require('./lib/generateArtifactDirectoryName');
|
||||
const generateCoreTemplate = require('./lib/generateCoreTemplate');
|
||||
const generateCompiledTemplate = require('./lib/generateCompiledTemplate');
|
||||
const mergeIamTemplates = require('./lib/mergeIamTemplates');
|
||||
const zipService = require('./lib/zipService');
|
||||
const packageService = require('./lib/packageService');
|
||||
const cleanup = require('./lib/cleanup');
|
||||
|
||||
class AwsPackage {
|
||||
constructor(serverless, options) {
|
||||
this.serverless = serverless;
|
||||
this.options = options;
|
||||
this.packagePath = this.options.package ||
|
||||
this.serverless.service.package.path ||
|
||||
path.join(this.serverless.config.servicePath, '.serverless');
|
||||
this.provider = this.serverless.getProvider('aws');
|
||||
|
||||
Object.assign(
|
||||
this,
|
||||
cleanup,
|
||||
validate,
|
||||
packageService,
|
||||
zipService,
|
||||
generateCoreTemplate,
|
||||
mergeIamTemplates,
|
||||
generateArtifactDirectoryName,
|
||||
mergeCustomProviderResources,
|
||||
generateCompiledTemplate
|
||||
);
|
||||
|
||||
this.hooks = {
|
||||
'package:cleanup': () => BbPromise.bind(this)
|
||||
.then(this.cleanup),
|
||||
|
||||
'package:createDeploymentArtifacts': () => BbPromise.bind(this)
|
||||
.then(this.validate)
|
||||
.then(this.packageService),
|
||||
|
||||
'package:initialize': () => BbPromise.bind(this)
|
||||
.then(this.generateCoreTemplate)
|
||||
.then(this.mergeIamTemplates)
|
||||
.then(this.generateArtifactDirectoryName),
|
||||
|
||||
'package:finalize': () => BbPromise.bind(this)
|
||||
.then(this.mergeCustomProviderResources)
|
||||
.then(this.generateCompiledTemplate),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AwsPackage;
|
||||
18
lib/plugins/aws/package/lib/generateCompiledTemplate.js
Normal file
18
lib/plugins/aws/package/lib/generateCompiledTemplate.js
Normal file
@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
const BbPromise = require('bluebird');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
generateCompiledTemplate() {
|
||||
const compiledTemplateFileName = this.provider.naming.getCompiledTemplateFileName();
|
||||
|
||||
const compiledTemplateFilePath = path.join(this.packagePath, compiledTemplateFileName);
|
||||
|
||||
this.serverless.utils.writeFileSync(compiledTemplateFilePath,
|
||||
this.serverless.service.provider.compiledCloudFormationTemplate);
|
||||
|
||||
return BbPromise.resolve();
|
||||
},
|
||||
|
||||
};
|
||||
@ -4,13 +4,13 @@ const BbPromise = require('bluebird');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
configureStack() {
|
||||
generateCoreTemplate() {
|
||||
this.serverless.service.provider
|
||||
.compiledCloudFormationTemplate = this.serverless.utils.readFileSync(
|
||||
path.join(this.serverless.config.serverlessPath,
|
||||
'plugins',
|
||||
'aws',
|
||||
'deploy',
|
||||
'package',
|
||||
'lib',
|
||||
'core-cloudformation-template.json')
|
||||
);
|
||||
@ -47,6 +47,17 @@ module.exports = {
|
||||
});
|
||||
}
|
||||
|
||||
if (this.serverless.service.provider.deploymentBucket) {
|
||||
return BbPromise.resolve();
|
||||
}
|
||||
|
||||
const coreTemplateFileName = this.provider.naming.getCoreTemplateFileName();
|
||||
|
||||
const coreTemplateFilePath = path.join(this.packagePath, coreTemplateFileName);
|
||||
|
||||
this.serverless.utils.writeFileSync(coreTemplateFilePath,
|
||||
this.serverless.service.provider.compiledCloudFormationTemplate);
|
||||
|
||||
return BbPromise.resolve();
|
||||
},
|
||||
|
||||
@ -6,7 +6,7 @@ const expect = require('chai').expect;
|
||||
const AwsProvider = require('../../provider/awsProvider');
|
||||
const Serverless = require('../../../../Serverless');
|
||||
const validate = require('../../lib/validate');
|
||||
const configureStack = require('../lib/configureStack');
|
||||
const configureStack = require('generateStackCreateTemplate');
|
||||
|
||||
describe('#configureStack', () => {
|
||||
let serverless;
|
||||
@ -53,7 +53,7 @@ module.exports = {
|
||||
path.join(this.serverless.config.serverlessPath,
|
||||
'plugins',
|
||||
'aws',
|
||||
'deploy',
|
||||
'package',
|
||||
'lib',
|
||||
'iam-role-lambda-execution-template.json')
|
||||
);
|
||||
@ -26,14 +26,6 @@ module.exports = {
|
||||
return _.union(this.defaultExcludes, packageExcludes, exclude);
|
||||
},
|
||||
|
||||
getServiceArtifactName() {
|
||||
return `${this.serverless.service.service}.zip`;
|
||||
},
|
||||
|
||||
getFunctionArtifactName(functionObject) {
|
||||
return `${functionObject.name}.zip`;
|
||||
},
|
||||
|
||||
packageService() {
|
||||
// check if the user has specified an own artifact
|
||||
if (this.serverless.service.package.artifact) {
|
||||
@ -42,6 +34,13 @@ module.exports = {
|
||||
|
||||
let shouldPackageService = false;
|
||||
|
||||
this.serverless.cli.log('Packaging service...');
|
||||
|
||||
if (this.serverless.service.package.individually) {
|
||||
const allFunctions = this.serverless.service.getAllFunctions();
|
||||
const packagePromises = _.map(allFunctions, functionName =>
|
||||
this.packageFunction(functionName));
|
||||
|
||||
this.serverless.cli.log('Packaging service...');
|
||||
const allFunctions = this.serverless.service.getAllFunctions();
|
||||
const packagePromises = _.map(allFunctions, functionName => {
|
||||
@ -65,42 +64,21 @@ module.exports = {
|
||||
},
|
||||
|
||||
packageAll() {
|
||||
const servicePath = this.serverless.config.servicePath;
|
||||
|
||||
const exclude = this.getExcludes();
|
||||
const include = this.getIncludes();
|
||||
const zipFileName = this.getServiceArtifactName();
|
||||
const zipFileName = this.provider.naming.getServiceArtifactName();
|
||||
|
||||
return this.zipDirectory(servicePath, exclude, include, zipFileName).then(filePath => {
|
||||
this.serverless.service.package.artifact = filePath;
|
||||
return filePath;
|
||||
});
|
||||
return this.zipDirectory(exclude, include, zipFileName);
|
||||
},
|
||||
|
||||
packageFunction(functionName) {
|
||||
const functionObject = this.serverless.service.getFunction(functionName);
|
||||
const funcPackageConfig = functionObject.package || {};
|
||||
|
||||
functionObject.artifact = null; // reset the current artifact
|
||||
|
||||
if (funcPackageConfig.artifact) {
|
||||
if (process.env.SLS_DEBUG) {
|
||||
this.serverless.cli.log('package.artifact is defined, skipping packaging');
|
||||
}
|
||||
|
||||
functionObject.artifact = funcPackageConfig.artifact;
|
||||
return BbPromise.resolve(funcPackageConfig.artifact);
|
||||
}
|
||||
|
||||
const servicePath = this.serverless.config.servicePath;
|
||||
|
||||
const exclude = this.getExcludes(funcPackageConfig.exclude);
|
||||
const include = this.getIncludes(funcPackageConfig.include);
|
||||
const zipFileName = this.getFunctionArtifactName(functionObject);
|
||||
const zipFileName = this.provider.naming.getFunctionArtifactName(functionName);
|
||||
|
||||
return this.zipDirectory(servicePath, exclude, include, zipFileName).then((artifactPath) => {
|
||||
functionObject.artifact = artifactPath;
|
||||
return artifactPath;
|
||||
});
|
||||
return this.zipDirectory(exclude, include, zipFileName);
|
||||
},
|
||||
};
|
||||
@ -7,7 +7,7 @@ const fs = require('fs');
|
||||
const globby = require('globby');
|
||||
|
||||
module.exports = {
|
||||
zipDirectory(servicePath, exclude, include, zipFileName) {
|
||||
zipDirectory(exclude, include, zipFileName) {
|
||||
const patterns = ['**'];
|
||||
|
||||
exclude.forEach((pattern) => {
|
||||
@ -26,9 +26,7 @@ module.exports = {
|
||||
|
||||
const zip = archiver.create('zip');
|
||||
|
||||
const artifactFilePath = path.join(
|
||||
servicePath,
|
||||
'.serverless',
|
||||
const artifactFilePath = path.join(this.packagePath,
|
||||
zipFileName
|
||||
);
|
||||
|
||||
@ -40,7 +38,7 @@ module.exports = {
|
||||
zip.pipe(output);
|
||||
|
||||
const files = globby.sync(patterns, {
|
||||
cwd: servicePath,
|
||||
cwd: this.serverless.config.servicePath,
|
||||
dot: true,
|
||||
silent: true,
|
||||
follow: true,
|
||||
@ -48,7 +46,7 @@ module.exports = {
|
||||
|
||||
files.forEach((filePath) => {
|
||||
const fullPath = path.resolve(
|
||||
servicePath,
|
||||
this.serverless.config.servicePath,
|
||||
filePath
|
||||
);
|
||||
|
||||
@ -8,13 +8,9 @@ class Deploy {
|
||||
deploy: {
|
||||
usage: 'Deploy a Serverless service',
|
||||
lifecycleEvents: [
|
||||
'cleanup',
|
||||
'initialize',
|
||||
'setupProviderConfiguration',
|
||||
'createDeploymentArtifacts',
|
||||
'compileFunctions',
|
||||
'compileEvents',
|
||||
'deploy',
|
||||
'finalize',
|
||||
],
|
||||
options: {
|
||||
stage: {
|
||||
@ -25,9 +21,9 @@ class Deploy {
|
||||
usage: 'Region of the service',
|
||||
shortcut: 'r',
|
||||
},
|
||||
noDeploy: {
|
||||
usage: 'Build artifacts without deploying',
|
||||
shortcut: 'n',
|
||||
package: {
|
||||
usage: 'Path of the deployment package',
|
||||
shortcut: 'p',
|
||||
},
|
||||
verbose: {
|
||||
usage: 'Show all stack events during deployment',
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const BbPromise = require('bluebird');
|
||||
const validate = require('./lib/validate');
|
||||
const zipService = require('./lib/zipService');
|
||||
const packageService = require('./lib/packageService');
|
||||
const cleanup = require('./lib/cleanup');
|
||||
|
||||
class Package {
|
||||
constructor(serverless, options) {
|
||||
this.serverless = serverless;
|
||||
this.options = options;
|
||||
|
||||
Object.assign(
|
||||
this,
|
||||
validate,
|
||||
zipService,
|
||||
packageService,
|
||||
cleanup
|
||||
);
|
||||
|
||||
this.hooks = {
|
||||
'deploy:cleanup': () => BbPromise.bind(this)
|
||||
.then(this.cleanup),
|
||||
|
||||
'deploy:createDeploymentArtifacts': () => BbPromise.bind(this)
|
||||
.then(this.validate)
|
||||
.then(this.packageService),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Package;
|
||||
@ -1,14 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const BbPromise = require('bluebird');
|
||||
|
||||
module.exports = {
|
||||
validate() {
|
||||
if (!this.serverless.config.servicePath) {
|
||||
throw new this.serverless.classes
|
||||
.Error('This command can only be run inside a service directory');
|
||||
}
|
||||
|
||||
return BbPromise.resolve();
|
||||
},
|
||||
};
|
||||
@ -1,25 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const expect = require('chai').expect;
|
||||
const Package = require('../index');
|
||||
const Serverless = require('../../../../lib/Serverless');
|
||||
|
||||
describe('#validate()', () => {
|
||||
let serverless;
|
||||
let packageService;
|
||||
|
||||
beforeEach(() => {
|
||||
serverless = new Serverless();
|
||||
packageService = new Package(serverless);
|
||||
});
|
||||
|
||||
it('should throw error if not inside service (servicePath not defined)', () => {
|
||||
packageService.serverless.config.servicePath = false;
|
||||
expect(() => packageService.validate()).to.throw(Error);
|
||||
});
|
||||
|
||||
it('should resolve if servicePath is given', (done) => {
|
||||
packageService.serverless.config.servicePath = true;
|
||||
packageService.validate().then(() => done());
|
||||
});
|
||||
});
|
||||
39
lib/plugins/package/package.js
Normal file
39
lib/plugins/package/package.js
Normal file
@ -0,0 +1,39 @@
|
||||
'use strict';
|
||||
|
||||
class Package {
|
||||
constructor(serverless, options) {
|
||||
this.serverless = serverless;
|
||||
this.options = options;
|
||||
|
||||
|
||||
this.commands = {
|
||||
package: {
|
||||
usage: 'Packages a Serverless service',
|
||||
lifecycleEvents: [
|
||||
'cleanup',
|
||||
'createDeploymentArtifacts',
|
||||
'initialize',
|
||||
'compileFunctions',
|
||||
'compileEvents',
|
||||
'finalize',
|
||||
],
|
||||
options: {
|
||||
stage: {
|
||||
usage: 'Stage of the service',
|
||||
shortcut: 's',
|
||||
},
|
||||
region: {
|
||||
usage: 'Region of the service',
|
||||
shortcut: 'r',
|
||||
},
|
||||
package: {
|
||||
usage: 'Output path for the package',
|
||||
shortcut: 'p',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Package;
|
||||
@ -2,7 +2,8 @@
|
||||
|
||||
const expect = require('chai').expect;
|
||||
const sinon = require('sinon');
|
||||
const Package = require('./index');
|
||||
const BbPromise = require('bluebird');
|
||||
const Package = require('./package');
|
||||
const Serverless = require('../../../lib/Serverless');
|
||||
|
||||
describe('#constructor()', () => {
|
||||
Loading…
x
Reference in New Issue
Block a user