1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-19 01:17:18 +02:00

feat: import dependencies (#5044)

This commit is contained in:
Jaanus Sellin 2023-10-17 08:22:54 +03:00 committed by GitHub
parent e9e110f702
commit 5619db33ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 17 deletions

View File

@ -50,6 +50,10 @@ import {
createFakeSegmentService, createFakeSegmentService,
createSegmentService, createSegmentService,
} from '../segment/createSegmentService'; } from '../segment/createSegmentService';
import {
createDependentFeaturesService,
createFakeDependentFeaturesService,
} from '../dependent-features/createDependentFeaturesService';
export const createFakeExportImportTogglesService = ( export const createFakeExportImportTogglesService = (
config: IUnleashConfig, config: IUnleashConfig,
@ -112,6 +116,8 @@ export const createFakeExportImportTogglesService = (
const segmentService = createFakeSegmentService(config); const segmentService = createFakeSegmentService(config);
const dependentFeaturesService = createFakeDependentFeaturesService(config);
const exportImportService = new ExportImportService( const exportImportService = new ExportImportService(
{ {
importTogglesStore, importTogglesStore,
@ -133,6 +139,7 @@ export const createFakeExportImportTogglesService = (
strategyService, strategyService,
tagTypeService, tagTypeService,
segmentService, segmentService,
dependentFeaturesService,
}, },
dependentFeaturesReadModel, dependentFeaturesReadModel,
); );
@ -229,6 +236,11 @@ export const deferredExportImportTogglesService = (
const segmentService = createSegmentService(db, config); const segmentService = createSegmentService(db, config);
const dependentFeaturesService = createDependentFeaturesService(
db,
config,
);
const exportImportService = new ExportImportService( const exportImportService = new ExportImportService(
{ {
importTogglesStore, importTogglesStore,
@ -250,6 +262,7 @@ export const deferredExportImportTogglesService = (
strategyService, strategyService,
tagTypeService, tagTypeService,
segmentService, segmentService,
dependentFeaturesService,
}, },
dependentFeaturesReadModel, dependentFeaturesReadModel,
); );

View File

@ -34,6 +34,7 @@ import { extractUsernameFromUser } from '../../util';
import { import {
AccessService, AccessService,
ContextService, ContextService,
DependentFeaturesService,
EventService, EventService,
FeatureTagService, FeatureTagService,
FeatureToggleService, FeatureToggleService,
@ -52,7 +53,6 @@ import { FeatureNameCheckResultWithFeaturePattern } from '../feature-toggle/feat
import { IDependentFeaturesReadModel } from '../dependent-features/dependent-features-read-model-type'; import { IDependentFeaturesReadModel } from '../dependent-features/dependent-features-read-model-type';
import groupBy from 'lodash.groupby'; import groupBy from 'lodash.groupby';
import { ISegmentService } from '../../segments/segment-service-interface'; import { ISegmentService } from '../../segments/segment-service-interface';
import { FeatureDependenciesSchema } from '../../openapi/spec/feature-dependencies-schema';
export type IImportService = { export type IImportService = {
validate( validate(
@ -113,6 +113,8 @@ export default class ExportImportService
private dependentFeaturesReadModel: IDependentFeaturesReadModel; private dependentFeaturesReadModel: IDependentFeaturesReadModel;
private dependentFeaturesService: DependentFeaturesService;
constructor( constructor(
stores: Pick< stores: Pick<
IUnleashStores, IUnleashStores,
@ -138,6 +140,7 @@ export default class ExportImportService
tagTypeService, tagTypeService,
featureTagService, featureTagService,
segmentService, segmentService,
dependentFeaturesService,
}: Pick< }: Pick<
IUnleashServices, IUnleashServices,
| 'featureToggleService' | 'featureToggleService'
@ -148,6 +151,7 @@ export default class ExportImportService
| 'tagTypeService' | 'tagTypeService'
| 'featureTagService' | 'featureTagService'
| 'segmentService' | 'segmentService'
| 'dependentFeaturesService'
>, >,
dependentFeaturesReadModel: IDependentFeaturesReadModel, dependentFeaturesReadModel: IDependentFeaturesReadModel,
) { ) {
@ -168,6 +172,7 @@ export default class ExportImportService
this.eventService = eventService; this.eventService = eventService;
this.tagTypeService = tagTypeService; this.tagTypeService = tagTypeService;
this.featureTagService = featureTagService; this.featureTagService = featureTagService;
this.dependentFeaturesService = dependentFeaturesService;
this.importPermissionsService = new ImportPermissionsService( this.importPermissionsService = new ImportPermissionsService(
this.importTogglesStore, this.importTogglesStore,
this.accessService, this.accessService,
@ -258,7 +263,7 @@ export default class ExportImportService
]); ]);
} }
async importToggleLevelInfo( async importFeatureData(
dto: ImportTogglesSchema, dto: ImportTogglesSchema,
user: User, user: User,
): Promise<void> { ): Promise<void> {
@ -274,9 +279,9 @@ export default class ExportImportService
await this.importVerify(cleanedDto, user); await this.importVerify(cleanedDto, user);
await this.importToggleLevelInfo(cleanedDto, user); await this.importFeatureData(cleanedDto, user);
await this.importDefault(cleanedDto, user); await this.importEnvironmentData(cleanedDto, user);
await this.eventService.storeEvent({ await this.eventService.storeEvent({
project: cleanedDto.project, project: cleanedDto.project,
environment: cleanedDto.environment, environment: cleanedDto.environment,
@ -285,10 +290,34 @@ export default class ExportImportService
}); });
} }
async importDefault(dto: ImportTogglesSchema, user: User): Promise<void> { async importEnvironmentData(
dto: ImportTogglesSchema,
user: User,
): Promise<void> {
await this.deleteStrategies(dto); await this.deleteStrategies(dto);
await this.importStrategies(dto, user); await this.importStrategies(dto, user);
await this.importToggleStatuses(dto, user); await this.importToggleStatuses(dto, user);
await this.importDependencies(dto, user);
}
private async importDependencies(dto: ImportTogglesSchema, user: User) {
await Promise.all(
(dto.data.dependencies || []).flatMap((dependency) => {
const projectId = dto.data.features.find(
(feature) => feature.name === dependency.feature,
)!.project!;
return dependency.dependencies.map((parentDependency) =>
this.dependentFeaturesService.upsertFeatureDependency(
{
child: dependency.feature,
projectId,
},
parentDependency,
user,
),
);
}),
);
} }
private async importToggleStatuses(dto: ImportTogglesSchema, user: User) { private async importToggleStatuses(dto: ImportTogglesSchema, user: User) {

View File

@ -161,6 +161,7 @@ beforeAll(async () => {
featuresExportImport: true, featuresExportImport: true,
featureNamingPattern: true, featureNamingPattern: true,
dependentFeatures: true, dependentFeatures: true,
transactionalDecorator: true,
}, },
}, },
}, },
@ -750,6 +751,10 @@ test('import features to existing project and environment', async () => {
...defaultImportPayload, ...defaultImportPayload,
data: { data: {
...defaultImportPayload.data, ...defaultImportPayload.data,
features: [
...defaultImportPayload.data.features,
anotherExportedFeature,
],
featureStrategies: [ featureStrategies: [
{ {
...exportedStrategy, ...exportedStrategy,
@ -762,6 +767,16 @@ test('import features to existing project and environment', async () => {
name: segment.name, name: segment.name,
}, },
], ],
dependencies: [
{
feature: exportedFeature.name,
dependencies: [
{
feature: anotherExportedFeature.name,
},
],
},
],
}, },
}); });
@ -779,6 +794,11 @@ test('import features to existing project and environment', async () => {
], ],
}, },
], ],
dependencies: [
{
feature: anotherExportedFeature.name,
},
],
}); });
const { body: importedFeatureEnvironment } = await getFeatureEnvironment( const { body: importedFeatureEnvironment } = await getFeatureEnvironment(

View File

@ -1731,8 +1731,9 @@ class FeatureToggleService {
); );
if (hasDisabledStrategies && shouldActivateDisabledStrategies) { if (hasDisabledStrategies && shouldActivateDisabledStrategies) {
strategies.map(async (strategy) => { await Promise.all(
return this.updateStrategy( strategies.map((strategy) =>
this.updateStrategy(
strategy.id, strategy.id,
{ disabled: false }, { disabled: false },
{ {
@ -1741,8 +1742,9 @@ class FeatureToggleService {
featureName, featureName,
}, },
createdBy, createdBy,
),
),
); );
});
} }
const hasOnlyDisabledStrategies = strategies.every( const hasOnlyDisabledStrategies = strategies.every(