mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-31 01:16:01 +02:00
task: enabled in OSS. (#8856)
Hardcode project and environment names to filter by when OSS
This commit is contained in:
parent
a454e14f28
commit
663b169c46
@ -85,6 +85,7 @@ exports[`should create default config 1`] = `
|
|||||||
},
|
},
|
||||||
"inlineSegmentConstraints": true,
|
"inlineSegmentConstraints": true,
|
||||||
"isEnterprise": false,
|
"isEnterprise": false,
|
||||||
|
"isOss": false,
|
||||||
"listen": {
|
"listen": {
|
||||||
"host": undefined,
|
"host": undefined,
|
||||||
"port": 4242,
|
"port": 4242,
|
||||||
|
@ -620,6 +620,10 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
|
|||||||
Boolean(options.enterpriseVersion) &&
|
Boolean(options.enterpriseVersion) &&
|
||||||
ui.environment?.toLowerCase() !== 'pro';
|
ui.environment?.toLowerCase() !== 'pro';
|
||||||
|
|
||||||
|
const isTest = process.env.NODE_ENV === 'test';
|
||||||
|
const isOss = isTest
|
||||||
|
? options.isOss || false
|
||||||
|
: !isEnterprise && ui.environment !== 'pro';
|
||||||
const metricsRateLimiting = loadMetricsRateLimitingConfig(options);
|
const metricsRateLimiting = loadMetricsRateLimitingConfig(options);
|
||||||
|
|
||||||
const rateLimiting = loadRateLimitingConfig(options);
|
const rateLimiting = loadRateLimitingConfig(options);
|
||||||
@ -760,6 +764,7 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
|
|||||||
publicFolder: options.publicFolder,
|
publicFolder: options.publicFolder,
|
||||||
disableScheduler: options.disableScheduler,
|
disableScheduler: options.disableScheduler,
|
||||||
isEnterprise: isEnterprise,
|
isEnterprise: isEnterprise,
|
||||||
|
isOss: isOss,
|
||||||
metricsRateLimiting,
|
metricsRateLimiting,
|
||||||
rateLimiting,
|
rateLimiting,
|
||||||
feedbackUriPath,
|
feedbackUriPath,
|
||||||
|
@ -3,13 +3,14 @@ import type {
|
|||||||
FeatureEnvironmentKey,
|
FeatureEnvironmentKey,
|
||||||
IFeatureEnvironmentStore,
|
IFeatureEnvironmentStore,
|
||||||
} from '../types/stores/feature-environment-store';
|
} from '../types/stores/feature-environment-store';
|
||||||
import type { Logger, LogProvider } from '../logger';
|
import type { Logger } from '../logger';
|
||||||
import metricsHelper from '../util/metrics-helper';
|
import metricsHelper from '../util/metrics-helper';
|
||||||
import { DB_TIME } from '../metric-events';
|
import { DB_TIME } from '../metric-events';
|
||||||
import type { IFeatureEnvironment, IVariant } from '../types/model';
|
import type { IFeatureEnvironment, IVariant } from '../types/model';
|
||||||
import NotFoundError from '../error/notfound-error';
|
import NotFoundError from '../error/notfound-error';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import type { Db } from './db';
|
import type { Db } from './db';
|
||||||
|
import type { IUnleashConfig } from '../types';
|
||||||
|
|
||||||
const T = {
|
const T = {
|
||||||
featureEnvs: 'feature_environments',
|
featureEnvs: 'feature_environments',
|
||||||
@ -36,7 +37,12 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore {
|
|||||||
|
|
||||||
private readonly timer: Function;
|
private readonly timer: Function;
|
||||||
|
|
||||||
constructor(db: Db, eventBus: EventEmitter, getLogger: LogProvider) {
|
private readonly isOss: boolean;
|
||||||
|
constructor(
|
||||||
|
db: Db,
|
||||||
|
eventBus: EventEmitter,
|
||||||
|
{ getLogger, isOss }: Pick<IUnleashConfig, 'getLogger' | 'isOss'>,
|
||||||
|
) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.logger = getLogger('feature-environment-store.ts');
|
this.logger = getLogger('feature-environment-store.ts');
|
||||||
this.timer = (action) =>
|
this.timer = (action) =>
|
||||||
@ -44,6 +50,7 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore {
|
|||||||
store: 'feature-environments',
|
store: 'feature-environments',
|
||||||
action,
|
action,
|
||||||
});
|
});
|
||||||
|
this.isOss = isOss;
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete({
|
async delete({
|
||||||
@ -96,11 +103,30 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addOssFilterIfNeeded(queryBuilder) {
|
||||||
|
if (this.isOss) {
|
||||||
|
return queryBuilder
|
||||||
|
.join(
|
||||||
|
'environments',
|
||||||
|
'environments.name',
|
||||||
|
'=',
|
||||||
|
`${T.featureEnvs}.environment`,
|
||||||
|
)
|
||||||
|
.whereIn('environments.name', [
|
||||||
|
'default',
|
||||||
|
'development',
|
||||||
|
'production',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return queryBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
async getAll(query?: Object): Promise<IFeatureEnvironment[]> {
|
async getAll(query?: Object): Promise<IFeatureEnvironment[]> {
|
||||||
let rows = this.db(T.featureEnvs);
|
let rows = this.db(T.featureEnvs);
|
||||||
if (query) {
|
if (query) {
|
||||||
rows = rows.where(query);
|
rows = rows.where(query);
|
||||||
}
|
}
|
||||||
|
this.addOssFilterIfNeeded(rows);
|
||||||
return (await rows).map((r) => ({
|
return (await rows).map((r) => ({
|
||||||
enabled: r.enabled,
|
enabled: r.enabled,
|
||||||
featureName: r.feature_name,
|
featureName: r.feature_name,
|
||||||
@ -119,6 +145,7 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore {
|
|||||||
if (environment) {
|
if (environment) {
|
||||||
rows = rows.where({ environment });
|
rows = rows.where({ environment });
|
||||||
}
|
}
|
||||||
|
this.addOssFilterIfNeeded(rows);
|
||||||
return (await rows).map((r) => ({
|
return (await rows).map((r) => ({
|
||||||
enabled: r.enabled,
|
enabled: r.enabled,
|
||||||
featureName: r.feature_name,
|
featureName: r.feature_name,
|
||||||
|
@ -94,12 +94,7 @@ export const createStores = (
|
|||||||
settingStore: new SettingStore(db, getLogger),
|
settingStore: new SettingStore(db, getLogger),
|
||||||
userStore: new UserStore(db, getLogger, config.flagResolver),
|
userStore: new UserStore(db, getLogger, config.flagResolver),
|
||||||
accountStore: new AccountStore(db, getLogger),
|
accountStore: new AccountStore(db, getLogger),
|
||||||
projectStore: new ProjectStore(
|
projectStore: new ProjectStore(db, eventBus, config),
|
||||||
db,
|
|
||||||
eventBus,
|
|
||||||
getLogger,
|
|
||||||
config.flagResolver,
|
|
||||||
),
|
|
||||||
tagStore: new TagStore(db, eventBus, getLogger),
|
tagStore: new TagStore(db, eventBus, getLogger),
|
||||||
tagTypeStore: new TagTypeStore(db, eventBus, getLogger),
|
tagTypeStore: new TagTypeStore(db, eventBus, getLogger),
|
||||||
addonStore: new AddonStore(db, eventBus, getLogger),
|
addonStore: new AddonStore(db, eventBus, getLogger),
|
||||||
@ -122,15 +117,14 @@ export const createStores = (
|
|||||||
clientFeatureToggleStore: new FeatureToggleClientStore(
|
clientFeatureToggleStore: new FeatureToggleClientStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
getLogger,
|
config,
|
||||||
config.flagResolver,
|
|
||||||
),
|
),
|
||||||
environmentStore: new EnvironmentStore(db, eventBus, getLogger),
|
environmentStore: new EnvironmentStore(db, eventBus, config),
|
||||||
featureTagStore: new FeatureTagStore(db, eventBus, getLogger),
|
featureTagStore: new FeatureTagStore(db, eventBus, getLogger),
|
||||||
featureEnvironmentStore: new FeatureEnvironmentStore(
|
featureEnvironmentStore: new FeatureEnvironmentStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
getLogger,
|
config,
|
||||||
),
|
),
|
||||||
userSplashStore: new UserSplashStore(db, eventBus, getLogger),
|
userSplashStore: new UserSplashStore(db, eventBus, getLogger),
|
||||||
roleStore: new RoleStore(db, eventBus, getLogger),
|
roleStore: new RoleStore(db, eventBus, getLogger),
|
||||||
|
@ -25,7 +25,7 @@ export const createAccessService = (
|
|||||||
const groupStore = new GroupStore(db);
|
const groupStore = new GroupStore(db);
|
||||||
const accountStore = new AccountStore(db, getLogger);
|
const accountStore = new AccountStore(db, getLogger);
|
||||||
const roleStore = new RoleStore(db, eventBus, getLogger);
|
const roleStore = new RoleStore(db, eventBus, getLogger);
|
||||||
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
|
const environmentStore = new EnvironmentStore(db, eventBus, config);
|
||||||
const accessStore = new AccessStore(db, eventBus, getLogger);
|
const accessStore = new AccessStore(db, eventBus, getLogger);
|
||||||
const eventService = createEventsService(db, config);
|
const eventService = createEventsService(db, config);
|
||||||
const groupService = new GroupService(
|
const groupService = new GroupService(
|
||||||
|
@ -21,7 +21,7 @@ export const createApiTokenService = (
|
|||||||
getLogger,
|
getLogger,
|
||||||
config.flagResolver,
|
config.flagResolver,
|
||||||
);
|
);
|
||||||
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
|
const environmentStore = new EnvironmentStore(db, eventBus, config);
|
||||||
const eventService = createEventsService(db, config);
|
const eventService = createEventsService(db, config);
|
||||||
|
|
||||||
return new ApiTokenService(
|
return new ApiTokenService(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import metricsHelper from '../../util/metrics-helper';
|
import metricsHelper from '../../util/metrics-helper';
|
||||||
import { DB_TIME } from '../../metric-events';
|
import { DB_TIME } from '../../metric-events';
|
||||||
import type { Logger, LogProvider } from '../../logger';
|
import type { Logger } from '../../logger';
|
||||||
import type {
|
import type {
|
||||||
IFeatureToggleClient,
|
IFeatureToggleClient,
|
||||||
IFeatureToggleClientStore,
|
IFeatureToggleClientStore,
|
||||||
@ -9,6 +9,7 @@ import type {
|
|||||||
IFlagResolver,
|
IFlagResolver,
|
||||||
IStrategyConfig,
|
IStrategyConfig,
|
||||||
ITag,
|
ITag,
|
||||||
|
IUnleashConfig,
|
||||||
PartialDeep,
|
PartialDeep,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
import {
|
import {
|
||||||
@ -46,11 +47,16 @@ export default class FeatureToggleClientStore
|
|||||||
|
|
||||||
private flagResolver: IFlagResolver;
|
private flagResolver: IFlagResolver;
|
||||||
|
|
||||||
|
private readonly isOss: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
db: Db,
|
db: Db,
|
||||||
eventBus: EventEmitter,
|
eventBus: EventEmitter,
|
||||||
getLogger: LogProvider,
|
{
|
||||||
flagResolver: IFlagResolver,
|
getLogger,
|
||||||
|
flagResolver,
|
||||||
|
isOss,
|
||||||
|
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver' | 'isOss'>,
|
||||||
) {
|
) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.logger = getLogger('feature-toggle-client-store.ts');
|
this.logger = getLogger('feature-toggle-client-store.ts');
|
||||||
@ -60,6 +66,7 @@ export default class FeatureToggleClientStore
|
|||||||
action,
|
action,
|
||||||
});
|
});
|
||||||
this.flagResolver = flagResolver;
|
this.flagResolver = flagResolver;
|
||||||
|
this.isOss = isOss;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getAll({
|
private async getAll({
|
||||||
@ -72,7 +79,6 @@ export default class FeatureToggleClientStore
|
|||||||
const isPlayground = requestType === 'playground';
|
const isPlayground = requestType === 'playground';
|
||||||
const environment = featureQuery?.environment || DEFAULT_ENV;
|
const environment = featureQuery?.environment || DEFAULT_ENV;
|
||||||
const stopTimer = this.timer(`getAllBy${requestType}`);
|
const stopTimer = this.timer(`getAllBy${requestType}`);
|
||||||
|
|
||||||
let selectColumns = [
|
let selectColumns = [
|
||||||
'features.name as name',
|
'features.name as name',
|
||||||
'features.description as description',
|
'features.description as description',
|
||||||
@ -103,6 +109,10 @@ export default class FeatureToggleClientStore
|
|||||||
|
|
||||||
let query = this.db('features')
|
let query = this.db('features')
|
||||||
.modify(FeatureToggleStore.filterByArchived, archived)
|
.modify(FeatureToggleStore.filterByArchived, archived)
|
||||||
|
.modify(
|
||||||
|
FeatureToggleStore.filterByProjectsAccessibleByOss,
|
||||||
|
this.isOss,
|
||||||
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
this.db('feature_strategies')
|
this.db('feature_strategies')
|
||||||
.select('*')
|
.select('*')
|
||||||
|
@ -10,13 +10,10 @@ export const createClientFeatureToggleService = (
|
|||||||
db: Db,
|
db: Db,
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
): ClientFeatureToggleService => {
|
): ClientFeatureToggleService => {
|
||||||
const { getLogger, eventBus, flagResolver } = config;
|
|
||||||
|
|
||||||
const featureToggleClientStore = new FeatureToggleClientStore(
|
const featureToggleClientStore = new FeatureToggleClientStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
config.eventBus,
|
||||||
getLogger,
|
config,
|
||||||
flagResolver,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const segmentReadModel = new SegmentReadModel(db);
|
const segmentReadModel = new SegmentReadModel(db);
|
||||||
@ -26,7 +23,7 @@ export const createClientFeatureToggleService = (
|
|||||||
clientFeatureToggleStore: featureToggleClientStore,
|
clientFeatureToggleStore: featureToggleClientStore,
|
||||||
},
|
},
|
||||||
segmentReadModel,
|
segmentReadModel,
|
||||||
{ getLogger, flagResolver },
|
config,
|
||||||
);
|
);
|
||||||
|
|
||||||
return clientFeatureToggleService;
|
return clientFeatureToggleService;
|
||||||
@ -35,8 +32,6 @@ export const createClientFeatureToggleService = (
|
|||||||
export const createFakeClientFeatureToggleService = (
|
export const createFakeClientFeatureToggleService = (
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
): ClientFeatureToggleService => {
|
): ClientFeatureToggleService => {
|
||||||
const { getLogger, flagResolver } = config;
|
|
||||||
|
|
||||||
const fakeClientFeatureToggleStore = new FakeClientFeatureToggleStore();
|
const fakeClientFeatureToggleStore = new FakeClientFeatureToggleStore();
|
||||||
|
|
||||||
const fakeSegmentReadModel = new FakeSegmentReadModel();
|
const fakeSegmentReadModel = new FakeSegmentReadModel();
|
||||||
@ -46,7 +41,7 @@ export const createFakeClientFeatureToggleService = (
|
|||||||
clientFeatureToggleStore: fakeClientFeatureToggleStore,
|
clientFeatureToggleStore: fakeClientFeatureToggleStore,
|
||||||
},
|
},
|
||||||
fakeSegmentReadModel,
|
fakeSegmentReadModel,
|
||||||
{ getLogger, flagResolver },
|
config,
|
||||||
);
|
);
|
||||||
|
|
||||||
return clientFeatureToggleService;
|
return clientFeatureToggleService;
|
||||||
|
@ -150,12 +150,7 @@ export const deferredExportImportTogglesService = (
|
|||||||
);
|
);
|
||||||
const tagStore = new TagStore(db, eventBus, getLogger);
|
const tagStore = new TagStore(db, eventBus, getLogger);
|
||||||
const tagTypeStore = new TagTypeStore(db, eventBus, getLogger);
|
const tagTypeStore = new TagTypeStore(db, eventBus, getLogger);
|
||||||
const projectStore = new ProjectStore(
|
const projectStore = new ProjectStore(db, eventBus, config);
|
||||||
db,
|
|
||||||
eventBus,
|
|
||||||
getLogger,
|
|
||||||
flagResolver,
|
|
||||||
);
|
|
||||||
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
|
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
|
||||||
const strategyStore = new StrategyStore(db, getLogger);
|
const strategyStore = new StrategyStore(db, getLogger);
|
||||||
const contextFieldStore = new ContextFieldStore(
|
const contextFieldStore = new ContextFieldStore(
|
||||||
@ -172,7 +167,7 @@ export const deferredExportImportTogglesService = (
|
|||||||
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
getLogger,
|
config,
|
||||||
);
|
);
|
||||||
const eventStore = new EventStore(db, getLogger);
|
const eventStore = new EventStore(db, getLogger);
|
||||||
const accessService = createAccessService(db, config);
|
const accessService = createAccessService(db, config);
|
||||||
|
@ -19,11 +19,11 @@ export const createFeatureLifecycleService =
|
|||||||
const { eventBus, getLogger } = config;
|
const { eventBus, getLogger } = config;
|
||||||
const eventStore = new EventStore(db, getLogger);
|
const eventStore = new EventStore(db, getLogger);
|
||||||
const featureLifecycleStore = new FeatureLifecycleStore(db);
|
const featureLifecycleStore = new FeatureLifecycleStore(db);
|
||||||
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
|
const environmentStore = new EnvironmentStore(db, eventBus, config);
|
||||||
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
getLogger,
|
config,
|
||||||
);
|
);
|
||||||
const eventService = createEventsService(db, config);
|
const eventService = createEventsService(db, config);
|
||||||
const featureLifecycleService = new FeatureLifecycleService(
|
const featureLifecycleService = new FeatureLifecycleService(
|
||||||
|
@ -80,19 +80,13 @@ export const createFeatureToggleService = (
|
|||||||
const featureToggleClientStore = new FeatureToggleClientStore(
|
const featureToggleClientStore = new FeatureToggleClientStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
getLogger,
|
config,
|
||||||
flagResolver,
|
|
||||||
);
|
|
||||||
const projectStore = new ProjectStore(
|
|
||||||
db,
|
|
||||||
eventBus,
|
|
||||||
getLogger,
|
|
||||||
flagResolver,
|
|
||||||
);
|
);
|
||||||
|
const projectStore = new ProjectStore(db, eventBus, config);
|
||||||
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
getLogger,
|
config,
|
||||||
);
|
);
|
||||||
const contextFieldStore = new ContextFieldStore(
|
const contextFieldStore = new ContextFieldStore(
|
||||||
db,
|
db,
|
||||||
@ -105,7 +99,7 @@ export const createFeatureToggleService = (
|
|||||||
const accessStore = new AccessStore(db, eventBus, getLogger);
|
const accessStore = new AccessStore(db, eventBus, getLogger);
|
||||||
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
|
const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
|
||||||
const roleStore = new RoleStore(db, eventBus, getLogger);
|
const roleStore = new RoleStore(db, eventBus, getLogger);
|
||||||
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
|
const environmentStore = new EnvironmentStore(db, eventBus, config);
|
||||||
const eventService = createEventsService(db, config);
|
const eventService = createEventsService(db, config);
|
||||||
const groupService = new GroupService(
|
const groupService = new GroupService(
|
||||||
{ groupStore, accountStore },
|
{ groupStore, accountStore },
|
||||||
|
@ -439,6 +439,16 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
|||||||
: queryBuilder.whereNull('archived_at');
|
: queryBuilder.whereNull('archived_at');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static filterByProjectsAccessibleByOss: Knex.QueryCallbackWithArgs = (
|
||||||
|
queryBuilder: Knex.QueryBuilder,
|
||||||
|
isOss: boolean,
|
||||||
|
) => {
|
||||||
|
if (isOss) {
|
||||||
|
return queryBuilder.andWhere('project', '=', 'default');
|
||||||
|
}
|
||||||
|
return queryBuilder;
|
||||||
|
};
|
||||||
|
|
||||||
rowToFeature(row: FeaturesTable): FeatureToggle {
|
rowToFeature(row: FeaturesTable): FeatureToggle {
|
||||||
if (!row) {
|
if (!row) {
|
||||||
throw new NotFoundError('No feature flag found');
|
throw new NotFoundError('No feature flag found');
|
||||||
|
@ -58,13 +58,8 @@ export const createInstanceStatsService = (db: Db, config: IUnleashConfig) => {
|
|||||||
flagResolver,
|
flagResolver,
|
||||||
);
|
);
|
||||||
const userStore = new UserStore(db, getLogger, flagResolver);
|
const userStore = new UserStore(db, getLogger, flagResolver);
|
||||||
const projectStore = new ProjectStore(
|
const projectStore = new ProjectStore(db, eventBus, config);
|
||||||
db,
|
const environmentStore = new EnvironmentStore(db, eventBus, config);
|
||||||
eventBus,
|
|
||||||
getLogger,
|
|
||||||
flagResolver,
|
|
||||||
);
|
|
||||||
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
|
|
||||||
const strategyStore = new StrategyStore(db, getLogger);
|
const strategyStore = new StrategyStore(db, getLogger);
|
||||||
const contextFieldStore = new ContextFieldStore(
|
const contextFieldStore = new ContextFieldStore(
|
||||||
db,
|
db,
|
||||||
|
@ -21,21 +21,16 @@ export const createEnvironmentService =
|
|||||||
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
getLogger,
|
config,
|
||||||
);
|
|
||||||
const projectStore = new ProjectStore(
|
|
||||||
db,
|
|
||||||
eventBus,
|
|
||||||
getLogger,
|
|
||||||
flagResolver,
|
|
||||||
);
|
);
|
||||||
|
const projectStore = new ProjectStore(db, eventBus, config);
|
||||||
const featureStrategiesStore = new FeatureStrategiesStore(
|
const featureStrategiesStore = new FeatureStrategiesStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
getLogger,
|
getLogger,
|
||||||
flagResolver,
|
flagResolver,
|
||||||
);
|
);
|
||||||
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
|
const environmentStore = new EnvironmentStore(db, eventBus, config);
|
||||||
const eventService = createEventsService(db, config);
|
const eventService = createEventsService(db, config);
|
||||||
return new EnvironmentService(
|
return new EnvironmentService(
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type EventEmitter from 'events';
|
import type EventEmitter from 'events';
|
||||||
import type { Db } from '../../db/db';
|
import type { Db } from '../../db/db';
|
||||||
import type { Logger, LogProvider } from '../../logger';
|
import type { Logger } from '../../logger';
|
||||||
import metricsHelper from '../../util/metrics-helper';
|
import metricsHelper from '../../util/metrics-helper';
|
||||||
import { DB_TIME } from '../../metric-events';
|
import { DB_TIME } from '../../metric-events';
|
||||||
import type {
|
import type {
|
||||||
@ -12,6 +12,7 @@ import NotFoundError from '../../error/notfound-error';
|
|||||||
import type { IEnvironmentStore } from './environment-store-type';
|
import type { IEnvironmentStore } from './environment-store-type';
|
||||||
import { snakeCaseKeys } from '../../util/snakeCase';
|
import { snakeCaseKeys } from '../../util/snakeCase';
|
||||||
import type { CreateFeatureStrategySchema } from '../../openapi';
|
import type { CreateFeatureStrategySchema } from '../../openapi';
|
||||||
|
import type { IUnleashConfig } from '../../types';
|
||||||
|
|
||||||
interface IEnvironmentsTable {
|
interface IEnvironmentsTable {
|
||||||
name: string;
|
name: string;
|
||||||
@ -104,11 +105,18 @@ export default class EnvironmentStore implements IEnvironmentStore {
|
|||||||
|
|
||||||
private db: Db;
|
private db: Db;
|
||||||
|
|
||||||
|
private isOss: boolean;
|
||||||
|
|
||||||
private timer: (string) => any;
|
private timer: (string) => any;
|
||||||
|
|
||||||
constructor(db: Db, eventBus: EventEmitter, getLogger: LogProvider) {
|
constructor(
|
||||||
|
db: Db,
|
||||||
|
eventBus: EventEmitter,
|
||||||
|
{ getLogger, isOss }: Pick<IUnleashConfig, 'getLogger' | 'isOss'>,
|
||||||
|
) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.logger = getLogger('db/environment-store.ts');
|
this.logger = getLogger('db/environment-store.ts');
|
||||||
|
this.isOss = isOss;
|
||||||
this.timer = (action) =>
|
this.timer = (action) =>
|
||||||
metricsHelper.wrapTimer(eventBus, DB_TIME, {
|
metricsHelper.wrapTimer(eventBus, DB_TIME, {
|
||||||
store: 'environment',
|
store: 'environment',
|
||||||
@ -148,9 +156,15 @@ export default class EnvironmentStore implements IEnvironmentStore {
|
|||||||
|
|
||||||
async get(key: string): Promise<IEnvironment> {
|
async get(key: string): Promise<IEnvironment> {
|
||||||
const stopTimer = this.timer('get');
|
const stopTimer = this.timer('get');
|
||||||
const row = await this.db<IEnvironmentsTable>(TABLE)
|
let keyQuery = this.db<IEnvironmentsTable>(TABLE).where({ name: key });
|
||||||
.where({ name: key })
|
if (this.isOss) {
|
||||||
.first();
|
keyQuery = keyQuery.whereIn('name', [
|
||||||
|
'default',
|
||||||
|
'development',
|
||||||
|
'production',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
const row = await keyQuery.first();
|
||||||
stopTimer();
|
stopTimer();
|
||||||
if (row) {
|
if (row) {
|
||||||
return mapRow(row);
|
return mapRow(row);
|
||||||
@ -169,6 +183,9 @@ export default class EnvironmentStore implements IEnvironmentStore {
|
|||||||
if (query) {
|
if (query) {
|
||||||
qB = qB.where(query);
|
qB = qB.where(query);
|
||||||
}
|
}
|
||||||
|
if (this.isOss) {
|
||||||
|
qB = qB.whereIn('name', ['default', 'development', 'production']);
|
||||||
|
}
|
||||||
const rows = await qB;
|
const rows = await qB;
|
||||||
stopTimer();
|
stopTimer();
|
||||||
return rows.map(mapRow);
|
return rows.map(mapRow);
|
||||||
@ -196,6 +213,9 @@ export default class EnvironmentStore implements IEnvironmentStore {
|
|||||||
if (query) {
|
if (query) {
|
||||||
qB = qB.where(query);
|
qB = qB.where(query);
|
||||||
}
|
}
|
||||||
|
if (this.isOss) {
|
||||||
|
qB = qB.whereIn('name', ['default', 'development', 'production']);
|
||||||
|
}
|
||||||
const rows = await qB;
|
const rows = await qB;
|
||||||
stopTimer();
|
stopTimer();
|
||||||
return rows.map(mapRowWithCounts);
|
return rows.map(mapRowWithCounts);
|
||||||
@ -230,6 +250,13 @@ export default class EnvironmentStore implements IEnvironmentStore {
|
|||||||
if (query) {
|
if (query) {
|
||||||
qB = qB.where(query);
|
qB = qB.where(query);
|
||||||
}
|
}
|
||||||
|
if (this.isOss) {
|
||||||
|
qB = qB.whereIn('environments.name', [
|
||||||
|
'default',
|
||||||
|
'production',
|
||||||
|
'development',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
const rows = await qB;
|
const rows = await qB;
|
||||||
stopTimer();
|
stopTimer();
|
||||||
|
@ -16,12 +16,7 @@ export const createProjectInsightsService = (
|
|||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
): ProjectInsightsService => {
|
): ProjectInsightsService => {
|
||||||
const { eventBus, getLogger, flagResolver } = config;
|
const { eventBus, getLogger, flagResolver } = config;
|
||||||
const projectStore = new ProjectStore(
|
const projectStore = new ProjectStore(db, eventBus, config);
|
||||||
db,
|
|
||||||
eventBus,
|
|
||||||
getLogger,
|
|
||||||
flagResolver,
|
|
||||||
);
|
|
||||||
const featureToggleStore = new FeatureToggleStore(
|
const featureToggleStore = new FeatureToggleStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
|
@ -24,12 +24,7 @@ export const createProjectStatusService = (
|
|||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
): ProjectStatusService => {
|
): ProjectStatusService => {
|
||||||
const eventStore = new EventStore(db, config.getLogger);
|
const eventStore = new EventStore(db, config.getLogger);
|
||||||
const projectStore = new ProjectStore(
|
const projectStore = new ProjectStore(db, config.eventBus, config);
|
||||||
db,
|
|
||||||
config.eventBus,
|
|
||||||
config.getLogger,
|
|
||||||
config.flagResolver,
|
|
||||||
);
|
|
||||||
const apiTokenStore = new ApiTokenStore(
|
const apiTokenStore = new ApiTokenStore(
|
||||||
db,
|
db,
|
||||||
config.eventBus,
|
config.eventBus,
|
||||||
|
@ -63,12 +63,7 @@ export const createProjectService = (
|
|||||||
): ProjectService => {
|
): ProjectService => {
|
||||||
const { eventBus, getLogger, flagResolver } = config;
|
const { eventBus, getLogger, flagResolver } = config;
|
||||||
const eventStore = new EventStore(db, getLogger);
|
const eventStore = new EventStore(db, getLogger);
|
||||||
const projectStore = new ProjectStore(
|
const projectStore = new ProjectStore(db, eventBus, config);
|
||||||
db,
|
|
||||||
eventBus,
|
|
||||||
getLogger,
|
|
||||||
flagResolver,
|
|
||||||
);
|
|
||||||
const projectOwnersReadModel = new ProjectOwnersReadModel(db);
|
const projectOwnersReadModel = new ProjectOwnersReadModel(db);
|
||||||
const projectFlagCreatorsReadModel = new ProjectFlagCreatorsReadModel(db);
|
const projectFlagCreatorsReadModel = new ProjectFlagCreatorsReadModel(db);
|
||||||
const groupStore = new GroupStore(db);
|
const groupStore = new GroupStore(db);
|
||||||
@ -79,11 +74,11 @@ export const createProjectService = (
|
|||||||
flagResolver,
|
flagResolver,
|
||||||
);
|
);
|
||||||
const accountStore = new AccountStore(db, getLogger);
|
const accountStore = new AccountStore(db, getLogger);
|
||||||
const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
|
const environmentStore = new EnvironmentStore(db, eventBus, config);
|
||||||
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
const featureEnvironmentStore = new FeatureEnvironmentStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
getLogger,
|
config,
|
||||||
);
|
);
|
||||||
const projectStatsStore = new ProjectStatsStore(db, eventBus, getLogger);
|
const projectStatsStore = new ProjectStatsStore(db, eventBus, getLogger);
|
||||||
const accessService: AccessService = createAccessService(db, config);
|
const accessService: AccessService = createAccessService(db, config);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { Logger, LogProvider } from '../../logger';
|
import type { Logger } from '../../logger';
|
||||||
|
|
||||||
import NotFoundError from '../../error/notfound-error';
|
import NotFoundError from '../../error/notfound-error';
|
||||||
import type {
|
import type {
|
||||||
@ -8,6 +8,7 @@ import type {
|
|||||||
IProjectApplication,
|
IProjectApplication,
|
||||||
IProjectApplications,
|
IProjectApplications,
|
||||||
IProjectUpdate,
|
IProjectUpdate,
|
||||||
|
IUnleashConfig,
|
||||||
ProjectMode,
|
ProjectMode,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
import type {
|
import type {
|
||||||
@ -72,11 +73,16 @@ class ProjectStore implements IProjectStore {
|
|||||||
|
|
||||||
private timer: Function;
|
private timer: Function;
|
||||||
|
|
||||||
|
private isOss: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
db: Db,
|
db: Db,
|
||||||
eventBus: EventEmitter,
|
eventBus: EventEmitter,
|
||||||
getLogger: LogProvider,
|
{
|
||||||
flagResolver: IFlagResolver,
|
getLogger,
|
||||||
|
flagResolver,
|
||||||
|
isOss,
|
||||||
|
}: Pick<IUnleashConfig, 'getLogger' | 'flagResolver' | 'isOss'>,
|
||||||
) {
|
) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.logger = getLogger('project-store.ts');
|
this.logger = getLogger('project-store.ts');
|
||||||
@ -86,6 +92,7 @@ class ProjectStore implements IProjectStore {
|
|||||||
action,
|
action,
|
||||||
});
|
});
|
||||||
this.flagResolver = flagResolver;
|
this.flagResolver = flagResolver;
|
||||||
|
this.isOss = isOss;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
@ -122,6 +129,9 @@ class ProjectStore implements IProjectStore {
|
|||||||
.orderBy('name', 'asc');
|
.orderBy('name', 'asc');
|
||||||
|
|
||||||
projects = projects.where(`${TABLE}.archived_at`, null);
|
projects = projects.where(`${TABLE}.archived_at`, null);
|
||||||
|
if (this.isOss) {
|
||||||
|
projects = projects.where('id', 'default');
|
||||||
|
}
|
||||||
|
|
||||||
const rows = await projects;
|
const rows = await projects;
|
||||||
|
|
||||||
|
@ -143,6 +143,7 @@ export interface IUnleashOptions {
|
|||||||
metricsRateLimiting?: Partial<IMetricsRateLimiting>;
|
metricsRateLimiting?: Partial<IMetricsRateLimiting>;
|
||||||
dailyMetricsStorageDays?: number;
|
dailyMetricsStorageDays?: number;
|
||||||
rateLimiting?: Partial<IRateLimiting>;
|
rateLimiting?: Partial<IRateLimiting>;
|
||||||
|
isOss?: boolean;
|
||||||
resourceLimits?: Partial<
|
resourceLimits?: Partial<
|
||||||
Pick<
|
Pick<
|
||||||
ResourceLimitsSchema,
|
ResourceLimitsSchema,
|
||||||
@ -273,6 +274,7 @@ export interface IUnleashConfig {
|
|||||||
publicFolder?: string;
|
publicFolder?: string;
|
||||||
disableScheduler?: boolean;
|
disableScheduler?: boolean;
|
||||||
isEnterprise: boolean;
|
isEnterprise: boolean;
|
||||||
|
isOss: boolean;
|
||||||
rateLimiting: IRateLimiting;
|
rateLimiting: IRateLimiting;
|
||||||
feedbackUriPath?: string;
|
feedbackUriPath?: string;
|
||||||
openAIAPIKey?: string;
|
openAIAPIKey?: string;
|
||||||
|
68
src/test/e2e/api/admin/environment-oss.e2e.test.ts
Normal file
68
src/test/e2e/api/admin/environment-oss.e2e.test.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import {
|
||||||
|
type IUnleashTest,
|
||||||
|
setupAppWithCustomConfig,
|
||||||
|
} from '../../helpers/test-helper';
|
||||||
|
import dbInit, { type ITestDb } from '../../helpers/database-init';
|
||||||
|
import getLogger from '../../../fixtures/no-logger';
|
||||||
|
|
||||||
|
let app: IUnleashTest;
|
||||||
|
let db: ITestDb;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
db = await dbInit('environment_api_is_oss_serial', getLogger, {
|
||||||
|
isOss: true,
|
||||||
|
});
|
||||||
|
app = await setupAppWithCustomConfig(
|
||||||
|
db.stores,
|
||||||
|
{
|
||||||
|
experimental: {
|
||||||
|
flags: {
|
||||||
|
strictSchemaValidation: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isOss: true,
|
||||||
|
},
|
||||||
|
db.rawDatabase,
|
||||||
|
);
|
||||||
|
await db.stores.environmentStore.create({
|
||||||
|
name: 'development',
|
||||||
|
type: 'development',
|
||||||
|
enabled: true,
|
||||||
|
});
|
||||||
|
await db.stores.environmentStore.create({
|
||||||
|
name: 'production',
|
||||||
|
type: 'production',
|
||||||
|
enabled: true,
|
||||||
|
});
|
||||||
|
await db.stores.environmentStore.create({
|
||||||
|
name: 'customenvironment',
|
||||||
|
type: 'production',
|
||||||
|
enabled: true,
|
||||||
|
});
|
||||||
|
await db.stores.environmentStore.create({
|
||||||
|
name: 'customenvironment2',
|
||||||
|
type: 'production',
|
||||||
|
enabled: true,
|
||||||
|
});
|
||||||
|
await db.stores.environmentStore.create({
|
||||||
|
name: 'customenvironment3',
|
||||||
|
type: 'production',
|
||||||
|
enabled: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await app.destroy();
|
||||||
|
await db.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('querying environments in OSS only returns environments that are included in oss', async () => {
|
||||||
|
await app.request
|
||||||
|
.get('/api/admin/environments')
|
||||||
|
.expect(200)
|
||||||
|
.expect((res) => {
|
||||||
|
expect(res.body.environments).toHaveLength(3);
|
||||||
|
const names = res.body.environments.map((env) => env.name);
|
||||||
|
expect(names).toEqual(['default', 'development', 'production']);
|
||||||
|
});
|
||||||
|
});
|
82
src/test/e2e/api/client/feature-oss.e2e.test.ts
Normal file
82
src/test/e2e/api/client/feature-oss.e2e.test.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import getLogger from '../../../fixtures/no-logger';
|
||||||
|
import {
|
||||||
|
type IUnleashTest,
|
||||||
|
setupAppWithCustomConfig,
|
||||||
|
} from '../../helpers/test-helper';
|
||||||
|
import dbInit from '../../helpers/database-init';
|
||||||
|
import type { ITestDb } from '../../helpers/database-init';
|
||||||
|
import type { IAuditUser, IUser } from '../../../../lib/types';
|
||||||
|
|
||||||
|
let app: IUnleashTest;
|
||||||
|
let db: ITestDb;
|
||||||
|
let testUser: IUser;
|
||||||
|
const auditUser = {
|
||||||
|
username: 'audituser',
|
||||||
|
id: -42,
|
||||||
|
ip: 'localhost',
|
||||||
|
} as IAuditUser;
|
||||||
|
|
||||||
|
let userIndex = 0;
|
||||||
|
const createUser = async (role?: number) => {
|
||||||
|
const name = `User ${userIndex}`;
|
||||||
|
const email = `user-${userIndex}@getunleash.io`;
|
||||||
|
userIndex++;
|
||||||
|
|
||||||
|
const { userStore } = db.stores;
|
||||||
|
return userStore.insert({ name, email });
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
db = await dbInit('feature_api_client_is_oss', getLogger, { isOss: true });
|
||||||
|
app = await setupAppWithCustomConfig(
|
||||||
|
db.stores,
|
||||||
|
{
|
||||||
|
experimental: {
|
||||||
|
flags: {
|
||||||
|
strictSchemaValidation: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isOss: true,
|
||||||
|
},
|
||||||
|
db.rawDatabase,
|
||||||
|
);
|
||||||
|
testUser = await createUser();
|
||||||
|
await app.services.projectService.createProject(
|
||||||
|
{ id: 'secondproject', name: 'Second project not returned when oss' },
|
||||||
|
testUser,
|
||||||
|
auditUser,
|
||||||
|
);
|
||||||
|
await app.services.featureToggleService.createFeatureToggle(
|
||||||
|
'secondproject',
|
||||||
|
{
|
||||||
|
name: 'my.feature.toggle',
|
||||||
|
},
|
||||||
|
auditUser,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
await app.services.featureToggleService.createFeatureToggle(
|
||||||
|
'default',
|
||||||
|
{
|
||||||
|
name: 'my.default.toggle',
|
||||||
|
},
|
||||||
|
auditUser,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
afterAll(async () => {
|
||||||
|
await app.destroy();
|
||||||
|
await db.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('OSS downgrade', () => {
|
||||||
|
test('features created in projects other than default is not visible in client endpoint', async () => {
|
||||||
|
return app.request
|
||||||
|
.get('/api/client/features')
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect(200)
|
||||||
|
.expect((res) => {
|
||||||
|
expect(res.body.features).toHaveLength(1);
|
||||||
|
expect(res.body.features[0].name).toBe('my.default.toggle');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user