codify-plugin-lib 1.0.182-beta70 → 1.0.182-beta71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/plan/plan.js +40 -4
- package/package.json +1 -1
- package/src/plan/plan.test.ts +46 -0
- package/src/plan/plan.ts +56 -5
package/dist/plan/plan.js
CHANGED
|
@@ -199,16 +199,22 @@ export class Plan {
|
|
|
199
199
|
console.log('Before exit', isStateful, desired);
|
|
200
200
|
// For stateful mode, we're done after filtering by the keys of desired + state. Stateless mode
|
|
201
201
|
// requires additional filtering for stateful parameter arrays and objects.
|
|
202
|
-
// We also want to filter parameters when in delete mode. We don't want to delete parameters that
|
|
203
|
-
// are not specified in the original config.
|
|
204
202
|
if (isStateful && desired) {
|
|
205
203
|
return filteredCurrent;
|
|
206
204
|
}
|
|
205
|
+
// We also want to filter parameters when in delete mode. We don't want to delete parameters that
|
|
206
|
+
// are not specified in the original config.
|
|
207
|
+
if (isStateful && !desired) {
|
|
208
|
+
const arrayStatefulParameters = Object.fromEntries(Object.entries(filteredCurrent)
|
|
209
|
+
.filter(([k, v]) => isArrayParameterWithFiltering(k, v))
|
|
210
|
+
.map(([k, v]) => [k, filterArrayParameterForDeletes(k, v)]));
|
|
211
|
+
return { ...filteredCurrent, ...arrayStatefulParameters };
|
|
212
|
+
}
|
|
207
213
|
console.log('Post exit', isStateful, desired);
|
|
208
214
|
// TODO: Add object handling here in addition to arrays in the future
|
|
209
215
|
const arrayStatefulParameters = Object.fromEntries(Object.entries(filteredCurrent)
|
|
210
216
|
.filter(([k, v]) => isArrayParameterWithFiltering(k, v))
|
|
211
|
-
.map(([k, v]) => [k,
|
|
217
|
+
.map(([k, v]) => [k, filterArrayParameterForStatelessMode(k, v)]));
|
|
212
218
|
console.log('Result', { ...filteredCurrent, ...arrayStatefulParameters });
|
|
213
219
|
return { ...filteredCurrent, ...arrayStatefulParameters };
|
|
214
220
|
function filterCurrent() {
|
|
@@ -250,7 +256,8 @@ export class Plan {
|
|
|
250
256
|
&& Array.isArray(v);
|
|
251
257
|
}
|
|
252
258
|
// For stateless mode, we must filter the current array so that the diff algorithm will not detect any deletes
|
|
253
|
-
function
|
|
259
|
+
function filterArrayParameterForStatelessMode(k, v) {
|
|
260
|
+
console.log('Attempting to filter (key, value)', k, v);
|
|
254
261
|
const desiredArray = desired[k];
|
|
255
262
|
const matcher = settings.parameterSettings[k].type === 'stateful'
|
|
256
263
|
? settings.parameterSettings[k]
|
|
@@ -278,6 +285,35 @@ export class Plan {
|
|
|
278
285
|
? filterParameter(desiredCopy, currentCopy)
|
|
279
286
|
: defaultFilterMethod(desiredCopy, currentCopy);
|
|
280
287
|
}
|
|
288
|
+
function filterArrayParameterForDeletes(k, v) {
|
|
289
|
+
console.log('Attempting to filter (key, value)', k, v);
|
|
290
|
+
const stateArray = state[k];
|
|
291
|
+
const matcher = settings.parameterSettings[k].type === 'stateful'
|
|
292
|
+
? settings.parameterSettings[k]
|
|
293
|
+
.nestedSettings
|
|
294
|
+
.isElementEqual
|
|
295
|
+
: settings.parameterSettings[k]
|
|
296
|
+
.isElementEqual;
|
|
297
|
+
const stateCopy = [...stateArray];
|
|
298
|
+
const currentCopy = [...v];
|
|
299
|
+
const defaultFilterMethod = ((state, current) => {
|
|
300
|
+
const result = [];
|
|
301
|
+
for (let counter = state.length - 1; counter >= 0; counter--) {
|
|
302
|
+
const idx = currentCopy.findIndex((e2) => matcher(state[counter], e2));
|
|
303
|
+
if (idx === -1) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
state.splice(counter, 1);
|
|
307
|
+
const [element] = current.splice(idx, 1);
|
|
308
|
+
result.push(element);
|
|
309
|
+
}
|
|
310
|
+
return result;
|
|
311
|
+
});
|
|
312
|
+
const filterParameter = getFilterParameter(k);
|
|
313
|
+
return typeof filterParameter === 'function'
|
|
314
|
+
? filterParameter(stateCopy, currentCopy)
|
|
315
|
+
: defaultFilterMethod(stateCopy, currentCopy);
|
|
316
|
+
}
|
|
281
317
|
}
|
|
282
318
|
// TODO: This needs to be revisited. I don't think this is valid anymore.
|
|
283
319
|
// 1. For all scenarios, there shouldn't be an apply without a plan beforehand
|
package/package.json
CHANGED
package/src/plan/plan.test.ts
CHANGED
|
@@ -180,6 +180,52 @@ describe('Plan entity tests', () => {
|
|
|
180
180
|
expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
|
|
181
181
|
})
|
|
182
182
|
|
|
183
|
+
it('Filters array parameters in delete mode (when desired is null)', async () => {
|
|
184
|
+
const resource = new class extends TestResource {
|
|
185
|
+
getSettings(): ResourceSettings<any> {
|
|
186
|
+
return {
|
|
187
|
+
id: 'type',
|
|
188
|
+
operatingSystems: [OS.Darwin],
|
|
189
|
+
parameterSettings: {
|
|
190
|
+
propZ: { type: 'array', isElementEqual: (a, b) => b.includes(a) }
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async refresh(): Promise<Partial<any> | null> {
|
|
196
|
+
return {
|
|
197
|
+
propZ: [
|
|
198
|
+
'20.15.0',
|
|
199
|
+
'20.15.1'
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const controller = new ResourceController(resource);
|
|
206
|
+
const plan = await controller.plan(
|
|
207
|
+
{ type: 'type' },
|
|
208
|
+
null,
|
|
209
|
+
{ propZ: ['20.15.0'], } as any,
|
|
210
|
+
true
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
console.log(JSON.stringify(plan, null, 2));
|
|
214
|
+
expect(plan).toMatchObject({
|
|
215
|
+
id: expect.any(String),
|
|
216
|
+
changeSet: expect.objectContaining({
|
|
217
|
+
operation: ResourceOperation.DESTROY,
|
|
218
|
+
parameterChanges: [
|
|
219
|
+
expect.objectContaining({ operation: 'remove', name: 'propZ', previousValue: ['20.15.0'], newValue: null }),
|
|
220
|
+
],
|
|
221
|
+
}),
|
|
222
|
+
coreParameters: expect.objectContaining({
|
|
223
|
+
type: 'type',
|
|
224
|
+
}),
|
|
225
|
+
isStateful: true,
|
|
226
|
+
})
|
|
227
|
+
})
|
|
228
|
+
|
|
183
229
|
it('Doesn\'t filters array parameters if filtering is disabled', async () => {
|
|
184
230
|
const resource = new class extends TestResource {
|
|
185
231
|
getSettings(): ResourceSettings<any> {
|
package/src/plan/plan.ts
CHANGED
|
@@ -330,19 +330,29 @@ export class Plan<T extends StringIndexedObject> {
|
|
|
330
330
|
|
|
331
331
|
// For stateful mode, we're done after filtering by the keys of desired + state. Stateless mode
|
|
332
332
|
// requires additional filtering for stateful parameter arrays and objects.
|
|
333
|
-
// We also want to filter parameters when in delete mode. We don't want to delete parameters that
|
|
334
|
-
// are not specified in the original config.
|
|
335
333
|
if (isStateful && desired) {
|
|
336
334
|
return filteredCurrent;
|
|
337
335
|
}
|
|
338
336
|
|
|
337
|
+
// We also want to filter parameters when in delete mode. We don't want to delete parameters that
|
|
338
|
+
// are not specified in the original config.
|
|
339
|
+
if (isStateful && !desired) {
|
|
340
|
+
const arrayStatefulParameters = Object.fromEntries(
|
|
341
|
+
Object.entries(filteredCurrent)
|
|
342
|
+
.filter(([k, v]) => isArrayParameterWithFiltering(k, v))
|
|
343
|
+
.map(([k, v]) => [k, filterArrayParameterForDeletes(k, v)])
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
return { ...filteredCurrent, ...arrayStatefulParameters }
|
|
347
|
+
}
|
|
348
|
+
|
|
339
349
|
console.log('Post exit', isStateful, desired);
|
|
340
350
|
|
|
341
351
|
// TODO: Add object handling here in addition to arrays in the future
|
|
342
352
|
const arrayStatefulParameters = Object.fromEntries(
|
|
343
353
|
Object.entries(filteredCurrent)
|
|
344
354
|
.filter(([k, v]) => isArrayParameterWithFiltering(k, v))
|
|
345
|
-
.map(([k, v]) => [k,
|
|
355
|
+
.map(([k, v]) => [k, filterArrayParameterForStatelessMode(k, v)])
|
|
346
356
|
)
|
|
347
357
|
|
|
348
358
|
console.log('Result', { ...filteredCurrent, ...arrayStatefulParameters });
|
|
@@ -388,7 +398,7 @@ export class Plan<T extends StringIndexedObject> {
|
|
|
388
398
|
|
|
389
399
|
function isArrayParameterWithFiltering(k: string, v: T[keyof T]): boolean {
|
|
390
400
|
const filterParameter = getFilterParameter(k);
|
|
391
|
-
|
|
401
|
+
|
|
392
402
|
if (settings.parameterSettings?.[k]?.type === 'stateful') {
|
|
393
403
|
const statefulSetting = settings.parameterSettings[k] as ParsedStatefulParameterSetting;
|
|
394
404
|
return statefulSetting.nestedSettings.type === 'array' &&
|
|
@@ -402,7 +412,9 @@ export class Plan<T extends StringIndexedObject> {
|
|
|
402
412
|
}
|
|
403
413
|
|
|
404
414
|
// For stateless mode, we must filter the current array so that the diff algorithm will not detect any deletes
|
|
405
|
-
function
|
|
415
|
+
function filterArrayParameterForStatelessMode(k: string, v: unknown[]): unknown[] {
|
|
416
|
+
console.log('Attempting to filter (key, value)', k, v);
|
|
417
|
+
|
|
406
418
|
const desiredArray = desired![k] as unknown[];
|
|
407
419
|
const matcher = settings.parameterSettings![k]!.type === 'stateful'
|
|
408
420
|
? ((settings.parameterSettings![k] as ParsedStatefulParameterSetting)
|
|
@@ -437,6 +449,45 @@ export class Plan<T extends StringIndexedObject> {
|
|
|
437
449
|
? filterParameter(desiredCopy, currentCopy)
|
|
438
450
|
: defaultFilterMethod(desiredCopy, currentCopy);
|
|
439
451
|
}
|
|
452
|
+
|
|
453
|
+
function filterArrayParameterForDeletes(k: string, v: unknown[]): unknown[] {
|
|
454
|
+
console.log('Attempting to filter (key, value)', k, v);
|
|
455
|
+
|
|
456
|
+
const stateArray = state![k] as unknown[];
|
|
457
|
+
const matcher = settings.parameterSettings![k]!.type === 'stateful'
|
|
458
|
+
? ((settings.parameterSettings![k] as ParsedStatefulParameterSetting)
|
|
459
|
+
.nestedSettings as ParsedArrayParameterSetting)
|
|
460
|
+
.isElementEqual
|
|
461
|
+
: (settings.parameterSettings![k] as ParsedArrayParameterSetting)
|
|
462
|
+
.isElementEqual
|
|
463
|
+
|
|
464
|
+
const stateCopy = [...stateArray];
|
|
465
|
+
const currentCopy = [...v];
|
|
466
|
+
|
|
467
|
+
const defaultFilterMethod = ((state: any[], current: any[]) => {
|
|
468
|
+
const result = [];
|
|
469
|
+
|
|
470
|
+
for (let counter = state.length - 1; counter >= 0; counter--) {
|
|
471
|
+
const idx = currentCopy.findIndex((e2) => matcher(state[counter], e2))
|
|
472
|
+
|
|
473
|
+
if (idx === -1) {
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
state.splice(counter, 1)
|
|
478
|
+
const [element] = current.splice(idx, 1)
|
|
479
|
+
result.push(element)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return result;
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
const filterParameter = getFilterParameter(k);
|
|
487
|
+
return typeof filterParameter === 'function'
|
|
488
|
+
? filterParameter(stateCopy, currentCopy)
|
|
489
|
+
: defaultFilterMethod(stateCopy, currentCopy);
|
|
490
|
+
}
|
|
440
491
|
}
|
|
441
492
|
|
|
442
493
|
// TODO: This needs to be revisited. I don't think this is valid anymore.
|