mirror of
https://github.com/Unleash/unleash.git
synced 2025-08-04 13:48:56 +02:00
feat: feature admin API returns dependencies and children (#4848)
This commit is contained in:
parent
fd8775f13d
commit
87a81120d2
@ -1,5 +1,7 @@
|
|||||||
|
import { IDependency } from '../../types';
|
||||||
|
|
||||||
export interface IDependentFeaturesReadModel {
|
export interface IDependentFeaturesReadModel {
|
||||||
getChildren(parent: string): Promise<string[]>;
|
getChildren(parent: string): Promise<string[]>;
|
||||||
getParents(child: string): Promise<string[]>;
|
getParents(child: string): Promise<IDependency[]>;
|
||||||
getParentOptions(child: string): Promise<string[]>;
|
getParentOptions(child: string): Promise<string[]>;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Db } from '../../db/db';
|
import { Db } from '../../db/db';
|
||||||
import { IDependentFeaturesReadModel } from './dependent-features-read-model-type';
|
import { IDependentFeaturesReadModel } from './dependent-features-read-model-type';
|
||||||
|
import { IDependency } from '../../types';
|
||||||
|
|
||||||
export class DependentFeaturesReadModel implements IDependentFeaturesReadModel {
|
export class DependentFeaturesReadModel implements IDependentFeaturesReadModel {
|
||||||
private db: Db;
|
private db: Db;
|
||||||
@ -17,10 +18,14 @@ export class DependentFeaturesReadModel implements IDependentFeaturesReadModel {
|
|||||||
return rows.map((row) => row.child);
|
return rows.map((row) => row.child);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getParents(child: string): Promise<string[]> {
|
async getParents(child: string): Promise<IDependency[]> {
|
||||||
const rows = await this.db('dependent_features').where('child', child);
|
const rows = await this.db('dependent_features').where('child', child);
|
||||||
|
|
||||||
return rows.map((row) => row.parent);
|
return rows.map((row) => ({
|
||||||
|
feature: row.parent,
|
||||||
|
enabled: row.enabled,
|
||||||
|
variants: row.variants,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
async getParentOptions(child: string): Promise<string[]> {
|
async getParentOptions(child: string): Promise<string[]> {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { IDependentFeaturesReadModel } from './dependent-features-read-model-type';
|
import { IDependentFeaturesReadModel } from './dependent-features-read-model-type';
|
||||||
|
import { IDependency } from '../../types';
|
||||||
|
|
||||||
export class FakeDependentFeaturesReadModel
|
export class FakeDependentFeaturesReadModel
|
||||||
implements IDependentFeaturesReadModel
|
implements IDependentFeaturesReadModel
|
||||||
@ -7,7 +8,7 @@ export class FakeDependentFeaturesReadModel
|
|||||||
return Promise.resolve([]);
|
return Promise.resolve([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
getParents(): Promise<string[]> {
|
getParents(): Promise<IDependency[]> {
|
||||||
return Promise.resolve([]);
|
return Promise.resolve([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,8 @@ import {
|
|||||||
createFakePrivateProjectChecker,
|
createFakePrivateProjectChecker,
|
||||||
createPrivateProjectChecker,
|
createPrivateProjectChecker,
|
||||||
} from '../private-project/createPrivateProjectChecker';
|
} from '../private-project/createPrivateProjectChecker';
|
||||||
|
import { DependentFeaturesReadModel } from '../dependent-features/dependent-features-read-model';
|
||||||
|
import { FakeDependentFeaturesReadModel } from '../dependent-features/fake-dependent-features-read-model';
|
||||||
|
|
||||||
export const createFeatureToggleService = (
|
export const createFeatureToggleService = (
|
||||||
db: Db,
|
db: Db,
|
||||||
@ -105,6 +107,8 @@ export const createFeatureToggleService = (
|
|||||||
|
|
||||||
const privateProjectChecker = createPrivateProjectChecker(db, config);
|
const privateProjectChecker = createPrivateProjectChecker(db, config);
|
||||||
|
|
||||||
|
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
|
||||||
|
|
||||||
const featureToggleService = new FeatureToggleService(
|
const featureToggleService = new FeatureToggleService(
|
||||||
{
|
{
|
||||||
featureStrategiesStore,
|
featureStrategiesStore,
|
||||||
@ -122,6 +126,7 @@ export const createFeatureToggleService = (
|
|||||||
accessService,
|
accessService,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
|
dependentFeaturesReadModel,
|
||||||
);
|
);
|
||||||
return featureToggleService;
|
return featureToggleService;
|
||||||
};
|
};
|
||||||
@ -155,7 +160,8 @@ export const createFakeFeatureToggleService = (
|
|||||||
);
|
);
|
||||||
const segmentService = createFakeSegmentService(config);
|
const segmentService = createFakeSegmentService(config);
|
||||||
const changeRequestAccessReadModel = createFakeChangeRequestAccessService();
|
const changeRequestAccessReadModel = createFakeChangeRequestAccessService();
|
||||||
const fakeprivateProjectChecker = createFakePrivateProjectChecker();
|
const fakePrivateProjectChecker = createFakePrivateProjectChecker();
|
||||||
|
const dependentFeaturesReadModel = new FakeDependentFeaturesReadModel();
|
||||||
const featureToggleService = new FeatureToggleService(
|
const featureToggleService = new FeatureToggleService(
|
||||||
{
|
{
|
||||||
featureStrategiesStore,
|
featureStrategiesStore,
|
||||||
@ -172,7 +178,8 @@ export const createFakeFeatureToggleService = (
|
|||||||
segmentService,
|
segmentService,
|
||||||
accessService,
|
accessService,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
fakeprivateProjectChecker,
|
fakePrivateProjectChecker,
|
||||||
|
dependentFeaturesReadModel,
|
||||||
);
|
);
|
||||||
return featureToggleService;
|
return featureToggleService;
|
||||||
};
|
};
|
||||||
|
@ -121,6 +121,47 @@ export const featureSchema = {
|
|||||||
nullable: true,
|
nullable: true,
|
||||||
description: 'The list of feature tags',
|
description: 'The list of feature tags',
|
||||||
},
|
},
|
||||||
|
children: {
|
||||||
|
type: 'array',
|
||||||
|
description:
|
||||||
|
'The list of child feature names. This is an experimental field and may change.',
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
example: 'some-feature',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dependencies: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
additionalProperties: false,
|
||||||
|
required: ['feature'],
|
||||||
|
properties: {
|
||||||
|
feature: {
|
||||||
|
description: 'The name of the parent feature',
|
||||||
|
type: 'string',
|
||||||
|
example: 'some-feature',
|
||||||
|
},
|
||||||
|
enabled: {
|
||||||
|
description:
|
||||||
|
'Whether the parent feature is enabled or not',
|
||||||
|
type: 'boolean',
|
||||||
|
example: true,
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
description:
|
||||||
|
'The list of variants the parent feature should resolve to. Only valid when feature is enabled.',
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
example: 'some-feature-blue-variant',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description:
|
||||||
|
'The list of parent dependencies. This is an experimental field and may change.',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
schemas: {
|
schemas: {
|
||||||
|
@ -10,6 +10,7 @@ import { AccessService } from './access-service';
|
|||||||
import { IChangeRequestAccessReadModel } from 'lib/features/change-request-access-service/change-request-access-read-model';
|
import { IChangeRequestAccessReadModel } from 'lib/features/change-request-access-service/change-request-access-read-model';
|
||||||
import { ISegmentService } from 'lib/segments/segment-service-interface';
|
import { ISegmentService } from 'lib/segments/segment-service-interface';
|
||||||
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';
|
||||||
|
|
||||||
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);
|
||||||
@ -51,6 +52,7 @@ test('Should only store events for potentially stale on', async () => {
|
|||||||
{} as AccessService,
|
{} as AccessService,
|
||||||
{} as IChangeRequestAccessReadModel,
|
{} as IChangeRequestAccessReadModel,
|
||||||
{} as IPrivateProjectChecker,
|
{} as IPrivateProjectChecker,
|
||||||
|
{} as IDependentFeaturesReadModel,
|
||||||
);
|
);
|
||||||
|
|
||||||
await featureToggleService.updatePotentiallyStaleFeatures();
|
await featureToggleService.updatePotentiallyStaleFeatures();
|
||||||
|
@ -16,9 +16,11 @@ import {
|
|||||||
FeatureToggle,
|
FeatureToggle,
|
||||||
FeatureToggleDTO,
|
FeatureToggleDTO,
|
||||||
FeatureToggleLegacy,
|
FeatureToggleLegacy,
|
||||||
|
FeatureToggleWithDependencies,
|
||||||
FeatureToggleWithEnvironment,
|
FeatureToggleWithEnvironment,
|
||||||
FeatureVariantEvent,
|
FeatureVariantEvent,
|
||||||
IConstraint,
|
IConstraint,
|
||||||
|
IDependency,
|
||||||
IEventStore,
|
IEventStore,
|
||||||
IFeatureEnvironmentInfo,
|
IFeatureEnvironmentInfo,
|
||||||
IFeatureEnvironmentStore,
|
IFeatureEnvironmentStore,
|
||||||
@ -96,6 +98,7 @@ import { ISegmentService } from 'lib/segments/segment-service-interface';
|
|||||||
import { IChangeRequestAccessReadModel } from '../features/change-request-access-service/change-request-access-read-model';
|
import { IChangeRequestAccessReadModel } from '../features/change-request-access-service/change-request-access-read-model';
|
||||||
import { checkFeatureFlagNamesAgainstPattern } from '../features/feature-naming-pattern/feature-naming-validation';
|
import { checkFeatureFlagNamesAgainstPattern } from '../features/feature-naming-pattern/feature-naming-validation';
|
||||||
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';
|
||||||
|
|
||||||
interface IFeatureContext {
|
interface IFeatureContext {
|
||||||
featureName: string;
|
featureName: string;
|
||||||
@ -157,6 +160,8 @@ class FeatureToggleService {
|
|||||||
|
|
||||||
private privateProjectChecker: IPrivateProjectChecker;
|
private privateProjectChecker: IPrivateProjectChecker;
|
||||||
|
|
||||||
|
private dependentFeaturesReadModel: IDependentFeaturesReadModel;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{
|
{
|
||||||
featureStrategiesStore,
|
featureStrategiesStore,
|
||||||
@ -188,6 +193,7 @@ class FeatureToggleService {
|
|||||||
accessService: AccessService,
|
accessService: AccessService,
|
||||||
changeRequestAccessReadModel: IChangeRequestAccessReadModel,
|
changeRequestAccessReadModel: IChangeRequestAccessReadModel,
|
||||||
privateProjectChecker: IPrivateProjectChecker,
|
privateProjectChecker: IPrivateProjectChecker,
|
||||||
|
dependentFeaturesReadModel: IDependentFeaturesReadModel,
|
||||||
) {
|
) {
|
||||||
this.logger = getLogger('services/feature-toggle-service.ts');
|
this.logger = getLogger('services/feature-toggle-service.ts');
|
||||||
this.featureStrategiesStore = featureStrategiesStore;
|
this.featureStrategiesStore = featureStrategiesStore;
|
||||||
@ -204,6 +210,7 @@ class FeatureToggleService {
|
|||||||
this.flagResolver = flagResolver;
|
this.flagResolver = flagResolver;
|
||||||
this.changeRequestAccessReadModel = changeRequestAccessReadModel;
|
this.changeRequestAccessReadModel = changeRequestAccessReadModel;
|
||||||
this.privateProjectChecker = privateProjectChecker;
|
this.privateProjectChecker = privateProjectChecker;
|
||||||
|
this.dependentFeaturesReadModel = dependentFeaturesReadModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateFeaturesContext(
|
async validateFeaturesContext(
|
||||||
@ -921,7 +928,7 @@ class FeatureToggleService {
|
|||||||
projectId,
|
projectId,
|
||||||
environmentVariants,
|
environmentVariants,
|
||||||
userId,
|
userId,
|
||||||
}: IGetFeatureParams): Promise<FeatureToggleWithEnvironment> {
|
}: IGetFeatureParams): Promise<FeatureToggleWithDependencies> {
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
await this.validateFeatureBelongsToProject({
|
await this.validateFeatureBelongsToProject({
|
||||||
featureName,
|
featureName,
|
||||||
@ -929,18 +936,31 @@ class FeatureToggleService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let dependencies: IDependency[] = [];
|
||||||
|
let children: string[] = [];
|
||||||
|
if (this.flagResolver.isEnabled('dependentFeatures')) {
|
||||||
|
[dependencies, children] = await Promise.all([
|
||||||
|
this.dependentFeaturesReadModel.getParents(featureName),
|
||||||
|
this.dependentFeaturesReadModel.getChildren(featureName),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
if (environmentVariants) {
|
if (environmentVariants) {
|
||||||
return this.featureStrategiesStore.getFeatureToggleWithVariantEnvs(
|
const result =
|
||||||
|
await this.featureStrategiesStore.getFeatureToggleWithVariantEnvs(
|
||||||
featureName,
|
featureName,
|
||||||
userId,
|
userId,
|
||||||
archived,
|
archived,
|
||||||
);
|
);
|
||||||
|
return { ...result, dependencies, children };
|
||||||
} else {
|
} else {
|
||||||
return this.featureStrategiesStore.getFeatureToggleWithEnvs(
|
const result =
|
||||||
|
await this.featureStrategiesStore.getFeatureToggleWithEnvs(
|
||||||
featureName,
|
featureName,
|
||||||
userId,
|
userId,
|
||||||
archived,
|
archived,
|
||||||
);
|
);
|
||||||
|
return { ...result, dependencies, children };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +73,8 @@ import {
|
|||||||
createDependentFeaturesService,
|
createDependentFeaturesService,
|
||||||
createFakeDependentFeaturesService,
|
createFakeDependentFeaturesService,
|
||||||
} from '../features/dependent-features/createDependentFeaturesService';
|
} from '../features/dependent-features/createDependentFeaturesService';
|
||||||
|
import { DependentFeaturesReadModel } from '../features/dependent-features/dependent-features-read-model';
|
||||||
|
import { FakeDependentFeaturesReadModel } from '../features/dependent-features/fake-dependent-features-read-model';
|
||||||
|
|
||||||
// TODO: will be moved to scheduler feature directory
|
// TODO: will be moved to scheduler feature directory
|
||||||
export const scheduleServices = async (
|
export const scheduleServices = async (
|
||||||
@ -175,6 +177,9 @@ export const createServices = (
|
|||||||
const privateProjectChecker = db
|
const privateProjectChecker = db
|
||||||
? createPrivateProjectChecker(db, config)
|
? createPrivateProjectChecker(db, config)
|
||||||
: createFakePrivateProjectChecker();
|
: createFakePrivateProjectChecker();
|
||||||
|
const dependentFeaturesReadModel = db
|
||||||
|
? new DependentFeaturesReadModel(db)
|
||||||
|
: new FakeDependentFeaturesReadModel();
|
||||||
|
|
||||||
const contextService = new ContextService(
|
const contextService = new ContextService(
|
||||||
stores,
|
stores,
|
||||||
@ -227,6 +232,7 @@ export const createServices = (
|
|||||||
accessService,
|
accessService,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
|
dependentFeaturesReadModel,
|
||||||
);
|
);
|
||||||
const environmentService = new EnvironmentService(stores, config);
|
const environmentService = new EnvironmentService(stores, config);
|
||||||
const featureTagService = new FeatureTagService(stores, config);
|
const featureTagService = new FeatureTagService(stores, config);
|
||||||
|
@ -96,6 +96,12 @@ export interface FeatureToggleWithEnvironment extends FeatureToggle {
|
|||||||
environments: IEnvironmentDetail[];
|
environments: IEnvironmentDetail[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FeatureToggleWithDependencies
|
||||||
|
extends FeatureToggleWithEnvironment {
|
||||||
|
dependencies: IDependency[];
|
||||||
|
children: string[];
|
||||||
|
}
|
||||||
|
|
||||||
// @deprecated
|
// @deprecated
|
||||||
export interface FeatureToggleLegacy extends FeatureToggle {
|
export interface FeatureToggleLegacy extends FeatureToggle {
|
||||||
strategies: IStrategyConfig[];
|
strategies: IStrategyConfig[];
|
||||||
|
@ -91,6 +91,7 @@ beforeAll(async () => {
|
|||||||
experimental: {
|
experimental: {
|
||||||
flags: {
|
flags: {
|
||||||
strictSchemaValidation: true,
|
strictSchemaValidation: true,
|
||||||
|
dependentFeatures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -214,6 +215,32 @@ test('Can get project overview', async () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should list dependencies and children', async () => {
|
||||||
|
const parent = uuidv4();
|
||||||
|
const child = uuidv4();
|
||||||
|
await app.createFeature(parent, 'default');
|
||||||
|
await app.createFeature(child, 'default');
|
||||||
|
await app.addDependency(child, parent);
|
||||||
|
|
||||||
|
const { body: childFeature } = await app.getProjectFeatures(
|
||||||
|
'default',
|
||||||
|
child,
|
||||||
|
);
|
||||||
|
const { body: parentFeature } = await app.getProjectFeatures(
|
||||||
|
'default',
|
||||||
|
parent,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(childFeature).toMatchObject({
|
||||||
|
children: [],
|
||||||
|
dependencies: [{ feature: parent, enabled: true, variants: [] }],
|
||||||
|
});
|
||||||
|
expect(parentFeature).toMatchObject({
|
||||||
|
children: [child],
|
||||||
|
dependencies: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
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')
|
||||||
|
@ -20,6 +20,7 @@ beforeAll(async () => {
|
|||||||
flags: {
|
flags: {
|
||||||
strictSchemaValidation: true,
|
strictSchemaValidation: true,
|
||||||
featureNamingPattern: true,
|
featureNamingPattern: true,
|
||||||
|
dependentFeatures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -63,6 +63,8 @@ export interface IUnleashHttpAPI {
|
|||||||
importPayload: ImportTogglesSchema,
|
importPayload: ImportTogglesSchema,
|
||||||
expectedResponseCode?: number,
|
expectedResponseCode?: number,
|
||||||
): supertest.Test;
|
): supertest.Test;
|
||||||
|
|
||||||
|
addDependency(child: string, parent: string): supertest.Test;
|
||||||
}
|
}
|
||||||
|
|
||||||
function httpApis(
|
function httpApis(
|
||||||
@ -161,6 +163,21 @@ function httpApis(
|
|||||||
.set('Content-Type', 'application/json')
|
.set('Content-Type', 'application/json')
|
||||||
.expect(expectedResponseCode);
|
.expect(expectedResponseCode);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addDependency(
|
||||||
|
child: string,
|
||||||
|
parent: string,
|
||||||
|
project = DEFAULT_PROJECT,
|
||||||
|
expectedResponseCode: number = 200,
|
||||||
|
): supertest.Test {
|
||||||
|
return request
|
||||||
|
.post(
|
||||||
|
`/api/admin/projects/${project}/features/${child}/dependencies`,
|
||||||
|
)
|
||||||
|
.send({ feature: parent })
|
||||||
|
.set('Content-Type', 'application/json')
|
||||||
|
.expect(expectedResponseCode);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import { GroupService } from '../../../lib/services/group-service';
|
|||||||
import { FavoritesService } from '../../../lib/services';
|
import { FavoritesService } from '../../../lib/services';
|
||||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
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';
|
||||||
|
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
@ -250,6 +251,9 @@ beforeAll(async () => {
|
|||||||
db.rawDatabase,
|
db.rawDatabase,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
|
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
||||||
|
db.rawDatabase,
|
||||||
|
);
|
||||||
featureToggleService = new FeatureToggleService(
|
featureToggleService = new FeatureToggleService(
|
||||||
stores,
|
stores,
|
||||||
config,
|
config,
|
||||||
@ -262,6 +266,7 @@ beforeAll(async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
|
dependentFeaturesReadModel,
|
||||||
);
|
);
|
||||||
favoritesService = new FavoritesService(stores, config);
|
favoritesService = new FavoritesService(stores, config);
|
||||||
projectService = new ProjectService(
|
projectService = new ProjectService(
|
||||||
|
@ -13,6 +13,7 @@ import { GroupService } from '../../../lib/services/group-service';
|
|||||||
import { FavoritesService } from '../../../lib/services';
|
import { FavoritesService } from '../../../lib/services';
|
||||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
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';
|
||||||
|
|
||||||
let db;
|
let db;
|
||||||
let stores;
|
let stores;
|
||||||
@ -36,6 +37,9 @@ beforeAll(async () => {
|
|||||||
db.rawDatabase,
|
db.rawDatabase,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
|
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
||||||
|
db.rawDatabase,
|
||||||
|
);
|
||||||
const featureToggleService = new FeatureToggleService(
|
const featureToggleService = new FeatureToggleService(
|
||||||
stores,
|
stores,
|
||||||
config,
|
config,
|
||||||
@ -48,6 +52,7 @@ beforeAll(async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
|
dependentFeaturesReadModel,
|
||||||
);
|
);
|
||||||
const project = {
|
const project = {
|
||||||
id: 'test-project',
|
id: 'test-project',
|
||||||
|
@ -24,6 +24,7 @@ import {
|
|||||||
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 { 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';
|
||||||
|
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
let db;
|
let db;
|
||||||
@ -63,6 +64,9 @@ beforeAll(async () => {
|
|||||||
db.rawDatabase,
|
db.rawDatabase,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
|
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
||||||
|
db.rawDatabase,
|
||||||
|
);
|
||||||
segmentService = new SegmentService(
|
segmentService = new SegmentService(
|
||||||
stores,
|
stores,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
@ -77,6 +81,7 @@ beforeAll(async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
|
dependentFeaturesReadModel,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -466,6 +471,9 @@ test('If change requests are enabled, cannot change variants without going via C
|
|||||||
db.rawDatabase,
|
db.rawDatabase,
|
||||||
unleashConfig,
|
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 = new FeatureToggleService(
|
||||||
stores,
|
stores,
|
||||||
@ -479,6 +487,7 @@ test('If change requests are enabled, cannot change variants without going via C
|
|||||||
accessService,
|
accessService,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
|
dependentFeaturesReadModel,
|
||||||
);
|
);
|
||||||
|
|
||||||
const newVariant: IVariant = {
|
const newVariant: IVariant = {
|
||||||
@ -554,6 +563,9 @@ test('If CRs are protected for any environment in the project stops bulk update
|
|||||||
db.rawDatabase,
|
db.rawDatabase,
|
||||||
unleashConfig,
|
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 = new FeatureToggleService(
|
||||||
stores,
|
stores,
|
||||||
@ -567,6 +579,7 @@ test('If CRs are protected for any environment in the project stops bulk update
|
|||||||
accessService,
|
accessService,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
|
dependentFeaturesReadModel,
|
||||||
);
|
);
|
||||||
|
|
||||||
const toggle = await service.createFeatureToggle(
|
const toggle = await service.createFeatureToggle(
|
||||||
|
@ -26,6 +26,7 @@ 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 { 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';
|
||||||
|
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
@ -47,6 +48,9 @@ beforeAll(async () => {
|
|||||||
db.rawDatabase,
|
db.rawDatabase,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
|
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
||||||
|
db.rawDatabase,
|
||||||
|
);
|
||||||
segmentService = new SegmentService(
|
segmentService = new SegmentService(
|
||||||
stores,
|
stores,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
@ -61,6 +65,7 @@ beforeAll(async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
|
dependentFeaturesReadModel,
|
||||||
);
|
);
|
||||||
service = new PlaygroundService(config, {
|
service = new PlaygroundService(config, {
|
||||||
featureToggleServiceV2: featureToggleService,
|
featureToggleServiceV2: featureToggleService,
|
||||||
|
@ -12,6 +12,7 @@ import { GroupService } from '../../../lib/services/group-service';
|
|||||||
import { FavoritesService } from '../../../lib/services';
|
import { FavoritesService } from '../../../lib/services';
|
||||||
import { ChangeRequestAccessReadModel } from '../../../lib/features/change-request-access-service/sql-change-request-access-read-model';
|
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';
|
||||||
|
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
@ -41,6 +42,9 @@ beforeAll(async () => {
|
|||||||
db.rawDatabase,
|
db.rawDatabase,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
|
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
||||||
|
db.rawDatabase,
|
||||||
|
);
|
||||||
featureToggleService = new FeatureToggleService(
|
featureToggleService = new FeatureToggleService(
|
||||||
stores,
|
stores,
|
||||||
config,
|
config,
|
||||||
@ -53,6 +57,7 @@ beforeAll(async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
|
dependentFeaturesReadModel,
|
||||||
);
|
);
|
||||||
favoritesService = new FavoritesService(stores, config);
|
favoritesService = new FavoritesService(stores, config);
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ 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 { 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';
|
||||||
|
|
||||||
let stores;
|
let stores;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
@ -62,6 +63,9 @@ beforeAll(async () => {
|
|||||||
db.rawDatabase,
|
db.rawDatabase,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
|
const dependentFeaturesReadModel = new DependentFeaturesReadModel(
|
||||||
|
db.rawDatabase,
|
||||||
|
);
|
||||||
featureToggleService = new FeatureToggleService(
|
featureToggleService = new FeatureToggleService(
|
||||||
stores,
|
stores,
|
||||||
config,
|
config,
|
||||||
@ -74,6 +78,7 @@ beforeAll(async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
changeRequestAccessReadModel,
|
changeRequestAccessReadModel,
|
||||||
privateProjectChecker,
|
privateProjectChecker,
|
||||||
|
dependentFeaturesReadModel,
|
||||||
);
|
);
|
||||||
|
|
||||||
favoritesService = new FavoritesService(stores, config);
|
favoritesService = new FavoritesService(stores, config);
|
||||||
|
Loading…
Reference in New Issue
Block a user