2024-03-18 13:58:05 +01:00
import type { Logger } from '../logger' ;
2021-08-12 15:04:37 +02:00
2021-10-07 10:22:20 +02:00
import {
FEATURE_ARCHIVED ,
FEATURE_CREATED ,
FEATURE_ENVIRONMENT_DISABLED ,
2024-03-18 13:58:05 +01:00
type IEvent ,
2021-10-07 10:22:20 +02:00
} from '../types/events' ;
2021-08-12 15:04:37 +02:00
import TeamsAddon from './teams' ;
import noLogger from '../../test/fixtures/no-logger' ;
chore: register integration events in webhooks (#7621)
https://linear.app/unleash/issue/2-2450/register-integration-events-webhook
Registers integration events in the **Webhook** integration.
Even though this touches a lot of files, most of it is preparation for
the next steps. The only actual implementation of registering
integration events is in the **Webhook** integration. The rest will
follow on separate PRs.
Here's an example of how this looks like in the database table:
```json
{
"id": 7,
"integration_id": 2,
"created_at": "2024-07-18T18:11:11.376348+01:00",
"state": "failed",
"state_details": "Webhook request failed with status code: ECONNREFUSED",
"event": {
"id": 130,
"data": null,
"tags": [],
"type": "feature-environment-enabled",
"preData": null,
"project": "default",
"createdAt": "2024-07-18T17:11:10.821Z",
"createdBy": "admin",
"environment": "development",
"featureName": "test",
"createdByUserId": 1
},
"details": {
"url": "http://localhost:1337",
"body": "{ \"id\": 130, \"type\": \"feature-environment-enabled\", \"createdBy\": \"admin\", \"createdAt\": \"2024-07-18T17: 11: 10.821Z\", \"createdByUserId\": 1, \"data\": null, \"preData\": null, \"tags\": [], \"featureName\": \"test\", \"project\": \"default\", \"environment\": \"development\" }"
}
}
```
2024-07-19 11:07:52 +02:00
import {
type IAddonConfig ,
2024-08-20 09:00:28 +02:00
type IFlagKey ,
chore: register integration events in webhooks (#7621)
https://linear.app/unleash/issue/2-2450/register-integration-events-webhook
Registers integration events in the **Webhook** integration.
Even though this touches a lot of files, most of it is preparation for
the next steps. The only actual implementation of registering
integration events is in the **Webhook** integration. The rest will
follow on separate PRs.
Here's an example of how this looks like in the database table:
```json
{
"id": 7,
"integration_id": 2,
"created_at": "2024-07-18T18:11:11.376348+01:00",
"state": "failed",
"state_details": "Webhook request failed with status code: ECONNREFUSED",
"event": {
"id": 130,
"data": null,
"tags": [],
"type": "feature-environment-enabled",
"preData": null,
"project": "default",
"createdAt": "2024-07-18T17:11:10.821Z",
"createdBy": "admin",
"environment": "development",
"featureName": "test",
"createdByUserId": 1
},
"details": {
"url": "http://localhost:1337",
"body": "{ \"id\": 130, \"type\": \"feature-environment-enabled\", \"createdBy\": \"admin\", \"createdAt\": \"2024-07-18T17: 11: 10.821Z\", \"createdByUserId\": 1, \"data\": null, \"preData\": null, \"tags\": [], \"featureName\": \"test\", \"project\": \"default\", \"environment\": \"development\" }"
}
}
```
2024-07-19 11:07:52 +02:00
type IFlagResolver ,
2024-07-22 13:13:10 +02:00
serializeDates ,
chore: register integration events in webhooks (#7621)
https://linear.app/unleash/issue/2-2450/register-integration-events-webhook
Registers integration events in the **Webhook** integration.
Even though this touches a lot of files, most of it is preparation for
the next steps. The only actual implementation of registering
integration events is in the **Webhook** integration. The rest will
follow on separate PRs.
Here's an example of how this looks like in the database table:
```json
{
"id": 7,
"integration_id": 2,
"created_at": "2024-07-18T18:11:11.376348+01:00",
"state": "failed",
"state_details": "Webhook request failed with status code: ECONNREFUSED",
"event": {
"id": 130,
"data": null,
"tags": [],
"type": "feature-environment-enabled",
"preData": null,
"project": "default",
"createdAt": "2024-07-18T17:11:10.821Z",
"createdBy": "admin",
"environment": "development",
"featureName": "test",
"createdByUserId": 1
},
"details": {
"url": "http://localhost:1337",
"body": "{ \"id\": 130, \"type\": \"feature-environment-enabled\", \"createdBy\": \"admin\", \"createdAt\": \"2024-07-18T17: 11: 10.821Z\", \"createdByUserId\": 1, \"data\": null, \"preData\": null, \"tags\": [], \"featureName\": \"test\", \"project\": \"default\", \"environment\": \"development\" }"
}
}
```
2024-07-19 11:07:52 +02:00
SYSTEM_USER_ID ,
} from '../types' ;
import type { IntegrationEventsService } from '../services' ;
2021-08-12 15:04:37 +02:00
let fetchRetryCalls : any [ ] ;
2024-07-22 13:13:10 +02:00
const registerEventMock = jest . fn ( ) ;
2021-04-28 12:38:11 +02:00
chore: register integration events in webhooks (#7621)
https://linear.app/unleash/issue/2-2450/register-integration-events-webhook
Registers integration events in the **Webhook** integration.
Even though this touches a lot of files, most of it is preparation for
the next steps. The only actual implementation of registering
integration events is in the **Webhook** integration. The rest will
follow on separate PRs.
Here's an example of how this looks like in the database table:
```json
{
"id": 7,
"integration_id": 2,
"created_at": "2024-07-18T18:11:11.376348+01:00",
"state": "failed",
"state_details": "Webhook request failed with status code: ECONNREFUSED",
"event": {
"id": 130,
"data": null,
"tags": [],
"type": "feature-environment-enabled",
"preData": null,
"project": "default",
"createdAt": "2024-07-18T17:11:10.821Z",
"createdBy": "admin",
"environment": "development",
"featureName": "test",
"createdByUserId": 1
},
"details": {
"url": "http://localhost:1337",
"body": "{ \"id\": 130, \"type\": \"feature-environment-enabled\", \"createdBy\": \"admin\", \"createdAt\": \"2024-07-18T17: 11: 10.821Z\", \"createdByUserId\": 1, \"data\": null, \"preData\": null, \"tags\": [], \"featureName\": \"test\", \"project\": \"default\", \"environment\": \"development\" }"
}
}
```
2024-07-19 11:07:52 +02:00
const INTEGRATION_ID = 1337 ;
const ARGS : IAddonConfig = {
getLogger : noLogger ,
unleashUrl : 'http://some-url.com' ,
integrationEventsService : { } as IntegrationEventsService ,
2024-08-20 09:00:28 +02:00
flagResolver : { isEnabled : ( expName : IFlagKey ) = > false } as IFlagResolver ,
eventBus : { } as any ,
chore: register integration events in webhooks (#7621)
https://linear.app/unleash/issue/2-2450/register-integration-events-webhook
Registers integration events in the **Webhook** integration.
Even though this touches a lot of files, most of it is preparation for
the next steps. The only actual implementation of registering
integration events is in the **Webhook** integration. The rest will
follow on separate PRs.
Here's an example of how this looks like in the database table:
```json
{
"id": 7,
"integration_id": 2,
"created_at": "2024-07-18T18:11:11.376348+01:00",
"state": "failed",
"state_details": "Webhook request failed with status code: ECONNREFUSED",
"event": {
"id": 130,
"data": null,
"tags": [],
"type": "feature-environment-enabled",
"preData": null,
"project": "default",
"createdAt": "2024-07-18T17:11:10.821Z",
"createdBy": "admin",
"environment": "development",
"featureName": "test",
"createdByUserId": 1
},
"details": {
"url": "http://localhost:1337",
"body": "{ \"id\": 130, \"type\": \"feature-environment-enabled\", \"createdBy\": \"admin\", \"createdAt\": \"2024-07-18T17: 11: 10.821Z\", \"createdByUserId\": 1, \"data\": null, \"preData\": null, \"tags\": [], \"featureName\": \"test\", \"project\": \"default\", \"environment\": \"development\" }"
}
}
```
2024-07-19 11:07:52 +02:00
} ;
2021-05-28 11:10:24 +02:00
jest . mock (
'./addon' ,
( ) = >
class Addon {
2021-08-12 15:04:37 +02:00
logger : Logger ;
2021-05-28 11:10:24 +02:00
constructor ( definition , { getLogger } ) {
this . logger = getLogger ( 'addon/test' ) ;
2021-08-12 15:04:37 +02:00
fetchRetryCalls = [ ] ;
2021-05-28 11:10:24 +02:00
}
2021-04-28 12:38:11 +02:00
2021-05-28 11:10:24 +02:00
async fetchRetry ( url , options , retries , backoff ) {
2021-08-12 15:04:37 +02:00
fetchRetryCalls . push ( {
url ,
options ,
retries ,
backoff ,
} ) ;
2024-07-22 13:13:10 +02:00
return Promise . resolve ( { ok : true , status : 200 } ) ;
2021-05-28 11:10:24 +02:00
}
chore: register integration events in webhooks (#7621)
https://linear.app/unleash/issue/2-2450/register-integration-events-webhook
Registers integration events in the **Webhook** integration.
Even though this touches a lot of files, most of it is preparation for
the next steps. The only actual implementation of registering
integration events is in the **Webhook** integration. The rest will
follow on separate PRs.
Here's an example of how this looks like in the database table:
```json
{
"id": 7,
"integration_id": 2,
"created_at": "2024-07-18T18:11:11.376348+01:00",
"state": "failed",
"state_details": "Webhook request failed with status code: ECONNREFUSED",
"event": {
"id": 130,
"data": null,
"tags": [],
"type": "feature-environment-enabled",
"preData": null,
"project": "default",
"createdAt": "2024-07-18T17:11:10.821Z",
"createdBy": "admin",
"environment": "development",
"featureName": "test",
"createdByUserId": 1
},
"details": {
"url": "http://localhost:1337",
"body": "{ \"id\": 130, \"type\": \"feature-environment-enabled\", \"createdBy\": \"admin\", \"createdAt\": \"2024-07-18T17: 11: 10.821Z\", \"createdByUserId\": 1, \"data\": null, \"preData\": null, \"tags\": [], \"featureName\": \"test\", \"project\": \"default\", \"environment\": \"development\" }"
}
}
```
2024-07-19 11:07:52 +02:00
2024-07-22 13:13:10 +02:00
async registerEvent ( event ) {
return registerEventMock ( event ) ;
chore: register integration events in webhooks (#7621)
https://linear.app/unleash/issue/2-2450/register-integration-events-webhook
Registers integration events in the **Webhook** integration.
Even though this touches a lot of files, most of it is preparation for
the next steps. The only actual implementation of registering
integration events is in the **Webhook** integration. The rest will
follow on separate PRs.
Here's an example of how this looks like in the database table:
```json
{
"id": 7,
"integration_id": 2,
"created_at": "2024-07-18T18:11:11.376348+01:00",
"state": "failed",
"state_details": "Webhook request failed with status code: ECONNREFUSED",
"event": {
"id": 130,
"data": null,
"tags": [],
"type": "feature-environment-enabled",
"preData": null,
"project": "default",
"createdAt": "2024-07-18T17:11:10.821Z",
"createdBy": "admin",
"environment": "development",
"featureName": "test",
"createdByUserId": 1
},
"details": {
"url": "http://localhost:1337",
"body": "{ \"id\": 130, \"type\": \"feature-environment-enabled\", \"createdBy\": \"admin\", \"createdAt\": \"2024-07-18T17: 11: 10.821Z\", \"createdByUserId\": 1, \"data\": null, \"preData\": null, \"tags\": [], \"featureName\": \"test\", \"project\": \"default\", \"environment\": \"development\" }"
}
}
```
2024-07-19 11:07:52 +02:00
}
2021-05-28 11:10:24 +02:00
} ,
) ;
2024-07-22 13:13:10 +02:00
describe ( 'Teams integration' , ( ) = > {
beforeEach ( ( ) = > {
registerEventMock . mockClear ( ) ;
} ) ;
2021-04-28 12:38:11 +02:00
2024-07-22 13:13:10 +02:00
test ( 'Should call teams webhook' , async ( ) = > {
const addon = new TeamsAddon ( ARGS ) ;
const event : IEvent = {
id : 1 ,
createdAt : new Date ( ) ,
type : FEATURE_CREATED ,
createdByUserId : SYSTEM_USER_ID ,
createdBy : 'some@user.com' ,
featureName : 'some-toggle' ,
data : {
name : 'some-toggle' ,
enabled : false ,
strategies : [ { name : 'default' } ] ,
} ,
} ;
2021-04-28 12:38:11 +02:00
2024-07-22 13:13:10 +02:00
const parameters = {
url : 'http://hooks.office.com' ,
} ;
2021-04-28 12:38:11 +02:00
2024-07-22 13:13:10 +02:00
await addon . handleEvent ( event , parameters , INTEGRATION_ID ) ;
expect ( fetchRetryCalls . length ) . toBe ( 1 ) ;
expect ( fetchRetryCalls [ 0 ] . url ) . toBe ( parameters . url ) ;
expect ( fetchRetryCalls [ 0 ] . options . body ) . toMatchSnapshot ( ) ;
} ) ;
2022-10-05 11:30:51 +02:00
2024-07-22 13:13:10 +02:00
test ( 'Should call teams webhook for archived toggle' , async ( ) = > {
const addon = new TeamsAddon ( ARGS ) ;
const event : IEvent = {
id : 1 ,
createdAt : new Date ( ) ,
createdByUserId : SYSTEM_USER_ID ,
type : FEATURE_ARCHIVED ,
createdBy : 'some@user.com' ,
featureName : 'some-toggle' ,
data : {
name : 'some-toggle' ,
} ,
} ;
2022-10-05 11:30:51 +02:00
2024-07-22 13:13:10 +02:00
const parameters = {
url : 'http://hooks.office.com' ,
} ;
2022-10-05 11:30:51 +02:00
2024-07-22 13:13:10 +02:00
await addon . handleEvent ( event , parameters , INTEGRATION_ID ) ;
expect ( fetchRetryCalls . length ) . toBe ( 1 ) ;
expect ( fetchRetryCalls [ 0 ] . url ) . toBe ( parameters . url ) ;
expect ( fetchRetryCalls [ 0 ] . options . body ) . toMatchSnapshot ( ) ;
} ) ;
2021-04-28 12:38:11 +02:00
2024-07-22 13:13:10 +02:00
test ( 'Should call teams webhook for archived toggle with project info' , async ( ) = > {
const addon = new TeamsAddon ( ARGS ) ;
const event : IEvent = {
id : 1 ,
createdAt : new Date ( ) ,
createdByUserId : SYSTEM_USER_ID ,
type : FEATURE_ARCHIVED ,
createdBy : 'some@user.com' ,
featureName : 'some-toggle' ,
project : 'some-project' ,
data : {
name : 'some-toggle' ,
} ,
} ;
2021-04-28 12:38:11 +02:00
2024-07-22 13:13:10 +02:00
const parameters = {
url : 'http://hooks.office.com' ,
} ;
2021-10-07 10:22:20 +02:00
2024-07-22 13:13:10 +02:00
await addon . handleEvent ( event , parameters , INTEGRATION_ID ) ;
expect ( fetchRetryCalls . length ) . toBe ( 1 ) ;
expect ( fetchRetryCalls [ 0 ] . url ) . toBe ( parameters . url ) ;
expect ( fetchRetryCalls [ 0 ] . options . body ) . toMatchSnapshot ( ) ;
} ) ;
2021-10-07 10:22:20 +02:00
2024-07-22 13:13:10 +02:00
test ( ` Should call teams webhook for toggled environment ` , async ( ) = > {
const addon = new TeamsAddon ( ARGS ) ;
const event : IEvent = {
id : 2 ,
createdAt : new Date ( ) ,
createdByUserId : SYSTEM_USER_ID ,
type : FEATURE_ENVIRONMENT_DISABLED ,
createdBy : 'some@user.com' ,
environment : 'development' ,
project : 'default' ,
featureName : 'some-toggle' ,
data : {
name : 'some-toggle' ,
} ,
} ;
2021-10-07 10:22:20 +02:00
2024-07-22 13:13:10 +02:00
const parameters = {
url : 'http://hooks.slack.com' ,
} ;
2023-07-05 09:42:17 +02:00
2024-07-22 13:13:10 +02:00
await addon . handleEvent ( event , parameters , INTEGRATION_ID ) ;
expect ( fetchRetryCalls ) . toHaveLength ( 1 ) ;
expect ( fetchRetryCalls [ 0 ] . url ) . toBe ( parameters . url ) ;
expect ( fetchRetryCalls [ 0 ] . options . body ) . toMatch ( /disabled/ ) ;
expect ( fetchRetryCalls [ 0 ] . options . body ) . toMatchSnapshot ( ) ;
} ) ;
test ( 'Should include custom headers in call to teams' , async ( ) = > {
const addon = new TeamsAddon ( ARGS ) ;
const event : IEvent = {
id : 2 ,
createdAt : new Date ( ) ,
createdByUserId : SYSTEM_USER_ID ,
type : FEATURE_ENVIRONMENT_DISABLED ,
createdBy : 'some@user.com' ,
environment : 'development' ,
project : 'default' ,
featureName : 'some-toggle' ,
data : {
name : 'some-toggle' ,
} ,
} ;
const parameters = {
url : 'http://hooks.slack.com' ,
customHeaders : ` { "MY_CUSTOM_HEADER": "MY_CUSTOM_VALUE" } ` ,
} ;
await addon . handleEvent ( event , parameters , INTEGRATION_ID ) ;
expect ( fetchRetryCalls ) . toHaveLength ( 1 ) ;
expect ( fetchRetryCalls [ 0 ] . url ) . toBe ( parameters . url ) ;
expect ( fetchRetryCalls [ 0 ] . options . body ) . toMatch ( /disabled/ ) ;
expect ( fetchRetryCalls [ 0 ] . options . body ) . toMatchSnapshot ( ) ;
expect ( fetchRetryCalls [ 0 ] . options . headers ) . toMatchSnapshot ( ) ;
} ) ;
test ( 'Should call registerEvent' , async ( ) = > {
const addon = new TeamsAddon ( ARGS ) ;
const event : IEvent = {
id : 2 ,
createdAt : new Date ( ) ,
createdByUserId : SYSTEM_USER_ID ,
type : FEATURE_ENVIRONMENT_DISABLED ,
createdBy : 'some@user.com' ,
environment : 'development' ,
project : 'default' ,
featureName : 'some-toggle' ,
data : {
name : 'some-toggle' ,
} ,
} ;
const parameters = {
url : 'http://hooks.teams.com' ,
customHeaders : ` { "MY_CUSTOM_HEADER": "MY_CUSTOM_VALUE" } ` ,
} ;
await addon . handleEvent ( event , parameters , INTEGRATION_ID ) ;
expect ( registerEventMock ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( registerEventMock ) . toHaveBeenCalledWith ( {
integrationId : INTEGRATION_ID ,
state : 'success' ,
stateDetails :
'Teams webhook request was successful with status code: 200.' ,
event : serializeDates ( event ) ,
details : {
url : parameters.url ,
body : {
themeColor : '0076D7' ,
summary : 'Message' ,
sections : [
{
activityTitle : ` * ${ event . createdBy } * disabled *[ ${ event . featureName } ]( ${ ARGS . unleashUrl } /projects/ ${ event . project } /features/ ${ event . featureName } )* for the * ${ event . environment } * environment in project *[ ${ event . project } ]( ${ ARGS . unleashUrl } /projects/ ${ event . project } )* ` ,
activitySubtitle : ` Unleash notification update ` ,
facts : [
{
name : 'User' ,
value : event.createdBy ,
} ,
{
name : 'Action' ,
value : event.type ,
} ,
] ,
} ,
] ,
potentialAction : [
{
'@type' : 'OpenUri' ,
name : 'Go to feature' ,
targets : [
{
os : 'default' ,
uri : ` ${ ARGS . unleashUrl } /projects/ ${ event . project } /features/ ${ event . featureName } ` ,
} ,
] ,
} ,
] ,
} ,
} ,
} ) ;
} ) ;
2023-07-05 09:42:17 +02:00
} ) ;