codify-plugin-lib 1.0.76 → 1.0.77

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.
Files changed (70) hide show
  1. package/.eslintrc.json +11 -4
  2. package/.github/workflows/release.yaml +19 -0
  3. package/.github/workflows/unit-test-ci.yaml +19 -0
  4. package/dist/errors.d.ts +4 -0
  5. package/dist/errors.js +7 -0
  6. package/dist/index.d.ts +10 -10
  7. package/dist/index.js +9 -9
  8. package/dist/messages/handlers.d.ts +1 -1
  9. package/dist/messages/handlers.js +2 -1
  10. package/dist/plan/change-set.d.ts +37 -0
  11. package/dist/plan/change-set.js +146 -0
  12. package/dist/plan/plan-types.d.ts +23 -0
  13. package/dist/plan/plan-types.js +1 -0
  14. package/dist/plan/plan.d.ts +59 -0
  15. package/dist/plan/plan.js +228 -0
  16. package/dist/plugin/plugin.d.ts +17 -0
  17. package/dist/plugin/plugin.js +83 -0
  18. package/dist/resource/config-parser.d.ts +14 -0
  19. package/dist/resource/config-parser.js +48 -0
  20. package/dist/resource/parsed-resource-settings.d.ts +26 -0
  21. package/dist/resource/parsed-resource-settings.js +126 -0
  22. package/dist/resource/resource-controller.d.ts +30 -0
  23. package/dist/resource/resource-controller.js +247 -0
  24. package/dist/resource/resource-settings.d.ts +149 -0
  25. package/dist/resource/resource-settings.js +9 -0
  26. package/dist/resource/resource.d.ts +137 -0
  27. package/dist/resource/resource.js +44 -0
  28. package/dist/resource/stateful-parameter.d.ts +164 -0
  29. package/dist/resource/stateful-parameter.js +94 -0
  30. package/dist/utils/utils.d.ts +19 -3
  31. package/dist/utils/utils.js +52 -3
  32. package/package.json +5 -3
  33. package/src/index.ts +10 -11
  34. package/src/messages/handlers.test.ts +10 -37
  35. package/src/messages/handlers.ts +2 -2
  36. package/src/plan/change-set.test.ts +220 -0
  37. package/src/plan/change-set.ts +225 -0
  38. package/src/plan/plan-types.ts +27 -0
  39. package/src/{entities → plan}/plan.test.ts +35 -29
  40. package/src/plan/plan.ts +353 -0
  41. package/src/{entities → plugin}/plugin.test.ts +14 -13
  42. package/src/{entities → plugin}/plugin.ts +28 -24
  43. package/src/resource/config-parser.ts +77 -0
  44. package/src/{entities/resource-options.test.ts → resource/parsed-resource-settings.test.ts} +8 -7
  45. package/src/resource/parsed-resource-settings.ts +179 -0
  46. package/src/{entities/resource-stateful-mode.test.ts → resource/resource-controller-stateful-mode.test.ts} +36 -39
  47. package/src/{entities/resource.test.ts → resource/resource-controller.test.ts} +116 -176
  48. package/src/resource/resource-controller.ts +340 -0
  49. package/src/resource/resource-settings.test.ts +494 -0
  50. package/src/resource/resource-settings.ts +192 -0
  51. package/src/resource/resource.ts +149 -0
  52. package/src/resource/stateful-parameter.test.ts +93 -0
  53. package/src/resource/stateful-parameter.ts +217 -0
  54. package/src/utils/test-utils.test.ts +87 -0
  55. package/src/utils/utils.test.ts +2 -2
  56. package/src/utils/utils.ts +51 -5
  57. package/tsconfig.json +0 -1
  58. package/vitest.config.ts +10 -0
  59. package/src/entities/change-set.test.ts +0 -155
  60. package/src/entities/change-set.ts +0 -244
  61. package/src/entities/plan-types.ts +0 -44
  62. package/src/entities/plan.ts +0 -178
  63. package/src/entities/resource-options.ts +0 -155
  64. package/src/entities/resource-parameters.test.ts +0 -604
  65. package/src/entities/resource-types.ts +0 -31
  66. package/src/entities/resource.ts +0 -470
  67. package/src/entities/stateful-parameter.test.ts +0 -114
  68. package/src/entities/stateful-parameter.ts +0 -92
  69. package/src/entities/transform-parameter.ts +0 -13
  70. /package/src/{entities/errors.ts → errors.ts} +0 -0
