codify-plugin-lib 1.0.81 → 1.0.82
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/change-set.js +1 -10
- package/dist/plan/plan.js +15 -2
- package/dist/resource/parsed-resource-settings.d.ts +0 -1
- package/dist/resource/parsed-resource-settings.js +2 -12
- package/dist/resource/resource-settings.d.ts +1 -1
- package/dist/resource/resource-settings.js +11 -2
- package/package.json +2 -2
- package/src/plan/change-set.test.ts +83 -23
- package/src/plan/change-set.ts +2 -12
- package/src/plan/plan.ts +19 -4
- package/src/resource/parsed-resource-settings.ts +2 -22
- package/src/resource/resource-settings.ts +15 -2
- package/src/resource/stateful-parameter.test.ts +50 -3
package/dist/plan/change-set.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ParameterOperation, ResourceOperation } from 'codify-schemas';
|
|
2
|
-
import { areArraysEqual } from '../utils/utils.js';
|
|
3
2
|
// Change set will coerce undefined values to null because undefined is not valid JSON
|
|
4
3
|
export class ChangeSet {
|
|
5
4
|
operation;
|
|
@@ -139,14 +138,6 @@ export class ChangeSet {
|
|
|
139
138
|
return orderOfOperations[Math.max(indexPrev, indexNext)];
|
|
140
139
|
}
|
|
141
140
|
static isSame(desired, current, setting) {
|
|
142
|
-
|
|
143
|
-
case 'array': {
|
|
144
|
-
const arrayParameter = setting;
|
|
145
|
-
return areArraysEqual(arrayParameter, desired, current);
|
|
146
|
-
}
|
|
147
|
-
default: {
|
|
148
|
-
return (setting?.isEqual ?? ((a, b) => a === b))(desired, current);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
141
|
+
return (setting?.isEqual ?? ((a, b) => a === b))(desired, current);
|
|
151
142
|
}
|
|
152
143
|
}
|
package/dist/plan/plan.js
CHANGED
|
@@ -148,13 +148,26 @@ export class Plan {
|
|
|
148
148
|
&& settings.parameterSettings[k].definition.getSettings().type === 'array'
|
|
149
149
|
&& Array.isArray(v);
|
|
150
150
|
}
|
|
151
|
+
// For stateless mode, we must filter the current array so that the diff algorithm will not detect any deletes
|
|
151
152
|
function filterArrayStatefulParameter(k, v) {
|
|
152
153
|
const desiredArray = desired[k];
|
|
153
154
|
const matcher = settings.parameterSettings[k]
|
|
154
155
|
.definition
|
|
155
156
|
.getSettings()
|
|
156
|
-
.isElementEqual;
|
|
157
|
-
|
|
157
|
+
.isElementEqual ?? ((a, b) => a === b);
|
|
158
|
+
const desiredCopy = [...desiredArray];
|
|
159
|
+
const currentCopy = [...v];
|
|
160
|
+
const result = [];
|
|
161
|
+
for (let counter = desiredCopy.length - 1; counter >= 0; counter--) {
|
|
162
|
+
const idx = currentCopy.findIndex((e2) => matcher(desiredCopy[counter], e2));
|
|
163
|
+
if (idx === -1) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
desiredCopy.splice(counter, 1);
|
|
167
|
+
const [element] = currentCopy.splice(idx, 1);
|
|
168
|
+
result.push(element);
|
|
169
|
+
}
|
|
170
|
+
return result;
|
|
158
171
|
}
|
|
159
172
|
}
|
|
160
173
|
// TODO: This needs to be revisited. I don't think this is valid anymore.
|
|
@@ -21,6 +21,5 @@ export declare class ParsedResourceSettings<T extends StringIndexedObject> imple
|
|
|
21
21
|
get statefulParameterOrder(): Map<keyof T, number>;
|
|
22
22
|
private validateSettings;
|
|
23
23
|
private validateParameterEqualsFn;
|
|
24
|
-
private resolveEqualsFn;
|
|
25
24
|
private getFromCacheOrCreate;
|
|
26
25
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ParameterEqualsDefaults } from './resource-settings.js';
|
|
1
|
+
import { resolveEqualsFn } from './resource-settings.js';
|
|
3
2
|
export class ParsedResourceSettings {
|
|
4
3
|
cache = new Map();
|
|
5
4
|
id;
|
|
@@ -35,7 +34,7 @@ export class ParsedResourceSettings {
|
|
|
35
34
|
const settings = Object.entries(this.settings.parameterSettings ?? {})
|
|
36
35
|
.map(([k, v]) => [k, v])
|
|
37
36
|
.map(([k, v]) => {
|
|
38
|
-
v.isEqual =
|
|
37
|
+
v.isEqual = resolveEqualsFn(v, k);
|
|
39
38
|
return [k, v];
|
|
40
39
|
});
|
|
41
40
|
return Object.fromEntries(settings);
|
|
@@ -106,15 +105,6 @@ export class ParsedResourceSettings {
|
|
|
106
105
|
}
|
|
107
106
|
// The rest of the types have defaults set already
|
|
108
107
|
}
|
|
109
|
-
resolveEqualsFn(parameter, key) {
|
|
110
|
-
if (parameter.type === 'array') {
|
|
111
|
-
return parameter.isEqual ?? areArraysEqual.bind(areArraysEqual, parameter);
|
|
112
|
-
}
|
|
113
|
-
if (parameter.type === 'stateful') {
|
|
114
|
-
return this.resolveEqualsFn(parameter.definition.getSettings(), key);
|
|
115
|
-
}
|
|
116
|
-
return parameter.isEqual ?? ParameterEqualsDefaults[parameter.type] ?? (((a, b) => a === b));
|
|
117
|
-
}
|
|
118
108
|
getFromCacheOrCreate(key, create) {
|
|
119
109
|
if (this.cache.has(key)) {
|
|
120
110
|
return this.cache.get(key);
|
|
@@ -146,4 +146,4 @@ export interface StatefulParameterSetting extends DefaultParameterSetting {
|
|
|
146
146
|
*/
|
|
147
147
|
order?: number;
|
|
148
148
|
}
|
|
149
|
-
export declare
|
|
149
|
+
export declare function resolveEqualsFn(parameter: ParameterSetting, key: string): (desired: unknown, current: unknown) => boolean;
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { untildify } from '../utils/utils.js';
|
|
3
|
-
|
|
2
|
+
import { areArraysEqual, untildify } from '../utils/utils.js';
|
|
3
|
+
const ParameterEqualsDefaults = {
|
|
4
4
|
'boolean': (a, b) => Boolean(a) === Boolean(b),
|
|
5
5
|
'directory': (a, b) => path.resolve(untildify(String(a))) === path.resolve(untildify(String(b))),
|
|
6
6
|
'number': (a, b) => Number(a) === Number(b),
|
|
7
7
|
'string': (a, b) => String(a) === String(b),
|
|
8
8
|
'version': (desired, current) => String(current).includes(String(desired))
|
|
9
9
|
};
|
|
10
|
+
export function resolveEqualsFn(parameter, key) {
|
|
11
|
+
if (parameter.type === 'array') {
|
|
12
|
+
return parameter.isEqual ?? areArraysEqual.bind(areArraysEqual, parameter);
|
|
13
|
+
}
|
|
14
|
+
if (parameter.type === 'stateful') {
|
|
15
|
+
return resolveEqualsFn(parameter.definition.getSettings(), key);
|
|
16
|
+
}
|
|
17
|
+
return parameter.isEqual ?? ParameterEqualsDefaults[parameter.type] ?? (((a, b) => a === b));
|
|
18
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codify-plugin-lib",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.82",
|
|
4
4
|
"description": "Library plugin library",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@oclif/prettier-config": "^0.2.1",
|
|
23
23
|
"@oclif/test": "^3",
|
|
24
24
|
"@types/npmcli__promise-spawn": "^6.0.3",
|
|
25
|
-
"@types/node": "^
|
|
25
|
+
"@types/node": "^20",
|
|
26
26
|
"@types/semver": "^7.5.4",
|
|
27
27
|
"@types/sinon": "^17.0.3",
|
|
28
28
|
"@types/uuid": "^10.0.0",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ChangeSet } from './change-set.js';
|
|
2
2
|
import { ParameterOperation, ResourceOperation } from 'codify-schemas';
|
|
3
3
|
import { describe, expect, it } from 'vitest';
|
|
4
|
+
import { ParsedResourceSettings } from '../resource/parsed-resource-settings.js';
|
|
4
5
|
|
|
5
6
|
describe('Change set tests', () => {
|
|
6
7
|
it ('Correctly diffs two resource configs (modify)', () => {
|
|
@@ -31,7 +32,7 @@ describe('Change set tests', () => {
|
|
|
31
32
|
propA: 'after',
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
const cs = ChangeSet.calculateModification(after, before
|
|
35
|
+
const cs = ChangeSet.calculateModification(after, before);
|
|
35
36
|
expect(cs.parameterChanges.length).to.eq(2);
|
|
36
37
|
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
37
38
|
expect(cs.parameterChanges[1].operation).to.eq(ParameterOperation.ADD);
|
|
@@ -104,7 +105,14 @@ describe('Change set tests', () => {
|
|
|
104
105
|
propA: ['b', 'a', 'c'],
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
const
|
|
108
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
109
|
+
id: 'type',
|
|
110
|
+
parameterSettings: {
|
|
111
|
+
propA: { type: 'array' }
|
|
112
|
+
}
|
|
113
|
+
}).parameterSettings
|
|
114
|
+
|
|
115
|
+
const cs = ChangeSet.calculateModification(after, before, parameterSettings);
|
|
108
116
|
expect(cs.parameterChanges.length).to.eq(1);
|
|
109
117
|
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.NOOP);
|
|
110
118
|
expect(cs.operation).to.eq(ResourceOperation.NOOP)
|
|
@@ -119,7 +127,14 @@ describe('Change set tests', () => {
|
|
|
119
127
|
propA: ['b', 'a'],
|
|
120
128
|
}
|
|
121
129
|
|
|
122
|
-
const
|
|
130
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
131
|
+
id: 'type',
|
|
132
|
+
parameterSettings: {
|
|
133
|
+
propA: { type: 'array' }
|
|
134
|
+
}
|
|
135
|
+
}).parameterSettings
|
|
136
|
+
|
|
137
|
+
const cs = ChangeSet.calculateModification(after, before, parameterSettings);
|
|
123
138
|
expect(cs.parameterChanges.length).to.eq(1);
|
|
124
139
|
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
125
140
|
expect(cs.operation).to.eq(ResourceOperation.RECREATE)
|
|
@@ -135,7 +150,14 @@ describe('Change set tests', () => {
|
|
|
135
150
|
propB: 'before'
|
|
136
151
|
}
|
|
137
152
|
|
|
138
|
-
const
|
|
153
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
154
|
+
id: 'type',
|
|
155
|
+
parameterSettings: {
|
|
156
|
+
propA: { canModify: true }
|
|
157
|
+
}
|
|
158
|
+
}).parameterSettings
|
|
159
|
+
|
|
160
|
+
const cs = ChangeSet.calculateModification(after, before, parameterSettings);
|
|
139
161
|
expect(cs.parameterChanges.length).to.eq(2);
|
|
140
162
|
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
141
163
|
expect(cs.parameterChanges[1].operation).to.eq(ParameterOperation.REMOVE);
|
|
@@ -152,10 +174,15 @@ describe('Change set tests', () => {
|
|
|
152
174
|
propB: 'before'
|
|
153
175
|
}
|
|
154
176
|
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
177
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
178
|
+
id: 'type',
|
|
179
|
+
parameterSettings: {
|
|
180
|
+
propA: { canModify: true },
|
|
181
|
+
propB: { canModify: true }
|
|
182
|
+
},
|
|
183
|
+
}).parameterSettings
|
|
184
|
+
|
|
185
|
+
const cs = ChangeSet.calculateModification<any>(after, before, parameterSettings);
|
|
159
186
|
expect(cs.parameterChanges.length).to.eq(2);
|
|
160
187
|
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
161
188
|
expect(cs.parameterChanges[1].operation).to.eq(ParameterOperation.REMOVE);
|
|
@@ -167,7 +194,15 @@ describe('Change set tests', () => {
|
|
|
167
194
|
const arrA = ['a', 'b', 'd'];
|
|
168
195
|
const arrB = ['a', 'b', 'd'];
|
|
169
196
|
|
|
170
|
-
const
|
|
197
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
198
|
+
id: 'type',
|
|
199
|
+
parameterSettings: {
|
|
200
|
+
propA: { type: 'array' }
|
|
201
|
+
},
|
|
202
|
+
}).parameterSettings
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
const result = ChangeSet.calculateModification({ propA: arrA }, { propA: arrB }, parameterSettings)
|
|
171
206
|
|
|
172
207
|
expect(result.operation).to.eq(ResourceOperation.NOOP);
|
|
173
208
|
})
|
|
@@ -176,7 +211,14 @@ describe('Change set tests', () => {
|
|
|
176
211
|
const arrA = ['a', 'b'];
|
|
177
212
|
const arrB = ['a', 'b', 'd'];
|
|
178
213
|
|
|
179
|
-
const
|
|
214
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
215
|
+
id: 'type',
|
|
216
|
+
parameterSettings: {
|
|
217
|
+
propA: { type: 'array' }
|
|
218
|
+
},
|
|
219
|
+
}).parameterSettings
|
|
220
|
+
|
|
221
|
+
const result = ChangeSet.calculateModification({ propA: arrA }, { propA: arrB }, parameterSettings)
|
|
180
222
|
|
|
181
223
|
expect(result.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
182
224
|
})
|
|
@@ -185,7 +227,14 @@ describe('Change set tests', () => {
|
|
|
185
227
|
const arrA = ['b', 'a', 'd'];
|
|
186
228
|
const arrB = ['a', 'b', 'd'];
|
|
187
229
|
|
|
188
|
-
const
|
|
230
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
231
|
+
id: 'type',
|
|
232
|
+
parameterSettings: {
|
|
233
|
+
propA: { type: 'array' }
|
|
234
|
+
},
|
|
235
|
+
}).parameterSettings
|
|
236
|
+
|
|
237
|
+
const result = ChangeSet.calculateModification({ propA: arrA }, { propA: arrB }, parameterSettings)
|
|
189
238
|
|
|
190
239
|
expect(result.parameterChanges[0].operation).to.eq(ParameterOperation.NOOP);
|
|
191
240
|
})
|
|
@@ -194,12 +243,18 @@ describe('Change set tests', () => {
|
|
|
194
243
|
const arrA = [{ key1: 'a' }, { key1: 'a' }, { key1: 'a' }];
|
|
195
244
|
const arrB = [{ key1: 'a' }, { key1: 'a' }, { key1: 'b' }];
|
|
196
245
|
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
246
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
247
|
+
id: 'type',
|
|
248
|
+
parameterSettings: {
|
|
249
|
+
propA: {
|
|
250
|
+
type: 'array',
|
|
251
|
+
isElementEqual: (a, b) => a.key1 === b.key1
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
}).parameterSettings
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
const result = ChangeSet.calculateModification({ propA: arrA }, { propA: arrB }, parameterSettings)
|
|
203
258
|
|
|
204
259
|
expect(result.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
205
260
|
})
|
|
@@ -208,12 +263,17 @@ describe('Change set tests', () => {
|
|
|
208
263
|
const arrA = [{ key1: 'b' }, { key1: 'a' }, { key1: 'a' }];
|
|
209
264
|
const arrB = [{ key1: 'a' }, { key1: 'a' }, { key1: 'b' }];
|
|
210
265
|
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
266
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
267
|
+
id: 'type',
|
|
268
|
+
parameterSettings: {
|
|
269
|
+
propA: {
|
|
270
|
+
type: 'array',
|
|
271
|
+
isElementEqual: (a, b) => a.key1 === b.key1
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
}).parameterSettings
|
|
275
|
+
|
|
276
|
+
const result = ChangeSet.calculateModification({ propA: arrA }, { propA: arrB }, parameterSettings)
|
|
217
277
|
|
|
218
278
|
expect(result.parameterChanges[0].operation).to.eq(ParameterOperation.NOOP);
|
|
219
279
|
})
|
package/src/plan/change-set.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ParameterOperation, ResourceOperation, StringIndexedObject } from 'codify-schemas';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { areArraysEqual } from '../utils/utils.js';
|
|
3
|
+
import { ParameterSetting } from '../resource/resource-settings.js';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* A parameter change describes a parameter level change to a resource.
|
|
@@ -215,15 +214,6 @@ export class ChangeSet<T extends StringIndexedObject> {
|
|
|
215
214
|
current: unknown,
|
|
216
215
|
setting?: ParameterSetting,
|
|
217
216
|
): boolean {
|
|
218
|
-
|
|
219
|
-
case 'array': {
|
|
220
|
-
const arrayParameter = setting as ArrayParameterSetting;
|
|
221
|
-
return areArraysEqual(arrayParameter, desired, current)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
default: {
|
|
225
|
-
return (setting?.isEqual ?? ((a, b) => a === b))(desired, current)
|
|
226
|
-
}
|
|
227
|
-
}
|
|
217
|
+
return (setting?.isEqual ?? ((a, b) => a === b))(desired, current)
|
|
228
218
|
}
|
|
229
219
|
}
|
package/src/plan/plan.ts
CHANGED
|
@@ -253,16 +253,31 @@ export class Plan<T extends StringIndexedObject> {
|
|
|
253
253
|
&& Array.isArray(v)
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
// For stateless mode, we must filter the current array so that the diff algorithm will not detect any deletes
|
|
256
257
|
function filterArrayStatefulParameter(k: string, v: unknown[]): unknown[] {
|
|
257
258
|
const desiredArray = desired![k] as unknown[];
|
|
258
259
|
const matcher = ((settings.parameterSettings![k] as StatefulParameterSetting)
|
|
259
260
|
.definition
|
|
260
261
|
.getSettings() as ArrayParameterSetting)
|
|
261
|
-
.isElementEqual;
|
|
262
|
+
.isElementEqual ?? ((a, b) => a === b);
|
|
262
263
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
264
|
+
const desiredCopy = [...desiredArray];
|
|
265
|
+
const currentCopy = [...v];
|
|
266
|
+
const result = [];
|
|
267
|
+
|
|
268
|
+
for (let counter = desiredCopy.length - 1; counter >= 0; counter--) {
|
|
269
|
+
const idx = currentCopy.findIndex((e2) => matcher(desiredCopy[counter], e2))
|
|
270
|
+
|
|
271
|
+
if (idx === -1) {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
desiredCopy.splice(counter, 1)
|
|
276
|
+
const [element] = currentCopy.splice(idx, 1)
|
|
277
|
+
result.push(element)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return result;
|
|
266
281
|
}
|
|
267
282
|
}
|
|
268
283
|
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import { StringIndexedObject } from 'codify-schemas';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
ArrayParameterSetting,
|
|
6
|
-
ParameterEqualsDefaults,
|
|
7
|
-
ParameterSetting,
|
|
8
|
-
ParameterSettingType,
|
|
9
|
-
ResourceSettings,
|
|
10
|
-
StatefulParameterSetting
|
|
11
|
-
} from './resource-settings.js';
|
|
3
|
+
import { ParameterSetting, resolveEqualsFn, ResourceSettings, StatefulParameterSetting } from './resource-settings.js';
|
|
12
4
|
import { StatefulParameter as StatefulParameterImpl } from './stateful-parameter.js'
|
|
13
5
|
|
|
14
6
|
export class ParsedResourceSettings<T extends StringIndexedObject> implements ResourceSettings<T> {
|
|
@@ -54,7 +46,7 @@ export class ParsedResourceSettings<T extends StringIndexedObject> implements Re
|
|
|
54
46
|
const settings = Object.entries(this.settings.parameterSettings ?? {})
|
|
55
47
|
.map(([k, v]) => [k, v!] as const)
|
|
56
48
|
.map(([k, v]) => {
|
|
57
|
-
v.isEqual =
|
|
49
|
+
v.isEqual = resolveEqualsFn(v, k);
|
|
58
50
|
|
|
59
51
|
return [k, v];
|
|
60
52
|
})
|
|
@@ -154,18 +146,6 @@ export class ParsedResourceSettings<T extends StringIndexedObject> implements Re
|
|
|
154
146
|
// The rest of the types have defaults set already
|
|
155
147
|
}
|
|
156
148
|
|
|
157
|
-
private resolveEqualsFn(parameter: ParameterSetting, key: string): (desired: unknown, current: unknown) => boolean {
|
|
158
|
-
if (parameter.type === 'array') {
|
|
159
|
-
return parameter.isEqual ?? areArraysEqual.bind(areArraysEqual, parameter as ArrayParameterSetting)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (parameter.type === 'stateful') {
|
|
163
|
-
return this.resolveEqualsFn((parameter as StatefulParameterSetting).definition.getSettings(), key)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return parameter.isEqual ?? ParameterEqualsDefaults[parameter.type as ParameterSettingType] ?? (((a, b) => a === b));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
149
|
private getFromCacheOrCreate<T2>(key: string, create: () => T2): T2 {
|
|
170
150
|
if (this.cache.has(key)) {
|
|
171
151
|
return this.cache.get(key) as T2
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { StringIndexedObject } from 'codify-schemas';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
-
import { untildify } from '../utils/utils.js';
|
|
4
|
+
import { areArraysEqual, untildify } from '../utils/utils.js';
|
|
5
5
|
import { StatefulParameter } from './stateful-parameter.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -183,10 +183,23 @@ export interface StatefulParameterSetting extends DefaultParameterSetting {
|
|
|
183
183
|
order?: number,
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
|
|
186
|
+
const ParameterEqualsDefaults: Partial<Record<ParameterSettingType, (a: unknown, b: unknown) => boolean>> = {
|
|
187
187
|
'boolean': (a: unknown, b: unknown) => Boolean(a) === Boolean(b),
|
|
188
188
|
'directory': (a: unknown, b: unknown) => path.resolve(untildify(String(a))) === path.resolve(untildify(String(b))),
|
|
189
189
|
'number': (a: unknown, b: unknown) => Number(a) === Number(b),
|
|
190
190
|
'string': (a: unknown, b: unknown) => String(a) === String(b),
|
|
191
191
|
'version': (desired: unknown, current: unknown) => String(current).includes(String(desired))
|
|
192
192
|
}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
export function resolveEqualsFn(parameter: ParameterSetting, key: string): (desired: unknown, current: unknown) => boolean {
|
|
196
|
+
if (parameter.type === 'array') {
|
|
197
|
+
return parameter.isEqual ?? areArraysEqual.bind(areArraysEqual, parameter as ArrayParameterSetting)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (parameter.type === 'stateful') {
|
|
201
|
+
return resolveEqualsFn((parameter as StatefulParameterSetting).definition.getSettings(), key)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return parameter.isEqual ?? ParameterEqualsDefaults[parameter.type as ParameterSettingType] ?? (((a, b) => a === b));
|
|
205
|
+
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import { spy } from 'sinon';
|
|
3
3
|
import { ParameterOperation, ResourceOperation } from 'codify-schemas';
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
TestArrayStatefulParameter,
|
|
6
|
+
TestConfig,
|
|
7
|
+
testPlan,
|
|
8
|
+
TestResource,
|
|
9
|
+
TestStatefulParameter
|
|
10
|
+
} from '../utils/test-utils.test.js';
|
|
11
|
+
import { ArrayParameterSetting, ParameterSetting, ResourceSettings } from './resource-settings.js';
|
|
12
|
+
import { ResourceController } from './resource-controller.js';
|
|
6
13
|
|
|
7
14
|
describe('Stateful parameter tests', () => {
|
|
8
15
|
it('addItem is called the correct number of times', async () => {
|
|
@@ -49,7 +56,7 @@ describe('Stateful parameter tests', () => {
|
|
|
49
56
|
expect(plan.changeSet.operation).to.eq(ResourceOperation.MODIFY);
|
|
50
57
|
expect(plan.changeSet.parameterChanges[0]).toMatchObject({
|
|
51
58
|
name: 'propZ',
|
|
52
|
-
previousValue: ['
|
|
59
|
+
previousValue: ['c', 'a'], // In stateless mode the previous value gets filtered to prevent deletes
|
|
53
60
|
newValue: ['a', 'c', 'd', 'e', 'f'],
|
|
54
61
|
operation: ParameterOperation.MODIFY,
|
|
55
62
|
})
|
|
@@ -108,4 +115,44 @@ describe('Stateful parameter tests', () => {
|
|
|
108
115
|
|
|
109
116
|
expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
|
|
110
117
|
})
|
|
118
|
+
|
|
119
|
+
it('isElementEquals test', async () => {
|
|
120
|
+
const testParameter = spy(new class extends TestArrayStatefulParameter {
|
|
121
|
+
getSettings(): ArrayParameterSetting {
|
|
122
|
+
return {
|
|
123
|
+
type: 'array',
|
|
124
|
+
isElementEqual: (desired, current) => current.includes(desired),
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async refresh(): Promise<any> {
|
|
129
|
+
return [
|
|
130
|
+
'20.15.0',
|
|
131
|
+
'20.15.1'
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const resource = new class extends TestResource {
|
|
137
|
+
getSettings(): ResourceSettings<any> {
|
|
138
|
+
return {
|
|
139
|
+
id: 'type',
|
|
140
|
+
parameterSettings: { nodeVersions: { type: 'stateful', definition: testParameter } }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async refresh(): Promise<Partial<any> | null> {
|
|
145
|
+
return {};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const controller = new ResourceController(resource);
|
|
150
|
+
const plan = await controller.plan({
|
|
151
|
+
nodeVersions: ['20.15'],
|
|
152
|
+
} as any)
|
|
153
|
+
|
|
154
|
+
console.log(JSON.stringify(plan, null, 2))
|
|
155
|
+
|
|
156
|
+
expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
|
|
157
|
+
})
|
|
111
158
|
})
|