mirror of
https://github.com/Unleash/unleash.git
synced 2025-03-04 00:18:40 +01:00
feat: support filtering on project and environment fields for events (#1801)
* feat: support filtering on project and environment fields for events Co-authored-by: Nuno Góis <github@nunogois.com>
This commit is contained in:
parent
847119f964
commit
e3c9eaae3a
@ -115,6 +115,8 @@ export default class AddonStore implements IAddonStore {
|
||||
description: row.description,
|
||||
parameters: row.parameters,
|
||||
events: row.events,
|
||||
projects: row.projects || [],
|
||||
environments: row.environments || [],
|
||||
createdAt: row.created_at,
|
||||
};
|
||||
}
|
||||
@ -127,6 +129,8 @@ export default class AddonStore implements IAddonStore {
|
||||
description: addon.description,
|
||||
parameters: JSON.stringify(addon.parameters),
|
||||
events: JSON.stringify(addon.events),
|
||||
projects: JSON.stringify(addon.projects || []),
|
||||
environments: JSON.stringify(addon.environments || []),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,18 @@ export const addonSchema = {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
projects: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
environments: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {},
|
||||
} as const;
|
||||
|
@ -12,5 +12,7 @@ export const addonSchema = joi
|
||||
.pattern(joi.string(), [joi.string(), joi.number(), joi.boolean()])
|
||||
.optional(),
|
||||
events: joi.array().optional().items(joi.string()),
|
||||
projects: joi.array().optional().items(joi.string()),
|
||||
environments: joi.array().optional().items(joi.string()),
|
||||
})
|
||||
.options({ allowUnknown: false, stripUnknown: true });
|
||||
|
@ -13,15 +13,17 @@ import createStores from '../../test/fixtures/store';
|
||||
import AddonService from './addon-service';
|
||||
import { IAddonDto } from '../types/stores/addon-store';
|
||||
import SimpleAddon from './addon-service-test-simple-addon';
|
||||
import { IAddonProviders } from '../addons';
|
||||
|
||||
const MASKED_VALUE = '*****';
|
||||
|
||||
const addonProvider = { simple: new SimpleAddon() };
|
||||
let addonProvider: IAddonProviders;
|
||||
|
||||
function getSetup() {
|
||||
const stores = createStores();
|
||||
const tagTypeService = new TagTypeService(stores, { getLogger });
|
||||
|
||||
addonProvider = { simple: new SimpleAddon() };
|
||||
return {
|
||||
addonService: new AddonService(
|
||||
stores,
|
||||
@ -49,7 +51,7 @@ test('should load addon configurations', async () => {
|
||||
test('should load provider definitions', async () => {
|
||||
const { addonService } = getSetup();
|
||||
|
||||
const providerDefinitions = await addonService.getProviderDefinitions();
|
||||
const providerDefinitions = addonService.getProviderDefinitions();
|
||||
|
||||
const simple = providerDefinitions.find((p) => p.name === 'simple');
|
||||
|
||||
@ -110,6 +112,276 @@ test('should trigger simple-addon eventHandler', async () => {
|
||||
expect(events[0].event.data.name).toBe('some-toggle');
|
||||
});
|
||||
|
||||
test('should not trigger event handler if project of event is different from addon', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const config = {
|
||||
provider: 'simple',
|
||||
enabled: true,
|
||||
events: [FEATURE_CREATED],
|
||||
projects: ['someproject'],
|
||||
description: '',
|
||||
parameters: {
|
||||
url: 'http://localhost:wh',
|
||||
},
|
||||
};
|
||||
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: 'someotherproject',
|
||||
data: {
|
||||
name: 'some-toggle',
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
const simpleProvider = addonService.addonProviders.simple;
|
||||
// @ts-expect-error
|
||||
const events = simpleProvider.getEvents();
|
||||
|
||||
expect(events.length).toBe(0);
|
||||
});
|
||||
|
||||
test('should trigger event handler if project for event is one of the desired projects for addon', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const desiredProject = 'desired';
|
||||
const otherProject = 'other';
|
||||
const config = {
|
||||
provider: 'simple',
|
||||
enabled: true,
|
||||
events: [FEATURE_CREATED],
|
||||
projects: [desiredProject],
|
||||
description: '',
|
||||
parameters: {
|
||||
url: 'http://localhost:wh',
|
||||
},
|
||||
};
|
||||
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProject,
|
||||
data: {
|
||||
name: 'some-toggle',
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: otherProject,
|
||||
data: {
|
||||
name: 'other-toggle',
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
const simpleProvider = addonService.addonProviders.simple;
|
||||
// @ts-expect-error
|
||||
const events = simpleProvider.getEvents();
|
||||
|
||||
expect(events.length).toBe(1);
|
||||
expect(events[0].event.type).toBe(FEATURE_CREATED);
|
||||
expect(events[0].event.data.name).toBe('some-toggle');
|
||||
});
|
||||
|
||||
test('should trigger events for multiple projects if addon is setup to filter multiple projects', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const desiredProjects = ['desired', 'desired2'];
|
||||
const otherProject = 'other';
|
||||
const config = {
|
||||
provider: 'simple',
|
||||
enabled: true,
|
||||
events: [FEATURE_CREATED],
|
||||
projects: desiredProjects,
|
||||
description: '',
|
||||
parameters: {
|
||||
url: 'http://localhost:wh',
|
||||
},
|
||||
};
|
||||
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[0],
|
||||
data: {
|
||||
name: 'some-toggle',
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: otherProject,
|
||||
data: {
|
||||
name: 'other-toggle',
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[1],
|
||||
data: {
|
||||
name: 'third-toggle',
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
const simpleProvider = addonService.addonProviders.simple;
|
||||
// @ts-expect-error
|
||||
const events = simpleProvider.getEvents();
|
||||
|
||||
expect(events.length).toBe(2);
|
||||
expect(events[0].event.type).toBe(FEATURE_CREATED);
|
||||
expect(events[0].event.data.name).toBe('some-toggle');
|
||||
expect(events[1].event.type).toBe(FEATURE_CREATED);
|
||||
expect(events[1].event.data.name).toBe('third-toggle');
|
||||
});
|
||||
|
||||
test('should filter events on environment if addon is setup to filter for it', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const desiredEnvironment = 'desired';
|
||||
const otherEnvironment = 'other';
|
||||
const config = {
|
||||
provider: 'simple',
|
||||
enabled: true,
|
||||
events: [FEATURE_CREATED],
|
||||
projects: [],
|
||||
environments: [desiredEnvironment],
|
||||
description: '',
|
||||
parameters: {
|
||||
url: 'http://localhost:wh',
|
||||
},
|
||||
};
|
||||
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredEnvironment,
|
||||
environment: desiredEnvironment,
|
||||
data: {
|
||||
name: 'some-toggle',
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
environment: otherEnvironment,
|
||||
data: {
|
||||
name: 'other-toggle',
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
const simpleProvider = addonService.addonProviders.simple;
|
||||
// @ts-expect-error
|
||||
const events = simpleProvider.getEvents();
|
||||
|
||||
expect(events.length).toBe(1);
|
||||
expect(events[0].event.type).toBe(FEATURE_CREATED);
|
||||
expect(events[0].event.data.name).toBe('some-toggle');
|
||||
});
|
||||
|
||||
test('Should support filtering by both project and environment', async () => {
|
||||
const { addonService, stores } = getSetup();
|
||||
const desiredProjects = ['desired1', 'desired2', 'desired3'];
|
||||
const desiredEnvironments = ['env1', 'env2', 'env3'];
|
||||
const config = {
|
||||
provider: 'simple',
|
||||
enabled: true,
|
||||
events: [FEATURE_CREATED],
|
||||
projects: desiredProjects,
|
||||
environments: desiredEnvironments,
|
||||
description: '',
|
||||
parameters: {
|
||||
url: 'http://localhost:wh',
|
||||
},
|
||||
};
|
||||
const expectedFeatureNames = [
|
||||
'desired-toggle1',
|
||||
'desired-toggle2',
|
||||
'desired-toggle3',
|
||||
];
|
||||
await addonService.createAddon(config, 'me@mail.com');
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[0],
|
||||
environment: desiredEnvironments[0],
|
||||
data: {
|
||||
name: expectedFeatureNames[0],
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[0],
|
||||
environment: 'wrongenvironment',
|
||||
data: {
|
||||
name: 'other-toggle',
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[2],
|
||||
environment: desiredEnvironments[1],
|
||||
data: {
|
||||
name: expectedFeatureNames[1],
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: desiredProjects[2],
|
||||
environment: desiredEnvironments[2],
|
||||
data: {
|
||||
name: expectedFeatureNames[2],
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
await stores.eventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
createdBy: 'some@user.com',
|
||||
project: 'wrongproject',
|
||||
environment: desiredEnvironments[0],
|
||||
data: {
|
||||
name: 'not-expected',
|
||||
enabled: false,
|
||||
strategies: [{ name: 'default' }],
|
||||
},
|
||||
});
|
||||
|
||||
const simpleProvider = addonService.addonProviders.simple;
|
||||
// @ts-expect-error
|
||||
const events = simpleProvider.getEvents();
|
||||
|
||||
expect(events.length).toBe(3);
|
||||
expect(events[0].event.type).toBe(FEATURE_CREATED);
|
||||
expect(events[0].event.data.name).toBe(expectedFeatureNames[0]);
|
||||
expect(events[1].event.type).toBe(FEATURE_CREATED);
|
||||
expect(events[1].event.data.name).toBe(expectedFeatureNames[1]);
|
||||
expect(events[2].event.type).toBe(FEATURE_CREATED);
|
||||
expect(events[2].event.data.name).toBe(expectedFeatureNames[2]);
|
||||
});
|
||||
|
||||
test('should create simple-addon config', async () => {
|
||||
const { addonService } = getSetup();
|
||||
|
||||
|
@ -105,6 +105,18 @@ export default class AddonService {
|
||||
this.fetchAddonConfigs().then((addonInstances) => {
|
||||
addonInstances
|
||||
.filter((addon) => addon.events.includes(eventName))
|
||||
.filter(
|
||||
(addon) =>
|
||||
!addon.projects ||
|
||||
addon.projects.length == 0 ||
|
||||
addon.projects.includes(event.project),
|
||||
)
|
||||
.filter(
|
||||
(addon) =>
|
||||
!addon.environments ||
|
||||
addon.environments.length == 0 ||
|
||||
addon.environments.includes(event.environment),
|
||||
)
|
||||
.filter((addon) => addonProviders[addon.provider])
|
||||
.forEach((addon) =>
|
||||
addonProviders[addon.provider].handleEvent(
|
||||
|
@ -5,6 +5,8 @@ export interface IAddonDto {
|
||||
description: string;
|
||||
enabled: boolean;
|
||||
parameters: Record<string, unknown>;
|
||||
projects?: string[];
|
||||
environments?: string[];
|
||||
events: string[];
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
exports.up = function (db, cb) {
|
||||
db.runSql(
|
||||
`ALTER TABLE addons
|
||||
ADD COLUMN
|
||||
projects jsonb DEFAULT '[]'::jsonb;
|
||||
ALTER TABLE addons
|
||||
ADD COLUMN environments jsonb DEFAULT '[]'::jsonb;
|
||||
`,
|
||||
cb,
|
||||
);
|
||||
};
|
||||
|
||||
exports.down = function (db, cb) {
|
||||
db.runSql(
|
||||
`
|
||||
ALTER TABLE addons DROP COLUMN projects;
|
||||
ALTER TABLE addons DROP COLUMN environments;
|
||||
`,
|
||||
cb,
|
||||
);
|
||||
};
|
@ -97,6 +97,12 @@ Object {
|
||||
"enabled": Object {
|
||||
"type": "boolean",
|
||||
},
|
||||
"environments": Object {
|
||||
"items": Object {
|
||||
"type": "string",
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
"events": Object {
|
||||
"items": Object {
|
||||
"type": "string",
|
||||
@ -110,6 +116,12 @@ Object {
|
||||
"additionalProperties": true,
|
||||
"type": "object",
|
||||
},
|
||||
"projects": Object {
|
||||
"items": Object {
|
||||
"type": "string",
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
"provider": Object {
|
||||
"type": "string",
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user