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, | ||||
| } from '../feature-links/createFeatureLinkService.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 = ( | ||||
|     db: Db, | ||||
| @ -141,6 +143,8 @@ export const createFeatureToggleService = ( | ||||
| 
 | ||||
|     const resourceLimitsService = new ResourceLimitsService(config); | ||||
| 
 | ||||
|     const releasePlanReadModel = new ReleasePlanReadModel(db); | ||||
| 
 | ||||
|     const featureToggleService = new FeatureToggleService( | ||||
|         { | ||||
|             featureStrategiesStore, | ||||
| @ -166,6 +170,7 @@ export const createFeatureToggleService = ( | ||||
|             featureLinksReadModel, | ||||
|             featureLinkService, | ||||
|             resourceLimitsService, | ||||
|             releasePlanReadModel, | ||||
|         }, | ||||
|     ); | ||||
|     return featureToggleService; | ||||
| @ -211,6 +216,7 @@ export const createFakeFeatureToggleService = (config: IUnleashConfig) => { | ||||
|     const { featureLinkService } = createFakeFeatureLinkService(config); | ||||
| 
 | ||||
|     const resourceLimitsService = new ResourceLimitsService(config); | ||||
|     const releasePlanReadModel = new FakeReleasePlanReadModel(); | ||||
| 
 | ||||
|     const featureToggleService = new FeatureToggleService( | ||||
|         { | ||||
| @ -241,6 +247,7 @@ export const createFakeFeatureToggleService = (config: IUnleashConfig) => { | ||||
|             featureLinksReadModel, | ||||
|             featureLinkService, | ||||
|             resourceLimitsService, | ||||
|             releasePlanReadModel, | ||||
|         }, | ||||
|     ); | ||||
|     return { | ||||
|  | ||||
| @ -19,6 +19,7 @@ import { | ||||
|     type IAuditUser, | ||||
|     type IConstraint, | ||||
|     type IDependency, | ||||
|     type IEnvironmentDetail, | ||||
|     type IFeatureCollaboratorsReadModel, | ||||
|     type IFeatureEnvironmentInfo, | ||||
|     type IFeatureEnvironmentStore, | ||||
| @ -117,6 +118,8 @@ import { sortStrategies } from '../../util/sortStrategies.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 { 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 { | ||||
|     featureName: string; | ||||
|     projectId: string; | ||||
| @ -177,6 +180,7 @@ export type ServicesAndReadModels = { | ||||
|     featureLinkService: FeatureLinkService; | ||||
|     featureLinksReadModel: IFeatureLinksReadModel; | ||||
|     resourceLimitsService: ResourceLimitsService; | ||||
|     releasePlanReadModel: IReleasePlanReadModel; | ||||
| }; | ||||
| 
 | ||||
| export class FeatureToggleService { | ||||
| @ -226,6 +230,8 @@ export class FeatureToggleService { | ||||
| 
 | ||||
|     private resourceLimitsService: ResourceLimitsService; | ||||
| 
 | ||||
|     private releasePlanReadModel: IReleasePlanReadModel; | ||||
| 
 | ||||
|     constructor( | ||||
|         { | ||||
|             featureStrategiesStore, | ||||
| @ -251,6 +257,7 @@ export class FeatureToggleService { | ||||
|             featureLinksReadModel, | ||||
|             featureLinkService, | ||||
|             resourceLimitsService, | ||||
|             releasePlanReadModel, | ||||
|         }: ServicesAndReadModels, | ||||
|     ) { | ||||
|         this.logger = getLogger('services/feature-toggle-service.ts'); | ||||
| @ -276,6 +283,7 @@ export class FeatureToggleService { | ||||
|         this.featureLinkService = featureLinkService; | ||||
|         this.eventBus = eventBus; | ||||
|         this.resourceLimitsService = resourceLimitsService; | ||||
|         this.releasePlanReadModel = releasePlanReadModel; | ||||
|     } | ||||
| 
 | ||||
|     async validateFeaturesContext( | ||||
| @ -1151,8 +1159,16 @@ export class FeatureToggleService { | ||||
|                     userId, | ||||
|                     archived, | ||||
|                 ); | ||||
| 
 | ||||
|             const environmentsWithReleasePlans = | ||||
|                 await this.addReleasePlansToEnvironments( | ||||
|                     featureName, | ||||
|                     result.environments, | ||||
|                 ); | ||||
| 
 | ||||
|             return { | ||||
|                 ...result, | ||||
|                 environments: environmentsWithReleasePlans, | ||||
|                 dependencies, | ||||
|                 children, | ||||
|                 lifecycle, | ||||
| @ -1171,8 +1187,15 @@ export class FeatureToggleService { | ||||
|                     archived, | ||||
|                 ); | ||||
| 
 | ||||
|             const environmentsWithReleasePlans = | ||||
|                 await this.addReleasePlansToEnvironments( | ||||
|                     featureName, | ||||
|                     result.environments, | ||||
|                 ); | ||||
| 
 | ||||
|             return { | ||||
|                 ...result, | ||||
|                 environments: environmentsWithReleasePlans, | ||||
|                 dependencies, | ||||
|                 children, | ||||
|                 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( | ||||
|         featureName: 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]; | ||||
|     } | ||||
| 
 | ||||
|     // 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( | ||||
|         featureName: string, | ||||
|         environment: string, | ||||
|  | ||||
| @ -13,6 +13,11 @@ import { constraintSchema } from './constraint-schema.js'; | ||||
| import { tagTypeSchema } from './tag-type-schema.js'; | ||||
| import { strategyVariantSchema } from './strategy-variant-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 { tagSchema } from './tag-schema.js'; | ||||
| import { featureLinksSchema } from './feature-links-schema.js'; | ||||
| @ -207,6 +212,11 @@ export const exportResultSchema = { | ||||
|             tagSchema, | ||||
|             featureLinksSchema, | ||||
|             featureLinkSchema, | ||||
|             releasePlanSchema, | ||||
|             releasePlanMilestoneSchema, | ||||
|             releasePlanMilestoneStrategySchema, | ||||
|             createFeatureStrategySchema, | ||||
|             createStrategyVariantSchema, | ||||
|         }, | ||||
|     }, | ||||
| } as const; | ||||
|  | ||||
| @ -4,6 +4,11 @@ import { parametersSchema } from './parameters-schema.js'; | ||||
| import { featureStrategySchema } from './feature-strategy-schema.js'; | ||||
| import { variantSchema } from './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 = { | ||||
|     $id: '#/components/schemas/featureEnvironmentSchema', | ||||
| @ -106,6 +111,14 @@ export const featureEnvironmentSchema = { | ||||
|             description: | ||||
|                 '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: { | ||||
|         schemas: { | ||||
| @ -114,6 +127,11 @@ export const featureEnvironmentSchema = { | ||||
|             featureStrategySchema, | ||||
|             strategyVariantSchema, | ||||
|             variantSchema, | ||||
|             releasePlanSchema, | ||||
|             releasePlanMilestoneSchema, | ||||
|             releasePlanMilestoneStrategySchema, | ||||
|             createFeatureStrategySchema, | ||||
|             createStrategyVariantSchema, | ||||
|         }, | ||||
|     }, | ||||
| } as const; | ||||
|  | ||||
| @ -7,6 +7,11 @@ import { featureStrategySchema } from './feature-strategy-schema.js'; | ||||
| import { tagSchema } from './tag-schema.js'; | ||||
| import { featureEnvironmentSchema } from './feature-environment-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 = { | ||||
|     $id: '#/components/schemas/featureSchema', | ||||
| @ -288,6 +293,11 @@ export const featureSchema = { | ||||
|             parametersSchema, | ||||
|             variantSchema, | ||||
|             tagSchema, | ||||
|             releasePlanSchema, | ||||
|             releasePlanMilestoneSchema, | ||||
|             releasePlanMilestoneStrategySchema, | ||||
|             createFeatureStrategySchema, | ||||
|             createStrategyVariantSchema, | ||||
|         }, | ||||
|     }, | ||||
| } as const; | ||||
|  | ||||
| @ -5,6 +5,11 @@ import { featureStrategySchema } from './feature-strategy-schema.js'; | ||||
| import { variantSchema } from './variant-schema.js'; | ||||
| import { strategyVariantSchema } from './strategy-variant-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 = { | ||||
|     $id: '#/components/schemas/featureSearchEnvironmentSchema', | ||||
| @ -37,6 +42,11 @@ export const featureSearchEnvironmentSchema = { | ||||
|             strategyVariantSchema, | ||||
|             featureEnvironmentSchema, | ||||
|             variantSchema, | ||||
|             releasePlanSchema, | ||||
|             releasePlanMilestoneSchema, | ||||
|             releasePlanMilestoneStrategySchema, | ||||
|             createFeatureStrategySchema, | ||||
|             createStrategyVariantSchema, | ||||
|         }, | ||||
|     }, | ||||
| } as const; | ||||
|  | ||||
| @ -10,6 +10,9 @@ import { featureEnvironmentSchema } from './feature-environment-schema.js'; | ||||
| import { projectStatsSchema } from './project-stats-schema.js'; | ||||
| import { createFeatureStrategySchema } from './create-feature-strategy-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 { strategyVariantSchema } from './strategy-variant-schema.js'; | ||||
| import { createFeatureNamingPatternSchema } from './create-feature-naming-pattern-schema.js'; | ||||
| @ -144,6 +147,9 @@ export const healthOverviewSchema = { | ||||
|             overrideSchema, | ||||
|             parametersSchema, | ||||
|             featureStrategySchema, | ||||
|             releasePlanSchema, | ||||
|             releasePlanMilestoneSchema, | ||||
|             releasePlanMilestoneStrategySchema, | ||||
|             strategyVariantSchema, | ||||
|             variantSchema, | ||||
|             projectStatsSchema, | ||||
|  | ||||
| @ -13,6 +13,11 @@ import { parametersSchema } from './parameters-schema.js'; | ||||
| import { legalValueSchema } from './legal-value-schema.js'; | ||||
| import { tagTypeSchema } from './tag-type-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 { featureDependenciesSchema } from './feature-dependencies-schema.js'; | ||||
| import { dependentFeatureSchema } from './dependent-feature-schema.js'; | ||||
| @ -53,6 +58,11 @@ export const importTogglesSchema = { | ||||
|             contextFieldSchema, | ||||
|             featureTagSchema, | ||||
|             segmentSchema, | ||||
|             releasePlanSchema, | ||||
|             releasePlanMilestoneSchema, | ||||
|             releasePlanMilestoneStrategySchema, | ||||
|             createFeatureStrategySchema, | ||||
|             createStrategyVariantSchema, | ||||
|             variantsSchema, | ||||
|             variantSchema, | ||||
|             overrideSchema, | ||||
|  | ||||
| @ -15,6 +15,9 @@ import { strategyVariantSchema } from './strategy-variant-schema.js'; | ||||
| import { createFeatureNamingPatternSchema } from './create-feature-naming-pattern-schema.js'; | ||||
| import { featureTypeCountSchema } from './feature-type-count-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 = { | ||||
|     $id: '#/components/schemas/projectOverviewSchema', | ||||
| @ -202,6 +205,9 @@ export const projectOverviewSchema = { | ||||
|             featureStrategySchema, | ||||
|             strategyVariantSchema, | ||||
|             variantSchema, | ||||
|             releasePlanSchema, | ||||
|             releasePlanMilestoneSchema, | ||||
|             releasePlanMilestoneStrategySchema, | ||||
|             projectStatsSchema, | ||||
|             createFeatureNamingPatternSchema, | ||||
|             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