diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a0c9ac5..82b6dfc 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,12 +4,17 @@ Changelog in development -------------- +0.9.7 +----- +* Fix Mattermost adapter [PR #193] (bug fix) + 0.9.6 +----- * Don't consider failed alias execution as a critical reason to exit hubot (bug fix) 0.9.5 ----- -* Exit hubot on invalid, expired `ST2_API_KEY` / `ST2_AUTH_TOKEN` or any other Unauthorized response from st2 server (bug fix) +* Exit hubot on invalid, expired ``ST2_API_KEY`` / ``ST2_AUTH_TOKEN`` or any other Unauthorized response from st2 server (bug fix) * When st2 username/password is used, re-generate st2 auth token in advance, giving enough time for request to complete, st2client.js (bug fix) 0.9.4 @@ -24,7 +29,7 @@ in development 0.9.2 ----- -* Rename ENV variable `ST2_API` -> `ST2_API_URL` for consistency, keep `ST2_API` for backwards compatibility (improvement) +* Rename ENV variable ``ST2_API`` -> ``ST2_API_URL`` for consistency, keep ``ST2_API`` for backwards compatibility (improvement) 0.9.1 ----- diff --git a/lib/post_data.js b/lib/post_data.js index 7b6e4ea..e9e8123 100644 --- a/lib/post_data.js +++ b/lib/post_data.js @@ -298,16 +298,20 @@ MattermostDataPostHandler.prototype.postData = function(data) { Inorder to accept the matteruser adapter message attachments changed the attachement json */ - attachment = { - room: recipient, - attachments: content.attachments ? content.attachments : content, + var envelope = { + room: recipient + }; + var message = { + props: { + attachments: (content.attachments ? content.attachments : [content]) + }, // There is likely a bug here - `split_message.text` being a true-y // value does not imply that `split_message.pretext` is also non-empty, // but we unconditionally set `text` to // `pretext + split_message.pretext` on the first message - text: i === 0 ? pretext + split_message.pretext : null + message: i === 0 ? pretext + split_message.pretext : null }; - robot.emit('slack-attachment', attachment); + robot.adapter.send(envelope, message); if (chunks.length > ++i) { setTimeout(function(){ sendChunk(i); }, 300); } diff --git a/package.json b/package.json index be512fa..0f9d048 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "hubot-stackstorm", "description": "A hubot plugin for integrating with StackStorm event-driven infrastructure automation platform.", - "version": "0.9.6", + "version": "0.9.7", "author": "StackStorm, Inc. ", "license": "Apache-2.0", "keywords": [ @@ -21,7 +21,6 @@ "url": "https://github.com/StackStorm/hubot-stackstorm/issues" }, "dependencies": { - "babel-eslint": "^10.0.1", "cli-table": "<=1.0.0", "coffee-register": "1.0.0", "coffee-script": "1.12.7", @@ -35,6 +34,7 @@ "hubot": "3.x" }, "devDependencies": { + "babel-eslint": "^10.0.1", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "eslint": "^5.16.0", diff --git a/tests/dummy-adapters.js b/tests/dummy-adapters.js index d6d1ea5..802c2e7 100644 --- a/tests/dummy-adapters.js +++ b/tests/dummy-adapters.js @@ -27,6 +27,14 @@ function MockSlackAdapter(logger) { this.client = new MockSlackClient(logger); } +function MockMattermostAdapter(logger) { + this.logger = logger; +} + +MockMattermostAdapter.prototype.send = function(envelope, message) { + this.logger.debug('Sending ' + JSON.stringify(message) + ' to ' + JSON.stringify(envelope)); +}; + function MockBotFrameworkAdapter(logger) { this.logger = logger; } @@ -35,5 +43,8 @@ MockBotFrameworkAdapter.prototype.send = function(envelope, message) { this.logger.info('Sending ' + JSON.stringify(message) + ' to ' + JSON.stringify(envelope)); }; -module.exports.MockSlackAdapter = MockSlackAdapter; -module.exports.MockBotFrameworkAdapter = MockBotFrameworkAdapter; +module.exports = { + MockSlackAdapter: MockSlackAdapter, + MockMattermostAdapter: MockMattermostAdapter, + MockBotFrameworkAdapter: MockBotFrameworkAdapter +}; diff --git a/tests/test-postdata.js b/tests/test-postdata.js index a275017..bfadf71 100644 --- a/tests/test-postdata.js +++ b/tests/test-postdata.js @@ -30,6 +30,7 @@ var chai = require("chai"), util = require('util'); var MockSlackAdapter = dummyAdapters.MockSlackAdapter; +var MockMattermostAdapter = dummyAdapters.MockMattermostAdapter; var MockBotFrameworkAdapter = dummyAdapters.MockBotFrameworkAdapter; chai.use(sinonChai); @@ -431,7 +432,7 @@ describe("mattermost post data", function() { env.ST2_MATTERMOST_FAIL_COLOR = 'danger'; it('should post to room and mention a user', function() { - robot.emit = sinon.spy(); + robot.adapter.send = sinon.spy(); var input = { user: 'stanley', channel: '#stackstorm', @@ -441,24 +442,27 @@ describe("mattermost post data", function() { var user = util.format('@%s: ', input.user); postDataHandler.postData(input); - expect(robot.emit).to.have.been.calledOnce; - expect(robot.emit).to.have.been.calledWith( - 'slack-attachment', + expect(robot.adapter.send).to.have.been.calledOnceWith( + { + room: '#stackstorm' + }, { - attachments: { - color: env.ST2_MATTERMOST_SUCCESS_COLOR, - fallback: "normal boring text", - mrkdwn_in: ["text", "pretext"], - text: "normal boring text" + props: { + attachments: [ + { + color: env.ST2_MATTERMOST_SUCCESS_COLOR, + fallback: "normal boring text", + mrkdwn_in: ["text", "pretext"], + text: "normal boring text" + } + ] }, - room: input.channel, - text: user + "NORMAL PRETEXT" - } - ); + message: user + "NORMAL PRETEXT" + }); }); it('should post to room and not mention a user', function() { - robot.emit = sinon.spy(); + robot.adapter.send = sinon.spy(); var input = { channel: '#stackstorm', message: util.format('NORMAL PRETEXT{~}normal boring text'), @@ -467,20 +471,23 @@ describe("mattermost post data", function() { var user = util.format('@%s: ', input.user); postDataHandler.postData(input); - expect(robot.emit).to.have.been.calledOnce; - expect(robot.emit).to.have.been.calledWith( - 'slack-attachment', + expect(robot.adapter.send).to.have.been.calledOnceWith( + { + room: input.channel + }, { - attachments: { - color: env.ST2_MATTERMOST_SUCCESS_COLOR, - fallback: "normal boring text", - mrkdwn_in: ["text", "pretext"], - text: "normal boring text" + props: { + attachments: [ + { + color: env.ST2_MATTERMOST_SUCCESS_COLOR, + fallback: "normal boring text", + mrkdwn_in: ["text", "pretext"], + text: "normal boring text" + } + ] }, - room: input.channel, - text: "NORMAL PRETEXT" - } - ); + message: "NORMAL PRETEXT" + }); }); it('should just post messgae with pretext to room', function() { @@ -494,15 +501,14 @@ describe("mattermost post data", function() { var user = util.format('@%s: ', input.user); postDataHandler.postData(input); - expect(robot.messageRoom).to.have.been.calledOnce; - expect(robot.messageRoom).to.have.been.calledWith( + expect(robot.messageRoom).to.have.been.calledOnceWith( input.channel, user + "NORMAL PRETEXT" ); }); it('should post success formatted slack attachment', function() { - robot.emit = sinon.spy(); + robot.adapter.send = sinon.spy(); var input = { user: 'stanley', channel: '#stackstorm', @@ -515,25 +521,28 @@ describe("mattermost post data", function() { var user = util.format('@%s: ', input.user); postDataHandler.postData(input); - expect(robot.emit).to.have.been.calledOnce; - expect(robot.emit).to.have.been.calledWith( - 'slack-attachment', + expect(robot.adapter.send).to.have.been.calledOnceWith( + { + room: input.channel + }, { - attachments: { - color: env.ST2_MATTERMOST_SUCCESS_COLOR, - fallback: input.message, - mrkdwn_in: ["text", "pretext"], - text: input.message + props: { + attachments: [ + { + color: env.ST2_MATTERMOST_SUCCESS_COLOR, + fallback: input.message, + mrkdwn_in: ["text", "pretext"], + text: input.message + } + ] }, - room: input.channel, - text: user - } - ); + message: user + }); }); it('should split a long attachment into chunks', function() { this.clock = sinon.useFakeTimers(); - robot.emit = sinon.spy(); + robot.adapter.send = sinon.spy(); var input = { user: 'stanley', channel: '#stackstorm', @@ -544,155 +553,167 @@ describe("mattermost post data", function() { chunks = input.message.match(/[\s\S]{1,3800}/g); postDataHandler.postData(input); - expect(robot.emit).to.have.been.calledWith( - 'slack-attachment', + expect(robot.adapter.send).to.have.been.calledWith( { - attachments: { - color: env.ST2_MATTERMOST_SUCCESS_COLOR, - fallback: input.message, - mrkdwn_in: ["text", "pretext"], - text: chunks[0], - fallback: chunks[0] + room: input.channel + }, + { + props: { + attachments: [ + { + color: env.ST2_MATTERMOST_SUCCESS_COLOR, + fallback: chunks[0], + mrkdwn_in: ["text", "pretext"], + text: chunks[0] + } + ] }, - room: input.channel, - text: user - } - ); + message: user + }); this.clock.tick(500); - expect(robot.emit).to.have.been.calledWith( - 'slack-attachment', + expect(robot.adapter.send).to.have.been.calledWith( { - attachments: { - color: env.ST2_MATTERMOST_SUCCESS_COLOR, - fallback: input.message, - mrkdwn_in: ["text", "pretext"], - text: chunks[1], - fallback: chunks[1] + room: input.channel + }, + { + props: { + attachments: [ + { + color: env.ST2_MATTERMOST_SUCCESS_COLOR, + fallback: chunks[1], + mrkdwn_in: ["text", "pretext"], + text: chunks[1] + } + ] }, - room: input.channel, - text: user - } - ); - expect(robot.emit).to.have.been.calledTwice; + message: user + }); + this.clock.tick(500); + expect(robot.adapter.send).to.have.been.calledTwice; this.clock.restore(); }); it('should post success with custom color', function() { - robot.emit = sinon.spy(); + robot.adapter.send = sinon.spy(); var message = util.format('%s\nstatus : %s\nexecution: %s', 'Short message', 'succeeded', '1'), input = { - user: 'stanley', - channel: '#stackstorm', - message: message, - whisper: false, - extra: { - color: 'CUSTOM_COLOR' - } - }; + user: 'stanley', + channel: '#stackstorm', + message: message, + whisper: false, + extra: { + color: 'CUSTOM_COLOR' + } + }; var user = util.format('@%s: ', input.user); postDataHandler.postData(input); - expect(robot.emit).to.have.been.calledOnce; - expect(robot.emit).to.have.been.calledWith( - 'slack-attachment', + expect(robot.adapter.send).to.have.been.calledOnceWith( + { + room: '#stackstorm' + }, { - attachments: { - color: 'CUSTOM_COLOR', - fallback: input.message, - mrkdwn_in: ["text", "pretext"], - text: input.message + props: { + attachments: [ + { + color: 'CUSTOM_COLOR', + fallback: input.message, + mrkdwn_in: ["text", "pretext"], + text: input.message + } + ], }, - room: input.channel, - text: user - } - ); + message: user + }); }); it('should post success formatted slack attachment with extra', function() { - robot.emit = sinon.spy(); + robot.adapter.send = sinon.spy(); var message = util.format('%s\nstatus : %s\nexecution: %s', 'Short message', 'succeeded', '1'), input = { - user: 'stanley', - channel: '#stackstorm', - message: message, - whisper: false, - extra: { - mattermost: { - icon_emoji: ":mattermost:", - username: "MattermostBot", - attachments: [ - { - color: "dfdfdf", - mrkdwn_in: ["text","pretext"], - pretext: "@stanley: ", - text: message, - fallback: message + user: 'stanley', + channel: '#stackstorm', + message: message, + whisper: false, + extra: { + mattermost: { + icon_emoji: ":mattermost:", + username: "MattermostBot", + attachments: [ + { + color: "dfdfdf", + mrkdwn_in: ["text","pretext"], + pretext: "@stanley: ", + text: message, + fallback: message + } + ] } - ] - } - } - }; + } + }; postDataHandler.postData(input); - expect(robot.emit).to.have.been.calledOnce; - expect(robot.emit).to.have.been.calledWith( - 'slack-attachment', + expect(robot.adapter.send).to.have.been.calledOnceWith( { - attachments: input.extra.mattermost.attachments, - room: input.channel, - text: "@stanley: " - } - ); + room: input.channel + }, + { + props: { + attachments: input.extra.mattermost.attachments + }, + message: "@stanley: " + }); }); it('should whisper a slack-attachment', function() { - robot.emit = sinon.spy(); + robot.adapter.send = sinon.spy(); var message = util.format('%s\nstatus : %s\nexecution: %s', 'Short message', 'succeeded', '1'), input = { - user: 'stanley', - channel: '#stackstorm', - message: message, - whisper: true, - extra: { - mattermost: { - icon_emoji: ":mattermost:", - username: "MattermostBot", - attachments: [ - { - color: "dfdfdf", - mrkdwn_in: ["text","pretext"], - pretext: "@stanley: ", - text: message, - fallback: message + user: 'stanley', + channel: '#stackstorm', + message: message, + whisper: true, + extra: { + mattermost: { + icon_emoji: ":mattermost:", + username: "MattermostBot", + attachments: [ + { + color: "dfdfdf", + mrkdwn_in: ["text","pretext"], + pretext: "@stanley: ", + text: message, + fallback: message + } + ] } - ] - } - } - }; + } + }; postDataHandler.postData(input); - expect(robot.emit).to.have.been.calledOnce; - expect(robot.emit).to.have.been.calledWith( - 'slack-attachment', + expect(robot.adapter.send).to.have.been.calledOnceWith( { - attachments: input.extra.mattermost.attachments, - room: input.user, - text: '' - } - ); + room: input.user + }, + { + props: { + attachments: input.extra.mattermost.attachments, + }, + message: '' + }); }); it('should post fail formatted slack attachment', function() { - robot.emit = sinon.spy(); + robot.adapter.send = sinon.spy(); var input = { user: 'stanley', channel: '#stackstorm', @@ -705,20 +726,23 @@ describe("mattermost post data", function() { var user = util.format('@%s: ', input.user); postDataHandler.postData(input); - expect(robot.emit).to.have.been.calledOnce; - expect(robot.emit).to.have.been.calledWith( - 'slack-attachment', + expect(robot.adapter.send).to.have.been.calledOnceWith( { - attachments: { - color: env.ST2_MATTERMOST_FAIL_COLOR, - fallback: input.message, - mrkdwn_in: ["text", "pretext"], - text: input.message + room: input.channel + }, + { + props: { + attachments: [ + { + color: env.ST2_MATTERMOST_FAIL_COLOR, + fallback: input.message, + mrkdwn_in: ["text", "pretext"], + text: input.message + } + ] }, - room: input.channel, - text: user - } - ); + message: user + }); }); });