mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	fix: don't create duplicate tags on import (#3688)
This commit is contained in:
		
							parent
							
								
									c21fafc8aa
								
							
						
					
					
						commit
						108e15940e
					
				@ -280,17 +280,17 @@ export default class ExportImportService {
 | 
			
		||||
        await this.importTogglesStore.deleteTagsForFeatures(
 | 
			
		||||
            dto.data.features.map((feature) => feature.name),
 | 
			
		||||
        );
 | 
			
		||||
        return Promise.all(
 | 
			
		||||
            (dto.data.featureTags || []).map((tag) => {
 | 
			
		||||
                return tag.tagType
 | 
			
		||||
                    ? this.featureTagService.addTag(
 | 
			
		||||
                          tag.featureName,
 | 
			
		||||
                          { type: tag.tagType, value: tag.tagValue },
 | 
			
		||||
                          extractUsernameFromUser(user),
 | 
			
		||||
                      )
 | 
			
		||||
                    : Promise.resolve();
 | 
			
		||||
            }),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const featureTags = dto.data.featureTags || [];
 | 
			
		||||
        for (const tag of featureTags) {
 | 
			
		||||
            if (tag.tagType) {
 | 
			
		||||
                await this.featureTagService.addTag(
 | 
			
		||||
                    tag.featureName,
 | 
			
		||||
                    { type: tag.tagType, value: tag.tagValue },
 | 
			
		||||
                    extractUsernameFromUser(user),
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async importContextFields(dto: ImportTogglesSchema, user: User) {
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ import {
 | 
			
		||||
    IProjectStore,
 | 
			
		||||
    ISegment,
 | 
			
		||||
    IStrategyConfig,
 | 
			
		||||
    ITagStore,
 | 
			
		||||
    IVariant,
 | 
			
		||||
} from '../../types';
 | 
			
		||||
import { DEFAULT_ENV } from '../../util';
 | 
			
		||||
@ -33,6 +34,7 @@ let environmentStore: IEnvironmentStore;
 | 
			
		||||
let contextFieldStore: IContextFieldStore;
 | 
			
		||||
let projectStore: IProjectStore;
 | 
			
		||||
let toggleStore: IFeatureToggleStore;
 | 
			
		||||
let tagStore: ITagStore;
 | 
			
		||||
 | 
			
		||||
const defaultStrategy: IStrategyConfig = {
 | 
			
		||||
    name: 'default',
 | 
			
		||||
@ -150,6 +152,7 @@ beforeAll(async () => {
 | 
			
		||||
    projectStore = db.stores.projectStore;
 | 
			
		||||
    contextFieldStore = db.stores.contextFieldStore;
 | 
			
		||||
    toggleStore = db.stores.featureToggleStore;
 | 
			
		||||
    tagStore = db.stores.tagStore;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
beforeEach(async () => {
 | 
			
		||||
@ -157,6 +160,7 @@ beforeEach(async () => {
 | 
			
		||||
    await toggleStore.deleteAll();
 | 
			
		||||
    await projectStore.deleteAll();
 | 
			
		||||
    await environmentStore.deleteAll();
 | 
			
		||||
    await tagStore.deleteAll();
 | 
			
		||||
 | 
			
		||||
    await contextFieldStore.deleteAll();
 | 
			
		||||
    await app.createContextField({ name: 'appName' });
 | 
			
		||||
@ -544,6 +548,10 @@ const exportedFeature: ImportTogglesSchema['data']['features'][0] = {
 | 
			
		||||
    project: 'old_project',
 | 
			
		||||
    name: 'first_feature',
 | 
			
		||||
};
 | 
			
		||||
const anotherExportedFeature: ImportTogglesSchema['data']['features'][0] = {
 | 
			
		||||
    project: 'old_project',
 | 
			
		||||
    name: 'second_feature',
 | 
			
		||||
};
 | 
			
		||||
const constraints: ImportTogglesSchema['data']['featureStrategies'][0]['constraints'] =
 | 
			
		||||
    [
 | 
			
		||||
        {
 | 
			
		||||
@ -614,6 +622,31 @@ const defaultImportPayload: ImportTogglesSchema = {
 | 
			
		||||
    environment: DEFAULT_ENV,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const importWithMultipleFeatures: ImportTogglesSchema = {
 | 
			
		||||
    data: {
 | 
			
		||||
        features: [exportedFeature, anotherExportedFeature],
 | 
			
		||||
        featureStrategies: [],
 | 
			
		||||
        featureEnvironments: [],
 | 
			
		||||
        featureTags: [
 | 
			
		||||
            {
 | 
			
		||||
                featureName: exportedFeature.name,
 | 
			
		||||
                tagType: 'simple',
 | 
			
		||||
                tagValue: 'tag1',
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                featureName: anotherExportedFeature.name,
 | 
			
		||||
                tagType: 'simple',
 | 
			
		||||
                tagValue: 'tag1',
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
        tagTypes,
 | 
			
		||||
        contextFields: [],
 | 
			
		||||
        segments: [],
 | 
			
		||||
    },
 | 
			
		||||
    project: DEFAULT_PROJECT,
 | 
			
		||||
    environment: DEFAULT_ENV,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getFeature = async (feature: string) =>
 | 
			
		||||
    app.request
 | 
			
		||||
        .get(`/api/admin/projects/${DEFAULT_PROJECT}/features/${feature}`)
 | 
			
		||||
@ -672,6 +705,24 @@ test('import features to existing project and environment', async () => {
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('import multiple features with same tag', async () => {
 | 
			
		||||
    await createProjects();
 | 
			
		||||
 | 
			
		||||
    await app.importToggles(importWithMultipleFeatures);
 | 
			
		||||
 | 
			
		||||
    const { body: tags1 } = await getTags(exportedFeature.name);
 | 
			
		||||
    const { body: tags2 } = await getTags(anotherExportedFeature.name);
 | 
			
		||||
 | 
			
		||||
    expect(tags1).toMatchObject({
 | 
			
		||||
        version: 1,
 | 
			
		||||
        tags: [{ value: 'tag1', type: 'simple' }],
 | 
			
		||||
    });
 | 
			
		||||
    expect(tags2).toMatchObject({
 | 
			
		||||
        version: 1,
 | 
			
		||||
        tags: [{ value: 'tag1', type: 'simple' }],
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('importing same JSON should work multiple times in a row', async () => {
 | 
			
		||||
    await createProjects();
 | 
			
		||||
    await app.importToggles(defaultImportPayload);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user