diff --git a/docs/docs/v1.0.x/the-deployment-context.md b/docs/docs/v1.0.x/the-deployment-context.md index c2066850..663f57d6 100644 --- a/docs/docs/v1.0.x/the-deployment-context.md +++ b/docs/docs/v1.0.x/the-deployment-context.md @@ -21,10 +21,53 @@ They do this by simply returning a simple hash from their hooks. When a hook is invoked its return value is **merged** back into the context Object. -**Example:** +## Example ![Example demonstrating context](../../../public/images/context-example.gif) The `ember-cli-deploy-revision-data` plugin uses its `prepare` hook to return an object with this shape: `{ revisionData: ... }`. Later in the lifecycle the `ember-cli-deploy-redis` plugin can find the same `revisionData` key in the `context` object that is passed to its `upload` hook, and use it to determine the key to use for saving the `index.html` file in redis. + +## Opting out of array concatenation + +When the hash returned from a hook contains an array, and the context also contains an array under a property of the same name, then ember-cli-deploy will concatenate them together. Example: + +```js +// Initial context +{ + pets: ['cat', 'dog'] +} + +// Return value of your hook +{ + pets: ['dog', 'hamster'] +} + +// Resulting context +{ + pets: ['cat', 'dog', 'dog', 'hamster'] +} +``` + +In most scenarios, this is very convenient: every hook enriches the context with more values. + +If this behavior is undesirable and instead you would like to replace the array, mention the array's property name in `_keysToDisableConcatenation` like this: + +```js +// Initial context +{ + pets: ['cat', 'dog'] +} + +// Return value of your hook +{ + _keysToDisableConcatenation: ['pets'], + pets: ['dog', 'hamster'] +} + +// Resulting context +{ + pets: ['dog', 'hamster'] +} +``` diff --git a/lib/models/pipeline.js b/lib/models/pipeline.js index d122e228..5282d5f6 100644 --- a/lib/models/pipeline.js +++ b/lib/models/pipeline.js @@ -174,8 +174,19 @@ Pipeline.prototype._notifyPipelinePluginHookExecution = function(ui, fnObject, h }; Pipeline.prototype._mergePluginHookResultIntoContext = function(context,result) { - return _.mergeWith(context, result, function(a, b) { - if (_.isArray(a)) { + var dontConcat = []; + + if (result && result._keysToDisableConcatenation) { + dontConcat = result._keysToDisableConcatenation; + delete result._keysToDisableConcatenation; + } + + if (typeof dontConcat === "string") { + dontConcat = [dontConcat]; + } + + return _.mergeWith(context, result, function(a, b, key) { + if (_.isArray(a) && dontConcat.indexOf(key) === -1) { return a.concat(b); } }); diff --git a/node-tests/unit/models/pipeline-test.js b/node-tests/unit/models/pipeline-test.js index 1852aad5..66179230 100644 --- a/node-tests/unit/models/pipeline-test.js +++ b/node-tests/unit/models/pipeline-test.js @@ -191,6 +191,27 @@ describe ('Pipeline', function() { expect(finalContext.paths).to.deep.equal(['/opt/path', '/tmp/path', '/var/path']); }); }); + + it('merges the return value of each hook with the context without concatenation for properties listed in _keysToDisableConcatenation', function() { + var subject = new Pipeline(['hook1'], {ui: {write: function() {}}}); + var finalContext = null; + + subject.register('hook1', function() { + return { + _keysToDisableConcatenation: ['paths'], + paths: ['/tmp/path', '/var/path'] + }; + }); + + subject.register('hook1', function(context) { + finalContext = context; + }); + + return expect(subject.execute({paths: ['/opt/path']})).to.be.fulfilled + .then(function() { + expect(finalContext.paths).to.deep.equal(['/tmp/path', '/var/path']); + }); + }); }); describe('#hookNames', function() {