From 94ae91acaf37079c2ed7ae98d3766af4ec58f3bd Mon Sep 17 00:00:00 2001 From: Aleksander Dikanski Date: Tue, 26 Mar 2019 21:07:04 +0100 Subject: [PATCH] allow configurable master alias --- lib/aliasRestructureStack.js | 21 ++++++++++++--- lib/removeAlias.js | 13 +++++----- lib/validate.js | 3 ++- test/aliasRestructureStack.test.js | 41 ++++++++++++++++++++++++++++++ test/data/sls-stack-2.json | 7 +++++ test/removeAlias.test.js | 18 ++++++++++--- test/updateAliasStack.test.js | 4 --- 7 files changed, 90 insertions(+), 17 deletions(-) diff --git a/lib/aliasRestructureStack.js b/lib/aliasRestructureStack.js index ac7d56e..36ca2d0 100644 --- a/lib/aliasRestructureStack.js +++ b/lib/aliasRestructureStack.js @@ -73,15 +73,30 @@ module.exports = { return BbPromise.resolve([ currentTemplate, aliasStackTemplates, currentAliasStackTemplate ]); }, - aliasRestructureStack(currentTemplate, aliasStackTemplates, currentAliasStackTemplate) { + addMasterAliasName(currentTemplate, aliasStackTemplates, currentAliasStackTemplate) { + const stageStack = this._serverless.service.provider.compiledCloudFormationTemplate; + if (stageStack && !stageStack.Outputs.MasterAliasName) { + const masterAlias = this._masterAlias || currentTemplate.Outputs.MasterAliasName.Value; + stageStack.Outputs.MasterAliasName = { + Description: 'Master Alias name (serverless-aws-alias plugin)', + Value: masterAlias, + Export: { + Name: `${this._provider.naming.getStackName()}-MasterAliasName` + } + }; + } + return BbPromise.resolve([ currentTemplate, aliasStackTemplates, currentAliasStackTemplate ]); + }, + aliasRestructureStack(currentTemplate, aliasStackTemplates, currentAliasStackTemplate) { this._serverless.cli.log('Preparing alias ...'); - if (_.isEmpty(aliasStackTemplates) && this._stage !== this._alias) { - throw new this._serverless.classes.Error(new Error('You have to deploy the master alias at least once with "serverless deploy"')); + if (_.isEmpty(aliasStackTemplates) && this._masterAlias !== this._alias) { + throw new this._serverless.classes.Error(new Error('You have to deploy the master alias at least once with "serverless deploy [--masterAlias]"')); } return BbPromise.resolve([ currentTemplate, aliasStackTemplates, currentAliasStackTemplate ]).bind(this) + .spread(this.addMasterAliasName) .spread(this.aliasInit) .spread(this.aliasHandleUserResources) .spread(this.aliasHandleLambdaRole) diff --git a/lib/removeAlias.js b/lib/removeAlias.js index 3bf717d..fae0e57 100644 --- a/lib/removeAlias.js +++ b/lib/removeAlias.js @@ -221,26 +221,27 @@ module.exports = { this._serverless.cli.log('noDeploy option active - will do nothing'); return BbPromise.resolve(); } - - if (this._stage && this._stage === this._alias) { + + this._masterAlias = currentTemplate.Outputs.MasterAliasName.Value; + if (this._stage && this._masterAlias === this._alias) { // Removal of the master alias is requested -> check if any other aliases are still deployed. const aliases = _.map(aliasStackTemplates, aliasTemplate => _.get(aliasTemplate, 'Outputs.ServerlessAliasName.Value')); if (!_.isEmpty(aliases)) { - throw new this._serverless.classes.Error(`Remove the other deployed aliases before removing the service: ${_.without(aliases, this._alias)}`); + throw new this._serverless.classes.Error(`Remove the other deployed aliases before removing the service: ${_.without(aliases, this._masterAlias)}`); } if (_.isEmpty(currentAliasStackTemplate)) { - throw new this._serverless.classes.Error(`Internal error: Stack for master alias ${this._alias} is not deployed. Try to solve the problem by manual interaction with the AWS console.`); + throw new this._serverless.classes.Error(`Internal error: Stack for master alias ${this._masterAlias} is not deployed. Try to solve the problem by manual interaction with the AWS console.`); } // We're ready for removal - this._serverless.cli.log(`Removing master alias and stage ${this._alias} ...`); + this._serverless.cli.log(`Removing master alias and stage ${this._masterAlias} ...`); return BbPromise.resolve([ currentTemplate, aliasStackTemplates, currentAliasStackTemplate ]).bind(this) .spread(this.aliasRemoveAliasStack) .then(() => this._serverless.pluginManager.spawn('remove')); } - this._serverless.cli.log(`Removing alias ${this._alias} ...`); + this._serverless.cli.log(`Removing alias ${this._masterAlias} ...`); return BbPromise.resolve([ currentTemplate, aliasStackTemplates, currentAliasStackTemplate ]).bind(this) .spread(this.aliasCreateStackChanges) diff --git a/lib/validate.js b/lib/validate.js index 2f446bb..f935238 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -17,7 +17,8 @@ module.exports = { // Set configuration this._stage = this._provider.getStage(); - this._alias = this._options.alias || this._stage; + this._masterAlias = this._options.masterAlias || this._stage; + this._alias = this._options.alias || this._masterAlias; this._stackName = this._provider.naming.getStackName(); // Make alias available as ${self:provider.alias} diff --git a/test/aliasRestructureStack.test.js b/test/aliasRestructureStack.test.js index aedc735..0baaf3f 100644 --- a/test/aliasRestructureStack.test.js +++ b/test/aliasRestructureStack.test.js @@ -56,6 +56,45 @@ describe('aliasRestructureStack', () => { sandbox.restore(); }); + describe('#addMasterAliasName', () => { + it('should add the master alias name as output from command line option', () => { + serverless.service.provider.compiledCloudFormationTemplate = _.cloneDeep({ + Resources: {}, + Outputs: {} + }); + awsAlias._masterAlias = 'master' + return expect(awsAlias.addMasterAliasName()).to.be.fulfilled + .then(() => + expect(serverless.service.provider.compiledCloudFormationTemplate.Outputs.MasterAliasName.Value) + .to.equal('master') + ); + }); + + it('should add the master alias name as output from existing stack', () => { + const masterAliasStackOutput = { + MasterAliasName: { + Description: 'Master Alias name (serverless-aws-alias plugin)', + Value: 'master', + Export: { + Name: 'sls-test-project-dev-master' + } + } + }; + const currentTemplate = { + Outputs: masterAliasStackOutput + }; + serverless.service.provider.compiledCloudFormationTemplate = _.cloneDeep({ + Resources: {}, + Outputs: {} + }); + return expect(awsAlias.addMasterAliasName(currentTemplate)).to.be.fulfilled + .then(() => + expect(serverless.service.provider.compiledCloudFormationTemplate.Outputs.MasterAliasName.Value) + .to.equal('master') + ); + }); + }); + describe('#aliasFinalize()', () => { it('should stringify flags', () => { serverless.service.provider.compiledCloudFormationAliasTemplate = { @@ -85,6 +124,7 @@ describe('aliasRestructureStack', () => { }); it('should propagate templates through all stack operations', () => { + const addMasterAliasNameSpy = sandbox.spy(awsAlias, 'addMasterAliasName'); const aliasInitSpy = sandbox.spy(awsAlias, 'aliasInit'); const aliasHandleUserResourcesSpy = sandbox.spy(awsAlias, 'aliasHandleUserResources'); const aliasHandleLambdaRoleSpy = sandbox.spy(awsAlias, 'aliasHandleLambdaRole'); @@ -102,6 +142,7 @@ describe('aliasRestructureStack', () => { return expect(awsAlias.aliasRestructureStack(currentTemplate, [ aliasTemplate ], currentAliasStackTemplate)) .to.be.fulfilled .then(() => BbPromise.all([ + expect(addMasterAliasNameSpy).to.have.been.calledWithExactly(currentTemplate, [ aliasTemplate ], currentAliasStackTemplate), expect(aliasInitSpy).to.have.been.calledWithExactly(currentTemplate, [ aliasTemplate ], currentAliasStackTemplate), expect(aliasHandleUserResourcesSpy).to.have.been.calledWithExactly(currentTemplate, [ aliasTemplate ], currentAliasStackTemplate), expect(aliasHandleLambdaRoleSpy).to.have.been.calledWithExactly(currentTemplate, [ aliasTemplate ], currentAliasStackTemplate), diff --git a/test/data/sls-stack-2.json b/test/data/sls-stack-2.json index 3b63a78..f3d6edb 100644 --- a/test/data/sls-stack-2.json +++ b/test/data/sls-stack-2.json @@ -322,6 +322,13 @@ ] ] } + }, + "MasterAliasName": { + "Description": "Master Alias name (serverless-aws-alias plugin)", + "Value": "master", + "Export": { + "Name": "sls-test-project-dev-master" + } } } } diff --git a/test/removeAlias.test.js b/test/removeAlias.test.js index b5201ca..015896c 100644 --- a/test/removeAlias.test.js +++ b/test/removeAlias.test.js @@ -90,7 +90,10 @@ describe('removeAlias', () => { it('should error if an alias is deployed on stage removal', () => { awsAlias._options = { alias: 'myStage' }; - awsAlias._alias = 'myStage'; + awsAlias._alias = 'master'; + slsStack1.Outputs.MasterAliasName = { + Value: 'master' + }; expect(() => awsAlias.removeAlias(slsStack1, [ aliasStack1 ], aliasStack2)).to.throw(/myAlias/); return BbPromise.all([ @@ -103,7 +106,10 @@ describe('removeAlias', () => { it('should error if the master alias is not deployed on stage removal', () => { awsAlias._options = { alias: 'myStage' }; - awsAlias._alias = 'myStage'; + awsAlias._alias = 'master'; + slsStack1.Outputs.MasterAliasName = { + Value: 'master' + }; expect(() => awsAlias.removeAlias(slsStack1, [], {})).to.throw(/Internal error/); return BbPromise.all([ @@ -116,7 +122,10 @@ describe('removeAlias', () => { it('should remove alias and service stack on stage removal', () => { awsAlias._options = { alias: 'myStage' }; - awsAlias._alias = 'myStage'; + awsAlias._alias = 'master'; + slsStack1.Outputs.MasterAliasName = { + Value: 'master' + }; return expect(awsAlias.removeAlias(slsStack1, [], aliasStack2)).to.be.fulfilled .then(() => BbPromise.all([ @@ -128,6 +137,9 @@ describe('removeAlias', () => { }); it('should remove alias stack', () => { + slsStack1.Outputs.MasterAliasName = { + Value: 'master' + }; aliasApplyStackChangesStub.returns([ slsStack1, [ aliasStack2 ], aliasStack1 ]); aliasCreateStackChangesStub.returns([ slsStack1, [ aliasStack2 ], aliasStack1 ]); aliasRemoveAliasStackStub.returns([ slsStack1, [ aliasStack2 ], aliasStack1 ]); diff --git a/test/updateAliasStack.test.js b/test/updateAliasStack.test.js index d60c933..41b115c 100644 --- a/test/updateAliasStack.test.js +++ b/test/updateAliasStack.test.js @@ -262,10 +262,6 @@ describe('updateAliasStack', () => { it('should resolve in case no updates are performed', () => { providerRequestStub.returns(BbPromise.resolve("done")); monitorStackStub.rejects(new Error('No updates are to be performed.')); -<<<<<<< HEAD -======= - ->>>>>>> 2b80fe1... useless exception messages are removed while mocha ci return expect(awsAlias.updateAlias()).to.be.fulfilled .then(() => expect(providerRequestStub).to.have.been.calledOnce); });