@@ -1,48 +1,17 @@
1
1
  import { Resource } from './resource.js';
2
- import { ResourceOperation, StringIndexedObject } from 'codify-schemas';
2
+ import { ResourceOperation } from 'codify-schemas';
3
3
  import { spy } from 'sinon';
4
- import { Plan } from './plan.js';
5
4
  import { describe, expect, it } from 'vitest'
6
- import { StatefulParameter } from './stateful-parameter.js';
7
- import { ResourceOptions } from './resource-options.js';
8
- import { CreatePlan, DestroyPlan, ModifyPlan } from './plan-types.js';
9
- import { ParameterChange } from './change-set.js';
10
-
11
- export interface TestConfig extends StringIndexedObject {
12
- propA: string;
13
- propB: number;
14
- propC?: string;
15
- }
16
-
17
- export class TestResource extends Resource<TestConfig> {
18
- constructor(options: ResourceOptions<TestConfig>) {
19
- super(options);
20
- }
21
-
22
- applyCreate(plan: Plan<TestConfig>): Promise<void> {
23
- return Promise.resolve(undefined);
24
- }
25
-
26
- applyDestroy(plan: Plan<TestConfig>): Promise<void> {
27
- return Promise.resolve(undefined);
28
- }
29
-
30
- async refresh(parameters: Partial<TestConfig>): Promise<Partial<TestConfig> | null> {
31
- return {
32
- propA: 'a',
33
- propB: 10,
34
- propC: 'c',
35
- };
36
- }
37
- }
5
+ import { ResourceSettings } from './resource-settings.js';
6
+ import { CreatePlan, DestroyPlan, ModifyPlan } from '../plan/plan-types.js';
7
+ import { ParameterChange } from '../plan/change-set.js';
8
+ import { ResourceController } from './resource-controller.js';
9
+ import { TestConfig, testPlan, TestResource, TestStatefulParameter } from '../utils/test-utils.test.js';
38
10
 
