1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

feat: file import (#7219)

This commit is contained in:
David Leek 2024-05-31 13:21:41 +02:00 committed by GitHub
parent 6340ecd6bf
commit 80ba3647a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 67 additions and 15 deletions

View File

@ -164,9 +164,9 @@ exports[`should create default config 1`] = `
],
"getLogger": [Function],
"import": {
"dropBeforeImport": false,
"environment": "development",
"file": undefined,
"keepExisting": false,
"project": "default",
},
"inlineSegmentConstraints": true,
"isEnterprise": false,

View File

@ -333,11 +333,8 @@ const defaultAuthentication: IAuthOption = {
const defaultImport: WithOptional<IImportOption, 'file'> = {
file: process.env.IMPORT_FILE,
dropBeforeImport: parseEnvVarBoolean(
process.env.IMPORT_DROP_BEFORE_IMPORT,
false,
),
keepExisting: parseEnvVarBoolean(process.env.IMPORT_KEEP_EXISTING, false),
project: process.env.IMPORT_PROJECT ?? 'default',
environment: process.env.IMPORT_ENVIRONMENT ?? 'development',
};
const defaultEmail: IEmailOption = {

View File

@ -5,6 +5,8 @@ import type { IFeatureStrategiesStore } from '../feature-toggle/types/feature-to
import {
FeaturesExportedEvent,
FeaturesImportedEvent,
SYSTEM_USER,
SYSTEM_USER_AUDIT,
type FeatureToggleDTO,
type IAuditUser,
type IContextFieldStore,
@ -55,6 +57,7 @@ import type { IDependentFeaturesReadModel } from '../dependent-features/dependen
import groupBy from 'lodash.groupby';
import { allSettledWithRejection } from '../../util/allSettledWithRejection';
import type { ISegmentReadModel } from '../segment/segment-read-model-type';
import { readFile } from './import-file-reader';
export type IImportService = {
validate(
@ -67,6 +70,12 @@ export type IImportService = {
user: IUser,
auditUser: IAuditUser,
): Promise<void>;
importFromFile(
file: string,
project: string,
environment: string,
): Promise<void>;
};
export type IExportService = {
@ -264,6 +273,16 @@ export default class ExportImportService
]);
}
async fileImportVerify(dto: ImportTogglesSchema): Promise<void> {
await allSettledWithRejection([
this.verifyStrategies(dto),
this.verifyContextFields(dto),
this.verifyFeatures(dto),
this.verifySegments(dto),
this.verifyDependencies(dto),
]);
}
async importFeatureData(
dto: ImportTogglesSchema,
auditUser: IAuditUser,
@ -281,16 +300,40 @@ export default class ExportImportService
auditUser: IAuditUser,
): Promise<void> {
const cleanedDto = await this.cleanData(dto);
await this.importVerify(cleanedDto, user);
await this.processImport(cleanedDto, user, auditUser);
}
await this.importFeatureData(cleanedDto, auditUser);
async importFromFile(
file: string,
project: string,
environment: string,
): Promise<void> {
const content = await readFile(file);
const data = JSON.parse(content);
const dto = {
project,
environment,
data,
};
const cleanedDto = await this.cleanData(dto);
await this.importEnvironmentData(cleanedDto, user, auditUser);
await this.fileImportVerify(cleanedDto);
await this.processImport(cleanedDto, SYSTEM_USER, SYSTEM_USER_AUDIT);
}
private async processImport(
dto: ImportTogglesSchema,
user: IUser,
auditUser: IAuditUser,
) {
await this.importFeatureData(dto, auditUser);
await this.importEnvironmentData(dto, user, auditUser);
await this.eventService.storeEvent(
new FeaturesImportedEvent({
project: cleanedDto.project,
environment: cleanedDto.environment,
project: dto.project,
environment: dto.environment,
auditUser,
}),
);

View File

@ -0,0 +1,8 @@
import * as fs from 'fs';
export const readFile: (file: string) => Promise<string> = async (file) =>
new Promise((resolve, reject) =>
fs.readFile(file, (err, v) =>
err ? reject(err) : resolve(v.toString('utf-8')),
),
);

View File

@ -97,7 +97,11 @@ async function createApp(
};
if (config.import.file) {
// TODO: stateservice was here
await services.importService.importFromFile(
config.import.file,
config.import.project,
config.import.environment,
);
}
if (

View File

@ -81,8 +81,8 @@ export interface IAuthOption {
export interface IImportOption {
file: string;
keepExisting: boolean;
dropBeforeImport: boolean;
project: string;
environment: string;
}
export interface IServerOption {