@@ -18,6 +18,7 @@ import { updateLambdaDeployment, uploadLambdaArtifact } from "./deployments/lamb
1818import { updateDeploymentParameters } from "./deployments/update-parameters" ;
1919import { groupByClassName , groupByRegion , groupByStackTag , groupByStageTag } from "./group-by" ;
2020import type {
21+ ClassName ,
2122 Region ,
2223 RiffRaffDeployment ,
2324 RiffRaffDeploymentName ,
@@ -47,100 +48,11 @@ function getGuStackDependencies(cdkStack: GuStack): GuStack[] {
4748 return cdkStack . dependencies . filter ( ( _ ) => _ instanceof GuStack ) as GuStack [ ] ;
4849}
4950
50- /**
51- * Checks if a list of {@link GuStack} includes a stack with expected `stack` and `stage` properties.
52- */
53- function isCdkStackPresent ( stacks : GuStack [ ] , expectedStack : StackTag , expectedStage : StageTag ) : boolean {
54- const matches = stacks . find ( ( cdkStack ) => {
55- const { stack, stage } = cdkStack ;
56- return stack === expectedStack && stage === expectedStage ;
57- } ) ;
58-
59- return ! ! matches ;
60- }
61-
62- /**
63- * Check there are the appropriate number of `GuStack`s.
64- * Expect to find an instance for each combination of `stack`, and `stage`.
65- *
66- * If not valid, a message is logged describing what is missing to aid debugging.
67- *
68- * Given the following:
69- *
70- * ```ts
71- * const app = new App();
72- *
73- * class MyApplicationStack extends GuStack { }
74- *
75- * new MyApplicationStack(app, "App-CODE-deploy", {
76- * env: {
77- * region: "eu-west-1",
78- * },
79- * stack: "deploy",
80- * stage: "CODE"
81- * });
82- *
83- * new MyApplicationStack(app, "App-PROD-media-service", {
84- * env: {
85- * region: "eu-west-1",
86- * },
87- * stack: "media-service",
88- * stage: "PROD",
89- * });
90- *
91- * new MyApplicationStack(app, "App-PROD-deploy", {
92- * env: {
93- * region: "eu-west-1",
94- * },
95- * stack: "deploy",
96- * stage: "PROD"
97- * });
98- * ```
99- *
100- * This will log a message like this, where ❌ denotes something missing,
101- * specifically there is no `CODE` template for `media-service`.
102- *
103- * ```log
104- * Unable to produce a working riff-raff.yaml file; missing 1 definitions (details below)
105- *
106- * ┌───────────────┬──────┬──────┐
107- * │ (index) │ CODE │ PROD │
108- * ├───────────────┼──────┼──────┤
109- * │ deploy │ '✅' │ '✅' │
110- * │ media-service │ '❌' │ '✅' │
111- * └───────────────┴──────┴──────┘
112- * ```
113- *
114- */
115- function validateStacksInApp ( stacks : GuStack [ ] , allStackTags : StackTag [ ] , allStageTags : StageTag [ ] ) : void {
116- type Found = "✅" ;
117- type NotFound = "❌" ;
118- type AppValidation = Record < StackTag , Record < StageTag , Found | NotFound > > ;
119-
120- const checks : AppValidation = allStackTags . reduce ( ( accStackTag , stackTag ) => {
121- return {
122- ...accStackTag ,
123- [ stackTag ] : allStageTags . reduce ( ( accStageTag , stageTag ) => {
124- return {
125- ...accStageTag ,
126- [ stageTag ] : isCdkStackPresent ( stacks , stackTag , stageTag ) ? "✅" : "❌" ,
127- } ;
128- } , { } ) ,
129- } ;
130- } , { } ) ;
131-
132- const missingDefinitions : Array < Found | NotFound > = Object . values ( checks ) . flatMap ( ( groupedByStackTag ) => {
133- return Object . values ( groupedByStackTag ) . filter ( ( _ ) => _ === "❌" ) ;
134- } ) ;
135-
136- if ( missingDefinitions . length > 0 ) {
137- const message = `Unable to produce a working riff-raff.yaml file; missing ${ missingDefinitions . length } definitions` ;
138-
139- console . log ( `${ message } (details below)` ) ;
140- console . table ( checks ) ;
141-
142- throw new Error ( message ) ;
143- }
51+ interface MissingStack {
52+ className : ClassName ;
53+ stack : StackTag ;
54+ stage : StageTag ;
55+ region : Region ;
14456}
14557
14658/**
@@ -206,22 +118,28 @@ export class RiffRaffYamlFile {
206118 constructor ( app : App ) {
207119 const allCdkStacks = app . node . findAll ( ) . filter ( ( _ ) => _ instanceof GuStack ) as GuStack [ ] ;
208120 const allowedStages = new Set ( allCdkStacks . map ( ( _ ) => _ . stage ) ) ;
209- const allStageTags = Array . from ( allowedStages ) ;
210- const allStackTags = Array . from ( new Set ( allCdkStacks . map ( ( _ ) => _ . stack ) ) ) ;
211121 const allRegions = Array . from ( new Set ( allCdkStacks . map ( ( _ ) => _ . region ) ) ) ;
212122
213- validateStacksInApp ( allCdkStacks , allStackTags , allStageTags ) ;
214123 validateAllRegionsAreResolved ( allRegions ) ;
215124
216125 this . outdir = app . outdir ;
217126
218127 const deployments = new Map < RiffRaffDeploymentName , RiffRaffDeploymentProps > ( ) ;
219128
220- Object . values ( groupByClassName ( allCdkStacks ) ) . forEach ( ( stacksGroupedByClassName ) => {
221- Object . values ( groupByStackTag ( stacksGroupedByClassName ) ) . forEach ( ( stacksGroupedByStackTag ) => {
222- Object . values ( groupByRegion ( stacksGroupedByStackTag ) ) . forEach ( ( stacksGroupedByRegion ) => {
129+ const missingStacks : MissingStack [ ] = [ ] ;
130+ const requiredStages = Array . from ( allowedStages ) ;
131+
132+ Object . entries ( groupByClassName ( allCdkStacks ) ) . forEach ( ( [ className , stacksGroupedByClassName ] ) => {
133+ Object . entries ( groupByStackTag ( stacksGroupedByClassName ) ) . forEach ( ( [ stackTag , stacksGroupedByStackTag ] ) => {
134+ Object . entries ( groupByRegion ( stacksGroupedByStackTag ) ) . forEach ( ( [ region , stacksGroupedByRegion ] ) => {
223135 const stacks : GuStack [ ] = Object . values ( groupByStageTag ( stacksGroupedByRegion ) ) . flat ( ) ;
224136
137+ requiredStages . forEach ( ( requiredStage ) => {
138+ if ( ! stacks . find ( ( { stage } ) => stage === requiredStage ) ) {
139+ missingStacks . push ( { className, region, stack : stackTag , stage : requiredStage } ) ;
140+ }
141+ } ) ;
142+
225143 // The items in `stacks` only differ by stage, so we can just use the first item in the list.
226144 const [ stack ] = stacks ;
227145
@@ -306,6 +224,14 @@ export class RiffRaffYamlFile {
306224 } ) ;
307225 } ) ;
308226
227+ if ( missingStacks . length > 0 ) {
228+ const message = `Unable to produce a working riff-raff.yaml file; missing ${ missingStacks . length } definitions` ;
229+ console . log ( `${ message } (details below)` ) ;
230+ console . table ( missingStacks ) ;
231+
232+ throw new Error ( message ) ;
233+ }
234+
309235 this . riffRaffYaml = {
310236 allowedStages,
311237 deployments,
0 commit comments