mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-11 00:08:30 +01:00
feat: slack app addon default channels (#4308)
https://linear.app/unleash/issue/2-1249/add-support-for-default-slack-channels Adds support for default Slack channels (multiple, comma-separated). Some of the events we are handling do not have associated tags, or maybe the tags are empty. This adds a "default Slack channels" parameter to the addon configuration in order to post messages to those channels in those cases. <img width="643" alt="image" src="https://github.com/Unleash/unleash/assets/14320932/ee23d6c7-33b7-4968-a0b1-13b546b5b2a2"> --------- Co-authored-by: Gastón Fournier <gaston@getunleash.io>
This commit is contained in:
parent
34c4dd573a
commit
d6c8493156
@ -83,3 +83,45 @@ exports[`SlackAppAddon should post to all channels in tags 2`] = `
|
||||
"text": "some@user.com *enabled* <http://some-url.com/projects/default/features/some-toggle|some-toggle> in *development* environment in project *default*",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`SlackAppAddon should use defaultChannels if no tagged channels are found 1`] = `
|
||||
{
|
||||
"attachments": [
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"name": "featureToggle",
|
||||
"style": "primary",
|
||||
"text": "Open in Unleash",
|
||||
"type": "button",
|
||||
"url": "http://some-url.com/projects/default/features/some-toggle",
|
||||
"value": "featureToggle",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"channel": 1,
|
||||
"text": "some@user.com *enabled* <http://some-url.com/projects/default/features/some-toggle|some-toggle> in *development* environment in project *default*",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`SlackAppAddon should use defaultChannels if no tagged channels are found 2`] = `
|
||||
{
|
||||
"attachments": [
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"name": "featureToggle",
|
||||
"style": "primary",
|
||||
"text": "Open in Unleash",
|
||||
"type": "button",
|
||||
"url": "http://some-url.com/projects/default/features/some-toggle",
|
||||
"value": "featureToggle",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"channel": 2,
|
||||
"text": "some@user.com *enabled* <http://some-url.com/projects/default/features/some-toggle|some-toggle> in *development* environment in project *default*",
|
||||
}
|
||||
`;
|
||||
|
@ -48,6 +48,15 @@ const slackAppDefinition: IAddonDefinition = {
|
||||
required: true,
|
||||
sensitive: true,
|
||||
},
|
||||
{
|
||||
name: 'defaultChannels',
|
||||
displayName: 'Default channels',
|
||||
description:
|
||||
'A comma-separated list of channels to post to if no tagged channels are found (e.g. a toggle without tags, or an event with no tags associated).',
|
||||
type: 'text',
|
||||
required: false,
|
||||
sensitive: false,
|
||||
},
|
||||
],
|
||||
events: [
|
||||
FEATURE_CREATED,
|
||||
|
@ -79,6 +79,7 @@ describe('SlackAppAddon', () => {
|
||||
jest.useFakeTimers();
|
||||
slackApiCalls.length = 0;
|
||||
conversationsList.mockClear();
|
||||
postMessage.mockClear();
|
||||
addon = new SlackAppAddon({
|
||||
getLogger,
|
||||
unleashUrl: 'http://some-url.com',
|
||||
@ -153,6 +154,37 @@ describe('SlackAppAddon', () => {
|
||||
expect(conversationsList).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should not post a message if there are no tagged channels and no defaultChannels', async () => {
|
||||
const eventWithoutTags: IEvent = {
|
||||
...event,
|
||||
tags: [],
|
||||
};
|
||||
|
||||
await addon.handleEvent(eventWithoutTags, {
|
||||
accessToken,
|
||||
});
|
||||
|
||||
expect(slackApiCalls.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should use defaultChannels if no tagged channels are found', async () => {
|
||||
const eventWithoutTags: IEvent = {
|
||||
...event,
|
||||
tags: [],
|
||||
};
|
||||
|
||||
await addon.handleEvent(eventWithoutTags, {
|
||||
accessToken,
|
||||
defaultChannels: 'general, another-channel-1',
|
||||
});
|
||||
|
||||
expect(slackApiCalls.length).toBe(2);
|
||||
expect(slackApiCalls[0].channel).toBe(1);
|
||||
expect(slackApiCalls[0]).toMatchSnapshot();
|
||||
expect(slackApiCalls[1].channel).toBe(2);
|
||||
expect(slackApiCalls[1]).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should log error when an API call fails', async () => {
|
||||
postMessage = jest.fn().mockRejectedValue(mockError);
|
||||
|
||||
|
@ -25,6 +25,7 @@ const CACHE_SECONDS = 30;
|
||||
|
||||
interface ISlackAppAddonParameters {
|
||||
accessToken: string;
|
||||
defaultChannels: string;
|
||||
}
|
||||
|
||||
export default class SlackAppAddon extends Addon {
|
||||
@ -52,17 +53,20 @@ export default class SlackAppAddon extends Addon {
|
||||
parameters: ISlackAppAddonParameters,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const { accessToken } = parameters;
|
||||
const { accessToken, defaultChannels } = parameters;
|
||||
if (!accessToken) {
|
||||
this.logger.warn('No access token provided.');
|
||||
return;
|
||||
}
|
||||
|
||||
const taggedChannels = this.findTaggedChannels(event);
|
||||
if (!taggedChannels.length) {
|
||||
const eventChannels = taggedChannels.length
|
||||
? taggedChannels
|
||||
: this.getDefaultChannels(defaultChannels);
|
||||
|
||||
if (!eventChannels.length) {
|
||||
this.logger.debug(
|
||||
`No Slack channels tagged for event ${event.type}`,
|
||||
event,
|
||||
`No Slack channels found for event ${event.type}.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -99,7 +103,7 @@ export default class SlackAppAddon extends Addon {
|
||||
const url = this.msgFormatter.featureLink(event);
|
||||
|
||||
const slackChannelsToPostTo = currentSlackChannels.filter(
|
||||
({ id, name }) => id && name && taggedChannels.includes(name),
|
||||
({ id, name }) => id && name && eventChannels.includes(name),
|
||||
);
|
||||
|
||||
const requests = slackChannelsToPostTo.map(({ id }) =>
|
||||
@ -151,6 +155,13 @@ export default class SlackAppAddon extends Addon {
|
||||
return [];
|
||||
}
|
||||
|
||||
getDefaultChannels(defaultChannels?: string): string[] {
|
||||
if (defaultChannels) {
|
||||
return defaultChannels.split(',').map((c) => c.trim());
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
startCacheInvalidation(): void {
|
||||
this.slackChannelsCacheTimeout = setInterval(() => {
|
||||
this.slackChannels = undefined;
|
||||
|
Loading…
Reference in New Issue
Block a user