mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-04 00:18:01 +01:00
feat: project environment added and removed events (#5459)
This commit is contained in:
parent
9ed2c37b25
commit
2965daa195
@ -18,11 +18,13 @@ import {
|
||||
insertLastSeenAt,
|
||||
insertFeatureEnvironmentsLastSeen,
|
||||
} from '../../../../test/e2e/helpers/test-helper';
|
||||
import { EventService } from '../../../services';
|
||||
|
||||
let stores: IUnleashStores;
|
||||
let db;
|
||||
let service: FeatureToggleService;
|
||||
let segmentService: ISegmentService;
|
||||
let eventService: EventService;
|
||||
let environmentService: EnvironmentService;
|
||||
let unleashConfig;
|
||||
|
||||
@ -48,6 +50,8 @@ beforeAll(async () => {
|
||||
segmentService = createSegmentService(db.rawDatabase, config);
|
||||
|
||||
service = createFeatureToggleService(db.rawDatabase, config);
|
||||
|
||||
eventService = new EventService(stores, config);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
@ -253,13 +257,17 @@ test('adding and removing an environment preserves variants when variants per en
|
||||
);
|
||||
|
||||
//force the variantEnvironments flag off so that we can test legacy behavior
|
||||
environmentService = new EnvironmentService(stores, {
|
||||
...unleashConfig,
|
||||
flagResolver: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
isEnabled: (toggleName: string) => false,
|
||||
environmentService = new EnvironmentService(
|
||||
stores,
|
||||
{
|
||||
...unleashConfig,
|
||||
flagResolver: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
isEnabled: (toggleName: string) => false,
|
||||
},
|
||||
},
|
||||
});
|
||||
eventService,
|
||||
);
|
||||
|
||||
await environmentService.addEnvironmentToProject(prodEnv, 'default');
|
||||
await environmentService.removeEnvironmentFromProject(prodEnv, 'default');
|
||||
|
@ -18,6 +18,8 @@ import {
|
||||
ProjectEnvironmentSchema,
|
||||
} from '../../../openapi';
|
||||
import { OpenApiService, ProjectService } from '../../../services';
|
||||
import { extractUsername } from '../../../util';
|
||||
import { IAuthRequest } from '../../unleash-types';
|
||||
|
||||
const PREFIX = '/:projectId/environments';
|
||||
|
||||
@ -124,7 +126,7 @@ export default class EnvironmentsController extends Controller {
|
||||
}
|
||||
|
||||
async addEnvironmentToProject(
|
||||
req: Request<
|
||||
req: IAuthRequest<
|
||||
Omit<IProjectEnvironmentParams, 'environment'>,
|
||||
void,
|
||||
ProjectEnvironmentSchema
|
||||
@ -138,13 +140,14 @@ export default class EnvironmentsController extends Controller {
|
||||
await this.environmentService.addEnvironmentToProject(
|
||||
environment,
|
||||
projectId,
|
||||
extractUsername(req),
|
||||
);
|
||||
|
||||
res.status(200).end();
|
||||
}
|
||||
|
||||
async removeEnvironmentFromProject(
|
||||
req: Request<IProjectEnvironmentParams>,
|
||||
req: IAuthRequest<IProjectEnvironmentParams>,
|
||||
res: Response<void>,
|
||||
): Promise<void> {
|
||||
const { projectId, environment } = req.params;
|
||||
@ -152,6 +155,7 @@ export default class EnvironmentsController extends Controller {
|
||||
await this.environmentService.removeEnvironmentFromProject(
|
||||
environment,
|
||||
projectId,
|
||||
extractUsername(req),
|
||||
);
|
||||
|
||||
res.status(200).end();
|
||||
|
@ -7,6 +7,8 @@ import {
|
||||
ISortOrder,
|
||||
IUnleashConfig,
|
||||
IUnleashStores,
|
||||
PROJECT_ENVIRONMENT_ADDED,
|
||||
PROJECT_ENVIRONMENT_REMOVED,
|
||||
} from '../types';
|
||||
import { Logger } from '../logger';
|
||||
import { BadDataError, UNIQUE_CONSTRAINT_VIOLATION } from '../error';
|
||||
@ -17,6 +19,7 @@ import { IProjectStore } from 'lib/types/stores/project-store';
|
||||
import MinimumOneEnvironmentError from '../error/minimum-one-environment-error';
|
||||
import { IFlagResolver } from 'lib/types/experimental';
|
||||
import { CreateFeatureStrategySchema } from '../openapi';
|
||||
import EventService from './event-service';
|
||||
|
||||
export default class EnvironmentService {
|
||||
private logger: Logger;
|
||||
@ -29,6 +32,8 @@ export default class EnvironmentService {
|
||||
|
||||
private featureEnvironmentStore: IFeatureEnvironmentStore;
|
||||
|
||||
private eventService: EventService;
|
||||
|
||||
private flagResolver: IFlagResolver;
|
||||
|
||||
constructor(
|
||||
@ -48,12 +53,14 @@ export default class EnvironmentService {
|
||||
getLogger,
|
||||
flagResolver,
|
||||
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>,
|
||||
eventService: EventService,
|
||||
) {
|
||||
this.logger = getLogger('services/environment-service.ts');
|
||||
this.environmentStore = environmentStore;
|
||||
this.featureStrategiesStore = featureStrategiesStore;
|
||||
this.featureEnvironmentStore = featureEnvironmentStore;
|
||||
this.projectStore = projectStore;
|
||||
this.eventService = eventService;
|
||||
this.flagResolver = flagResolver;
|
||||
}
|
||||
|
||||
@ -92,6 +99,7 @@ export default class EnvironmentService {
|
||||
async addEnvironmentToProject(
|
||||
environment: string,
|
||||
projectId: string,
|
||||
username = 'unknown',
|
||||
): Promise<void> {
|
||||
try {
|
||||
await this.featureEnvironmentStore.connectProject(
|
||||
@ -102,6 +110,12 @@ export default class EnvironmentService {
|
||||
environment,
|
||||
projectId,
|
||||
);
|
||||
await this.eventService.storeEvent({
|
||||
type: PROJECT_ENVIRONMENT_ADDED,
|
||||
project: projectId,
|
||||
environment,
|
||||
createdBy: username,
|
||||
});
|
||||
} catch (e) {
|
||||
if (e.code === UNIQUE_CONSTRAINT_VIOLATION) {
|
||||
throw new NameExistsError(
|
||||
@ -213,6 +227,7 @@ export default class EnvironmentService {
|
||||
async removeEnvironmentFromProject(
|
||||
environment: string,
|
||||
projectId: string,
|
||||
username = 'unknown',
|
||||
): Promise<void> {
|
||||
const projectEnvs =
|
||||
await this.projectStore.getEnvironmentsForProject(projectId);
|
||||
@ -222,6 +237,12 @@ export default class EnvironmentService {
|
||||
environment,
|
||||
projectId,
|
||||
);
|
||||
await this.eventService.storeEvent({
|
||||
type: PROJECT_ENVIRONMENT_REMOVED,
|
||||
project: projectId,
|
||||
environment,
|
||||
createdBy: username,
|
||||
});
|
||||
return;
|
||||
}
|
||||
throw new MinimumOneEnvironmentError(
|
||||
|
@ -222,7 +222,11 @@ export const createServices = (
|
||||
dependentFeaturesReadModel,
|
||||
dependentFeaturesService,
|
||||
);
|
||||
const environmentService = new EnvironmentService(stores, config);
|
||||
const environmentService = new EnvironmentService(
|
||||
stores,
|
||||
config,
|
||||
eventService,
|
||||
);
|
||||
const featureTagService = new FeatureTagService(
|
||||
stores,
|
||||
config,
|
||||
|
@ -108,6 +108,9 @@ export const GROUP_DELETED = 'group-deleted' as const;
|
||||
export const SETTING_CREATED = 'setting-created' as const;
|
||||
export const SETTING_UPDATED = 'setting-updated' as const;
|
||||
export const SETTING_DELETED = 'setting-deleted' as const;
|
||||
export const PROJECT_ENVIRONMENT_ADDED = 'project-environment-added' as const;
|
||||
export const PROJECT_ENVIRONMENT_REMOVED =
|
||||
'project-environment-removed' as const;
|
||||
|
||||
export const CLIENT_METRICS = 'client-metrics' as const;
|
||||
export const CLIENT_REGISTER = 'client-register' as const;
|
||||
@ -292,6 +295,8 @@ export const IEventTypes = [
|
||||
BANNER_CREATED,
|
||||
BANNER_UPDATED,
|
||||
BANNER_DELETED,
|
||||
PROJECT_ENVIRONMENT_ADDED,
|
||||
PROJECT_ENVIRONMENT_REMOVED,
|
||||
] as const;
|
||||
export type IEventType = (typeof IEventTypes)[number];
|
||||
|
||||
|
@ -4,16 +4,19 @@ import dbInit from '../helpers/database-init';
|
||||
import NotFoundError from '../../../lib/error/notfound-error';
|
||||
import { IUnleashStores } from '../../../lib/types';
|
||||
import NameExistsError from '../../../lib/error/name-exists-error';
|
||||
import { EventService } from '../../../lib/services';
|
||||
|
||||
let stores: IUnleashStores;
|
||||
let db;
|
||||
let service: EnvironmentService;
|
||||
let eventService: EventService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const config = createTestConfig();
|
||||
db = await dbInit('environment_service_serial', config.getLogger);
|
||||
stores = db.stores;
|
||||
service = new EnvironmentService(stores, config);
|
||||
eventService = new EventService(stores, config);
|
||||
service = new EnvironmentService(stores, config, eventService);
|
||||
});
|
||||
afterAll(async () => {
|
||||
await db.destroy();
|
||||
@ -50,7 +53,7 @@ test('Can connect environment to project', async () => {
|
||||
description: '',
|
||||
stale: false,
|
||||
});
|
||||
await service.addEnvironmentToProject('test-connection', 'default');
|
||||
await service.addEnvironmentToProject('test-connection', 'default', 'user');
|
||||
const overview = await stores.featureStrategiesStore.getFeatureOverview({
|
||||
projectId: 'default',
|
||||
});
|
||||
@ -68,6 +71,13 @@ test('Can connect environment to project', async () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
const { events } = await eventService.getEvents();
|
||||
expect(events[0]).toMatchObject({
|
||||
type: 'project-environment-added',
|
||||
project: 'default',
|
||||
environment: 'test-connection',
|
||||
createdBy: 'user',
|
||||
});
|
||||
});
|
||||
|
||||
test('Can remove environment from project', async () => {
|
||||
@ -98,7 +108,11 @@ test('Can remove environment from project', async () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
await service.removeEnvironmentFromProject('removal-test', 'default');
|
||||
await service.removeEnvironmentFromProject(
|
||||
'removal-test',
|
||||
'default',
|
||||
'user',
|
||||
);
|
||||
overview = await stores.featureStrategiesStore.getFeatureOverview({
|
||||
projectId: 'default',
|
||||
});
|
||||
@ -106,6 +120,13 @@ test('Can remove environment from project', async () => {
|
||||
overview.forEach((o) => {
|
||||
expect(o.environments).toEqual([]);
|
||||
});
|
||||
const { events } = await eventService.getEvents();
|
||||
expect(events[0]).toMatchObject({
|
||||
type: 'project-environment-removed',
|
||||
project: 'default',
|
||||
environment: 'removal-test',
|
||||
createdBy: 'user',
|
||||
});
|
||||
});
|
||||
|
||||
test('Adding same environment twice should throw a NameExistsError', async () => {
|
||||
|
@ -64,7 +64,7 @@ beforeAll(async () => {
|
||||
|
||||
featureToggleService = createFeatureToggleService(db.rawDatabase, config);
|
||||
|
||||
environmentService = new EnvironmentService(stores, config);
|
||||
environmentService = new EnvironmentService(stores, config, eventService);
|
||||
projectService = createProjectService(db.rawDatabase, config);
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user