mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: Deprecate feature toggle environment variants api (#7066)
This commit is contained in:
parent
9281d6b694
commit
150a7b3ed4
@ -490,4 +490,13 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async variantExists(featureName: string): Promise<boolean> {
|
||||
const result = await this.db.raw(
|
||||
`SELECT EXISTS (SELECT 1 FROM ${T.featureEnvs} WHERE feature_name = ? AND variants <> '[]'::jsonb) AS present`,
|
||||
[featureName],
|
||||
);
|
||||
const { present } = result.rows[0];
|
||||
return present;
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ beforeAll(async () => {
|
||||
experimental: {
|
||||
flags: {
|
||||
strictSchemaValidation: true,
|
||||
enableLegacyVariants: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -457,7 +457,7 @@ export default class ExportImportService
|
||||
await Promise.all(
|
||||
featureEnvsWithVariants.map((featureEnvironment) => {
|
||||
return featureEnvironment.featureName
|
||||
? this.featureToggleService.saveVariantsOnEnv(
|
||||
? this.featureToggleService.legacySaveVariantsOnEnv(
|
||||
dto.project,
|
||||
featureEnvironment.featureName,
|
||||
dto.environment,
|
||||
|
@ -103,7 +103,7 @@ const createContext = async (context: ContextFieldSchema = defaultContext) => {
|
||||
};
|
||||
|
||||
const createVariants = async (feature: string, variants: IVariant[]) => {
|
||||
await app.services.featureToggleService.saveVariantsOnEnv(
|
||||
await app.services.featureToggleService.legacySaveVariantsOnEnv(
|
||||
DEFAULT_PROJECT,
|
||||
feature,
|
||||
DEFAULT_ENV,
|
||||
|
@ -2184,6 +2184,21 @@ class FeatureToggleService {
|
||||
return featureToggle;
|
||||
}
|
||||
|
||||
private async verifyLegacyVariants(featureName: string) {
|
||||
const existingLegacyVariantsExist =
|
||||
await this.featureEnvironmentStore.variantExists(featureName);
|
||||
const enableLegacyVariants = this.flagResolver.isEnabled(
|
||||
'enableLegacyVariants',
|
||||
);
|
||||
const useLegacyVariants =
|
||||
existingLegacyVariantsExist || enableLegacyVariants;
|
||||
if (!useLegacyVariants) {
|
||||
throw new InvalidOperationError(
|
||||
`Environment variants deprecated for feature: ${featureName}. Use strategy variants instead.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async saveVariantsOnEnv(
|
||||
projectId: string,
|
||||
featureName: string,
|
||||
@ -2191,6 +2206,25 @@ class FeatureToggleService {
|
||||
newVariants: IVariant[],
|
||||
auditUser: IAuditUser,
|
||||
oldVariants?: IVariant[],
|
||||
): Promise<IVariant[]> {
|
||||
await this.verifyLegacyVariants(featureName);
|
||||
return this.legacySaveVariantsOnEnv(
|
||||
projectId,
|
||||
featureName,
|
||||
environment,
|
||||
newVariants,
|
||||
auditUser,
|
||||
oldVariants,
|
||||
);
|
||||
}
|
||||
|
||||
async legacySaveVariantsOnEnv(
|
||||
projectId: string,
|
||||
featureName: string,
|
||||
environment: string,
|
||||
newVariants: IVariant[],
|
||||
auditUser: IAuditUser,
|
||||
oldVariants?: IVariant[],
|
||||
): Promise<IVariant[]> {
|
||||
await variantsArraySchema.validateAsync(newVariants);
|
||||
const fixedVariants = this.fixVariantWeights(newVariants);
|
||||
|
@ -86,4 +86,6 @@ export interface IFeatureEnvironmentStore
|
||||
): Promise<void>;
|
||||
|
||||
clonePreviousVariants(environment: string, project: string): Promise<void>;
|
||||
|
||||
variantExists(featureName: string): Promise<boolean>;
|
||||
}
|
||||
|
114
src/test/e2e/api/admin/project/variants-sunset.e2e.test.ts
Normal file
114
src/test/e2e/api/admin/project/variants-sunset.e2e.test.ts
Normal file
@ -0,0 +1,114 @@
|
||||
import {
|
||||
type IUnleashTest,
|
||||
setupAppWithCustomConfig,
|
||||
} from '../../../helpers/test-helper';
|
||||
import dbInit, { type ITestDb } from '../../../helpers/database-init';
|
||||
import getLogger from '../../../../fixtures/no-logger';
|
||||
import { WeightType } from '../../../../../lib/types/model';
|
||||
|
||||
let app: IUnleashTest;
|
||||
let db: ITestDb;
|
||||
|
||||
beforeAll(async () => {
|
||||
db = await dbInit('project_feature_variants_api_sunset', getLogger);
|
||||
app = await setupAppWithCustomConfig(db.stores, {
|
||||
experimental: {
|
||||
flags: {
|
||||
strictSchemaValidation: true,
|
||||
enableLegacyVariants: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
await db.stores.environmentStore.create({
|
||||
name: 'development',
|
||||
type: 'development',
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await app.destroy();
|
||||
await db.destroy();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await db.stores.featureToggleStore.deleteAll();
|
||||
});
|
||||
|
||||
test('Cannot add environment variants to a new feature', async () => {
|
||||
const featureName = 'feature-variants-patch';
|
||||
|
||||
await db.stores.featureToggleStore.create('default', {
|
||||
name: featureName,
|
||||
createdByUserId: 9999,
|
||||
});
|
||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||
featureName,
|
||||
'development',
|
||||
true,
|
||||
);
|
||||
|
||||
const patch = [
|
||||
{
|
||||
op: 'add',
|
||||
path: '/0',
|
||||
value: {
|
||||
name: 'a',
|
||||
weightType: WeightType.VARIABLE,
|
||||
weight: 1000,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
await app.request
|
||||
.patch(
|
||||
`/api/admin/projects/default/features/${featureName}/environments/development/variants`,
|
||||
)
|
||||
.send(patch)
|
||||
.expect(403)
|
||||
.expect((res) => {
|
||||
expect(res.body.message).toBe(
|
||||
'Environment variants deprecated for feature: feature-variants-patch. Use strategy variants instead.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('Can add environment variants when existing ones exist for this feature', async () => {
|
||||
const featureName = 'feature-variants-patch';
|
||||
|
||||
await db.stores.featureToggleStore.create('default', {
|
||||
name: featureName,
|
||||
createdByUserId: 9999,
|
||||
});
|
||||
await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
|
||||
featureName,
|
||||
'development',
|
||||
true,
|
||||
);
|
||||
await db.stores.featureToggleStore.saveVariants('default', featureName, [
|
||||
{
|
||||
name: 'existing-variant',
|
||||
stickiness: 'default',
|
||||
weight: 1000,
|
||||
weightType: WeightType.VARIABLE,
|
||||
},
|
||||
]);
|
||||
|
||||
const patch = [
|
||||
{
|
||||
op: 'add',
|
||||
path: '/0',
|
||||
value: {
|
||||
name: 'a',
|
||||
weightType: WeightType.VARIABLE,
|
||||
weight: 1000,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
await app.request
|
||||
.patch(
|
||||
`/api/admin/projects/default/features/${featureName}/environments/development/variants`,
|
||||
)
|
||||
.send(patch)
|
||||
.expect(200);
|
||||
});
|
@ -16,6 +16,7 @@ beforeAll(async () => {
|
||||
experimental: {
|
||||
flags: {
|
||||
strictSchemaValidation: true,
|
||||
enableLegacyVariants: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -245,4 +245,13 @@ export default class FakeFeatureEnvironmentStore
|
||||
features.includes(featureEnv.featureName),
|
||||
);
|
||||
}
|
||||
|
||||
async variantExists(featureName: string) {
|
||||
return this.featureEnvironments.some(
|
||||
(featureEnvironment) =>
|
||||
featureEnvironment.featureName === featureName &&
|
||||
featureEnvironment.variants &&
|
||||
featureEnvironment.variants.length > 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user