39
11
  describe('Resource tests', () => {
40
12
 
41
13
  it('Plans successfully', async () => {
42
14
  const resource = new class extends TestResource {
43
- constructor() {
44
- super({ type: 'type' });
45
- }
46
15
 
47
16
  async refresh(): Promise<TestConfig> {
48
17
  return {
@@ -52,7 +21,9 @@ describe('Resource tests', () => {
52
21
  }
53
22
  }
54
23
 
55
- const resourceSpy = spy(resource);
24
+ const controller = new ResourceController(resource)
25
+
26
+ const resourceSpy = spy(controller);
56
27
  const result = await resourceSpy.plan({
57
28
  type: 'type',
58
29
  name: 'name',
@@ -83,16 +54,13 @@ describe('Resource tests', () => {
83
54
 
84
55
  it('creates the resource if it doesnt exist', async () => {
85
56
  const resource = new class extends TestResource {
86
- constructor() {
87
- super({ type: 'type' });
88
- }
89
-
90
57
  async refresh(): Promise<TestConfig | null> {
91
58
  return null;
92
59
  }
93
60
  }
61
+ const controller = new ResourceController(resource);
94
62
 
95
- const resourceSpy = spy(resource);
63
+ const resourceSpy = spy(controller);
96
64
  const result = await resourceSpy.plan({
97
65
  type: 'type',
98
66
  name: 'name',
@@ -101,22 +69,21 @@ describe('Resource tests', () => {
101
69
  propC: 'somethingAfter'
102
70
  })
103
71
 
72
+ console.log(result.changeSet.parameterChanges)
73
+
104
74
  expect(result.changeSet.operation).to.eq(ResourceOperation.CREATE);
105
75
  expect(result.changeSet.parameterChanges.length).to.eq(3);
106
76
  })
107
77
 
108
78
  it('handles empty parameters', async () => {
109
79
  const resource = new class extends TestResource {
110
- constructor() {
111
- super({ type: 'type' });
112
- }
113
-
114
80
  async refresh(): Promise<Partial<TestConfig> | null> {
115
81
  return null;
116
82
  }
117
83
  }
84
+ const controller = new ResourceController(resource);
118
85
 
119
- const resourceSpy = spy(resource);
86
+ const resourceSpy = spy(controller);
120
87
  const result = await resourceSpy.plan({ type: 'type' })
121
88
 
122
89
  expect(result.changeSet.operation).to.eq(ResourceOperation.CREATE);
@@ -125,169 +92,137 @@ describe('Resource tests', () => {
125
92
 
126
93
  it('chooses the create apply properly', async () => {
127
94
  const resource = new class extends TestResource {
128
- constructor() {
129
- super({ type: 'resource' });
130
- }
131
95
  }
96
+ const controller = new ResourceController(resource);
132
97
 
98
+ const controllerSpy = spy(controller);
133
99
  const resourceSpy = spy(resource);
134
- const result = await resourceSpy.apply(
135
- Plan.create<TestConfig>(
136
- { type: 'resource', propA: 'a', propB: 0 },
137
- null,
138
- { type: 'resource' },
139
- { statefulMode: false },
140
- )
100
+
101
+ await controllerSpy.apply(
102
+ testPlan({
103
+ desired: { propA: 'a', propB: 0 },
104
+ })
141
105
  )
142
106
 
143
- expect(resourceSpy.applyCreate.calledOnce).to.be.true;
107
+ expect(resourceSpy.create.calledOnce).to.be.true;
144
108
  })
145
109
 
146
110
  it('chooses the destroy apply properly', async () => {
147
111
  const resource = new class extends TestResource {
148
- constructor() {
149
- super({ type: 'resource' });
150
- }
151
112
  }
113
+ const controller = new ResourceController(resource);
152
114
 
115
+ const controllerSpy = spy(controller);
153
116
  const resourceSpy = spy(resource);
154
- const result = await resourceSpy.apply(
155
- Plan.create<TestConfig>(
156
- null,
157
- { propA: 'a', propB: 0 },
158
- { type: 'resource' },
159
- { statefulMode: true },
160
- )
117
+
118
+ await controllerSpy.apply(
119
+ testPlan({
120
+ current: [{ propA: 'a', propB: 0 }],
121
+ state: { propA: 'a', propB: 0 },
122
+ statefulMode: true,
123
+ })
161
124
  )
162
125
 
163
- expect(resourceSpy.applyDestroy.calledOnce).to.be.true;
126
+ expect(resourceSpy.destroy.calledOnce).to.be.true;
164
127
  })
165
128
 
166
129
  it('Defaults parameter changes to recreate', async () => {
167
130
  const resource = new class extends TestResource {
168
- constructor() {
169
- super({ type: 'resource' });
170
- }
171
131
  }
132
+ const controller = new ResourceController(resource);
172
133
 
134
+ const controllerSpy = spy(controller);
173
135
  const resourceSpy = spy(resource);
174
- const result = await resourceSpy.apply(
175
- Plan.create<TestConfig>(
176
- { propA: 'a', propB: 0 },
177
- { propA: 'b', propB: -1 },
178
- { type: 'resource' },
179
- { statefulMode: true },
180
- )
136
+
137
+ await controllerSpy.apply(
138
+ testPlan({
139
+ desired: { propA: 'a', propB: 0 },
140
+ current: [{ propA: 'b', propB: -1 }],
141
+ statefulMode: true
142
+ })
181
143
  );
182
144
 
183
- expect(resourceSpy.applyDestroy.calledOnce).to.be.true;
184
- expect(resourceSpy.applyCreate.calledOnce).to.be.true;
145
+ expect(resourceSpy.destroy.calledOnce).to.be.true;
146
+ expect(resourceSpy.create.calledOnce).to.be.true;
185
147
  })
186
148
 
187
149
  it('Allows modification of parameter behavior to allow modify for parameters', async () => {
188
150
  const resource = new class extends TestResource {
189
- constructor() {
190
- super({
191
- type: 'resource',
192
- parameterOptions: {
193
- propA: { modifyOnChange: true },
194
- propB: { modifyOnChange: true },
151
+ getSettings(): ResourceSettings<TestConfig> {
152
+ return {
153
+ id: 'resource',
154
+ parameterSettings: {
155
+ propA: { canModify: true },
156
+ propB: { canModify: true },
195
157
  }
196
- });
158
+ }
197
159
  }
198
160
 
199
161
  async refresh(): Promise<TestConfig | null> {
200
162
  return { propA: 'b', propB: -1 };
201
163
  }
202
164
  }
165
+ const controller = new ResourceController(resource);
203
166
 
204
- const plan = await resource.plan({ type: 'resource', propA: 'a', propB: 0 })
167
+ const plan = await controller.plan({ type: 'resource', propA: 'a', propB: 0 })
205
168
 
206
169
  const resourceSpy = spy(resource);
207
- const result = await resourceSpy.apply(
170
+ await controller.apply(
208
171
  plan
209
172
  );
210
173
 
211
- expect(resourceSpy.applyModify.calledTwice).to.be.true;
174
+ expect(resourceSpy.modify.calledTwice).to.be.true;
212
175
  })
213
176
 
214
177
  it('Validates the resource options correct (pass)', () => {
215
- const statefulParameter = new class extends StatefulParameter<TestConfig, string> {
216
- async refresh(): Promise<string | null> {
217
- return null;
218
- }
178
+ const statefulParameter = new TestStatefulParameter();
219
179
 
220
- applyAdd(valueToAdd: string, plan: Plan<TestConfig>): Promise<void> {
221
- throw new Error('Method not implemented.');
222
- }
223
-
224
- applyModify(newValue: string, previousValue: string, allowDeletes: boolean, plan: Plan<TestConfig>): Promise<void> {
225
- throw new Error('Method not implemented.');
226
- }
227
-
228
- applyRemove(valueToRemove: string, plan: Plan<TestConfig>): Promise<void> {
229
- throw new Error('Method not implemented.');
230
- }
231
- }
232
-
233
- expect(() => new class extends TestResource {
234
- constructor() {
235
- super({
236
- type: 'type',
180
+ expect(() => new ResourceController(new class extends TestResource {
181
+ getSettings(): ResourceSettings<TestConfig> {
182
+ return {
183
+ id: 'type',
237
184
  dependencies: ['homebrew', 'python'],
238
- parameterOptions: {
239
- propA: { modifyOnChange: true },
240
- propB: { statefulParameter },
185
+ parameterSettings: {
186
+ propA: { canModify: true },
187
+ propB: { type: 'stateful', definition: statefulParameter },
241
188
  propC: { isEqual: (a, b) => true },
242
189
  }
243
- });
190
+ }
244
191
  }
245
- }).to.not.throw;
192
+ })).to.not.throw;
246
193
  })
247
194
 
248
195
  it('Validates the resource options correct (fail)', () => {
249
- const statefulParameter = new class extends StatefulParameter<TestConfig, string> {
250
- async refresh(): Promise<string | null> {
196
+ const statefulParameter = new class extends TestStatefulParameter {
197
+ async refresh(desired: string | null): Promise<string | null> {
251
198
  return null;
252
199
  }
253
-
254
- applyAdd(valueToAdd: string, plan: Plan<TestConfig>): Promise<void> {
255
- throw new Error('Method not implemented.');
256
- }
257
-
258
- applyModify(newValue: string, previousValue: string, allowDeletes: boolean, plan: Plan<TestConfig>): Promise<void> {
259
- throw new Error('Method not implemented.');
260
- }
261
-
262
- applyRemove(valueToRemove: string, plan: Plan<TestConfig>): Promise<void> {
263
- throw new Error('Method not implemented.');
264
- }
265
200
  }
266
201
 
267
- expect(() => new class extends TestResource {
268
- constructor() {
269
- super({
270
- type: 'type',
202
+ expect(() => new ResourceController(new class extends TestResource {
203
+ getSettings(): ResourceSettings<TestConfig> {
204
+ return {
205
+ id: 'type',
271
206
  dependencies: ['homebrew', 'python'],
272
- parameterOptions: {
273
- propA: { modifyOnChange: true },
274
- propB: { statefulParameter },
207
+ parameterSettings: {
208
+ propA: { canModify: true },
209
+ propB: { type: 'stateful', definition: statefulParameter },
275
210
  propC: { isEqual: (a, b) => true },
276
211
  }
277
- });
212
+ }
278
213
  }
279
- }).to.not.throw;
214
+ })).to.not.throw;
280
215
  })
281
216
 
282
217
  it('Allows default values to be added', async () => {
283
218
  const resource = new class extends TestResource {
284
- constructor() {
285
- super({
286
- type: 'type',
287
- parameterOptions: {
219
+ getSettings(): ResourceSettings<TestConfig> {
220
+ return {
221
+ id: 'type',
222
+ parameterSettings: {
288
223
  propA: { default: 'propADefault' }
289
224
  }
290
- });
225
+ }
291
226
  }
292
227
 
293
228
  // @ts-ignore
@@ -299,8 +234,9 @@ describe('Resource tests', () => {
299
234
  };
300
235
  }
301
236
  }
237
+ const controller = new ResourceController(resource);
302
238
 
303
- const plan = await resource.plan({ type: 'resource' })
239
+ const plan = await controller.plan({ type: 'resource' })
304
240
  expect(plan.currentConfig?.propA).to.eq('propAAfter');
305
241
  expect(plan.desiredConfig?.propA).to.eq('propADefault');
306
242
  expect(plan.changeSet.operation).to.eq(ResourceOperation.RECREATE);
@@ -308,13 +244,13 @@ describe('Resource tests', () => {
308
244
 
309
245
  it('Allows default values to be added to both desired and current', async () => {
310
246
  const resource = new class extends TestResource {
311
- constructor() {
312
- super({
313
- type: 'type',
314
- parameterOptions: {
247
+ getSettings(): ResourceSettings<TestConfig> {
248
+ return {
249
+ id: 'type',
250
+ parameterSettings: {
315
251
  propE: { default: 'propEDefault' }
316
252
  }
317
- });
253
+ }
318
254
  }
319
255
 
320
256
  async refresh(parameters: Partial<TestConfig>): Promise<Partial<TestConfig> | null> {
@@ -325,8 +261,9 @@ describe('Resource tests', () => {
325
261
  };
326
262
  }
327
263
  }
264
+ const controller = new ResourceController(resource);
328
265
 
329
- const plan = await resource.plan({ type: 'resource' })
266
+ const plan = await controller.plan({ type: 'resource' })
330
267
  expect(plan.currentConfig?.propE).to.eq('propEDefault');
331
268
  expect(plan.desiredConfig?.propE).to.eq('propEDefault');
332
269
  expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
@@ -334,21 +271,22 @@ describe('Resource tests', () => {
334
271
 
335
272
  it('Allows default values to be added even when refresh returns null', async () => {
336
273
  const resource = new class extends TestResource {
337
- constructor() {
338
- super({
339
- type: 'type',
340
- parameterOptions: {
274
+ getSettings(): ResourceSettings<TestConfig> {
275
+ return {
276
+ id: 'type',
277
+ parameterSettings: {
341
278
  propE: { default: 'propEDefault' }
342
279
  }
343
- });
280
+ }
344
281
  }
345
282
 
346
283
  async refresh(): Promise<Partial<TestConfig> | null> {
347
284
  return null;
348
285
  }
349
286
  }
287
+ const controller = new ResourceController(resource);
350
288
 
351
- const plan = await resource.plan({ type: 'resource' })
289
+ const plan = await controller.plan({ type: 'resource' })
352
290
  expect(plan.currentConfig).to.be.null
353
291
  expect(plan.desiredConfig!.propE).to.eq('propEDefault');
354
292
  expect(plan.changeSet.operation).to.eq(ResourceOperation.CREATE);
@@ -356,13 +294,13 @@ describe('Resource tests', () => {
356
294
 
357
295
  it('Allows default values to be added (ignore default value if already present)', async () => {
358
296
  const resource = new class extends TestResource {
359
- constructor() {
360
- super({
361
- type: 'type',
362
- parameterOptions: {
297
+ getSettings(): ResourceSettings<TestConfig> {
298
+ return {
299
+ id: 'type',
300
+ parameterSettings: {
363
301
  propA: { default: 'propADefault' }
364
302
  }
365
- });
303
+ }
366
304
  }
367
305
 
368
306
  // @ts-ignore
@@ -374,8 +312,9 @@ describe('Resource tests', () => {
374
312
  };
375
313
  }
376
314
  }
315
+ const controller = new ResourceController(resource);
377
316
 
378
- const plan = await resource.plan({ type: 'resource', propA: 'propA' })
317
+ const plan = await controller.plan({ type: 'resource', propA: 'propA' })
379
318
  expect(plan.currentConfig?.propA).to.eq('propAAfter');
380
319
  expect(plan.desiredConfig?.propA).to.eq('propA');
381
320
  expect(plan.changeSet.operation).to.eq(ResourceOperation.RECREATE);
@@ -383,40 +322,41 @@ describe('Resource tests', () => {
383
322
 
384
323
  it('Sets the default value properly on the resource', () => {
385
324
  const resource = new class extends TestResource {
386
- constructor() {
387
- super({
388
- type: 'type',
389
- parameterOptions: {
325
+ getSettings(): ResourceSettings<TestConfig> {
326
+ return {
327
+ id: 'type',
328
+ parameterSettings: {
390
329
  propA: { default: 'propADefault' }
391
330
  }
392
- });
331
+ }
393
332
  }
394
333
  }
334
+ const controller = new ResourceController(resource);
395
335
 
396
- expect(resource.defaultValues).to.deep.eq({
336
+ expect(controller.parsedSettings.defaultValues).to.deep.eq({
397
337
  propA: 'propADefault',
398
338
  })
399
339
  })
400
340
 
401
341
  it('Has the correct typing for applys', () => {
402
342
  const resource = new class extends Resource<TestConfig> {
403
- constructor() {
404
- super({ type: 'type' });
343
+ getSettings(): ResourceSettings<TestConfig> {
344
+ return { id: 'type' }
405
345
  }
406
346
 
407
347
  async refresh(): Promise<Partial<TestConfig> | null> {
408
348
  return null;
409
349
  }
410
350
 
411
- async applyCreate(plan: CreatePlan<TestConfig>): Promise<void> {
351
+ async create(plan: CreatePlan<TestConfig>): Promise<void> {
412
352
  plan.desiredConfig.propA
413
353
  }
414
354
 
415
- async applyDestroy(plan: DestroyPlan<TestConfig>): Promise<void> {
355
+ async destroy(plan: DestroyPlan<TestConfig>): Promise<void> {
416
356
  plan.currentConfig.propB
417
357
  }
418
358
 
419
- async applyModify(pc: ParameterChange<TestConfig>, plan: ModifyPlan<TestConfig>): Promise<void> {
359
+ async modify(pc: ParameterChange<TestConfig>, plan: ModifyPlan<TestConfig>): Promise<void> {
420
360
  plan.desiredConfig.propA
421
361
  plan.currentConfig.propB
422
362
  }