codify-plugin-lib 1.0.129 → 1.0.130
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.d.ts +12 -12
- package/dist/plan/plan.js +52 -58
- package/dist/plugin/plugin.d.ts +2 -2
- package/dist/plugin/plugin.js +17 -14
- package/dist/resource/config-parser.d.ts +2 -5
- package/dist/resource/config-parser.js +1 -28
- package/dist/resource/resource-controller.d.ts +4 -4
- package/dist/resource/resource-controller.js +44 -46
- package/package.json +2 -2
- package/src/messages/handlers.test.ts +9 -3
- package/src/plan/plan.test.ts +16 -15
- package/src/plan/plan.ts +83 -89
- package/src/plugin/plugin.test.ts +2 -3
- package/src/plugin/plugin.ts +23 -15
- package/src/resource/config-parser.ts +6 -41
- package/src/resource/resource-controller-stateful-mode.test.ts +4 -4
- package/src/resource/resource-controller.test.ts +45 -30
- package/src/resource/resource-controller.ts +53 -53
- package/src/resource/resource-settings.test.ts +110 -80
- package/src/stateful-parameter/stateful-parameter-controller.test.ts +18 -9
- package/src/utils/test-utils.test.ts +4 -4
|
@@ -34,11 +34,14 @@ describe('Resource tests', () => {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
const controller = new ResourceController(resource);
|
|
37
|
-
await controller.validate(
|
|
38
|
-
type: 'type',
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
await controller.validate(
|
|
38
|
+
{ type: 'type' },
|
|
39
|
+
{
|
|
40
|
+
type: 'type',
|
|
41
|
+
propA: '~/.tool_versions',
|
|
42
|
+
propB: 10,
|
|
43
|
+
}
|
|
44
|
+
)
|
|
42
45
|
})
|
|
43
46
|
|
|
44
47
|
it('Plans successfully', async () => {
|
|
@@ -55,16 +58,17 @@ describe('Resource tests', () => {
|
|
|
55
58
|
const controller = new ResourceController(resource)
|
|
56
59
|
|
|
57
60
|
const resourceSpy = spy(controller);
|
|
58
|
-
const result = await resourceSpy.plan(
|
|
59
|
-
type: 'type',
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
const result = await resourceSpy.plan(
|
|
62
|
+
{ type: 'type', name: 'name' },
|
|
63
|
+
{
|
|
64
|
+
propA: 'propA',
|
|
65
|
+
propB: 10,
|
|
66
|
+
},
|
|
67
|
+
null,
|
|
68
|
+
false,
|
|
69
|
+
)
|
|
64
70
|
|
|
65
71
|
expect(result.desiredConfig).to.deep.eq({
|
|
66
|
-
type: 'type',
|
|
67
|
-
name: 'name',
|
|
68
72
|
propA: 'propA',
|
|
69
73
|
propB: 10,
|
|
70
74
|
});
|
|
@@ -92,15 +96,16 @@ describe('Resource tests', () => {
|
|
|
92
96
|
const controller = new ResourceController(resource);
|
|
93
97
|
|
|
94
98
|
const resourceSpy = spy(controller);
|
|
95
|
-
const result = await resourceSpy.plan(
|
|
96
|
-
type: 'type',
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
const result = await resourceSpy.plan(
|
|
100
|
+
{ type: 'type', name: 'name' },
|
|
101
|
+
{
|
|
102
|
+
propA: 'propA',
|
|
103
|
+
propB: 10,
|
|
104
|
+
propC: 'somethingAfter'
|
|
105
|
+
},
|
|
106
|
+
null,
|
|
107
|
+
false,
|
|
108
|
+
)
|
|
104
109
|
|
|
105
110
|
expect(result.changeSet.operation).to.eq(ResourceOperation.CREATE);
|
|
106
111
|
expect(result.changeSet.parameterChanges.length).to.eq(3);
|
|
@@ -115,7 +120,12 @@ describe('Resource tests', () => {
|
|
|
115
120
|
const controller = new ResourceController(resource);
|
|
116
121
|
|
|
117
122
|
const resourceSpy = spy(controller);
|
|
118
|
-
const result = await resourceSpy.plan(
|
|
123
|
+
const result = await resourceSpy.plan(
|
|
124
|
+
{ type: 'type' },
|
|
125
|
+
{},
|
|
126
|
+
null,
|
|
127
|
+
false
|
|
128
|
+
)
|
|
119
129
|
|
|
120
130
|
expect(result.changeSet.operation).to.eq(ResourceOperation.CREATE);
|
|
121
131
|
expect(result.changeSet.parameterChanges.length).to.eq(0);
|
|
@@ -195,7 +205,12 @@ describe('Resource tests', () => {
|
|
|
195
205
|
}
|
|
196
206
|
const controller = new ResourceController(resource);
|
|
197
207
|
|
|
198
|
-
const plan = await controller.plan(
|
|
208
|
+
const plan = await controller.plan(
|
|
209
|
+
{ type: 'resource' },
|
|
210
|
+
{ propA: 'a', propB: 0 },
|
|
211
|
+
null,
|
|
212
|
+
false,
|
|
213
|
+
)
|
|
199
214
|
|
|
200
215
|
const resourceSpy = spy(resource);
|
|
201
216
|
await controller.apply(
|
|
@@ -267,7 +282,7 @@ describe('Resource tests', () => {
|
|
|
267
282
|
}
|
|
268
283
|
const controller = new ResourceController(resource);
|
|
269
284
|
|
|
270
|
-
const plan = await controller.plan({ type: 'resource' })
|
|
285
|
+
const plan = await controller.plan({ type: 'resource' }, {}, null, false)
|
|
271
286
|
expect(plan.currentConfig?.propA).to.eq('propAAfter');
|
|
272
287
|
expect(plan.desiredConfig?.propA).to.eq('propADefault');
|
|
273
288
|
expect(plan.changeSet.operation).to.eq(ResourceOperation.RECREATE);
|
|
@@ -294,7 +309,7 @@ describe('Resource tests', () => {
|
|
|
294
309
|
}
|
|
295
310
|
const controller = new ResourceController(resource);
|
|
296
311
|
|
|
297
|
-
const plan = await controller.plan({ type: 'resource' })
|
|
312
|
+
const plan = await controller.plan({ type: 'resource' }, {}, null, false)
|
|
298
313
|
expect(plan.currentConfig?.propE).to.eq('propEDefault');
|
|
299
314
|
expect(plan.desiredConfig?.propE).to.eq('propEDefault');
|
|
300
315
|
expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
|
|
@@ -317,7 +332,7 @@ describe('Resource tests', () => {
|
|
|
317
332
|
}
|
|
318
333
|
const controller = new ResourceController(resource);
|
|
319
334
|
|
|
320
|
-
const plan = await controller.plan({ type: 'resource' })
|
|
335
|
+
const plan = await controller.plan({ type: 'resource' }, {}, null, false)
|
|
321
336
|
expect(plan.currentConfig).to.be.null
|
|
322
337
|
expect(plan.desiredConfig!.propE).to.eq('propEDefault');
|
|
323
338
|
expect(plan.changeSet.operation).to.eq(ResourceOperation.CREATE);
|
|
@@ -345,7 +360,7 @@ describe('Resource tests', () => {
|
|
|
345
360
|
}
|
|
346
361
|
const controller = new ResourceController(resource);
|
|
347
362
|
|
|
348
|
-
const plan = await controller.plan({ type: 'resource', propA: 'propA' })
|
|
363
|
+
const plan = await controller.plan({ type: 'resource' }, { propA: 'propA' }, null, false)
|
|
349
364
|
expect(plan.currentConfig?.propA).to.eq('propAAfter');
|
|
350
365
|
expect(plan.desiredConfig?.propA).to.eq('propA');
|
|
351
366
|
expect(plan.changeSet.operation).to.eq(ResourceOperation.RECREATE);
|
|
@@ -455,7 +470,7 @@ describe('Resource tests', () => {
|
|
|
455
470
|
}
|
|
456
471
|
|
|
457
472
|
const controller = new ResourceController(resource);
|
|
458
|
-
const plan = await controller.plan({ type: 'nvm', global: '20.12', nodeVersions: ['18', '20'] })
|
|
473
|
+
const plan = await controller.plan({ type: 'nvm' }, { global: '20.12', nodeVersions: ['18', '20'] }, null, false)
|
|
459
474
|
|
|
460
475
|
expect(plan).toMatchObject({
|
|
461
476
|
changeSet: {
|
|
@@ -507,7 +522,7 @@ describe('Resource tests', () => {
|
|
|
507
522
|
}
|
|
508
523
|
|
|
509
524
|
const controller = new ResourceController(resource);
|
|
510
|
-
const plan = await controller.plan({ type: 'nvm', global: '20.12', nodeVersions: ['18', '20'] })
|
|
525
|
+
const plan = await controller.plan({ type: 'nvm' }, { global: '20.12', nodeVersions: ['18', '20'] }, null, false)
|
|
511
526
|
|
|
512
527
|
expect(plan).toMatchObject({
|
|
513
528
|
changeSet: {
|
|
@@ -2,6 +2,7 @@ import { Ajv, ValidateFunction } from 'ajv';
|
|
|
2
2
|
import {
|
|
3
3
|
ParameterOperation,
|
|
4
4
|
ResourceConfig,
|
|
5
|
+
ResourceJson,
|
|
5
6
|
ResourceOperation,
|
|
6
7
|
StringIndexedObject,
|
|
7
8
|
ValidateResponseData
|
|
@@ -10,7 +11,6 @@ import {
|
|
|
10
11
|
import { ParameterChange } from '../plan/change-set.js';
|
|
11
12
|
import { Plan } from '../plan/plan.js';
|
|
12
13
|
import { CreatePlan, DestroyPlan, ModifyPlan } from '../plan/plan-types.js';
|
|
13
|
-
import { splitUserConfig } from '../utils/utils.js';
|
|
14
14
|
import { ConfigParser } from './config-parser.js';
|
|
15
15
|
import { ParsedResourceSettings } from './parsed-resource-settings.js';
|
|
16
16
|
import { Resource } from './resource.js';
|
|
@@ -54,23 +54,21 @@ export class ResourceController<T extends StringIndexedObject> {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
async validate(
|
|
57
|
-
|
|
57
|
+
core: ResourceConfig,
|
|
58
|
+
parameters: Partial<T>,
|
|
58
59
|
): Promise<ValidateResponseData['resourceValidations'][0]> {
|
|
59
|
-
|
|
60
|
-
await this.applyTransformParameters(configToValidate);
|
|
61
|
-
|
|
62
|
-
const { parameters, coreParameters } = splitUserConfig(configToValidate);
|
|
60
|
+
await this.applyTransformParameters(parameters);
|
|
63
61
|
this.addDefaultValues(parameters);
|
|
64
62
|
|
|
65
63
|
if (this.schemaValidator) {
|
|
66
64
|
// Schema validator uses pre transformation parameters
|
|
67
|
-
const isValid = this.schemaValidator(
|
|
65
|
+
const isValid = this.schemaValidator(parameters);
|
|
68
66
|
|
|
69
67
|
if (!isValid) {
|
|
70
68
|
return {
|
|
71
69
|
isValid: false,
|
|
72
|
-
resourceName:
|
|
73
|
-
resourceType:
|
|
70
|
+
resourceName: core.name,
|
|
71
|
+
resourceType: core.type,
|
|
74
72
|
schemaValidationErrors: this.schemaValidator?.errors ?? [],
|
|
75
73
|
}
|
|
76
74
|
}
|
|
@@ -89,59 +87,57 @@ export class ResourceController<T extends StringIndexedObject> {
|
|
|
89
87
|
return {
|
|
90
88
|
customValidationErrorMessage,
|
|
91
89
|
isValid: false,
|
|
92
|
-
resourceName:
|
|
93
|
-
resourceType:
|
|
90
|
+
resourceName: core.name,
|
|
91
|
+
resourceType: core.type,
|
|
94
92
|
schemaValidationErrors: this.schemaValidator?.errors ?? [],
|
|
95
93
|
}
|
|
96
94
|
}
|
|
97
95
|
|
|
98
96
|
return {
|
|
99
97
|
isValid: true,
|
|
100
|
-
resourceName:
|
|
101
|
-
resourceType:
|
|
98
|
+
resourceName: core.name,
|
|
99
|
+
resourceType: core.type,
|
|
102
100
|
schemaValidationErrors: [],
|
|
103
101
|
}
|
|
104
102
|
}
|
|
105
103
|
|
|
106
104
|
async plan(
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
core: ResourceConfig,
|
|
106
|
+
desired: Partial<T> | null,
|
|
107
|
+
state: Partial<T> | null,
|
|
109
108
|
isStateful = false,
|
|
110
109
|
): Promise<Plan<T>> {
|
|
111
|
-
this.validatePlanInputs(
|
|
110
|
+
this.validatePlanInputs(core, desired, state, isStateful);
|
|
112
111
|
|
|
113
|
-
this.addDefaultValues(
|
|
114
|
-
await this.applyTransformParameters(
|
|
112
|
+
this.addDefaultValues(desired);
|
|
113
|
+
await this.applyTransformParameters(desired);
|
|
115
114
|
|
|
116
|
-
this.addDefaultValues(
|
|
117
|
-
await this.applyTransformParameters(
|
|
115
|
+
this.addDefaultValues(state);
|
|
116
|
+
await this.applyTransformParameters(state);
|
|
118
117
|
|
|
119
118
|
// Parse data from the user supplied config
|
|
120
|
-
const parsedConfig = new ConfigParser(
|
|
119
|
+
const parsedConfig = new ConfigParser(desired, state, this.parsedSettings.statefulParameters)
|
|
121
120
|
const {
|
|
122
|
-
coreParameters,
|
|
123
|
-
desiredParameters,
|
|
124
|
-
stateParameters,
|
|
125
121
|
allParameters,
|
|
126
122
|
allNonStatefulParameters,
|
|
127
123
|
allStatefulParameters,
|
|
128
124
|
} = parsedConfig;
|
|
129
125
|
|
|
130
126
|
// Refresh resource parameters. This refreshes the parameters that configure the resource itself
|
|
131
|
-
const
|
|
127
|
+
const currentArray = await this.refreshNonStatefulParameters(allNonStatefulParameters);
|
|
132
128
|
|
|
133
129
|
// Short circuit here. If the resource is non-existent, there's no point checking stateful parameters
|
|
134
|
-
if (
|
|
135
|
-
||
|
|
130
|
+
if (currentArray === null
|
|
131
|
+
|| currentArray === undefined
|
|
136
132
|
|| this.settings.allowMultiple // Stateful parameters are not supported currently if allowMultiple is true
|
|
137
|
-
||
|
|
138
|
-
||
|
|
133
|
+
|| currentArray.length === 0
|
|
134
|
+
|| currentArray.filter(Boolean).length === 0
|
|
139
135
|
) {
|
|
140
136
|
return Plan.calculate({
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
137
|
+
desired,
|
|
138
|
+
currentArray,
|
|
139
|
+
state,
|
|
140
|
+
core,
|
|
145
141
|
settings: this.parsedSettings,
|
|
146
142
|
isStateful,
|
|
147
143
|
});
|
|
@@ -152,10 +148,10 @@ export class ResourceController<T extends StringIndexedObject> {
|
|
|
152
148
|
const statefulCurrentParameters = await this.refreshStatefulParameters(allStatefulParameters, allParameters);
|
|
153
149
|
|
|
154
150
|
return Plan.calculate({
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
151
|
+
desired,
|
|
152
|
+
currentArray: [{ ...currentArray[0], ...statefulCurrentParameters }] as Partial<T>[],
|
|
153
|
+
state,
|
|
154
|
+
core,
|
|
159
155
|
settings: this.parsedSettings,
|
|
160
156
|
isStateful
|
|
161
157
|
})
|
|
@@ -186,9 +182,12 @@ export class ResourceController<T extends StringIndexedObject> {
|
|
|
186
182
|
}
|
|
187
183
|
}
|
|
188
184
|
|
|
189
|
-
async import(
|
|
190
|
-
|
|
191
|
-
|
|
185
|
+
async import(
|
|
186
|
+
core: ResourceConfig,
|
|
187
|
+
parameters: Partial<T>
|
|
188
|
+
): Promise<Array<ResourceJson> | null> {
|
|
189
|
+
this.addDefaultValues(parameters);
|
|
190
|
+
await this.applyTransformParameters(parameters);
|
|
192
191
|
|
|
193
192
|
// Use refresh parameters if specified, otherwise try to refresh as many parameters as possible here
|
|
194
193
|
const parametersToRefresh = this.settings.import?.refreshKeys
|
|
@@ -197,14 +196,14 @@ export class ResourceController<T extends StringIndexedObject> {
|
|
|
197
196
|
this.settings.import?.refreshKeys.map((k) => [k, null])
|
|
198
197
|
),
|
|
199
198
|
...this.settings.import?.defaultRefreshValues,
|
|
200
|
-
...
|
|
199
|
+
...parameters,
|
|
201
200
|
}
|
|
202
201
|
: {
|
|
203
202
|
...Object.fromEntries(
|
|
204
203
|
this.getAllParameterKeys().map((k) => [k, null])
|
|
205
204
|
),
|
|
206
205
|
...this.settings.import?.defaultRefreshValues,
|
|
207
|
-
...
|
|
206
|
+
...parameters,
|
|
208
207
|
};
|
|
209
208
|
|
|
210
209
|
// Parse data from the user supplied config
|
|
@@ -212,7 +211,6 @@ export class ResourceController<T extends StringIndexedObject> {
|
|
|
212
211
|
const {
|
|
213
212
|
allNonStatefulParameters,
|
|
214
213
|
allStatefulParameters,
|
|
215
|
-
coreParameters,
|
|
216
214
|
} = parsedConfig;
|
|
217
215
|
|
|
218
216
|
const currentParametersArray = await this.refreshNonStatefulParameters(allNonStatefulParameters);
|
|
@@ -220,16 +218,15 @@ export class ResourceController<T extends StringIndexedObject> {
|
|
|
220
218
|
if (currentParametersArray === null
|
|
221
219
|
|| currentParametersArray === undefined
|
|
222
220
|
|| this.settings.allowMultiple // Stateful parameters are not supported currently if allowMultiple is true
|
|
223
|
-
|| currentParametersArray.length === 0
|
|
224
221
|
|| currentParametersArray.filter(Boolean).length === 0
|
|
225
222
|
) {
|
|
226
223
|
return currentParametersArray
|
|
227
|
-
?.map((r) => ({
|
|
224
|
+
?.map((r) => ({ core, parameters: r }))
|
|
228
225
|
?? null;
|
|
229
226
|
}
|
|
230
227
|
|
|
231
228
|
const statefulCurrentParameters = await this.refreshStatefulParameters(allStatefulParameters, parametersToRefresh);
|
|
232
|
-
return [{
|
|
229
|
+
return [{ core, parameters: { ...currentParametersArray[0], ...statefulCurrentParameters } }];
|
|
233
230
|
}
|
|
234
231
|
|
|
235
232
|
private async applyCreate(plan: Plan<T>): Promise<void> {
|
|
@@ -308,7 +305,7 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
308
305
|
}
|
|
309
306
|
}
|
|
310
307
|
|
|
311
|
-
private async applyTransformParameters(config: Partial<T>
|
|
308
|
+
private async applyTransformParameters(config: Partial<T> | null): Promise<void> {
|
|
312
309
|
if (!config) {
|
|
313
310
|
return;
|
|
314
311
|
}
|
|
@@ -322,11 +319,9 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
322
319
|
}
|
|
323
320
|
|
|
324
321
|
if (this.settings.inputTransformation) {
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
const transformed = await this.settings.inputTransformation(parameters)
|
|
322
|
+
const transformed = await this.settings.inputTransformation({ ...config })
|
|
328
323
|
Object.keys(config).forEach((k) => delete config[k])
|
|
329
|
-
Object.assign(config, transformed
|
|
324
|
+
Object.assign(config, transformed);
|
|
330
325
|
}
|
|
331
326
|
}
|
|
332
327
|
|
|
@@ -375,10 +370,15 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
375
370
|
}
|
|
376
371
|
|
|
377
372
|
private validatePlanInputs(
|
|
378
|
-
|
|
379
|
-
|
|
373
|
+
core: ResourceConfig,
|
|
374
|
+
desired: Partial<T> | null,
|
|
375
|
+
current: Partial<T> | null,
|
|
380
376
|
isStateful: boolean,
|
|
381
377
|
) {
|
|
378
|
+
if (!core || !core.type) {
|
|
379
|
+
throw new Error('Core parameters type must be defined');
|
|
380
|
+
}
|
|
381
|
+
|
|
382
382
|
if (!desired && !current) {
|
|
383
383
|
throw new Error('Desired config and current config cannot both be missing')
|
|
384
384
|
}
|