1
0
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:
sighphyre 2022-03-11 11:16:58 +02:00
parent 3910e23d2d
commit c3b064adfc
9 changed files with 169 additions and 0 deletions

View File

@ -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([]);
});

View File

@ -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,
};
}

View File

@ -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();
}

View File

@ -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(

View File

@ -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,

View File

@ -158,4 +158,5 @@ export interface IUnleashConfig {
enterpriseVersion?: string;
eventBus: EventEmitter;
disableLegacyFeaturesApi?: boolean;
environmentEnableOverrides?: string[];
}

View File

@ -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>;
}

View File

@ -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);
});

View File

@ -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;
}