mirror of
https://github.com/Unleash/unleash.git
synced 2025-10-27 11:02:16 +01:00
feat: move release plans to feature environments (#10746)
This commit is contained in:
parent
183d436e59
commit
f2115cc3db
@ -66,6 +66,8 @@ import {
|
|||||||
createFeatureLinkService,
|
createFeatureLinkService,
|
||||||
} from '../feature-links/createFeatureLinkService.js';
|
} from '../feature-links/createFeatureLinkService.js';
|
||||||
import { ResourceLimitsService } from '../resource-limits/resource-limits-service.js';
|
import { ResourceLimitsService } from '../resource-limits/resource-limits-service.js';
|
||||||
|
import { ReleasePlanReadModel } from '../release-plans/release-plan-read-model.js';
|
||||||
|
import { FakeReleasePlanReadModel } from '../../../test/fixtures/fake/fake-release-plan-read-model.js';
|
||||||
|
|
||||||
export const createFeatureToggleService = (
|
export const createFeatureToggleService = (
|
||||||
db: Db,
|
db: Db,
|
||||||
@ -141,6 +143,8 @@ export const createFeatureToggleService = (
|
|||||||
|
|
||||||
const resourceLimitsService = new ResourceLimitsService(config);
|
const resourceLimitsService = new ResourceLimitsService(config);
|
||||||
|
|
||||||
|
const releasePlanReadModel = new ReleasePlanReadModel(db);
|
||||||
|
|
||||||
const featureToggleService = new FeatureToggleService(
|
const featureToggleService = new FeatureToggleService(
|
||||||
{
|
{
|
||||||
featureStrategiesStore,
|
featureStrategiesStore,
|
||||||
@ -166,6 +170,7 @@ export const createFeatureToggleService = (
|
|||||||
featureLinksReadModel,
|
featureLinksReadModel,
|
||||||
featureLinkService,
|
featureLinkService,
|
||||||
resourceLimitsService,
|
resourceLimitsService,
|
||||||
|
releasePlanReadModel,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return featureToggleService;
|
return featureToggleService;
|
||||||
@ -211,6 +216,7 @@ export const createFakeFeatureToggleService = (config: IUnleashConfig) => {
|
|||||||
const { featureLinkService } = createFakeFeatureLinkService(config);
|
const { featureLinkService } = createFakeFeatureLinkService(config);
|
||||||
|
|
||||||
const resourceLimitsService = new ResourceLimitsService(config);
|
const resourceLimitsService = new ResourceLimitsService(config);
|
||||||
|
const releasePlanReadModel = new FakeReleasePlanReadModel();
|
||||||
|
|
||||||
const featureToggleService = new FeatureToggleService(
|
const featureToggleService = new FeatureToggleService(
|
||||||
{
|
{
|
||||||
@ -241,6 +247,7 @@ export const createFakeFeatureToggleService = (config: IUnleashConfig) => {
|
|||||||
featureLinksReadModel,
|
featureLinksReadModel,
|
||||||
featureLinkService,
|
featureLinkService,
|
||||||
resourceLimitsService,
|
resourceLimitsService,
|
||||||
|
releasePlanReadModel,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import {
|
|||||||
type IAuditUser,
|
type IAuditUser,
|
||||||
type IConstraint,
|
type IConstraint,
|
||||||
type IDependency,
|
type IDependency,
|
||||||
|
type IEnvironmentDetail,
|
||||||
type IFeatureCollaboratorsReadModel,
|
type IFeatureCollaboratorsReadModel,
|
||||||
type IFeatureEnvironmentInfo,
|
type IFeatureEnvironmentInfo,
|
||||||
type IFeatureEnvironmentStore,
|
type IFeatureEnvironmentStore,
|
||||||
@ -117,6 +118,8 @@ import { sortStrategies } from '../../util/sortStrategies.js';
|
|||||||
import type FeatureLinkService from '../feature-links/feature-link-service.js';
|
import type FeatureLinkService from '../feature-links/feature-link-service.js';
|
||||||
import type { IFeatureLink } from '../feature-links/feature-links-read-model-type.js';
|
import type { IFeatureLink } from '../feature-links/feature-links-read-model-type.js';
|
||||||
import type { ResourceLimitsService } from '../resource-limits/resource-limits-service.js';
|
import type { ResourceLimitsService } from '../resource-limits/resource-limits-service.js';
|
||||||
|
import type { IReleasePlanReadModel } from '../release-plans/release-plan-read-model-type.js';
|
||||||
|
import type { ReleasePlan } from '../release-plans/release-plan.js';
|
||||||
interface IFeatureContext {
|
interface IFeatureContext {
|
||||||
featureName: string;
|
featureName: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
@ -177,6 +180,7 @@ export type ServicesAndReadModels = {
|
|||||||
featureLinkService: FeatureLinkService;
|
featureLinkService: FeatureLinkService;
|
||||||
featureLinksReadModel: IFeatureLinksReadModel;
|
featureLinksReadModel: IFeatureLinksReadModel;
|
||||||
resourceLimitsService: ResourceLimitsService;
|
resourceLimitsService: ResourceLimitsService;
|
||||||
|
releasePlanReadModel: IReleasePlanReadModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FeatureToggleService {
|
export class FeatureToggleService {
|
||||||
@ -226,6 +230,8 @@ export class FeatureToggleService {
|
|||||||
|
|
||||||
private resourceLimitsService: ResourceLimitsService;
|
private resourceLimitsService: ResourceLimitsService;
|
||||||
|
|
||||||
|
private releasePlanReadModel: IReleasePlanReadModel;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{
|
{
|
||||||
featureStrategiesStore,
|
featureStrategiesStore,
|
||||||
@ -251,6 +257,7 @@ export class FeatureToggleService {
|
|||||||
featureLinksReadModel,
|
featureLinksReadModel,
|
||||||
featureLinkService,
|
featureLinkService,
|
||||||
resourceLimitsService,
|
resourceLimitsService,
|
||||||
|
releasePlanReadModel,
|
||||||
}: ServicesAndReadModels,
|
}: ServicesAndReadModels,
|
||||||
) {
|
) {
|
||||||
this.logger = getLogger('services/feature-toggle-service.ts');
|
this.logger = getLogger('services/feature-toggle-service.ts');
|
||||||
@ -276,6 +283,7 @@ export class FeatureToggleService {
|
|||||||
this.featureLinkService = featureLinkService;
|
this.featureLinkService = featureLinkService;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.resourceLimitsService = resourceLimitsService;
|
this.resourceLimitsService = resourceLimitsService;
|
||||||
|
this.releasePlanReadModel = releasePlanReadModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateFeaturesContext(
|
async validateFeaturesContext(
|
||||||
@ -1151,8 +1159,16 @@ export class FeatureToggleService {
|
|||||||
userId,
|
userId,
|
||||||
archived,
|
archived,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const environmentsWithReleasePlans =
|
||||||
|
await this.addReleasePlansToEnvironments(
|
||||||
|
featureName,
|
||||||
|
result.environments,
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...result,
|
...result,
|
||||||
|
environments: environmentsWithReleasePlans,
|
||||||
dependencies,
|
dependencies,
|
||||||
children,
|
children,
|
||||||
lifecycle,
|
lifecycle,
|
||||||
@ -1171,8 +1187,15 @@ export class FeatureToggleService {
|
|||||||
archived,
|
archived,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const environmentsWithReleasePlans =
|
||||||
|
await this.addReleasePlansToEnvironments(
|
||||||
|
featureName,
|
||||||
|
result.environments,
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...result,
|
...result,
|
||||||
|
environments: environmentsWithReleasePlans,
|
||||||
dependencies,
|
dependencies,
|
||||||
children,
|
children,
|
||||||
lifecycle,
|
lifecycle,
|
||||||
@ -1182,6 +1205,27 @@ export class FeatureToggleService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async addReleasePlansToEnvironments(
|
||||||
|
featureName: string,
|
||||||
|
environments: IEnvironmentDetail[],
|
||||||
|
): Promise<(IEnvironmentDetail & { releasePlans?: ReleasePlan[] })[]> {
|
||||||
|
if (!this.flagResolver.isEnabled('milestoneProgression')) {
|
||||||
|
return environments;
|
||||||
|
}
|
||||||
|
|
||||||
|
const environmentNames = environments.map((env) => env.name);
|
||||||
|
const releasePlansByEnvironment =
|
||||||
|
await this.releasePlanReadModel.getReleasePlans(
|
||||||
|
featureName,
|
||||||
|
environmentNames,
|
||||||
|
);
|
||||||
|
|
||||||
|
return environments.map((env) => ({
|
||||||
|
...env,
|
||||||
|
releasePlans: releasePlansByEnvironment[env.name] || [],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
async getVariantsForEnv(
|
async getVariantsForEnv(
|
||||||
featureName: string,
|
featureName: string,
|
||||||
environment: string,
|
environment: string,
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
import type { ReleasePlan } from './release-plan.js';
|
||||||
|
|
||||||
|
export interface IReleasePlanReadModel {
|
||||||
|
getReleasePlans(
|
||||||
|
featureName: string,
|
||||||
|
environments: string[],
|
||||||
|
): Promise<Record<string, ReleasePlan[]>>;
|
||||||
|
}
|
||||||
184
src/lib/features/release-plans/release-plan-read-model.ts
Normal file
184
src/lib/features/release-plans/release-plan-read-model.ts
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
import type { Db } from '../../db/db.js';
|
||||||
|
import type { IReleasePlanReadModel } from './release-plan-read-model-type.js';
|
||||||
|
import type { ReleasePlan } from './release-plan.js';
|
||||||
|
|
||||||
|
const TABLE = 'release_plan_definitions';
|
||||||
|
|
||||||
|
const selectColumns = [
|
||||||
|
'rpd.id AS planId',
|
||||||
|
'rpd.discriminator AS planDiscriminator',
|
||||||
|
'rpd.name AS planName',
|
||||||
|
'rpd.description as planDescription',
|
||||||
|
'rpd.feature_name as planFeatureName',
|
||||||
|
'rpd.environment as planEnvironment',
|
||||||
|
'rpd.created_by_user_id as planCreatedByUserId',
|
||||||
|
'rpd.created_at as planCreatedAt',
|
||||||
|
'rpd.active_milestone_id as planActiveMilestoneId',
|
||||||
|
'rpd.release_plan_template_id as planTemplateId',
|
||||||
|
'mi.id AS milestoneId',
|
||||||
|
'mi.name AS milestoneName',
|
||||||
|
'mi.sort_order AS milestoneSortOrder',
|
||||||
|
'ms.id AS strategyId',
|
||||||
|
'ms.sort_order AS strategySortOrder',
|
||||||
|
'ms.title AS strategyTitle',
|
||||||
|
'ms.strategy_name AS strategyName',
|
||||||
|
'ms.parameters AS strategyParameters',
|
||||||
|
'ms.constraints AS strategyConstraints',
|
||||||
|
'ms.variants AS strategyVariants',
|
||||||
|
'mss.segment_id AS segmentId',
|
||||||
|
];
|
||||||
|
|
||||||
|
const processReleasePlanRows = (templateRows): ReleasePlan[] =>
|
||||||
|
templateRows.reduce(
|
||||||
|
(
|
||||||
|
acc: ReleasePlan[],
|
||||||
|
{
|
||||||
|
planId,
|
||||||
|
planDiscriminator,
|
||||||
|
planName,
|
||||||
|
planDescription,
|
||||||
|
planFeatureName,
|
||||||
|
planEnvironment,
|
||||||
|
planCreatedByUserId,
|
||||||
|
planCreatedAt,
|
||||||
|
planActiveMilestoneId,
|
||||||
|
planTemplateId,
|
||||||
|
milestoneId,
|
||||||
|
milestoneName,
|
||||||
|
milestoneSortOrder,
|
||||||
|
strategyId,
|
||||||
|
strategySortOrder,
|
||||||
|
strategyTitle,
|
||||||
|
strategyName,
|
||||||
|
strategyParameters,
|
||||||
|
strategyConstraints,
|
||||||
|
strategyVariants,
|
||||||
|
segmentId,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
let plan = acc.find(({ id }) => id === planId);
|
||||||
|
|
||||||
|
if (!plan) {
|
||||||
|
plan = {
|
||||||
|
id: planId,
|
||||||
|
discriminator: planDiscriminator,
|
||||||
|
name: planName,
|
||||||
|
description: planDescription,
|
||||||
|
featureName: planFeatureName,
|
||||||
|
environment: planEnvironment,
|
||||||
|
createdByUserId: planCreatedByUserId,
|
||||||
|
createdAt: planCreatedAt,
|
||||||
|
activeMilestoneId: planActiveMilestoneId,
|
||||||
|
releasePlanTemplateId: planTemplateId,
|
||||||
|
milestones: [],
|
||||||
|
};
|
||||||
|
acc.push(plan);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!milestoneId) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
let milestone = plan.milestones.find(
|
||||||
|
({ id }) => id === milestoneId,
|
||||||
|
);
|
||||||
|
if (!milestone) {
|
||||||
|
milestone = {
|
||||||
|
id: milestoneId,
|
||||||
|
name: milestoneName,
|
||||||
|
sortOrder: milestoneSortOrder,
|
||||||
|
strategies: [],
|
||||||
|
releasePlanDefinitionId: planId,
|
||||||
|
};
|
||||||
|
plan.milestones.push(milestone);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strategyId) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
let strategy = milestone.strategies?.find(
|
||||||
|
({ id }) => id === strategyId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!strategy) {
|
||||||
|
strategy = {
|
||||||
|
id: strategyId,
|
||||||
|
milestoneId: milestoneId,
|
||||||
|
sortOrder: strategySortOrder,
|
||||||
|
title: strategyTitle,
|
||||||
|
strategyName: strategyName,
|
||||||
|
parameters: strategyParameters ?? {},
|
||||||
|
constraints: strategyConstraints,
|
||||||
|
variants: strategyVariants ?? [],
|
||||||
|
segments: [],
|
||||||
|
};
|
||||||
|
milestone.strategies = [
|
||||||
|
...(milestone.strategies || []),
|
||||||
|
strategy,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (segmentId) {
|
||||||
|
strategy.segments = [...(strategy.segments || []), segmentId];
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
export class ReleasePlanReadModel implements IReleasePlanReadModel {
|
||||||
|
private db: Db;
|
||||||
|
|
||||||
|
constructor(db: Db) {
|
||||||
|
this.db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getReleasePlans(
|
||||||
|
featureName: string,
|
||||||
|
environments: string[],
|
||||||
|
): Promise<Record<string, ReleasePlan[]>> {
|
||||||
|
if (environments.length === 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const planRows = await this.db(`${TABLE} AS rpd`)
|
||||||
|
.where('rpd.discriminator', 'plan')
|
||||||
|
.andWhere('rpd.feature_name', featureName)
|
||||||
|
.whereIn('rpd.environment', environments)
|
||||||
|
.leftJoin(
|
||||||
|
'milestones AS mi',
|
||||||
|
'mi.release_plan_definition_id',
|
||||||
|
'rpd.id',
|
||||||
|
)
|
||||||
|
.leftJoin('milestone_strategies AS ms', 'ms.milestone_id', 'mi.id')
|
||||||
|
.leftJoin(
|
||||||
|
'milestone_strategy_segments AS mss',
|
||||||
|
'mss.milestone_strategy_id',
|
||||||
|
'ms.id',
|
||||||
|
)
|
||||||
|
.orderBy('rpd.environment', 'asc')
|
||||||
|
.orderBy('mi.sort_order', 'asc')
|
||||||
|
.orderBy('ms.sort_order', 'asc')
|
||||||
|
.select(selectColumns);
|
||||||
|
|
||||||
|
const allPlans = processReleasePlanRows(planRows);
|
||||||
|
|
||||||
|
const plansByEnvironment: Record<string, ReleasePlan[]> = {};
|
||||||
|
for (const plan of allPlans) {
|
||||||
|
if (!plansByEnvironment[plan.environment]) {
|
||||||
|
plansByEnvironment[plan.environment] = [];
|
||||||
|
}
|
||||||
|
plansByEnvironment[plan.environment].push(plan);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const env of environments) {
|
||||||
|
if (!plansByEnvironment[env]) {
|
||||||
|
plansByEnvironment[env] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return plansByEnvironment;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -252,6 +252,10 @@ export class ReleasePlanStore extends CRUDStore<
|
|||||||
}
|
}
|
||||||
return releasePlans[0];
|
return releasePlans[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// should be deprecated soon in favor of IReleasePlanReadModel.getReleasePlans
|
||||||
|
// this will remove read model responsibility from the store
|
||||||
|
// also we're moving release plans to feature environments (DB join) instead of separate API calls (browser join)
|
||||||
async getByFeatureFlagAndEnvironment(
|
async getByFeatureFlagAndEnvironment(
|
||||||
featureName: string,
|
featureName: string,
|
||||||
environment: string,
|
environment: string,
|
||||||
|
|||||||
@ -13,6 +13,11 @@ import { constraintSchema } from './constraint-schema.js';
|
|||||||
import { tagTypeSchema } from './tag-type-schema.js';
|
import { tagTypeSchema } from './tag-type-schema.js';
|
||||||
import { strategyVariantSchema } from './strategy-variant-schema.js';
|
import { strategyVariantSchema } from './strategy-variant-schema.js';
|
||||||
import { featureDependenciesSchema } from './feature-dependencies-schema.js';
|
import { featureDependenciesSchema } from './feature-dependencies-schema.js';
|
||||||
|
import { releasePlanSchema } from './release-plan-schema.js';
|
||||||
|
import { releasePlanMilestoneSchema } from './release-plan-milestone-schema.js';
|
||||||
|
import { releasePlanMilestoneStrategySchema } from './release-plan-milestone-strategy-schema.js';
|
||||||
|
import { createFeatureStrategySchema } from './create-feature-strategy-schema.js';
|
||||||
|
import { createStrategyVariantSchema } from './create-strategy-variant-schema.js';
|
||||||
import { dependentFeatureSchema } from './dependent-feature-schema.js';
|
import { dependentFeatureSchema } from './dependent-feature-schema.js';
|
||||||
import { tagSchema } from './tag-schema.js';
|
import { tagSchema } from './tag-schema.js';
|
||||||
import { featureLinksSchema } from './feature-links-schema.js';
|
import { featureLinksSchema } from './feature-links-schema.js';
|
||||||
@ -207,6 +212,11 @@ export const exportResultSchema = {
|
|||||||
tagSchema,
|
tagSchema,
|
||||||
featureLinksSchema,
|
featureLinksSchema,
|
||||||
featureLinkSchema,
|
featureLinkSchema,
|
||||||
|
releasePlanSchema,
|
||||||
|
releasePlanMilestoneSchema,
|
||||||
|
releasePlanMilestoneStrategySchema,
|
||||||
|
createFeatureStrategySchema,
|
||||||
|
createStrategyVariantSchema,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@ -4,6 +4,11 @@ import { parametersSchema } from './parameters-schema.js';
|
|||||||
import { featureStrategySchema } from './feature-strategy-schema.js';
|
import { featureStrategySchema } from './feature-strategy-schema.js';
|
||||||
import { variantSchema } from './variant-schema.js';
|
import { variantSchema } from './variant-schema.js';
|
||||||
import { strategyVariantSchema } from './strategy-variant-schema.js';
|
import { strategyVariantSchema } from './strategy-variant-schema.js';
|
||||||
|
import { releasePlanSchema } from './release-plan-schema.js';
|
||||||
|
import { releasePlanMilestoneSchema } from './release-plan-milestone-schema.js';
|
||||||
|
import { releasePlanMilestoneStrategySchema } from './release-plan-milestone-strategy-schema.js';
|
||||||
|
import { createFeatureStrategySchema } from './create-feature-strategy-schema.js';
|
||||||
|
import { createStrategyVariantSchema } from './create-strategy-variant-schema.js';
|
||||||
|
|
||||||
export const featureEnvironmentSchema = {
|
export const featureEnvironmentSchema = {
|
||||||
$id: '#/components/schemas/featureEnvironmentSchema',
|
$id: '#/components/schemas/featureEnvironmentSchema',
|
||||||
@ -106,6 +111,14 @@ export const featureEnvironmentSchema = {
|
|||||||
description:
|
description:
|
||||||
'Whether the feature has any enabled strategies defined.',
|
'Whether the feature has any enabled strategies defined.',
|
||||||
},
|
},
|
||||||
|
releasePlans: {
|
||||||
|
type: 'array',
|
||||||
|
description:
|
||||||
|
'Release plans for this feature environment (only available when milestoneProgression feature flag is enabled)',
|
||||||
|
items: {
|
||||||
|
$ref: '#/components/schemas/releasePlanSchema',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
schemas: {
|
schemas: {
|
||||||
@ -114,6 +127,11 @@ export const featureEnvironmentSchema = {
|
|||||||
featureStrategySchema,
|
featureStrategySchema,
|
||||||
strategyVariantSchema,
|
strategyVariantSchema,
|
||||||
variantSchema,
|
variantSchema,
|
||||||
|
releasePlanSchema,
|
||||||
|
releasePlanMilestoneSchema,
|
||||||
|
releasePlanMilestoneStrategySchema,
|
||||||
|
createFeatureStrategySchema,
|
||||||
|
createStrategyVariantSchema,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@ -7,6 +7,11 @@ import { featureStrategySchema } from './feature-strategy-schema.js';
|
|||||||
import { tagSchema } from './tag-schema.js';
|
import { tagSchema } from './tag-schema.js';
|
||||||
import { featureEnvironmentSchema } from './feature-environment-schema.js';
|
import { featureEnvironmentSchema } from './feature-environment-schema.js';
|
||||||
import { strategyVariantSchema } from './strategy-variant-schema.js';
|
import { strategyVariantSchema } from './strategy-variant-schema.js';
|
||||||
|
import { releasePlanSchema } from './release-plan-schema.js';
|
||||||
|
import { releasePlanMilestoneSchema } from './release-plan-milestone-schema.js';
|
||||||
|
import { releasePlanMilestoneStrategySchema } from './release-plan-milestone-strategy-schema.js';
|
||||||
|
import { createFeatureStrategySchema } from './create-feature-strategy-schema.js';
|
||||||
|
import { createStrategyVariantSchema } from './create-strategy-variant-schema.js';
|
||||||
|
|
||||||
export const featureSchema = {
|
export const featureSchema = {
|
||||||
$id: '#/components/schemas/featureSchema',
|
$id: '#/components/schemas/featureSchema',
|
||||||
@ -288,6 +293,11 @@ export const featureSchema = {
|
|||||||
parametersSchema,
|
parametersSchema,
|
||||||
variantSchema,
|
variantSchema,
|
||||||
tagSchema,
|
tagSchema,
|
||||||
|
releasePlanSchema,
|
||||||
|
releasePlanMilestoneSchema,
|
||||||
|
releasePlanMilestoneStrategySchema,
|
||||||
|
createFeatureStrategySchema,
|
||||||
|
createStrategyVariantSchema,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@ -5,6 +5,11 @@ import { featureStrategySchema } from './feature-strategy-schema.js';
|
|||||||
import { variantSchema } from './variant-schema.js';
|
import { variantSchema } from './variant-schema.js';
|
||||||
import { strategyVariantSchema } from './strategy-variant-schema.js';
|
import { strategyVariantSchema } from './strategy-variant-schema.js';
|
||||||
import { featureEnvironmentSchema } from './feature-environment-schema.js';
|
import { featureEnvironmentSchema } from './feature-environment-schema.js';
|
||||||
|
import { releasePlanSchema } from './release-plan-schema.js';
|
||||||
|
import { releasePlanMilestoneSchema } from './release-plan-milestone-schema.js';
|
||||||
|
import { releasePlanMilestoneStrategySchema } from './release-plan-milestone-strategy-schema.js';
|
||||||
|
import { createFeatureStrategySchema } from './create-feature-strategy-schema.js';
|
||||||
|
import { createStrategyVariantSchema } from './create-strategy-variant-schema.js';
|
||||||
|
|
||||||
export const featureSearchEnvironmentSchema = {
|
export const featureSearchEnvironmentSchema = {
|
||||||
$id: '#/components/schemas/featureSearchEnvironmentSchema',
|
$id: '#/components/schemas/featureSearchEnvironmentSchema',
|
||||||
@ -37,6 +42,11 @@ export const featureSearchEnvironmentSchema = {
|
|||||||
strategyVariantSchema,
|
strategyVariantSchema,
|
||||||
featureEnvironmentSchema,
|
featureEnvironmentSchema,
|
||||||
variantSchema,
|
variantSchema,
|
||||||
|
releasePlanSchema,
|
||||||
|
releasePlanMilestoneSchema,
|
||||||
|
releasePlanMilestoneStrategySchema,
|
||||||
|
createFeatureStrategySchema,
|
||||||
|
createStrategyVariantSchema,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@ -10,6 +10,9 @@ import { featureEnvironmentSchema } from './feature-environment-schema.js';
|
|||||||
import { projectStatsSchema } from './project-stats-schema.js';
|
import { projectStatsSchema } from './project-stats-schema.js';
|
||||||
import { createFeatureStrategySchema } from './create-feature-strategy-schema.js';
|
import { createFeatureStrategySchema } from './create-feature-strategy-schema.js';
|
||||||
import { projectEnvironmentSchema } from './project-environment-schema.js';
|
import { projectEnvironmentSchema } from './project-environment-schema.js';
|
||||||
|
import { releasePlanSchema } from './release-plan-schema.js';
|
||||||
|
import { releasePlanMilestoneSchema } from './release-plan-milestone-schema.js';
|
||||||
|
import { releasePlanMilestoneStrategySchema } from './release-plan-milestone-strategy-schema.js';
|
||||||
import { createStrategyVariantSchema } from './create-strategy-variant-schema.js';
|
import { createStrategyVariantSchema } from './create-strategy-variant-schema.js';
|
||||||
import { strategyVariantSchema } from './strategy-variant-schema.js';
|
import { strategyVariantSchema } from './strategy-variant-schema.js';
|
||||||
import { createFeatureNamingPatternSchema } from './create-feature-naming-pattern-schema.js';
|
import { createFeatureNamingPatternSchema } from './create-feature-naming-pattern-schema.js';
|
||||||
@ -144,6 +147,9 @@ export const healthOverviewSchema = {
|
|||||||
overrideSchema,
|
overrideSchema,
|
||||||
parametersSchema,
|
parametersSchema,
|
||||||
featureStrategySchema,
|
featureStrategySchema,
|
||||||
|
releasePlanSchema,
|
||||||
|
releasePlanMilestoneSchema,
|
||||||
|
releasePlanMilestoneStrategySchema,
|
||||||
strategyVariantSchema,
|
strategyVariantSchema,
|
||||||
variantSchema,
|
variantSchema,
|
||||||
projectStatsSchema,
|
projectStatsSchema,
|
||||||
|
|||||||
@ -13,6 +13,11 @@ import { parametersSchema } from './parameters-schema.js';
|
|||||||
import { legalValueSchema } from './legal-value-schema.js';
|
import { legalValueSchema } from './legal-value-schema.js';
|
||||||
import { tagTypeSchema } from './tag-type-schema.js';
|
import { tagTypeSchema } from './tag-type-schema.js';
|
||||||
import { featureEnvironmentSchema } from './feature-environment-schema.js';
|
import { featureEnvironmentSchema } from './feature-environment-schema.js';
|
||||||
|
import { releasePlanSchema } from './release-plan-schema.js';
|
||||||
|
import { releasePlanMilestoneSchema } from './release-plan-milestone-schema.js';
|
||||||
|
import { releasePlanMilestoneStrategySchema } from './release-plan-milestone-strategy-schema.js';
|
||||||
|
import { createFeatureStrategySchema } from './create-feature-strategy-schema.js';
|
||||||
|
import { createStrategyVariantSchema } from './create-strategy-variant-schema.js';
|
||||||
import { strategyVariantSchema } from './strategy-variant-schema.js';
|
import { strategyVariantSchema } from './strategy-variant-schema.js';
|
||||||
import { featureDependenciesSchema } from './feature-dependencies-schema.js';
|
import { featureDependenciesSchema } from './feature-dependencies-schema.js';
|
||||||
import { dependentFeatureSchema } from './dependent-feature-schema.js';
|
import { dependentFeatureSchema } from './dependent-feature-schema.js';
|
||||||
@ -53,6 +58,11 @@ export const importTogglesSchema = {
|
|||||||
contextFieldSchema,
|
contextFieldSchema,
|
||||||
featureTagSchema,
|
featureTagSchema,
|
||||||
segmentSchema,
|
segmentSchema,
|
||||||
|
releasePlanSchema,
|
||||||
|
releasePlanMilestoneSchema,
|
||||||
|
releasePlanMilestoneStrategySchema,
|
||||||
|
createFeatureStrategySchema,
|
||||||
|
createStrategyVariantSchema,
|
||||||
variantsSchema,
|
variantsSchema,
|
||||||
variantSchema,
|
variantSchema,
|
||||||
overrideSchema,
|
overrideSchema,
|
||||||
|
|||||||
@ -15,6 +15,9 @@ import { strategyVariantSchema } from './strategy-variant-schema.js';
|
|||||||
import { createFeatureNamingPatternSchema } from './create-feature-naming-pattern-schema.js';
|
import { createFeatureNamingPatternSchema } from './create-feature-naming-pattern-schema.js';
|
||||||
import { featureTypeCountSchema } from './feature-type-count-schema.js';
|
import { featureTypeCountSchema } from './feature-type-count-schema.js';
|
||||||
import { projectLinkTemplateSchema } from './project-link-template-schema.js';
|
import { projectLinkTemplateSchema } from './project-link-template-schema.js';
|
||||||
|
import { releasePlanSchema } from './release-plan-schema.js';
|
||||||
|
import { releasePlanMilestoneSchema } from './release-plan-milestone-schema.js';
|
||||||
|
import { releasePlanMilestoneStrategySchema } from './release-plan-milestone-strategy-schema.js';
|
||||||
|
|
||||||
export const projectOverviewSchema = {
|
export const projectOverviewSchema = {
|
||||||
$id: '#/components/schemas/projectOverviewSchema',
|
$id: '#/components/schemas/projectOverviewSchema',
|
||||||
@ -202,6 +205,9 @@ export const projectOverviewSchema = {
|
|||||||
featureStrategySchema,
|
featureStrategySchema,
|
||||||
strategyVariantSchema,
|
strategyVariantSchema,
|
||||||
variantSchema,
|
variantSchema,
|
||||||
|
releasePlanSchema,
|
||||||
|
releasePlanMilestoneSchema,
|
||||||
|
releasePlanMilestoneStrategySchema,
|
||||||
projectStatsSchema,
|
projectStatsSchema,
|
||||||
createFeatureNamingPatternSchema,
|
createFeatureNamingPatternSchema,
|
||||||
featureTypeCountSchema,
|
featureTypeCountSchema,
|
||||||
|
|||||||
17
src/test/fixtures/fake/fake-release-plan-read-model.ts
vendored
Normal file
17
src/test/fixtures/fake/fake-release-plan-read-model.ts
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import type { IReleasePlanReadModel } from '../../../lib/features/release-plans/release-plan-read-model-type.js';
|
||||||
|
import type { ReleasePlan } from '../../../lib/features/release-plans/release-plan.js';
|
||||||
|
|
||||||
|
export class FakeReleasePlanReadModel implements IReleasePlanReadModel {
|
||||||
|
private releasePlans: Record<string, ReleasePlan[]>;
|
||||||
|
|
||||||
|
constructor(releasePlans: Record<string, ReleasePlan[]> = {}) {
|
||||||
|
this.releasePlans = releasePlans;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getReleasePlans(
|
||||||
|
_featureName: string,
|
||||||
|
_environments: string[],
|
||||||
|
): Promise<Record<string, ReleasePlan[]>> {
|
||||||
|
return this.releasePlans;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user