mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-14 00:19:16 +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);
|
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 {
|
export function createConfig(options: IUnleashOptions): IUnleashConfig {
|
||||||
let extraDbOptions = {};
|
let extraDbOptions = {};
|
||||||
|
|
||||||
@ -275,6 +283,8 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
|
|||||||
{ initApiTokens: initApiTokens },
|
{ initApiTokens: initApiTokens },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const environmentEnableOverrides = loadEnvironmentEnableOverrides();
|
||||||
|
|
||||||
const importSetting: IImportOption = mergeAll([
|
const importSetting: IImportOption = mergeAll([
|
||||||
defaultImport,
|
defaultImport,
|
||||||
options.import,
|
options.import,
|
||||||
@ -323,6 +333,7 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
|
|||||||
eventHook: options.eventHook,
|
eventHook: options.eventHook,
|
||||||
enterpriseVersion: options.enterpriseVersion,
|
enterpriseVersion: options.enterpriseVersion,
|
||||||
eventBus: new EventEmitter(),
|
eventBus: new EventEmitter(),
|
||||||
|
environmentEnableOverrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +163,22 @@ export default class EnvironmentStore implements IEnvironmentStore {
|
|||||||
return mapRow(row[0]);
|
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> {
|
async delete(name: string): Promise<void> {
|
||||||
await this.db(TABLE).where({ name, protected: false }).del();
|
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) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (startApp) {
|
if (startApp) {
|
||||||
const server = stoppable(
|
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(
|
async removeEnvironmentFromProject(
|
||||||
environment: string,
|
environment: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
|
@ -158,4 +158,5 @@ export interface IUnleashConfig {
|
|||||||
enterpriseVersion?: string;
|
enterpriseVersion?: string;
|
||||||
eventBus: EventEmitter;
|
eventBus: EventEmitter;
|
||||||
disableLegacyFeaturesApi?: boolean;
|
disableLegacyFeaturesApi?: boolean;
|
||||||
|
environmentEnableOverrides?: string[];
|
||||||
}
|
}
|
||||||
|
@ -16,4 +16,6 @@ export interface IEnvironmentStore extends Store<IEnvironment, string> {
|
|||||||
updateSortOrder(id: string, value: number): Promise<void>;
|
updateSortOrder(id: string, value: number): Promise<void>;
|
||||||
importEnvironments(environments: IEnvironment[]): Promise<IEnvironment[]>;
|
importEnvironments(environments: IEnvironment[]): Promise<IEnvironment[]>;
|
||||||
delete(name: string): Promise<void>;
|
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}`),
|
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[] = [];
|
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[]> {
|
async getAll(): Promise<IEnvironment[]> {
|
||||||
return this.environments;
|
return this.environments;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user