mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-09 01:17:06 +02:00
feat: copy feature with parent (#4918)
This commit is contained in:
parent
5141d9db67
commit
257414424d
@ -84,7 +84,7 @@ export const AddDependencyDialogue = ({
|
|||||||
secondaryButtonText='Cancel'
|
secondaryButtonText='Cancel'
|
||||||
>
|
>
|
||||||
<Box>
|
<Box>
|
||||||
You feature will be evaluated only when the selected parent
|
Your feature will be evaluated only when the selected parent
|
||||||
feature is enabled in the same environment.
|
feature is enabled in the same environment.
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
@ -22,6 +22,32 @@ export class DependentFeaturesService {
|
|||||||
this.eventService = eventService;
|
this.eventService = eventService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async cloneDependencies(
|
||||||
|
{
|
||||||
|
featureName,
|
||||||
|
newFeatureName,
|
||||||
|
projectId,
|
||||||
|
}: { featureName: string; newFeatureName: string; projectId: string },
|
||||||
|
user: string,
|
||||||
|
) {
|
||||||
|
const parents = await this.dependentFeaturesReadModel.getParents(
|
||||||
|
featureName,
|
||||||
|
);
|
||||||
|
await Promise.all(
|
||||||
|
parents.map((parent) =>
|
||||||
|
this.upsertFeatureDependency(
|
||||||
|
{ child: newFeatureName, projectId },
|
||||||
|
{
|
||||||
|
feature: parent.feature,
|
||||||
|
enabled: parent.enabled,
|
||||||
|
variants: parent.variants,
|
||||||
|
},
|
||||||
|
user,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async upsertFeatureDependency(
|
async upsertFeatureDependency(
|
||||||
{ child, projectId }: { child: string; projectId: string },
|
{ child, projectId }: { child: string; projectId: string },
|
||||||
dependentFeature: CreateDependentFeatureSchema,
|
dependentFeature: CreateDependentFeatureSchema,
|
||||||
|
@ -48,6 +48,10 @@ import { DependentFeaturesReadModel } from '../dependent-features/dependent-feat
|
|||||||
import { FakeDependentFeaturesReadModel } from '../dependent-features/fake-dependent-features-read-model';
|
import { FakeDependentFeaturesReadModel } from '../dependent-features/fake-dependent-features-read-model';
|
||||||
import FeatureTagStore from '../../db/feature-tag-store';
|
import FeatureTagStore from '../../db/feature-tag-store';
|
||||||
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
|
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
|
||||||
|
import {
|
||||||
|
createDependentFeaturesService,
|
||||||
|
createFakeDependentFeaturesService,
|
||||||
|
} from '../dependent-features/createDependentFeaturesService';
|
||||||
|
|
||||||
export const createFeatureToggleService = (
|
export const createFeatureToggleService = (
|
||||||
db: Db,
|
db: Db,
|
||||||
@ -115,6 +119,8 @@ export const createFeatureToggleService = (
|
|||||||
|
|
||||||
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
|
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
|
||||||
|
|
||||||
|
const dependentFeaturesService = createDependentFeaturesService(db, config);
|
||||||
|
|
||||||
const featureToggleService = new FeatureToggleService(
|
const featureToggleService = new FeatureToggleService(
|
||||||
{
|
{
|
||||||
featureStrategiesStore,
|
featureStrategiesStore,
|
||||||
@ -133,6 +139,7 @@ export const createFeatureToggleService = (
|
|||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
dependentFeaturesReadModel,
|
dependentFeaturesReadModel,
|
||||||
|
dependentFeaturesService,
|
||||||
);
|
);
|
||||||
return featureToggleService;
|
return featureToggleService;
|
||||||
};
|
};
|
||||||
@ -173,6 +180,7 @@ export const createFakeFeatureToggleService = (
|
|||||||
const changeRequestAccessReadModel = createFakeChangeRequestAccessService();
|
const changeRequestAccessReadModel = createFakeChangeRequestAccessService();
|
||||||
const fakePrivateProjectChecker = createFakePrivateProjectChecker();
|
const fakePrivateProjectChecker = createFakePrivateProjectChecker();
|
||||||
const dependentFeaturesReadModel = new FakeDependentFeaturesReadModel();
|
const dependentFeaturesReadModel = new FakeDependentFeaturesReadModel();
|
||||||
|
const dependentFeaturesService = createFakeDependentFeaturesService(config);
|
||||||
const featureToggleService = new FeatureToggleService(
|
const featureToggleService = new FeatureToggleService(
|
||||||
{
|
{
|
||||||
featureStrategiesStore,
|
featureStrategiesStore,
|
||||||
@ -191,6 +199,7 @@ export const createFakeFeatureToggleService = (
|
|||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
fakePrivateProjectChecker,
|
fakePrivateProjectChecker,
|
||||||
dependentFeaturesReadModel,
|
dependentFeaturesReadModel,
|
||||||
|
dependentFeaturesService,
|
||||||
);
|
);
|
||||||
return featureToggleService;
|
return featureToggleService;
|
||||||
};
|
};
|
||||||
|
@ -13,6 +13,7 @@ import { IPrivateProjectChecker } from '../features/private-project/privateProje
|
|||||||
import { IDependentFeaturesReadModel } from '../features/dependent-features/dependent-features-read-model-type';
|
import { IDependentFeaturesReadModel } from '../features/dependent-features/dependent-features-read-model-type';
|
||||||
import EventService from './event-service';
|
import EventService from './event-service';
|
||||||
import FakeFeatureTagStore from '../../test/fixtures/fake-feature-tag-store';
|
import FakeFeatureTagStore from '../../test/fixtures/fake-feature-tag-store';
|
||||||
|
import { DependentFeaturesService } from '../features/dependent-features/dependent-features-service';
|
||||||
|
|
||||||
test('Should only store events for potentially stale on', async () => {
|
test('Should only store events for potentially stale on', async () => {
|
||||||
expect.assertions(2);
|
expect.assertions(2);
|
||||||
@ -64,6 +65,7 @@ test('Should only store events for potentially stale on', async () => {
|
|||||||
{} as IChangeRequestAccessReadModel,
|
{} as IChangeRequestAccessReadModel,
|
||||||
{} as IPrivateProjectChecker,
|
{} as IPrivateProjectChecker,
|
||||||
{} as IDependentFeaturesReadModel,
|
{} as IDependentFeaturesReadModel,
|
||||||
|
{} as DependentFeaturesService,
|
||||||
);
|
);
|
||||||
|
|
||||||
await featureToggleService.updatePotentiallyStaleFeatures();
|
await featureToggleService.updatePotentiallyStaleFeatures();
|
||||||
|
@ -99,6 +99,7 @@ import { checkFeatureFlagNamesAgainstPattern } from '../features/feature-naming-
|
|||||||
import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
|
import { IPrivateProjectChecker } from '../features/private-project/privateProjectCheckerType';
|
||||||
import { IDependentFeaturesReadModel } from '../features/dependent-features/dependent-features-read-model-type';
|
import { IDependentFeaturesReadModel } from '../features/dependent-features/dependent-features-read-model-type';
|
||||||
import EventService from './event-service';
|
import EventService from './event-service';
|
||||||
|
import { DependentFeaturesService } from '../features/dependent-features/dependent-features-service';
|
||||||
|
|
||||||
interface IFeatureContext {
|
interface IFeatureContext {
|
||||||
featureName: string;
|
featureName: string;
|
||||||
@ -162,6 +163,8 @@ class FeatureToggleService {
|
|||||||
|
|
||||||
private dependentFeaturesReadModel: IDependentFeaturesReadModel;
|
private dependentFeaturesReadModel: IDependentFeaturesReadModel;
|
||||||
|
|
||||||
|
private dependentFeaturesService: DependentFeaturesService;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{
|
{
|
||||||
featureStrategiesStore,
|
featureStrategiesStore,
|
||||||
@ -193,6 +196,7 @@ class FeatureToggleService {
|
|||||||
changeRequestAccessReadModel: IChangeRequestAccessReadModel,
|
changeRequestAccessReadModel: IChangeRequestAccessReadModel,
|
||||||
privateProjectChecker: IPrivateProjectChecker,
|
privateProjectChecker: IPrivateProjectChecker,
|
||||||
dependentFeaturesReadModel: IDependentFeaturesReadModel,
|
dependentFeaturesReadModel: IDependentFeaturesReadModel,
|
||||||
|
dependentFeaturesService: DependentFeaturesService,
|
||||||
) {
|
) {
|
||||||
this.logger = getLogger('services/feature-toggle-service.ts');
|
this.logger = getLogger('services/feature-toggle-service.ts');
|
||||||
this.featureStrategiesStore = featureStrategiesStore;
|
this.featureStrategiesStore = featureStrategiesStore;
|
||||||
@ -210,6 +214,7 @@ class FeatureToggleService {
|
|||||||
this.changeRequestAccessReadModel = changeRequestAccessReadModel;
|
this.changeRequestAccessReadModel = changeRequestAccessReadModel;
|
||||||
this.privateProjectChecker = privateProjectChecker;
|
this.privateProjectChecker = privateProjectChecker;
|
||||||
this.dependentFeaturesReadModel = dependentFeaturesReadModel;
|
this.dependentFeaturesReadModel = dependentFeaturesReadModel;
|
||||||
|
this.dependentFeaturesService = dependentFeaturesService;
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateFeaturesContext(
|
async validateFeaturesContext(
|
||||||
@ -1255,7 +1260,17 @@ class FeatureToggleService {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await Promise.all([...strategyTasks, ...variantTasks]);
|
const cloneDependencies =
|
||||||
|
this.dependentFeaturesService.cloneDependencies(
|
||||||
|
{ featureName, newFeatureName, projectId },
|
||||||
|
userName,
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
...strategyTasks,
|
||||||
|
...variantTasks,
|
||||||
|
cloneDependencies,
|
||||||
|
]);
|
||||||
return created;
|
return created;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,6 +233,13 @@ export const createServices = (
|
|||||||
config,
|
config,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const dependentFeaturesService = db
|
||||||
|
? createDependentFeaturesService(db, config)
|
||||||
|
: createFakeDependentFeaturesService(config);
|
||||||
|
const transactionalDependentFeaturesService = (txDb: Knex.Transaction) =>
|
||||||
|
createDependentFeaturesService(txDb, config);
|
||||||
|
|
||||||
const featureToggleServiceV2 = new FeatureToggleService(
|
const featureToggleServiceV2 = new FeatureToggleService(
|
||||||
stores,
|
stores,
|
||||||
config,
|
config,
|
||||||
@ -242,6 +249,7 @@ export const createServices = (
|
|||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
dependentFeaturesReadModel,
|
dependentFeaturesReadModel,
|
||||||
|
dependentFeaturesService,
|
||||||
);
|
);
|
||||||
const environmentService = new EnvironmentService(stores, config);
|
const environmentService = new EnvironmentService(stores, config);
|
||||||
const featureTagService = new FeatureTagService(
|
const featureTagService = new FeatureTagService(
|
||||||
@ -327,12 +335,6 @@ export const createServices = (
|
|||||||
|
|
||||||
const eventAnnouncerService = new EventAnnouncerService(stores, config);
|
const eventAnnouncerService = new EventAnnouncerService(stores, config);
|
||||||
|
|
||||||
const dependentFeaturesService = db
|
|
||||||
? createDependentFeaturesService(db, config)
|
|
||||||
: createFakeDependentFeaturesService(config);
|
|
||||||
const transactionalDependentFeaturesService = (txDb: Knex.Transaction) =>
|
|
||||||
createDependentFeaturesService(txDb, config);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accessService,
|
accessService,
|
||||||
accountService,
|
accountService,
|
||||||
|
@ -295,6 +295,29 @@ test('Should not allow to archive/delete feature with children', async () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should clone feature with parent dependencies', async () => {
|
||||||
|
const parent = uuidv4();
|
||||||
|
const child = uuidv4();
|
||||||
|
const childClone = uuidv4();
|
||||||
|
await app.createFeature(parent, 'default');
|
||||||
|
await app.createFeature(child, 'default');
|
||||||
|
await app.addDependency(child, parent);
|
||||||
|
|
||||||
|
await app.request
|
||||||
|
.post(`/api/admin/projects/default/features/${child}/clone`)
|
||||||
|
.send({ name: childClone, replaceGroupId: false })
|
||||||
|
.expect(201);
|
||||||
|
|
||||||
|
const { body: clonedFeature } = await app.getProjectFeatures(
|
||||||
|
'default',
|
||||||
|
child,
|
||||||
|
);
|
||||||
|
expect(clonedFeature).toMatchObject({
|
||||||
|
children: [],
|
||||||
|
dependencies: [{ feature: parent, enabled: true, variants: [] }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('Can get features for project', async () => {
|
test('Can get features for project', async () => {
|
||||||
await app.request
|
await app.request
|
||||||
.post('/api/admin/projects/default/features')
|
.post('/api/admin/projects/default/features')
|
||||||
|
@ -13,25 +13,19 @@ import {
|
|||||||
IUnleashStores,
|
IUnleashStores,
|
||||||
IUserAccessOverview,
|
IUserAccessOverview,
|
||||||
} from '../../../lib/types';
|
} from '../../../lib/types';
|
||||||
import FeatureToggleService from '../../../lib/services/feature-toggle-service';
|
|
||||||
import ProjectService from '../../../lib/services/project-service';
|
|
||||||
import { createTestConfig } from '../../config/test-config';
|
import { createTestConfig } from '../../config/test-config';
|
||||||
import { DEFAULT_PROJECT } from '../../../lib/types/project';
|
import { DEFAULT_PROJECT } from '../../../lib/types/project';
|
||||||
import { ALL_PROJECTS } from '../../../lib/util/constants';
|
import { ALL_PROJECTS } from '../../../lib/util/constants';
|
||||||
import { SegmentService } from '../../../lib/services/segment-service';
|
import {
|
||||||
import { GroupService } from '../../../lib/services/group-service';
|
createAccessService,
|
||||||
import { EventService, FavoritesService } from '../../../lib/services';
|
createFeatureToggleService,
|
||||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
createProjectService,
|
||||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
} from '../../../lib/features';
|
||||||
import { DependentFeaturesReadModel } from '../../../lib/features/dependent-features/dependent-features-read-model';
|
|
||||||
|
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
let accessService: AccessService;
|
let accessService: AccessService;
|
||||||
let eventService: EventService;
|
|
||||||
let groupService: GroupService;
|
|
||||||
let featureToggleService;
|
let featureToggleService;
|
||||||
let favoritesService;
|
|
||||||
let projectService;
|
let projectService;
|
||||||
let editorUser;
|
let editorUser;
|
||||||
let editorRole;
|
let editorRole;
|
||||||
@ -238,51 +232,14 @@ beforeAll(async () => {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
experimental: { environments: { enabled: true } },
|
experimental: { environments: { enabled: true } },
|
||||||
});
|
});
|
||||||
eventService = new EventService(stores, config);
|
accessService = createAccessService(db.rawDatabase, config);
|
||||||
groupService = new GroupService(stores, { getLogger }, eventService);
|
|
||||||
accessService = new AccessService(stores, config, groupService);
|
|
||||||
const roles = await accessService.getRootRoles();
|
const roles = await accessService.getRootRoles();
|
||||||
editorRole = roles.find((r) => r.name === RoleName.EDITOR);
|
editorRole = roles.find((r) => r.name === RoleName.EDITOR);
|
||||||
adminRole = roles.find((r) => r.name === RoleName.ADMIN);
|
adminRole = roles.find((r) => r.name === RoleName.ADMIN);
|
||||||
readRole = roles.find((r) => r.name === RoleName.VIEWER);
|
readRole = roles.find((r) => r.name === RoleName.VIEWER);
|
||||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
|
||||||
db.rawDatabase,
|
featureToggleService = createFeatureToggleService(db.rawDatabase, config);
|
||||||
accessService,
|
projectService = createProjectService(db.rawDatabase, config);
|
||||||
);
|
|
||||||
const privateProjectChecker = createPrivateProjectChecker(
|
|
||||||
db.rawDatabase,
|
|
||||||
config,
|
|
||||||
);
|
|
||||||
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
);
|
|
||||||
featureToggleService = new FeatureToggleService(
|
|
||||||
stores,
|
|
||||||
config,
|
|
||||||
new SegmentService(
|
|
||||||
stores,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
config,
|
|
||||||
eventService,
|
|
||||||
privateProjectChecker,
|
|
||||||
),
|
|
||||||
accessService,
|
|
||||||
eventService,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
privateProjectChecker,
|
|
||||||
dependentFeaturesReadModel,
|
|
||||||
);
|
|
||||||
favoritesService = new FavoritesService(stores, config, eventService);
|
|
||||||
projectService = new ProjectService(
|
|
||||||
stores,
|
|
||||||
config,
|
|
||||||
accessService,
|
|
||||||
featureToggleService,
|
|
||||||
groupService,
|
|
||||||
favoritesService,
|
|
||||||
eventService,
|
|
||||||
privateProjectChecker,
|
|
||||||
);
|
|
||||||
|
|
||||||
editorUser = await createUser(editorRole.id);
|
editorUser = await createUser(editorRole.id);
|
||||||
|
|
||||||
|
@ -6,20 +6,13 @@ import { ApiTokenType, IApiToken } from '../../../lib/types/models/api-token';
|
|||||||
import { DEFAULT_ENV } from '../../../lib/util/constants';
|
import { DEFAULT_ENV } from '../../../lib/util/constants';
|
||||||
import { addDays, subDays } from 'date-fns';
|
import { addDays, subDays } from 'date-fns';
|
||||||
import ProjectService from '../../../lib/services/project-service';
|
import ProjectService from '../../../lib/services/project-service';
|
||||||
import FeatureToggleService from '../../../lib/services/feature-toggle-service';
|
import { EventService } from '../../../lib/services';
|
||||||
import { AccessService } from '../../../lib/services/access-service';
|
import { createProjectService } from '../../../lib/features';
|
||||||
import { SegmentService } from '../../../lib/services/segment-service';
|
|
||||||
import { GroupService } from '../../../lib/services/group-service';
|
|
||||||
import { EventService, FavoritesService } from '../../../lib/services';
|
|
||||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
|
||||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
|
||||||
import { DependentFeaturesReadModel } from '../../../lib/features/dependent-features/dependent-features-read-model';
|
|
||||||
|
|
||||||
let db;
|
let db;
|
||||||
let stores;
|
let stores;
|
||||||
let apiTokenService: ApiTokenService;
|
let apiTokenService: ApiTokenService;
|
||||||
let projectService: ProjectService;
|
let projectService: ProjectService;
|
||||||
let favoritesService: FavoritesService;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const config = createTestConfig({
|
const config = createTestConfig({
|
||||||
@ -28,35 +21,6 @@ beforeAll(async () => {
|
|||||||
db = await dbInit('api_token_service_serial', getLogger);
|
db = await dbInit('api_token_service_serial', getLogger);
|
||||||
stores = db.stores;
|
stores = db.stores;
|
||||||
const eventService = new EventService(stores, config);
|
const eventService = new EventService(stores, config);
|
||||||
const groupService = new GroupService(stores, config, eventService);
|
|
||||||
const accessService = new AccessService(stores, config, groupService);
|
|
||||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
accessService,
|
|
||||||
);
|
|
||||||
const privateProjectChecker = createPrivateProjectChecker(
|
|
||||||
db.rawDatabase,
|
|
||||||
config,
|
|
||||||
);
|
|
||||||
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
);
|
|
||||||
const featureToggleService = new FeatureToggleService(
|
|
||||||
stores,
|
|
||||||
config,
|
|
||||||
new SegmentService(
|
|
||||||
stores,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
config,
|
|
||||||
eventService,
|
|
||||||
privateProjectChecker,
|
|
||||||
),
|
|
||||||
accessService,
|
|
||||||
eventService,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
privateProjectChecker,
|
|
||||||
dependentFeaturesReadModel,
|
|
||||||
);
|
|
||||||
const project = {
|
const project = {
|
||||||
id: 'test-project',
|
id: 'test-project',
|
||||||
name: 'Test Project',
|
name: 'Test Project',
|
||||||
@ -68,17 +32,7 @@ beforeAll(async () => {
|
|||||||
name: 'Some Name',
|
name: 'Some Name',
|
||||||
email: 'test@getunleash.io',
|
email: 'test@getunleash.io',
|
||||||
});
|
});
|
||||||
favoritesService = new FavoritesService(stores, config, eventService);
|
projectService = createProjectService(db.rawDatabase, config);
|
||||||
projectService = new ProjectService(
|
|
||||||
stores,
|
|
||||||
config,
|
|
||||||
accessService,
|
|
||||||
featureToggleService,
|
|
||||||
groupService,
|
|
||||||
favoritesService,
|
|
||||||
eventService,
|
|
||||||
privateProjectChecker,
|
|
||||||
);
|
|
||||||
|
|
||||||
await projectService.createProject(project, user);
|
await projectService.createProject(project, user);
|
||||||
|
|
||||||
|
@ -2,12 +2,6 @@ import FeatureToggleService from '../../../lib/services/feature-toggle-service';
|
|||||||
import { createTestConfig } from '../../config/test-config';
|
import { createTestConfig } from '../../config/test-config';
|
||||||
import dbInit from '../helpers/database-init';
|
import dbInit from '../helpers/database-init';
|
||||||
import { DEFAULT_ENV } from '../../../lib/util';
|
import { DEFAULT_ENV } from '../../../lib/util';
|
||||||
import {
|
|
||||||
AccessService,
|
|
||||||
EventService,
|
|
||||||
GroupService,
|
|
||||||
SegmentService,
|
|
||||||
} from '../../../lib/services';
|
|
||||||
import { FeatureStrategySchema } from '../../../lib/openapi';
|
import { FeatureStrategySchema } from '../../../lib/openapi';
|
||||||
import User from '../../../lib/types/user';
|
import User from '../../../lib/types/user';
|
||||||
import {
|
import {
|
||||||
@ -23,9 +17,10 @@ import {
|
|||||||
PermissionError,
|
PermissionError,
|
||||||
} from '../../../lib/error';
|
} from '../../../lib/error';
|
||||||
import { ISegmentService } from '../../../lib/segments/segment-service-interface';
|
import { ISegmentService } from '../../../lib/segments/segment-service-interface';
|
||||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
import {
|
||||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
createFeatureToggleService,
|
||||||
import { DependentFeaturesReadModel } from '../../../lib/features/dependent-features/dependent-features-read-model';
|
createSegmentService,
|
||||||
|
} from '../../../lib/features';
|
||||||
|
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
let db;
|
let db;
|
||||||
@ -54,38 +49,10 @@ beforeAll(async () => {
|
|||||||
);
|
);
|
||||||
unleashConfig = config;
|
unleashConfig = config;
|
||||||
stores = db.stores;
|
stores = db.stores;
|
||||||
const eventService = new EventService(stores, config);
|
|
||||||
const groupService = new GroupService(stores, config, eventService);
|
|
||||||
const accessService = new AccessService(stores, config, groupService);
|
|
||||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
accessService,
|
|
||||||
);
|
|
||||||
const privateProjectChecker = createPrivateProjectChecker(
|
|
||||||
db.rawDatabase,
|
|
||||||
config,
|
|
||||||
);
|
|
||||||
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
);
|
|
||||||
segmentService = new SegmentService(
|
|
||||||
stores,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
config,
|
|
||||||
eventService,
|
|
||||||
privateProjectChecker,
|
|
||||||
);
|
|
||||||
|
|
||||||
service = new FeatureToggleService(
|
segmentService = createSegmentService(db.rawDatabase, config);
|
||||||
stores,
|
|
||||||
config,
|
service = createFeatureToggleService(db.rawDatabase, config);
|
||||||
segmentService,
|
|
||||||
accessService,
|
|
||||||
eventService,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
privateProjectChecker,
|
|
||||||
dependentFeaturesReadModel,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@ -462,40 +429,14 @@ test('If change requests are enabled, cannot change variants without going via C
|
|||||||
{ name: featureName },
|
{ name: featureName },
|
||||||
'test-user',
|
'test-user',
|
||||||
);
|
);
|
||||||
const eventService = new EventService(stores, unleashConfig);
|
|
||||||
const groupService = new GroupService(stores, unleashConfig, eventService);
|
|
||||||
const accessService = new AccessService(
|
|
||||||
stores,
|
|
||||||
unleashConfig,
|
|
||||||
groupService,
|
|
||||||
);
|
|
||||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
accessService,
|
|
||||||
);
|
|
||||||
const privateProjectChecker = createPrivateProjectChecker(
|
|
||||||
db.rawDatabase,
|
|
||||||
unleashConfig,
|
|
||||||
);
|
|
||||||
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
);
|
|
||||||
// Force all feature flags on to make sure we have Change requests on
|
// Force all feature flags on to make sure we have Change requests on
|
||||||
const customFeatureService = new FeatureToggleService(
|
const customFeatureService = createFeatureToggleService(db.rawDatabase, {
|
||||||
stores,
|
...unleashConfig,
|
||||||
{
|
flagResolver: {
|
||||||
...unleashConfig,
|
isEnabled: () => true,
|
||||||
flagResolver: {
|
|
||||||
isEnabled: () => true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
segmentService,
|
});
|
||||||
accessService,
|
|
||||||
eventService,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
privateProjectChecker,
|
|
||||||
dependentFeaturesReadModel,
|
|
||||||
);
|
|
||||||
|
|
||||||
const newVariant: IVariant = {
|
const newVariant: IVariant = {
|
||||||
name: 'cr-enabled',
|
name: 'cr-enabled',
|
||||||
@ -556,40 +497,14 @@ test('If CRs are protected for any environment in the project stops bulk update
|
|||||||
project.id,
|
project.id,
|
||||||
disabledEnv.name,
|
disabledEnv.name,
|
||||||
);
|
);
|
||||||
const eventService = new EventService(stores, unleashConfig);
|
|
||||||
const groupService = new GroupService(stores, unleashConfig, eventService);
|
|
||||||
const accessService = new AccessService(
|
|
||||||
stores,
|
|
||||||
unleashConfig,
|
|
||||||
groupService,
|
|
||||||
);
|
|
||||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
accessService,
|
|
||||||
);
|
|
||||||
const privateProjectChecker = createPrivateProjectChecker(
|
|
||||||
db.rawDatabase,
|
|
||||||
unleashConfig,
|
|
||||||
);
|
|
||||||
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
);
|
|
||||||
// Force all feature flags on to make sure we have Change requests on
|
// Force all feature flags on to make sure we have Change requests on
|
||||||
const customFeatureService = new FeatureToggleService(
|
const customFeatureService = createFeatureToggleService(db.rawDatabase, {
|
||||||
stores,
|
...unleashConfig,
|
||||||
{
|
flagResolver: {
|
||||||
...unleashConfig,
|
isEnabled: () => true,
|
||||||
flagResolver: {
|
|
||||||
isEnabled: () => true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
segmentService,
|
});
|
||||||
accessService,
|
|
||||||
eventService,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
privateProjectChecker,
|
|
||||||
dependentFeaturesReadModel,
|
|
||||||
);
|
|
||||||
|
|
||||||
const toggle = await service.createFeatureToggle(
|
const toggle = await service.createFeatureToggle(
|
||||||
project.id,
|
project.id,
|
||||||
|
@ -12,7 +12,6 @@ import { createTestConfig } from '../../config/test-config';
|
|||||||
import dbInit, { ITestDb } from '../helpers/database-init';
|
import dbInit, { ITestDb } from '../helpers/database-init';
|
||||||
import { IUnleashStores } from '../../../lib/types/stores';
|
import { IUnleashStores } from '../../../lib/types/stores';
|
||||||
import FeatureToggleService from '../../../lib/services/feature-toggle-service';
|
import FeatureToggleService from '../../../lib/services/feature-toggle-service';
|
||||||
import { SegmentService } from '../../../lib/services/segment-service';
|
|
||||||
import { FeatureToggle, ISegment, WeightType } from '../../../lib/types/model';
|
import { FeatureToggle, ISegment, WeightType } from '../../../lib/types/model';
|
||||||
import { PlaygroundFeatureSchema } from '../../../lib/openapi/spec/playground-feature-schema';
|
import { PlaygroundFeatureSchema } from '../../../lib/openapi/spec/playground-feature-schema';
|
||||||
import { offlineUnleashClientNode } from '../../../lib/features/playground/offline-unleash-client.test';
|
import { offlineUnleashClientNode } from '../../../lib/features/playground/offline-unleash-client.test';
|
||||||
@ -21,13 +20,12 @@ import { SdkContextSchema } from 'lib/openapi/spec/sdk-context-schema';
|
|||||||
import { SegmentSchema } from 'lib/openapi/spec/segment-schema';
|
import { SegmentSchema } from 'lib/openapi/spec/segment-schema';
|
||||||
import { playgroundStrategyEvaluation } from '../../../lib/openapi/spec/playground-strategy-schema';
|
import { playgroundStrategyEvaluation } from '../../../lib/openapi/spec/playground-strategy-schema';
|
||||||
import { PlaygroundSegmentSchema } from 'lib/openapi/spec/playground-segment-schema';
|
import { PlaygroundSegmentSchema } from 'lib/openapi/spec/playground-segment-schema';
|
||||||
import { GroupService } from '../../../lib/services/group-service';
|
|
||||||
import { AccessService } from '../../../lib/services/access-service';
|
|
||||||
import { ISegmentService } from '../../../lib/segments/segment-service-interface';
|
import { ISegmentService } from '../../../lib/segments/segment-service-interface';
|
||||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
|
||||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
||||||
import { DependentFeaturesReadModel } from '../../../lib/features/dependent-features/dependent-features-read-model';
|
import {
|
||||||
import { EventService } from '../../../lib/services';
|
createFeatureToggleService,
|
||||||
|
createSegmentService,
|
||||||
|
} from '../../../lib/features';
|
||||||
|
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
@ -39,38 +37,13 @@ beforeAll(async () => {
|
|||||||
const config = createTestConfig();
|
const config = createTestConfig();
|
||||||
db = await dbInit('playground_service_serial', config.getLogger);
|
db = await dbInit('playground_service_serial', config.getLogger);
|
||||||
stores = db.stores;
|
stores = db.stores;
|
||||||
const eventService = new EventService(stores, config);
|
|
||||||
const groupService = new GroupService(stores, config, eventService);
|
|
||||||
const accessService = new AccessService(stores, config, groupService);
|
|
||||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
accessService,
|
|
||||||
);
|
|
||||||
const privateProjectChecker = createPrivateProjectChecker(
|
const privateProjectChecker = createPrivateProjectChecker(
|
||||||
db.rawDatabase,
|
db.rawDatabase,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
segmentService = createSegmentService(db.rawDatabase, config);
|
||||||
db.rawDatabase,
|
|
||||||
);
|
|
||||||
segmentService = new SegmentService(
|
|
||||||
stores,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
config,
|
|
||||||
eventService,
|
|
||||||
privateProjectChecker,
|
|
||||||
);
|
|
||||||
|
|
||||||
featureToggleService = new FeatureToggleService(
|
featureToggleService = createFeatureToggleService(db.rawDatabase, config);
|
||||||
stores,
|
|
||||||
config,
|
|
||||||
segmentService,
|
|
||||||
accessService,
|
|
||||||
eventService,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
privateProjectChecker,
|
|
||||||
dependentFeaturesReadModel,
|
|
||||||
);
|
|
||||||
service = new PlaygroundService(config, {
|
service = new PlaygroundService(config, {
|
||||||
featureToggleServiceV2: featureToggleService,
|
featureToggleServiceV2: featureToggleService,
|
||||||
segmentService,
|
segmentService,
|
||||||
|
@ -1,28 +1,21 @@
|
|||||||
import dbInit, { ITestDb } from '../helpers/database-init';
|
import dbInit, { ITestDb } from '../helpers/database-init';
|
||||||
import getLogger from '../../fixtures/no-logger';
|
import getLogger from '../../fixtures/no-logger';
|
||||||
import FeatureToggleService from '../../../lib/services/feature-toggle-service';
|
|
||||||
import { AccessService } from '../../../lib/services/access-service';
|
|
||||||
import ProjectService from '../../../lib/services/project-service';
|
|
||||||
import ProjectHealthService from '../../../lib/services/project-health-service';
|
import ProjectHealthService from '../../../lib/services/project-health-service';
|
||||||
import { createTestConfig } from '../../config/test-config';
|
import { createTestConfig } from '../../config/test-config';
|
||||||
import { IUnleashStores } from '../../../lib/types';
|
import { IUnleashStores } from '../../../lib/types';
|
||||||
import { IUser } from '../../../lib/server-impl';
|
import { IUser } from '../../../lib/server-impl';
|
||||||
import { SegmentService } from '../../../lib/services/segment-service';
|
import { EventService } from '../../../lib/services';
|
||||||
import { GroupService } from '../../../lib/services/group-service';
|
import {
|
||||||
import { EventService, FavoritesService } from '../../../lib/services';
|
createFeatureToggleService,
|
||||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
createProjectService,
|
||||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
} from '../../../lib/features';
|
||||||
import { DependentFeaturesReadModel } from '../../../lib/features/dependent-features/dependent-features-read-model';
|
|
||||||
|
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
let projectService;
|
let projectService;
|
||||||
let groupService;
|
|
||||||
let accessService;
|
|
||||||
let eventService: EventService;
|
let eventService: EventService;
|
||||||
let projectHealthService;
|
let projectHealthService;
|
||||||
let featureToggleService;
|
let featureToggleService;
|
||||||
let favoritesService;
|
|
||||||
let user: IUser;
|
let user: IUser;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
@ -34,47 +27,10 @@ beforeAll(async () => {
|
|||||||
email: 'test@getunleash.io',
|
email: 'test@getunleash.io',
|
||||||
});
|
});
|
||||||
eventService = new EventService(stores, config);
|
eventService = new EventService(stores, config);
|
||||||
groupService = new GroupService(stores, config, eventService);
|
|
||||||
accessService = new AccessService(stores, config, groupService);
|
|
||||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
accessService,
|
|
||||||
);
|
|
||||||
const privateProjectChecker = createPrivateProjectChecker(
|
|
||||||
db.rawDatabase,
|
|
||||||
config,
|
|
||||||
);
|
|
||||||
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
);
|
|
||||||
featureToggleService = new FeatureToggleService(
|
|
||||||
stores,
|
|
||||||
config,
|
|
||||||
new SegmentService(
|
|
||||||
stores,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
config,
|
|
||||||
eventService,
|
|
||||||
privateProjectChecker,
|
|
||||||
),
|
|
||||||
accessService,
|
|
||||||
eventService,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
privateProjectChecker,
|
|
||||||
dependentFeaturesReadModel,
|
|
||||||
);
|
|
||||||
favoritesService = new FavoritesService(stores, config, eventService);
|
|
||||||
|
|
||||||
projectService = new ProjectService(
|
featureToggleService = createFeatureToggleService(db.rawDatabase, config);
|
||||||
stores,
|
|
||||||
config,
|
projectService = createProjectService(db.rawDatabase, config);
|
||||||
accessService,
|
|
||||||
featureToggleService,
|
|
||||||
groupService,
|
|
||||||
favoritesService,
|
|
||||||
eventService,
|
|
||||||
privateProjectChecker,
|
|
||||||
);
|
|
||||||
projectHealthService = new ProjectHealthService(
|
projectHealthService = new ProjectHealthService(
|
||||||
stores,
|
stores,
|
||||||
config,
|
config,
|
||||||
|
@ -9,25 +9,23 @@ import { RoleName } from '../../../lib/types/model';
|
|||||||
import { randomId } from '../../../lib/util/random-id';
|
import { randomId } from '../../../lib/util/random-id';
|
||||||
import EnvironmentService from '../../../lib/services/environment-service';
|
import EnvironmentService from '../../../lib/services/environment-service';
|
||||||
import IncompatibleProjectError from '../../../lib/error/incompatible-project-error';
|
import IncompatibleProjectError from '../../../lib/error/incompatible-project-error';
|
||||||
import { SegmentService } from '../../../lib/services/segment-service';
|
import { EventService } from '../../../lib/services';
|
||||||
import { GroupService } from '../../../lib/services/group-service';
|
|
||||||
import { EventService, FavoritesService } from '../../../lib/services';
|
|
||||||
import { FeatureEnvironmentEvent } from '../../../lib/types/events';
|
import { FeatureEnvironmentEvent } from '../../../lib/types/events';
|
||||||
import { addDays, subDays } from 'date-fns';
|
import { addDays, subDays } from 'date-fns';
|
||||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
import {
|
||||||
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker';
|
createAccessService,
|
||||||
import { DependentFeaturesReadModel } from '../../../lib/features/dependent-features/dependent-features-read-model';
|
createFeatureToggleService,
|
||||||
|
createProjectService,
|
||||||
|
} from '../../../lib/features';
|
||||||
|
|
||||||
let stores;
|
let stores;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
|
|
||||||
let projectService: ProjectService;
|
let projectService: ProjectService;
|
||||||
let groupService: GroupService;
|
|
||||||
let accessService: AccessService;
|
let accessService: AccessService;
|
||||||
let eventService: EventService;
|
let eventService: EventService;
|
||||||
let environmentService: EnvironmentService;
|
let environmentService: EnvironmentService;
|
||||||
let featureToggleService: FeatureToggleService;
|
let featureToggleService: FeatureToggleService;
|
||||||
let favoritesService: FavoritesService;
|
|
||||||
let user;
|
let user;
|
||||||
|
|
||||||
const isProjectUser = async (
|
const isProjectUser = async (
|
||||||
@ -55,48 +53,12 @@ beforeAll(async () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
eventService = new EventService(stores, config);
|
eventService = new EventService(stores, config);
|
||||||
groupService = new GroupService(stores, config, eventService);
|
accessService = createAccessService(db.rawDatabase, config);
|
||||||
accessService = new AccessService(stores, config, groupService);
|
|
||||||
const changeRequestAccessReadModel = new ChangeRequestAccessReadModel(
|
featureToggleService = createFeatureToggleService(db.rawDatabase, config);
|
||||||
db.rawDatabase,
|
|
||||||
accessService,
|
|
||||||
);
|
|
||||||
const privateProjectChecker = createPrivateProjectChecker(
|
|
||||||
db.rawDatabase,
|
|
||||||
config,
|
|
||||||
);
|
|
||||||
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
|
||||||
db.rawDatabase,
|
|
||||||
);
|
|
||||||
featureToggleService = new FeatureToggleService(
|
|
||||||
stores,
|
|
||||||
config,
|
|
||||||
new SegmentService(
|
|
||||||
stores,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
config,
|
|
||||||
eventService,
|
|
||||||
privateProjectChecker,
|
|
||||||
),
|
|
||||||
accessService,
|
|
||||||
eventService,
|
|
||||||
changeRequestAccessReadModel,
|
|
||||||
privateProjectChecker,
|
|
||||||
dependentFeaturesReadModel,
|
|
||||||
);
|
|
||||||
|
|
||||||
favoritesService = new FavoritesService(stores, config, eventService);
|
|
||||||
environmentService = new EnvironmentService(stores, config);
|
environmentService = new EnvironmentService(stores, config);
|
||||||
projectService = new ProjectService(
|
projectService = createProjectService(db.rawDatabase, config);
|
||||||
stores,
|
|
||||||
config,
|
|
||||||
accessService,
|
|
||||||
featureToggleService,
|
|
||||||
groupService,
|
|
||||||
favoritesService,
|
|
||||||
eventService,
|
|
||||||
privateProjectChecker,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user