Skip to content

Commit

Permalink
feat: backfill archived features lifecycle (#8824)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew authored Nov 21, 2024
1 parent f8ae7fd commit 5c7f4d5
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 9 deletions.
8 changes: 8 additions & 0 deletions src/lib/features/feature-lifecycle/feature-lifecycle-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
49 changes: 40 additions & 9 deletions src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) },
]);
});

0 comments on commit 5c7f4d5

Please sign in to comment.