mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-08 01:15:49 +02:00
fix: clone variants (featureEnv and strategy) when cloning an env (#6026)
Fixes 2 bugs - Strategy variants - Feature env variants not being cloned when cloning an environment Closes # [SR-350](https://linear.app/unleash/issue/SR-350/cloning-environment-does-not-clone-variants-or-strategy-variants) Manual test verifies the fix <img width="1659" alt="Screenshot 2024-01-24 at 16 48 28" src="https://github.com/Unleash/unleash/assets/104830839/ba9fc9b8-e792-47bb-b6e8-660350384ea8"> <img width="1408" alt="Screenshot 2024-01-24 at 16 48 10" src="https://github.com/Unleash/unleash/assets/104830839/1e2d5287-35d0-42d2-9ab2-8caa313bd5a8"> --------- Signed-off-by: andreas-unleash <andreas@getunleash.ai>
This commit is contained in:
parent
41351a694e
commit
89bea0d532
@ -152,7 +152,7 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore {
|
|||||||
await this.db('feature_environments')
|
await this.db('feature_environments')
|
||||||
.insert({ feature_name: featureName, environment, enabled })
|
.insert({ feature_name: featureName, environment, enabled })
|
||||||
.onConflict(['environment', 'feature_name'])
|
.onConflict(['environment', 'feature_name'])
|
||||||
.merge('enabled');
|
.merge(['enabled']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move to project store.
|
// TODO: move to project store.
|
||||||
@ -366,8 +366,11 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore {
|
|||||||
projects: string[],
|
projects: string[],
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.db.raw(
|
await this.db.raw(
|
||||||
`INSERT INTO ${T.featureEnvs} (
|
`INSERT INTO ${T.featureEnvs} (environment, feature_name, enabled, variants)
|
||||||
SELECT distinct ? AS environment, feature_name, enabled FROM ${T.featureEnvs} INNER JOIN ${T.features} ON ${T.featureEnvs}.feature_name = ${T.features}.name WHERE environment = ? AND project = ANY(?))`,
|
SELECT DISTINCT ? AS environemnt, fe.feature_name, fe.enabled, fe.variants
|
||||||
|
FROM ${T.featureEnvs} AS fe
|
||||||
|
INNER JOIN ${T.features} AS f ON fe.feature_name = f.name
|
||||||
|
WHERE fe.environment = ? AND f.project = ANY(?)`,
|
||||||
[destinationEnvironment, sourceEnvironment, projects],
|
[destinationEnvironment, sourceEnvironment, projects],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -441,6 +444,7 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore {
|
|||||||
parameters: JSON.stringify(featureStrategy.parameters),
|
parameters: JSON.stringify(featureStrategy.parameters),
|
||||||
constraints: JSON.stringify(featureStrategy.constraints),
|
constraints: JSON.stringify(featureStrategy.constraints),
|
||||||
sort_order: featureStrategy.sort_order,
|
sort_order: featureStrategy.sort_order,
|
||||||
|
variants: JSON.stringify(featureStrategy.variants),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { IUnleashStores } from '../../../lib/types';
|
import { IFeatureStrategiesStore, IUnleashStores } from '../../../lib/types';
|
||||||
import dbInit, { ITestDb } from '../helpers/database-init';
|
import dbInit, { ITestDb } from '../helpers/database-init';
|
||||||
import getLogger from '../../fixtures/no-logger';
|
import getLogger from '../../fixtures/no-logger';
|
||||||
import { IFeatureEnvironmentStore } from '../../../lib/types/stores/feature-environment-store';
|
import { IFeatureEnvironmentStore } from '../../../lib/types/stores/feature-environment-store';
|
||||||
@ -10,6 +10,7 @@ let stores: IUnleashStores;
|
|||||||
let featureEnvironmentStore: IFeatureEnvironmentStore;
|
let featureEnvironmentStore: IFeatureEnvironmentStore;
|
||||||
let featureStore: IFeatureToggleStore;
|
let featureStore: IFeatureToggleStore;
|
||||||
let environmentStore: IEnvironmentStore;
|
let environmentStore: IEnvironmentStore;
|
||||||
|
let featureStrategiesStore: IFeatureStrategiesStore;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
db = await dbInit('feature_environment_store_serial', getLogger);
|
db = await dbInit('feature_environment_store_serial', getLogger);
|
||||||
@ -17,6 +18,7 @@ beforeAll(async () => {
|
|||||||
featureEnvironmentStore = stores.featureEnvironmentStore;
|
featureEnvironmentStore = stores.featureEnvironmentStore;
|
||||||
environmentStore = stores.environmentStore;
|
environmentStore = stores.environmentStore;
|
||||||
featureStore = stores.featureToggleStore;
|
featureStore = stores.featureToggleStore;
|
||||||
|
featureStrategiesStore = stores.featureStrategiesStore;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@ -74,3 +76,100 @@ test('Setting enabled to not existing value returns 1', async () => {
|
|||||||
);
|
);
|
||||||
expect(changed).toBe(1);
|
expect(changed).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Copying features also copies variants', async () => {
|
||||||
|
const envName = 'copy-env';
|
||||||
|
const featureName = 'copy-env-toggle-feature';
|
||||||
|
await environmentStore.create({
|
||||||
|
name: envName,
|
||||||
|
enabled: true,
|
||||||
|
type: 'test',
|
||||||
|
});
|
||||||
|
await featureStore.create('default', {
|
||||||
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
|
await featureEnvironmentStore.connectProject(envName, 'default');
|
||||||
|
await featureEnvironmentStore.connectFeatures(envName, 'default');
|
||||||
|
|
||||||
|
const variant = {
|
||||||
|
name: 'a',
|
||||||
|
weight: 1,
|
||||||
|
stickiness: 'default',
|
||||||
|
weightType: 'fix' as any,
|
||||||
|
};
|
||||||
|
await featureEnvironmentStore.setVariantsToFeatureEnvironments(
|
||||||
|
featureName,
|
||||||
|
[envName],
|
||||||
|
[variant],
|
||||||
|
);
|
||||||
|
|
||||||
|
await environmentStore.create({
|
||||||
|
name: 'clone',
|
||||||
|
enabled: true,
|
||||||
|
type: 'test',
|
||||||
|
});
|
||||||
|
await featureEnvironmentStore.connectProject('clone', 'default');
|
||||||
|
|
||||||
|
await featureEnvironmentStore.copyEnvironmentFeaturesByProjects(
|
||||||
|
envName,
|
||||||
|
'clone',
|
||||||
|
['default'],
|
||||||
|
);
|
||||||
|
|
||||||
|
const cloned = await featureEnvironmentStore.get({
|
||||||
|
featureName: featureName,
|
||||||
|
environment: 'clone',
|
||||||
|
});
|
||||||
|
expect(cloned.variants).toMatchObject([variant]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Copying strategies also copies strategy variants', async () => {
|
||||||
|
const envName = 'copy-strategy';
|
||||||
|
const featureName = 'copy-env-strategy-feature';
|
||||||
|
await environmentStore.create({
|
||||||
|
name: envName,
|
||||||
|
enabled: true,
|
||||||
|
type: 'test',
|
||||||
|
});
|
||||||
|
await featureStore.create('default', {
|
||||||
|
name: featureName,
|
||||||
|
createdByUserId: 9999,
|
||||||
|
});
|
||||||
|
await featureEnvironmentStore.connectProject(envName, 'default');
|
||||||
|
await featureEnvironmentStore.connectFeatures(envName, 'default');
|
||||||
|
|
||||||
|
const strategyVariant = {
|
||||||
|
name: 'a',
|
||||||
|
weight: 1,
|
||||||
|
stickiness: 'default',
|
||||||
|
weightType: 'fix' as any,
|
||||||
|
};
|
||||||
|
await featureStrategiesStore.createStrategyFeatureEnv({
|
||||||
|
environment: envName,
|
||||||
|
projectId: 'default',
|
||||||
|
featureName,
|
||||||
|
strategyName: 'default',
|
||||||
|
variants: [strategyVariant],
|
||||||
|
parameters: {},
|
||||||
|
constraints: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
await environmentStore.create({
|
||||||
|
name: 'clone-2',
|
||||||
|
enabled: true,
|
||||||
|
type: 'test',
|
||||||
|
});
|
||||||
|
await featureEnvironmentStore.connectProject('clone-2', 'default');
|
||||||
|
|
||||||
|
await featureEnvironmentStore.cloneStrategies(envName, 'clone-2');
|
||||||
|
|
||||||
|
const clonedStrategy =
|
||||||
|
await featureStrategiesStore.getStrategiesForFeatureEnv(
|
||||||
|
'default',
|
||||||
|
featureName,
|
||||||
|
'clone-2',
|
||||||
|
);
|
||||||
|
expect(clonedStrategy.length).toBe(1);
|
||||||
|
expect(clonedStrategy[0].variants).toMatchObject([strategyVariant]);
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user