1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-10-28 19:06:12 +01:00
unleash.unleash/src/lib/addons/slack.ts
Nuno Góis 521cc24a22
feat: add more events in integrations (#4815)
https://linear.app/unleash/issue/2-1253/add-support-for-more-events-in-the-slack-app-integration

Adds support for a lot more events in our integrations. Here is how the
full list looks like:

- ADDON_CONFIG_CREATED
- ADDON_CONFIG_DELETED
- ADDON_CONFIG_UPDATED
- API_TOKEN_CREATED
- API_TOKEN_DELETED
- CHANGE_ADDED
- CHANGE_DISCARDED
- CHANGE_EDITED
- CHANGE_REQUEST_APPLIED
- CHANGE_REQUEST_APPROVAL_ADDED
- CHANGE_REQUEST_APPROVED
- CHANGE_REQUEST_CANCELLED
- CHANGE_REQUEST_CREATED
- CHANGE_REQUEST_DISCARDED
- CHANGE_REQUEST_REJECTED
- CHANGE_REQUEST_SENT_TO_REVIEW
- CONTEXT_FIELD_CREATED
- CONTEXT_FIELD_DELETED
- CONTEXT_FIELD_UPDATED
- FEATURE_ARCHIVED
- FEATURE_CREATED
- FEATURE_DELETED
- FEATURE_ENVIRONMENT_DISABLED
- FEATURE_ENVIRONMENT_ENABLED
- FEATURE_ENVIRONMENT_VARIANTS_UPDATED
- FEATURE_METADATA_UPDATED
- FEATURE_POTENTIALLY_STALE_ON
- FEATURE_PROJECT_CHANGE
- FEATURE_REVIVED
- FEATURE_STALE_OFF
- FEATURE_STALE_ON
- FEATURE_STRATEGY_ADD
- FEATURE_STRATEGY_REMOVE
- FEATURE_STRATEGY_UPDATE
- FEATURE_TAGGED
- FEATURE_UNTAGGED
- GROUP_CREATED
- GROUP_DELETED
- GROUP_UPDATED
- PROJECT_CREATED
- PROJECT_DELETED
- SEGMENT_CREATED
- SEGMENT_DELETED
- SEGMENT_UPDATED
- SERVICE_ACCOUNT_CREATED
- SERVICE_ACCOUNT_DELETED
- SERVICE_ACCOUNT_UPDATED
- USER_CREATED
- USER_DELETED
- USER_UPDATED

I added the events that I thought were relevant based on my own
discretion. Know of any event we should add? Let me know and I'll add it
🙂

For now I only added these events to the new Slack App integration, but
we can add them to the other integrations as well since they are now
supported.

The event formatter was refactored and changed quite a bit in order to
make it easier to maintain and add new events in the future. As a
result, events are now posted with different text. Do we consider this a
breaking change? If so, I can keep the old event formatter around,
create a new one and only use it for the new Slack App integration.

I noticed we don't have good 404 behaviors in the UI for things that are
deleted in the meantime, that's why I avoided some links to specific
resources (like feature strategies, integration configurations, etc),
but we could add them later if we improve this.

This PR also tries to add some consistency to the the way we log events.
2023-09-29 16:11:59 +01:00

111 lines
3.3 KiB
TypeScript

import Addon from './addon';
import slackDefinition from './slack-definition';
import { IAddonConfig } from '../types/model';
import {
FeatureEventFormatter,
FeatureEventFormatterMd,
LinkStyle,
} from './feature-event-formatter-md';
import { IEvent } from '../types/events';
interface ISlackAddonParameters {
url: string;
username?: string;
defaultChannel: string;
emojiIcon?: string;
customHeaders?: string;
}
export default class SlackAddon extends Addon {
private msgFormatter: FeatureEventFormatter;
constructor(args: IAddonConfig) {
super(slackDefinition, args);
this.msgFormatter = new FeatureEventFormatterMd(
args.unleashUrl,
LinkStyle.SLACK,
);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
async handleEvent(
event: IEvent,
parameters: ISlackAddonParameters,
): Promise<void> {
const {
url,
defaultChannel,
username = 'Unleash',
emojiIcon = ':unleash:',
customHeaders,
} = parameters;
const slackChannels = this.findSlackChannels(event);
if (slackChannels.length === 0) {
slackChannels.push(defaultChannel);
}
const { text, url: featureLink } = this.msgFormatter.format(event);
const requests = slackChannels.map((channel) => {
const body = {
username,
icon_emoji: emojiIcon, // eslint-disable-line camelcase
text,
channel: `#${channel}`,
attachments: [
{
actions: [
{
name: 'featureToggle',
text: 'Open in Unleash',
type: 'button',
value: 'featureToggle',
style: 'primary',
url: featureLink,
},
],
},
],
};
let extraHeaders = {};
if (typeof customHeaders === 'string' && customHeaders.length > 1) {
try {
extraHeaders = JSON.parse(customHeaders);
} catch (e) {
this.logger.warn(
`Could not parse the json in the customHeaders parameter. [${customHeaders}]`,
);
}
}
const requestOpts = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...extraHeaders,
},
body: JSON.stringify(body),
};
return this.fetchRetry(url, requestOpts);
});
const results = await Promise.all(requests);
const codes = results.map((res) => res.status).join(', ');
this.logger.info(`Handled event ${event.type}. Status codes=${codes}`);
}
findSlackChannels({ tags }: Pick<IEvent, 'tags'>): string[] {
if (tags) {
return tags
.filter((tag) => tag.type === 'slack')
.map((t) => t.value);
}
return [];
}
}
module.exports = SlackAddon;