diff --git a/lib/createChangeSet.js b/lib/createChangeSet.js index 7255703..12090d9 100644 --- a/lib/createChangeSet.js +++ b/lib/createChangeSet.js @@ -5,9 +5,11 @@ const _ = require('lodash') const createChangeSet = (plugin, stackName, changeSetName, changeSetType) => { const compiledTemplateFileName = 'compiled-cloudformation-template.json' const templateUrl = `https://s3.amazonaws.com/${plugin.bucketName}/${plugin.serverless.service.package.artifactDirectoryName}/${compiledTemplateFileName}` + const stage = plugin.serverless.service.provider.stage + const region = plugin.serverless.service.provider.region let stackTags = { - STAGE: plugin.options.stage + STAGE: stage } // Merge additional stack tags if (typeof plugin.serverless.service.provider.stackTags === 'object') { @@ -39,8 +41,8 @@ const createChangeSet = (plugin, stackName, changeSetName, changeSetType) => { 'CloudFormation', 'createChangeSet', params, - plugin.options.stage, - plugin.options.region + stage, + region ) } diff --git a/lib/createChangeSet.test.js b/lib/createChangeSet.test.js index 8e458f5..eea7fc9 100644 --- a/lib/createChangeSet.test.js +++ b/lib/createChangeSet.test.js @@ -11,127 +11,255 @@ describe('updateStack', () => { let serverless let serverlessChangeSets - beforeEach(() => { - serverless = new Serverless() - serverless.config.servicePath = 'foo' - serverless.setProvider('aws', new AwsProvider(serverless)) - const options = { - stage: 'dev', - region: 'us-east-1', - changeset: 'test' - } - serverlessChangeSets = new ServerlessCloudFormationChangeSets(serverless, options) - serverless.service.service = `service-${(new Date()).getTime().toString()}` - serverlessChangeSets.bucketName = 'deployment-bucket' - serverlessChangeSets.serverless.service.package.artifactDirectoryName = 'somedir' - serverlessChangeSets.serverless.cli = new serverless.classes.CLI() - }) - - describe('#createChangeSet()', () => { - let createChangeSetStub - + describe('with options', () => { beforeEach(() => { - createChangeSetStub = sinon - .stub(serverlessChangeSets.provider, 'request').resolves() + serverless = new Serverless() + serverless.config.servicePath = 'foo' + serverless.setProvider('aws', new AwsProvider(serverless)) + const options = { + stage: 'dev', + region: 'us-east-1', + changeset: 'test' + } + serverlessChangeSets = new ServerlessCloudFormationChangeSets(serverless, options) + serverless.service.service = `service-${(new Date()).getTime().toString()}` + serverlessChangeSets.bucketName = 'deployment-bucket' + serverlessChangeSets.serverless.service.package.artifactDirectoryName = 'somedir' + serverlessChangeSets.serverless.cli = new serverless.classes.CLI() }) - afterEach(() => { - createChangeSetStub.restore() - }) + describe('#createChangeSet()', () => { + let createChangeSetStub - it('should create the CF ChangeSet', () => createChangeSet.bind(serverlessChangeSets)() - .then(() => { - sinon.assert.calledOnce(createChangeSetStub) - sinon.assert.calledWithExactly(createChangeSetStub, - 'CloudFormation', - 'createChangeSet', - { - StackName: serverlessChangeSets.provider.naming.getStackName(), - ChangeSetName: 'test', - Capabilities: [ - 'CAPABILITY_IAM', - 'CAPABILITY_NAMED_IAM' - ], - ChangeSetType: 'UPDATE', - Parameters: [], - TemplateURL: 'https://s3.amazonaws.com/deployment-bucket/somedir/compiled-cloudformation-template.json', - Tags: [{ Key: 'STAGE', Value: 'dev' }] - }, - 'dev', - 'us-east-1' + beforeEach(() => { + createChangeSetStub = sinon + .stub(serverlessChangeSets.provider, 'request').resolves() + }) + + afterEach(() => { + createChangeSetStub.restore() + }) + + it('should create the CF ChangeSet', () => createChangeSet.bind(serverlessChangeSets)() + .then(() => { + sinon.assert.calledOnce(createChangeSetStub) + sinon.assert.calledWithExactly(createChangeSetStub, + 'CloudFormation', + 'createChangeSet', + { + StackName: serverlessChangeSets.provider.naming.getStackName(), + ChangeSetName: 'test', + Capabilities: [ + 'CAPABILITY_IAM', + 'CAPABILITY_NAMED_IAM' + ], + ChangeSetType: 'UPDATE', + Parameters: [], + TemplateURL: 'https://s3.amazonaws.com/deployment-bucket/somedir/compiled-cloudformation-template.json', + Tags: [{ Key: 'STAGE', Value: 'dev' }] + }, + 'dev', + 'us-east-1' + ) + }) ) + + it('should generate ChangSet name if it\'s not provided', () => { + const fakeTimer = sinon.useFakeTimers(1510926650275) + const stackName = serverlessChangeSets.provider.naming.getStackName() + serverlessChangeSets.options.changeSetName = undefined + + return createChangeSet.bind(serverlessChangeSets)() + .then(() => { + sinon.assert.calledWithExactly(createChangeSetStub, + 'CloudFormation', + 'createChangeSet', + { + StackName: stackName, + ChangeSetName: `${stackName}-1510926650275`, + Capabilities: [ + 'CAPABILITY_IAM', + 'CAPABILITY_NAMED_IAM' + ], + ChangeSetType: 'UPDATE', + Parameters: [], + TemplateURL: 'https://s3.amazonaws.com/deployment-bucket/somedir/compiled-cloudformation-template.json', + Tags: [{ Key: 'STAGE', Value: 'dev' }] + }, + 'dev', + 'us-east-1' + ) + fakeTimer.restore() + }) }) - ) - - it('should generate ChangSet name if it\'s not provided', () => { - const fakeTimer = sinon.useFakeTimers(1510926650275) - const stackName = serverlessChangeSets.provider.naming.getStackName() - serverlessChangeSets.options.changeSetName = undefined - - return createChangeSet.bind(serverlessChangeSets)() - .then(() => { - sinon.assert.calledWithExactly(createChangeSetStub, - 'CloudFormation', - 'createChangeSet', - { - StackName: stackName, - ChangeSetName: `${stackName}-1510926650275`, - Capabilities: [ - 'CAPABILITY_IAM', - 'CAPABILITY_NAMED_IAM' - ], - ChangeSetType: 'UPDATE', - Parameters: [], - TemplateURL: 'https://s3.amazonaws.com/deployment-bucket/somedir/compiled-cloudformation-template.json', - Tags: [{ Key: 'STAGE', Value: 'dev' }] - }, - 'dev', - 'us-east-1' - ) - fakeTimer.restore() + + it('should include custom stack tags and CF service role', () => { + serverlessChangeSets.serverless.service.provider.stackTags = { STAGE: 'overridden', tag1: 'value1' } + serverlessChangeSets.serverless.service.provider.cfnRole = 'arn:aws:iam::123456789012:role/myrole' + + return createChangeSet.bind(serverlessChangeSets)().then(() => { + expect(createChangeSetStub.args[0][2].Tags) + .to.deep.equal([ + { Key: 'STAGE', Value: 'overridden' }, + { Key: 'tag1', Value: 'value1' } + ]) + expect(createChangeSetStub.args[0][2].RoleARN).to.equal('arn:aws:iam::123456789012:role/myrole') }) - }) + }) + + it('should create the CF empty stack if it does not exist', () => { + const stackName = serverlessChangeSets.provider.naming.getStackName() + createChangeSetStub.onCall(0).rejects(new Error(`Stack [${stackName}] does not exist`)) - it('should include custom stack tags and CF service role', () => { - serverlessChangeSets.serverless.service.provider.stackTags = { STAGE: 'overridden', tag1: 'value1' } - serverlessChangeSets.serverless.service.provider.cfnRole = 'arn:aws:iam::123456789012:role/myrole' - - return createChangeSet.bind(serverlessChangeSets)().then(() => { - expect(createChangeSetStub.args[0][2].Tags) - .to.deep.equal([ - { Key: 'STAGE', Value: 'overridden' }, - { Key: 'tag1', Value: 'value1' } - ]) - expect(createChangeSetStub.args[0][2].RoleARN).to.equal('arn:aws:iam::123456789012:role/myrole') + return createChangeSet.bind(serverlessChangeSets)() + .then(() => { + sinon.assert.calledTwice(createChangeSetStub) + sinon.assert.calledWithExactly(createChangeSetStub, + 'CloudFormation', + 'createChangeSet', + { + StackName: stackName, + ChangeSetName: 'test', + Capabilities: [ + 'CAPABILITY_IAM', + 'CAPABILITY_NAMED_IAM' + ], + ChangeSetType: 'CREATE', + Parameters: [], + TemplateURL: 'https://s3.amazonaws.com/deployment-bucket/somedir/compiled-cloudformation-template.json', + Tags: [{ Key: 'STAGE', Value: 'dev' }] + }, + 'dev', + 'us-east-1' + ) + }) }) }) + }) + + describe('with ', () => { + beforeEach(() => { + serverless = new Serverless() + serverless.config.servicePath = 'foo' + serverless.setProvider('aws', new AwsProvider(serverless)) + const options = { + changeset: 'test' + } + serverlessChangeSets = new ServerlessCloudFormationChangeSets(serverless, options) + serverless.service.service = `service-${(new Date()).getTime().toString()}` + serverlessChangeSets.bucketName = 'deployment-bucket' + serverlessChangeSets.serverless.service.package.artifactDirectoryName = 'somedir' + serverlessChangeSets.serverless.cli = new serverless.classes.CLI() + serverlessChangeSets.serverless.service.provider.stage = 'dev' + serverlessChangeSets.serverless.service.provider.region = 'us-east-1' + }) + + describe('#createChangeSet()', () => { + let createChangeSetStub + + beforeEach(() => { + createChangeSetStub = sinon + .stub(serverlessChangeSets.provider, 'request').resolves() + }) + + afterEach(() => { + createChangeSetStub.restore() + }) + + it('should create the CF ChangeSet', () => createChangeSet.bind(serverlessChangeSets)() + .then(() => { + sinon.assert.calledOnce(createChangeSetStub) + sinon.assert.calledWithExactly(createChangeSetStub, + 'CloudFormation', + 'createChangeSet', + { + StackName: serverlessChangeSets.provider.naming.getStackName(), + ChangeSetName: 'test', + Capabilities: [ + 'CAPABILITY_IAM', + 'CAPABILITY_NAMED_IAM' + ], + ChangeSetType: 'UPDATE', + Parameters: [], + TemplateURL: 'https://s3.amazonaws.com/deployment-bucket/somedir/compiled-cloudformation-template.json', + Tags: [{ Key: 'STAGE', Value: 'dev' }] + }, + 'dev', + 'us-east-1' + ) + }) + ) - it('should create the CF empty stack if it does not exist', () => { - const stackName = serverlessChangeSets.provider.naming.getStackName() - createChangeSetStub.onCall(0).rejects(new Error(`Stack [${stackName}] does not exist`)) - - return createChangeSet.bind(serverlessChangeSets)() - .then(() => { - sinon.assert.calledTwice(createChangeSetStub) - sinon.assert.calledWithExactly(createChangeSetStub, - 'CloudFormation', - 'createChangeSet', - { - StackName: stackName, - ChangeSetName: 'test', - Capabilities: [ - 'CAPABILITY_IAM', - 'CAPABILITY_NAMED_IAM' - ], - ChangeSetType: 'CREATE', - Parameters: [], - TemplateURL: 'https://s3.amazonaws.com/deployment-bucket/somedir/compiled-cloudformation-template.json', - Tags: [{ Key: 'STAGE', Value: 'dev' }] - }, - 'dev', - 'us-east-1' - ) + it('should generate ChangSet name if it\'s not provided', () => { + const fakeTimer = sinon.useFakeTimers(1510926650275) + const stackName = serverlessChangeSets.provider.naming.getStackName() + serverlessChangeSets.options.changeSetName = undefined + + return createChangeSet.bind(serverlessChangeSets)() + .then(() => { + sinon.assert.calledWithExactly(createChangeSetStub, + 'CloudFormation', + 'createChangeSet', + { + StackName: stackName, + ChangeSetName: `${stackName}-1510926650275`, + Capabilities: [ + 'CAPABILITY_IAM', + 'CAPABILITY_NAMED_IAM' + ], + ChangeSetType: 'UPDATE', + Parameters: [], + TemplateURL: 'https://s3.amazonaws.com/deployment-bucket/somedir/compiled-cloudformation-template.json', + Tags: [{ Key: 'STAGE', Value: 'dev' }] + }, + 'dev', + 'us-east-1' + ) + fakeTimer.restore() + }) + }) + + it('should include custom stack tags and CF service role', () => { + serverlessChangeSets.serverless.service.provider.stackTags = { STAGE: 'overridden', tag1: 'value1' } + serverlessChangeSets.serverless.service.provider.cfnRole = 'arn:aws:iam::123456789012:role/myrole' + + return createChangeSet.bind(serverlessChangeSets)().then(() => { + expect(createChangeSetStub.args[0][2].Tags) + .to.deep.equal([ + { Key: 'STAGE', Value: 'overridden' }, + { Key: 'tag1', Value: 'value1' } + ]) + expect(createChangeSetStub.args[0][2].RoleARN).to.equal('arn:aws:iam::123456789012:role/myrole') }) + }) + + it('should create the CF empty stack if it does not exist', () => { + const stackName = serverlessChangeSets.provider.naming.getStackName() + createChangeSetStub.onCall(0).rejects(new Error(`Stack [${stackName}] does not exist`)) + + return createChangeSet.bind(serverlessChangeSets)() + .then(() => { + sinon.assert.calledTwice(createChangeSetStub) + sinon.assert.calledWithExactly(createChangeSetStub, + 'CloudFormation', + 'createChangeSet', + { + StackName: stackName, + ChangeSetName: 'test', + Capabilities: [ + 'CAPABILITY_IAM', + 'CAPABILITY_NAMED_IAM' + ], + ChangeSetType: 'CREATE', + Parameters: [], + TemplateURL: 'https://s3.amazonaws.com/deployment-bucket/somedir/compiled-cloudformation-template.json', + Tags: [{ Key: 'STAGE', Value: 'dev' }] + }, + 'dev', + 'us-east-1' + ) + }) + }) }) }) })