mirror of
https://github.com/serverless/serverless.git
synced 2026-02-01 16:07:28 +00:00
Merge pull request #3668 from hassankhan/validate-cf-template-locally
Add support for validating CF templates
This commit is contained in:
commit
9e068b81b3
@ -15,6 +15,7 @@ const createStack = require('./lib/createStack');
|
||||
const setBucketName = require('../lib/setBucketName');
|
||||
const cleanupS3Bucket = require('./lib/cleanupS3Bucket');
|
||||
const uploadArtifacts = require('./lib/uploadArtifacts');
|
||||
const validateTemplate = require('./lib/validateTemplate');
|
||||
const updateStack = require('../lib/updateStack');
|
||||
const path = require('path');
|
||||
|
||||
@ -35,6 +36,7 @@ class AwsDeploy {
|
||||
setBucketName,
|
||||
cleanupS3Bucket,
|
||||
uploadArtifacts,
|
||||
validateTemplate,
|
||||
updateStack,
|
||||
monitorStack
|
||||
);
|
||||
@ -50,6 +52,7 @@ class AwsDeploy {
|
||||
lifecycleEvents: [
|
||||
'createStack',
|
||||
'uploadArtifacts',
|
||||
'validateTemplate',
|
||||
'updateStack',
|
||||
],
|
||||
},
|
||||
@ -95,6 +98,9 @@ class AwsDeploy {
|
||||
.then(this.setBucketName)
|
||||
.then(this.uploadArtifacts),
|
||||
|
||||
'aws:deploy:deploy:validateTemplate': () => BbPromise.bind(this)
|
||||
.then(this.validateTemplate),
|
||||
|
||||
'aws:deploy:deploy:updateStack': () => BbPromise.bind(this)
|
||||
.then(this.updateStack),
|
||||
|
||||
|
||||
@ -1,12 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
/* eslint-disable no-unused-expressions */
|
||||
|
||||
const AwsProvider = require('../provider/awsProvider');
|
||||
const AwsDeploy = require('./index');
|
||||
const chai = require('chai');
|
||||
const Serverless = require('../../../Serverless');
|
||||
const expect = require('chai').expect;
|
||||
const sinon = require('sinon');
|
||||
const path = require('path');
|
||||
|
||||
// Configure chai
|
||||
chai.use(require('chai-as-promised'));
|
||||
chai.use(require('sinon-chai'));
|
||||
const expect = require('chai').expect;
|
||||
|
||||
describe('AwsDeploy', () => {
|
||||
let awsDeploy;
|
||||
let serverless;
|
||||
@ -78,6 +85,7 @@ describe('AwsDeploy', () => {
|
||||
let createStackStub;
|
||||
let setBucketNameStub;
|
||||
let uploadArtifactsStub;
|
||||
let validateTemplateStub;
|
||||
let updateStackStub;
|
||||
|
||||
beforeEach(() => {
|
||||
@ -89,6 +97,8 @@ describe('AwsDeploy', () => {
|
||||
.stub(awsDeploy, 'setBucketName').resolves();
|
||||
uploadArtifactsStub = sinon
|
||||
.stub(awsDeploy, 'uploadArtifacts').resolves();
|
||||
validateTemplateStub = sinon
|
||||
.stub(awsDeploy, 'validateTemplate').resolves();
|
||||
updateStackStub = sinon
|
||||
.stub(awsDeploy, 'updateStack').resolves();
|
||||
});
|
||||
@ -98,6 +108,7 @@ describe('AwsDeploy', () => {
|
||||
awsDeploy.createStack.restore();
|
||||
awsDeploy.setBucketName.restore();
|
||||
awsDeploy.uploadArtifacts.restore();
|
||||
awsDeploy.validateTemplate.restore();
|
||||
awsDeploy.updateStack.restore();
|
||||
});
|
||||
|
||||
@ -189,6 +200,12 @@ describe('AwsDeploy', () => {
|
||||
})
|
||||
);
|
||||
|
||||
it('should run "aws:deploy:deploy:validateTemplate" hook', () => expect(awsDeploy
|
||||
.hooks['aws:deploy:deploy:validateTemplate']()).to.be.fulfilled.then(() => {
|
||||
expect(validateTemplateStub).to.have.been.calledOnce;
|
||||
})
|
||||
);
|
||||
|
||||
it('should run "aws:deploy:deploy:updateStack" hook', () => awsDeploy
|
||||
.hooks['aws:deploy:deploy:updateStack']().then(() => {
|
||||
expect(updateStackStub.calledOnce).to.equal(true);
|
||||
|
||||
28
lib/plugins/aws/deploy/lib/validateTemplate.js
Normal file
28
lib/plugins/aws/deploy/lib/validateTemplate.js
Normal file
@ -0,0 +1,28 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
validateTemplate() {
|
||||
const bucketName = this.bucketName;
|
||||
const artifactDirectoryName = this.serverless.service.package.artifactDirectoryName;
|
||||
const compiledTemplateFileName = 'compiled-cloudformation-template.json';
|
||||
|
||||
this.serverless.cli.log('Validating template...');
|
||||
const params = {
|
||||
TemplateURL: `https://s3.amazonaws.com/${bucketName}/${artifactDirectoryName}/${compiledTemplateFileName}`,
|
||||
};
|
||||
|
||||
return this.provider.request(
|
||||
'CloudFormation',
|
||||
'validateTemplate',
|
||||
params,
|
||||
this.options.stage,
|
||||
this.options.region
|
||||
).catch((error) => {
|
||||
const errorMessage = [
|
||||
'The CloudFormation template is invalid:',
|
||||
` ${error.message}`,
|
||||
].join('');
|
||||
throw new Error(errorMessage);
|
||||
});
|
||||
},
|
||||
};
|
||||
85
lib/plugins/aws/deploy/lib/validateTemplate.test.js
Normal file
85
lib/plugins/aws/deploy/lib/validateTemplate.test.js
Normal file
@ -0,0 +1,85 @@
|
||||
'use strict';
|
||||
|
||||
/* eslint-disable no-unused-expressions */
|
||||
|
||||
const sinon = require('sinon');
|
||||
const chai = require('chai');
|
||||
const AwsProvider = require('../../provider/awsProvider');
|
||||
const AwsDeploy = require('../index');
|
||||
const Serverless = require('../../../../Serverless');
|
||||
|
||||
// Configure chai
|
||||
chai.use(require('chai-as-promised'));
|
||||
chai.use(require('sinon-chai'));
|
||||
const expect = require('chai').expect;
|
||||
|
||||
describe('validateTemplate', () => {
|
||||
let awsDeploy;
|
||||
let serverless;
|
||||
let validateTemplateStub;
|
||||
|
||||
beforeEach(() => {
|
||||
serverless = new Serverless();
|
||||
serverless.config.servicePath = 'foo';
|
||||
serverless.setProvider('aws', new AwsProvider(serverless));
|
||||
const options = {
|
||||
stage: 'dev',
|
||||
region: 'us-east-1',
|
||||
};
|
||||
awsDeploy = new AwsDeploy(serverless, options);
|
||||
awsDeploy.bucketName = 'deployment-bucket';
|
||||
awsDeploy.serverless.service.package.artifactDirectoryName = 'somedir';
|
||||
awsDeploy.serverless.service.functions = {
|
||||
first: {
|
||||
handler: 'foo',
|
||||
},
|
||||
};
|
||||
validateTemplateStub = sinon.stub(awsDeploy.provider, 'request');
|
||||
awsDeploy.serverless.cli = {
|
||||
log: sinon.spy(),
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
awsDeploy.provider.request.restore();
|
||||
});
|
||||
|
||||
describe('#validateTemplate()', () => {
|
||||
it('should resolve if the CloudFormation template is valid', () => {
|
||||
validateTemplateStub.resolves();
|
||||
|
||||
return expect(awsDeploy.validateTemplate()).to.be.fulfilled.then(() => {
|
||||
expect(awsDeploy.serverless.cli.log).to.have.been.called;
|
||||
expect(validateTemplateStub).to.have.been.calledOnce;
|
||||
expect(validateTemplateStub).to.have.been.calledWithExactly(
|
||||
'CloudFormation',
|
||||
'validateTemplate',
|
||||
{
|
||||
TemplateURL: 'https://s3.amazonaws.com/deployment-bucket/somedir/compiled-cloudformation-template.json',
|
||||
},
|
||||
awsDeploy.options.stage,
|
||||
awsDeploy.options.region
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if the CloudFormation template is invalid', () => {
|
||||
validateTemplateStub.rejects({ message: 'Some error while validating' });
|
||||
|
||||
return expect(awsDeploy.validateTemplate()).to.be.rejected.then((error) => {
|
||||
expect(awsDeploy.serverless.cli.log).to.have.been.called;
|
||||
expect(validateTemplateStub).to.have.been.calledOnce;
|
||||
expect(validateTemplateStub).to.have.been.calledWithExactly(
|
||||
'CloudFormation',
|
||||
'validateTemplate',
|
||||
{
|
||||
TemplateURL: 'https://s3.amazonaws.com/deployment-bucket/somedir/compiled-cloudformation-template.json',
|
||||
},
|
||||
awsDeploy.options.stage,
|
||||
awsDeploy.options.region
|
||||
);
|
||||
expect(error.message).to.match(/is invalid: Some error while validating/);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user