mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: revived feature goes to initial lifecycle stage (#6944)
This commit is contained in:
		
							parent
							
								
									675e1a9f8b
								
							
						
					
					
						commit
						8ed15165d2
					
				@ -35,6 +35,10 @@ export class FakeFeatureLifecycleStore implements IFeatureLifecycleStore {
 | 
			
		||||
        return this.lifecycles[feature] || [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async delete(feature: string): Promise<void> {
 | 
			
		||||
        this.lifecycles[feature] = [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async stageExists(stage: FeatureLifecycleStage): Promise<boolean> {
 | 
			
		||||
        const lifecycle = await this.get(stage.feature);
 | 
			
		||||
        return Boolean(lifecycle.find((s) => s.stage === stage.stage));
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ import {
 | 
			
		||||
    FEATURE_ARCHIVED,
 | 
			
		||||
    FEATURE_COMPLETED,
 | 
			
		||||
    FEATURE_CREATED,
 | 
			
		||||
    FEATURE_REVIVED,
 | 
			
		||||
    type IEnvironment,
 | 
			
		||||
    type IUnleashConfig,
 | 
			
		||||
    type StageName,
 | 
			
		||||
@ -82,6 +83,14 @@ test('can insert and read lifecycle stages', async () => {
 | 
			
		||||
        { stage: 'completed', enteredStageAt: expect.any(Date) },
 | 
			
		||||
        { stage: 'archived', enteredStageAt: expect.any(Date) },
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    eventStore.emit(FEATURE_REVIVED, { featureName });
 | 
			
		||||
    await reachedStage('initial');
 | 
			
		||||
    const initialLifecycle =
 | 
			
		||||
        await featureLifecycleService.getFeatureLifecycle(featureName);
 | 
			
		||||
    expect(initialLifecycle).toEqual([
 | 
			
		||||
        { stage: 'initial', enteredStageAt: expect.any(Date) },
 | 
			
		||||
    ]);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('ignores lifecycle state updates when flag disabled', async () => {
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ import {
 | 
			
		||||
    FEATURE_ARCHIVED,
 | 
			
		||||
    FEATURE_COMPLETED,
 | 
			
		||||
    FEATURE_CREATED,
 | 
			
		||||
    FEATURE_REVIVED,
 | 
			
		||||
    type IEnvironmentStore,
 | 
			
		||||
    type IEventStore,
 | 
			
		||||
    type IFlagResolver,
 | 
			
		||||
@ -93,6 +94,11 @@ export class FeatureLifecycleService extends EventEmitter {
 | 
			
		||||
                this.featureArchived(event.featureName),
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        this.eventStore.on(FEATURE_REVIVED, async (event) => {
 | 
			
		||||
            await this.checkEnabled(() =>
 | 
			
		||||
                this.featureRevived(event.featureName),
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async getFeatureLifecycle(feature: string): Promise<FeatureLifecycleView> {
 | 
			
		||||
@ -155,4 +161,9 @@ export class FeatureLifecycleService extends EventEmitter {
 | 
			
		||||
        ]);
 | 
			
		||||
        this.emit(STAGE_ENTERED, { stage: 'archived' });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async featureRevived(feature: string) {
 | 
			
		||||
        await this.featureLifecycleStore.delete(feature);
 | 
			
		||||
        await this.featureInitialized(feature);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -11,4 +11,5 @@ export interface IFeatureLifecycleStore {
 | 
			
		||||
    insert(featureLifecycleStages: FeatureLifecycleStage[]): Promise<void>;
 | 
			
		||||
    get(feature: string): Promise<FeatureLifecycleView>;
 | 
			
		||||
    stageExists(stage: FeatureLifecycleStage): Promise<boolean>;
 | 
			
		||||
    delete(feature: string): Promise<void>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,10 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore {
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async delete(feature: string): Promise<void> {
 | 
			
		||||
        await this.db('feature_lifecycles').where({ feature }).del();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async stageExists(stage: FeatureLifecycleStage): Promise<boolean> {
 | 
			
		||||
        const result = await this.db.raw(
 | 
			
		||||
            `SELECT EXISTS(SELECT 1 FROM feature_lifecycles WHERE stage = ? and feature = ?) AS present`,
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@ import {
 | 
			
		||||
    CLIENT_METRICS,
 | 
			
		||||
    FEATURE_ARCHIVED,
 | 
			
		||||
    FEATURE_CREATED,
 | 
			
		||||
    FEATURE_REVIVED,
 | 
			
		||||
    type IEventStore,
 | 
			
		||||
    type StageName,
 | 
			
		||||
} from '../../types';
 | 
			
		||||
@ -117,4 +118,7 @@ test('should return lifecycle stages', async () => {
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    await expectFeatureStage('archived');
 | 
			
		||||
 | 
			
		||||
    eventStore.emit(FEATURE_REVIVED, { featureName: 'my_feature_a' });
 | 
			
		||||
    await reachedStage('initial');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user