mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +01:00
feat: Add environment variable to set override enabled environments
This commit is contained in:
parent
3910e23d2d
commit
c3b064adfc
@ -224,3 +224,47 @@ test('should handle cases where no env var specified for tokens', async () => {
|
||||
|
||||
expect(config.authentication.initApiTokens).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('should load environment overrides from env var', async () => {
|
||||
process.env.ENABLED_ENVIRONMENTS = 'default,production';
|
||||
|
||||
const config = createConfig({
|
||||
db: {
|
||||
host: 'localhost',
|
||||
port: 4242,
|
||||
user: 'unleash',
|
||||
password: 'password',
|
||||
database: 'unleash_db',
|
||||
},
|
||||
server: {
|
||||
port: 4242,
|
||||
},
|
||||
authentication: {
|
||||
initApiTokens: [],
|
||||
},
|
||||
});
|
||||
|
||||
expect(config.environmentEnableOverrides).toHaveLength(2);
|
||||
expect(config.environmentEnableOverrides).toContain('production');
|
||||
delete process.env.ENABLED_ENVIRONMENTS;
|
||||
});
|
||||
|
||||
test('should yield an empty list when no environment overrides are specified', async () => {
|
||||
const config = createConfig({
|
||||
db: {
|
||||
host: 'localhost',
|
||||
port: 4242,
|
||||
user: 'unleash',
|
||||
password: 'password',
|
||||
database: 'unleash_db',
|
||||
},
|
||||
server: {
|
||||
port: 4242,
|
||||
},
|
||||
authentication: {
|
||||
initApiTokens: [],
|
||||
},
|
||||
});
|
||||
|
||||
expect(config.environmentEnableOverrides).toStrictEqual([]);
|
||||
});
|
||||
|
@ -217,6 +217,14 @@ const loadInitApiTokens = () => {
|
||||
];
|
||||
};
|
||||
|
||||
const loadEnvironmentEnableOverrides = () => {
|
||||
const environmentsString = process.env.ENABLED_ENVIRONMENTS;
|
||||
if (environmentsString) {
|
||||
return environmentsString.split(',');
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
export function createConfig(options: IUnleashOptions): IUnleashConfig {
|
||||
let extraDbOptions = {};
|
||||
|
||||
@ -275,6 +283,8 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
|
||||
{ initApiTokens: initApiTokens },
|
||||
]);
|
||||
|
||||
const environmentEnableOverrides = loadEnvironmentEnableOverrides();
|
||||
|
||||
const importSetting: IImportOption = mergeAll([
|
||||
defaultImport,
|
||||
options.import,
|
||||
@ -323,6 +333,7 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
|
||||
eventHook: options.eventHook,
|
||||
enterpriseVersion: options.enterpriseVersion,
|
||||
eventBus: new EventEmitter(),
|
||||
environmentEnableOverrides,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -163,6 +163,22 @@ export default class EnvironmentStore implements IEnvironmentStore {
|
||||
return mapRow(row[0]);
|
||||
}
|
||||
|
||||
async disableAllExcept(environments: string[]): Promise<void> {
|
||||
await this.db(TABLE)
|
||||
.update({
|
||||
enabled: false,
|
||||
})
|
||||
.whereNotIn('name', environments);
|
||||
}
|
||||
|
||||
async enable(environments: string[]): Promise<void> {
|
||||
await this.db(TABLE)
|
||||
.update({
|
||||
enabled: true,
|
||||
})
|
||||
.whereIn('name', environments);
|
||||
}
|
||||
|
||||
async delete(name: string): Promise<void> {
|
||||
await this.db(TABLE).where({ name, protected: false }).del();
|
||||
}
|
||||
|
@ -87,6 +87,12 @@ async function createApp(
|
||||
});
|
||||
}
|
||||
|
||||
if (config.environmentEnableOverrides?.length > 0) {
|
||||
await services.environmentService.overrideEnabledProjects(
|
||||
config.environmentEnableOverrides,
|
||||
);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (startApp) {
|
||||
const server = stoppable(
|
||||
|
@ -94,6 +94,28 @@ export default class EnvironmentService {
|
||||
}
|
||||
}
|
||||
|
||||
async overrideEnabledProjects(
|
||||
environmentsToEnable: string[],
|
||||
): Promise<void> {
|
||||
if (environmentsToEnable.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const environmentsExist = await Promise.all(
|
||||
environmentsToEnable.map((env) =>
|
||||
this.environmentStore.exists(env),
|
||||
),
|
||||
);
|
||||
if (!environmentsExist.every((exists) => exists)) {
|
||||
this.logger.error(
|
||||
"Found environment enabled overrides but some of the specified environments don't exist, no overrides will be executed",
|
||||
);
|
||||
return;
|
||||
}
|
||||
await this.environmentStore.disableAllExcept(environmentsToEnable);
|
||||
await this.environmentStore.enable(environmentsToEnable);
|
||||
}
|
||||
|
||||
async removeEnvironmentFromProject(
|
||||
environment: string,
|
||||
projectId: string,
|
||||
|
@ -158,4 +158,5 @@ export interface IUnleashConfig {
|
||||
enterpriseVersion?: string;
|
||||
eventBus: EventEmitter;
|
||||
disableLegacyFeaturesApi?: boolean;
|
||||
environmentEnableOverrides?: string[];
|
||||
}
|
||||
|
@ -16,4 +16,6 @@ export interface IEnvironmentStore extends Store<IEnvironment, string> {
|
||||
updateSortOrder(id: string, value: number): Promise<void>;
|
||||
importEnvironments(environments: IEnvironment[]): Promise<IEnvironment[]>;
|
||||
delete(name: string): Promise<void>;
|
||||
disableAllExcept(environments: string[]): Promise<void>;
|
||||
enable(environments: string[]): Promise<void>;
|
||||
}
|
||||
|
@ -136,3 +136,56 @@ test('Trying to get an environment that does not exist throws NotFoundError', as
|
||||
new NotFoundError(`Could not find environment with name: ${envName}`),
|
||||
);
|
||||
});
|
||||
|
||||
test('Setting an override disables all other envs', async () => {
|
||||
const enabledEnvName = 'should-get-enabled';
|
||||
const disabledEnvName = 'should-get-disabled';
|
||||
await db.stores.environmentStore.create({
|
||||
name: disabledEnvName,
|
||||
type: 'production',
|
||||
});
|
||||
|
||||
await db.stores.environmentStore.create({
|
||||
name: enabledEnvName,
|
||||
type: 'production',
|
||||
});
|
||||
|
||||
//Set these to the wrong state so we can assert that overriding them flips
|
||||
await service.toggleEnvironment(disabledEnvName, true);
|
||||
await service.toggleEnvironment(enabledEnvName, false);
|
||||
|
||||
await service.overrideEnabledProjects([enabledEnvName]);
|
||||
|
||||
const environments = await service.getAll();
|
||||
const targetedEnvironment = environments.find(
|
||||
(env) => env.name == enabledEnvName,
|
||||
);
|
||||
|
||||
const allOtherEnvironments = environments
|
||||
.filter((x) => x.name != enabledEnvName)
|
||||
.map((env) => env.enabled);
|
||||
|
||||
console.log(allOtherEnvironments);
|
||||
expect(targetedEnvironment.enabled).toBe(true);
|
||||
expect(allOtherEnvironments.every((x) => x === false)).toBe(true);
|
||||
});
|
||||
|
||||
test('Passing an empty override does nothing', async () => {
|
||||
const enabledEnvName = 'should-be-enabled';
|
||||
|
||||
await db.stores.environmentStore.create({
|
||||
name: enabledEnvName,
|
||||
type: 'production',
|
||||
});
|
||||
|
||||
await service.toggleEnvironment(enabledEnvName, true);
|
||||
|
||||
await service.overrideEnabledProjects([]);
|
||||
|
||||
const environments = await service.getAll();
|
||||
const targetedEnvironment = environments.find(
|
||||
(env) => env.name == enabledEnvName,
|
||||
);
|
||||
|
||||
expect(targetedEnvironment.enabled).toBe(true);
|
||||
});
|
||||
|
14
src/test/fixtures/fake-environment-store.ts
vendored
14
src/test/fixtures/fake-environment-store.ts
vendored
@ -10,6 +10,20 @@ export default class FakeEnvironmentStore implements IEnvironmentStore {
|
||||
|
||||
environments: IEnvironment[] = [];
|
||||
|
||||
disableAllExcept(environments: string[]): Promise<void> {
|
||||
for (let env of this.environments) {
|
||||
if (!environments.includes(env.name)) env.enabled = false;
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
enable(environments: string[]): Promise<void> {
|
||||
for (let env of this.environments) {
|
||||
if (environments.includes(env.name)) env.enabled = true;
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
async getAll(): Promise<IEnvironment[]> {
|
||||
return this.environments;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user