From 5c7f4d5fc18271c9296b3b81b38cec753a249bd0 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Thu, 21 Nov 2024 14:41:20 +0100 Subject: [PATCH] feat: backfill archived features lifecycle (#8824) --- .../feature-lifecycle-store.ts | 8 +++ .../feature-lifecycle.e2e.test.ts | 49 +++++++++++++++---- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle-store.ts b/src/lib/features/feature-lifecycle/feature-lifecycle-store.ts index e71cb98f5dac..1fe2f1acf665 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle-store.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle-store.ts @@ -35,6 +35,14 @@ export class FeatureLifecycleStore implements IFeatureLifecycleStore { LEFT JOIN feature_lifecycles ON features.name = feature_lifecycles.feature WHERE feature_lifecycles.feature IS NULL `); + await this.db.raw(` + INSERT INTO feature_lifecycles (feature, stage, created_at) + SELECT features.name, 'archived', features.archived_at + FROM features + LEFT JOIN feature_lifecycles ON features.name = feature_lifecycles.feature AND feature_lifecycles.stage = 'archived' + WHERE features.archived_at IS NOT NULL + AND feature_lifecycles.feature IS NULL + `); } async insert( diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts b/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts index 7f05c5e27408..5e8f0b9d1f43 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts @@ -192,19 +192,50 @@ test('should be able to toggle between completed/uncompleted', async () => { expect(body).toEqual([]); }); -test('should backfill initial stage when no stages', async () => { +test('should backfill intialized feature', async () => { await app.createFeature('my_feature_c'); - await featureLifecycleStore.delete('my_feature_c'); - const currentStage = await getCurrentStage('my_feature_c'); - expect(currentStage).toBe(undefined); + await featureLifecycleStore.backfill(); + + const { body } = await getFeatureLifecycle('my_feature_c'); + expect(body).toEqual([ + { stage: 'initial', enteredStageAt: expect.any(String) }, + ]); +}); + +test('should backfill archived feature', async () => { + await app.createFeature('my_feature_d'); + await app.archiveFeature('my_feature_d'); + await featureLifecycleStore.delete('my_feature_d'); await featureLifecycleStore.backfill(); - const backfilledCurrentStage = await getCurrentStage('my_feature_c'); - expect(backfilledCurrentStage).toEqual({ - stage: 'initial', - enteredStageAt: expect.any(Date), - }); + const { body } = await getFeatureLifecycle('my_feature_d'); + expect(body).toEqual([ + { stage: 'initial', enteredStageAt: expect.any(String) }, + { stage: 'archived', enteredStageAt: expect.any(String) }, + ]); +}); + +test('should not backfill for existing lifecycle', async () => { + await app.createFeature('my_feature_e'); + await app.enableFeature('my_feature_e', 'default'); + eventStore.emit(FEATURE_CREATED, { featureName: 'my_feature_e' }); + eventBus.emit(CLIENT_METRICS_ADDED, [ + { + featureName: 'my_feature_e', + environment: 'default', + }, + ]); + await reachedStage('my_feature_e', 'live'); + + await featureLifecycleStore.backfill(); + + const { body } = await getFeatureLifecycle('my_feature_e'); + expect(body).toEqual([ + { stage: 'initial', enteredStageAt: expect.any(String) }, + { stage: 'pre-live', enteredStageAt: expect.any(String) }, + { stage: 'live', enteredStageAt: expect.any(String) }, + ]); });