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.
@@ -26,7 +26,6 @@ describe('Plan entity tests', () => {
26
26
  expect(plan.currentConfig).to.be.null;
27
27
 
28
28
  expect(plan.desiredConfig).toMatchObject({
29
- type: 'type',
30
29
  propA: 'defaultA',
31
30
  propB: 'propBValue',
32
31
  })
@@ -53,7 +52,6 @@ describe('Plan entity tests', () => {
53
52
  }, controller.parsedSettings.defaultValues);
54
53
 
55
54
  expect(plan.currentConfig).toMatchObject({
56
- type: 'type',
57
55
  propA: 'defaultA',
58
56
  propB: 'propBValue',
59
57
  })
@@ -82,13 +80,11 @@ describe('Plan entity tests', () => {
82
80
  }, controller.parsedSettings.defaultValues);
83
81
 
84
82
  expect(plan.currentConfig).toMatchObject({
85
- type: 'type',
86
83
  propA: 'defaultA',
87
84
  propB: 'propBValue',
88
85
  })
89
86
 
90
87
  expect(plan.desiredConfig).toMatchObject({
91
- type: 'type',
92
88
  propA: 'defaultA',
93
89
  propB: 'propBValue',
94
90
  })
@@ -122,7 +118,6 @@ describe('Plan entity tests', () => {
122
118
  expect(plan.currentConfig).to.be.null
123
119
 
124
120
  expect(plan.desiredConfig).toMatchObject({
125
- type: 'type',
126
121
  propA: 'propAValue',
127
122
  propB: 'propBValue',
128
123
  })
@@ -134,10 +129,10 @@ describe('Plan entity tests', () => {
134
129
 
135
130
  it('Returns the original resource names', () => {
136
131
  const plan = Plan.calculate<TestConfig>({
137
- desiredParameters: { propA: 'propA' },
138
- currentParametersArray: [{ propA: 'propA2' }],
139
- stateParameters: null,
140
- coreParameters: {
132
+ desired: { propA: 'propA' },
133
+ currentArray: [{ propA: 'propA2' }],
134
+ state: null,
135
+ core: {
141
136
  type: 'type',
142
137
  name: 'name1'
143
138
  },
@@ -174,9 +169,12 @@ describe('Plan entity tests', () => {
174
169
  }
175
170
 
176
171
  const controller = new ResourceController(resource);
177
- const plan = await controller.plan({
178
- propZ: ['20.15'],
179
- } as any)
172
+ const plan = await controller.plan(
173
+ { type: 'type' },
174
+ { propZ: ['20.15'], } as any,
175
+ null,
176
+ false
177
+ )
180
178
 
181
179
  expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
182
180
  })
@@ -208,9 +206,12 @@ describe('Plan entity tests', () => {
208
206
  }
209
207
 
210
208
  const controller = new ResourceController(resource);
211
- const plan = await controller.plan({
212
- propZ: ['20.15'],
213
- } as any)
209
+ const plan = await controller.plan(
210
+ { type: 'type' },
211
+ { propZ: ['20.15'], } as any,
212
+ null,
213
+ false
214
+ )
214
215
 
215
216
  expect(plan.changeSet).toMatchObject({
216
217
  operation: ResourceOperation.MODIFY,
package/src/plan/plan.ts CHANGED
@@ -36,10 +36,10 @@ export class Plan<T extends StringIndexedObject> {
36
36
 
37
37
  isStateful: boolean;
38
38
 
39
- constructor(id: string, changeSet: ChangeSet<T>, resourceMetadata: ResourceConfig, isStateful: boolean) {
39
+ constructor(id: string, changeSet: ChangeSet<T>, coreParameters: ResourceConfig, isStateful: boolean) {
40
40
  this.id = id;
41
41
  this.changeSet = changeSet;
42
- this.coreParameters = resourceMetadata;
42
+ this.coreParameters = coreParameters;
43
43
  this.isStateful = isStateful;
44
44
  }
45
45
 
@@ -51,10 +51,7 @@ export class Plan<T extends StringIndexedObject> {
51
51
  return null;
52
52
  }
53
53
 
54
- return {
55
- ...this.coreParameters,
56
- ...this.changeSet.desiredParameters,
57
- }
54
+ return this.changeSet.desiredParameters;
58
55
  }
59
56
 
60
57
  /**
@@ -65,10 +62,7 @@ export class Plan<T extends StringIndexedObject> {
65
62
  return null;
66
63
  }
67
64
 
68
- return {
69
- ...this.coreParameters,
70
- ...this.changeSet.currentParameters,
71
- }
65
+ return this.changeSet.currentParameters;
72
66
  }
73
67
 
74
68
  get resourceId(): string {
@@ -78,71 +72,71 @@ export class Plan<T extends StringIndexedObject> {
78
72
  }
79
73
 
80
74
  static calculate<T extends StringIndexedObject>(params: {
81
- desiredParameters: Partial<T> | null,
82
- currentParametersArray: Partial<T>[] | null,
83
- stateParameters: Partial<T> | null,
84
- coreParameters: ResourceConfig,
75
+ desired: Partial<T> | null,
76
+ currentArray: Partial<T>[] | null,
77
+ state: Partial<T> | null,
78
+ core: ResourceConfig,
85
79
  settings: ParsedResourceSettings<T>,
86
80
  isStateful: boolean,
87
81
  }): Plan<T> {
88
82
  const {
89
- desiredParameters,
90
- currentParametersArray,
91
- stateParameters,
92
- coreParameters,
83
+ desired,
84
+ currentArray,
85
+ state,
86
+ core,
93
87
  settings,
94
88
  isStateful
95
89
  } = params
96
90
 
97
- const currentParameters = Plan.matchCurrentParameters<T>({
98
- desiredParameters,
99
- currentParametersArray,
100
- stateParameters,
91
+ const current = Plan.matchCurrentParameters<T>({
92
+ desired,
93
+ currentArray,
94
+ state,
101
95
  settings,
102
96
  isStateful
103
97
  });
104
98
 
105
99
  const filteredCurrentParameters = Plan.filterCurrentParams<T>({
106
- desiredParameters,
107
- currentParameters,
108
- stateParameters,
100
+ desired,
101
+ current,
102
+ state,
109
103
  settings,
110
104
  isStateful
111
105
  });
112
106
 
113
107
  // Empty
114
- if (!filteredCurrentParameters && !desiredParameters) {
108
+ if (!filteredCurrentParameters && !desired) {
115
109
  return new Plan(
116
110
  uuidV4(),
117
111
  ChangeSet.empty<T>(),
118
- coreParameters,
112
+ core,
119
113
  isStateful,
120
114
  )
121
115
  }
122
116
 
123
117
  // CREATE
124
- if (!filteredCurrentParameters && desiredParameters) {
118
+ if (!filteredCurrentParameters && desired) {
125
119
  return new Plan(
126
120
  uuidV4(),
127
- ChangeSet.create(desiredParameters),
128
- coreParameters,
121
+ ChangeSet.create(desired),
122
+ core,
129
123
  isStateful,
130
124
  )
131
125
  }
132
126
 
133
127
  // DESTROY
134
- if (filteredCurrentParameters && !desiredParameters) {
128
+ if (filteredCurrentParameters && !desired) {
135
129
  return new Plan(
136
130
  uuidV4(),
137
131
  ChangeSet.destroy(filteredCurrentParameters),
138
- coreParameters,
132
+ core,
139
133
  isStateful,
140
134
  )
141
135
  }
142
136
 
143
137
  // NO-OP, MODIFY or RE-CREATE
144
138
  const changeSet = ChangeSet.calculateModification(
145
- desiredParameters!,
139
+ desired!,
146
140
  filteredCurrentParameters!,
147
141
  settings.parameterSettings,
148
142
  );
@@ -150,60 +144,11 @@ export class Plan<T extends StringIndexedObject> {
150
144
  return new Plan(
151
145
  uuidV4(),
152
146
  changeSet,
153
- coreParameters,
147
+ core,
154
148
  isStateful,
155
149
  );
156
150
  }
157
151
 
158
- /**
159
- * When multiples of the same resource are allowed, this matching function will match a given config with one of the
160
- * existing configs on the system. For example if there are multiple versions of Android Studios installed, we can use
161
- * the application name and location to match it to our desired configs name and location.
162
- *
163
- * @param params
164
- * @private
165
- */
166
- private static matchCurrentParameters<T extends StringIndexedObject>(params: {
167
- desiredParameters: Partial<T> | null,
168
- currentParametersArray: Partial<T>[] | null,
169
- stateParameters: Partial<T> | null,
170
- settings: ResourceSettings<T>,
171
- isStateful: boolean,
172
- }): Partial<T> | null {
173
- const {
174
- desiredParameters,
175
- currentParametersArray,
176
- stateParameters,
177
- settings,
178
- isStateful
179
- } = params;
180
-
181
- if (!settings.allowMultiple) {
182
- return currentParametersArray?.[0] ?? null;
183
- }
184
-
185
- if (!currentParametersArray) {
186
- return null;
187
- }
188
-
189
- if (isStateful) {
190
- return stateParameters
191
- ? settings.allowMultiple.matcher(stateParameters, currentParametersArray)
192
- : null
193
- }
194
-
195
- return settings.allowMultiple.matcher(desiredParameters!, currentParametersArray);
196
- }
197
-
198
- /**
199
- * The type (id) of the resource
200
- *
201
- * @return string
202
- */
203
- getResourceType(): string {
204
- return this.coreParameters.type
205
- }
206
-
207
152
  // 2. Even if there was (maybe for testing reasons), the plan values should not be adjusted
208
153
  static fromResponse<T extends ResourceConfig>(data: ApplyRequestData['plan'], defaultValues?: Partial<Record<keyof T, unknown>>): Plan<T> {
209
154
  if (!data) {
@@ -275,6 +220,55 @@ export class Plan<T extends StringIndexedObject> {
275
220
 
276
221
  }
277
222
 
223
+ /**
224
+ * The type (id) of the resource
225
+ *
226
+ * @return string
227
+ */
228
+ getResourceType(): string {
229
+ return this.coreParameters.type
230
+ }
231
+
232
+ /**
233
+ * When multiples of the same resource are allowed, this matching function will match a given config with one of the
234
+ * existing configs on the system. For example if there are multiple versions of Android Studios installed, we can use
235
+ * the application name and location to match it to our desired configs name and location.
236
+ *
237
+ * @param params
238
+ * @private
239
+ */
240
+ private static matchCurrentParameters<T extends StringIndexedObject>(params: {
241
+ desired: Partial<T> | null,
242
+ currentArray: Partial<T>[] | null,
243
+ state: Partial<T> | null,
244
+ settings: ResourceSettings<T>,
245
+ isStateful: boolean,
246
+ }): Partial<T> | null {
247
+ const {
248
+ desired,
249
+ currentArray,
250
+ state,
251
+ settings,
252
+ isStateful
253
+ } = params;
254
+
255
+ if (!settings.allowMultiple) {
256
+ return currentArray?.[0] ?? null;
257
+ }
258
+
259
+ if (!currentArray) {
260
+ return null;
261
+ }
262
+
263
+ if (isStateful) {
264
+ return state
265
+ ? settings.allowMultiple.matcher(state, currentArray)
266
+ : null
267
+ }
268
+
269
+ return settings.allowMultiple.matcher(desired!, currentArray);
270
+ }
271
+
278
272
  /**
279
273
  * Only keep relevant params for the plan. We don't want to change settings that were not already
280
274
  * defined.
@@ -284,16 +278,16 @@ export class Plan<T extends StringIndexedObject> {
284
278
  * or wants to set. If a parameter is not specified then it's not managed by Codify.
285
279
  */
286
280
  private static filterCurrentParams<T extends StringIndexedObject>(params: {
287
- desiredParameters: Partial<T> | null,
288
- currentParameters: Partial<T> | null,
289
- stateParameters: Partial<T> | null,
281
+ desired: Partial<T> | null,
282
+ current: Partial<T> | null,
283
+ state: Partial<T> | null,
290
284
  settings: ResourceSettings<T>,
291
285
  isStateful: boolean,
292
286
  }): Partial<T> | null {
293
287
  const {
294
- desiredParameters: desired,
295
- currentParameters: current,
296
- stateParameters: state,
288
+ desired,
289
+ current,
290
+ state,
297
291
  settings,
298
292
  isStateful
299
293
  } = params;
@@ -245,9 +245,8 @@ describe('Plugin tests', () => {
245
245
 
246
246
  const testPlugin = Plugin.create('testPlugin', [resource as any]);
247
247
  await testPlugin.plan({
248
- desired: {
249
- type: 'testResource'
250
- },
248
+ core: { type: 'testResource' },
249
+ desired: {},
251
250
  state: undefined,
252
251
  isStateful: false,
253
252
  })
@@ -9,6 +9,7 @@ import {
9
9
  PlanRequestData,
10
10
  PlanResponseData,
11
11
  ResourceConfig,
12
+ ResourceJson,
12
13
  ValidateRequestData,
13
14
  ValidateResponseData
14
15
  } from 'codify-schemas';
@@ -83,18 +84,20 @@ export class Plugin {
83
84
  }
84
85
 
85
86
  async import(data: ImportRequestData): Promise<ImportResponseData> {
86
- if (!this.resourceControllers.has(data.config.type)) {
87
- throw new Error(`Cannot get info for resource ${data.config.type}, resource doesn't exist`);
87
+ const { core, parameters } = data;
88
+
89
+ if (!this.resourceControllers.has(core.type)) {
90
+ throw new Error(`Cannot get info for resource ${core.type}, resource doesn't exist`);
88
91
  }
89
92
 
90
93
  const result = await ptyLocalStorage.run(this.planPty, () =>
91
94
  this.resourceControllers
92
- .get(data.config.type!)
93
- ?.import(data.config)
95
+ .get(core.type!)
96
+ ?.import(core, parameters)
94
97
  )
95
98
 
96
99
  return {
97
- request: data.config,
100
+ request: data,
98
101
  result: result ?? [],
99
102
  }
100
103
  }
@@ -102,13 +105,15 @@ export class Plugin {
102
105
  async validate(data: ValidateRequestData): Promise<ValidateResponseData> {
103
106
  const validationResults = [];
104
107
  for (const config of data.configs) {
105
- if (!this.resourceControllers.has(config.type)) {
106
- throw new Error(`Resource type not found: ${config.type}`);
108
+ const { core, parameters } = config;
109
+
110
+ if (!this.resourceControllers.has(core.type)) {
111
+ throw new Error(`Resource type not found: ${core.type}`);
107
112
  }
108
113
 
109
114
  const validation = await this.resourceControllers
110
- .get(config.type)!
111
- .validate(config);
115
+ .get(core.type)!
116
+ .validate(core, parameters);
112
117
 
113
118
  validationResults.push(validation);
114
119
  }
@@ -120,16 +125,17 @@ export class Plugin {
120
125
  }
121
126
 
122
127
  async plan(data: PlanRequestData): Promise<PlanResponseData> {
123
- const type = data.desired?.type ?? data.state?.type
128
+ const { type } = data.core
124
129
 
125
- if (!type || !this.resourceControllers.has(type)) {
130
+ if (!this.resourceControllers.has(type)) {
126
131
  throw new Error(`Resource type not found: ${type}`);
127
132
  }
128
133
 
129
134
  const plan = await ptyLocalStorage.run(this.planPty, async () => this.resourceControllers.get(type)!.plan(
130
- data.desired ?? null,
131
- data.state ?? null,
132
- data.isStateful
135
+ data.core,
136
+ data.desired ?? null,
137
+ data.state ?? null,
138
+ data.isStateful
133
139
  ))
134
140
 
135
141
  this.planStorage.set(plan.id, plan);
@@ -155,6 +161,7 @@ export class Plugin {
155
161
  // Default back desired back to current if it is not defined (for destroys only)
156
162
  const validationPlan = await ptyLocalStorage.run(new BackgroundPty(), async () => {
157
163
  const result = await resource.plan(
164
+ plan.coreParameters,
158
165
  plan.desiredConfig,
159
166
  plan.desiredConfig ?? plan.currentConfig,
160
167
  plan.isStateful
@@ -192,5 +199,6 @@ export class Plugin {
192
199
  return Plan.fromResponse(planRequest, resource.parsedSettings.defaultValues);
193
200
  }
194
201
 
195
- protected async crossValidateResources(configs: ResourceConfig[]): Promise<void> {}
202
+ protected async crossValidateResources(resources: ResourceJson[]): Promise<void> {
203
+ }
196
204
  }
@@ -1,16 +1,15 @@
1
- import { ResourceConfig, StringIndexedObject } from 'codify-schemas';
1
+ import { StringIndexedObject } from 'codify-schemas';
2
2
 
3
3
  import { StatefulParameterController } from '../stateful-parameter/stateful-parameter-controller.js';
4
- import { splitUserConfig } from '../utils/utils.js';
5
4
 
6
5
  export class ConfigParser<T extends StringIndexedObject> {
7
- private readonly desiredConfig: Partial<T> & ResourceConfig | null;
8
- private readonly stateConfig: Partial<T> & ResourceConfig | null;
6
+ private readonly desiredConfig: Partial<T> | null;
7
+ private readonly stateConfig: Partial<T> | null;
9
8
  private statefulParametersMap: Map<keyof T, StatefulParameterController<T, T[keyof T]>>;
10
9
 
11
10
  constructor(
12
- desiredConfig: Partial<T> & ResourceConfig | null,
13
- stateConfig: Partial<T> & ResourceConfig | null,
11
+ desiredConfig: Partial<T> | null,
12
+ stateConfig: Partial<T> | null,
14
13
  statefulParameters: Map<keyof T, StatefulParameterController<T, T[keyof T]>>,
15
14
  ) {
16
15
  this.desiredConfig = desiredConfig;
@@ -18,42 +17,8 @@ export class ConfigParser<T extends StringIndexedObject> {
18
17
  this.statefulParametersMap = statefulParameters;
19
18
  }
20
19
 
21
- get coreParameters(): ResourceConfig {
22
- const desiredCoreParameters = this.desiredConfig ? splitUserConfig(this.desiredConfig).coreParameters : undefined;
23
- const currentCoreParameters = this.stateConfig ? splitUserConfig(this.stateConfig).coreParameters : undefined;
24
-
25
- if (!desiredCoreParameters && !currentCoreParameters) {
26
- throw new Error(`Unable to parse resource core parameters from:
27
-
28
- Desired: ${JSON.stringify(this.desiredConfig, null, 2)}
29
-
30
- Current: ${JSON.stringify(this.stateConfig, null, 2)}`)
31
- }
32
-
33
- return desiredCoreParameters ?? currentCoreParameters!;
34
- }
35
-
36
- get desiredParameters(): Partial<T> | null {
37
- if (!this.desiredConfig) {
38
- return null;
39
- }
40
-
41
- const { parameters } = splitUserConfig(this.desiredConfig);
42
- return parameters;
43
- }
44
-
45
- get stateParameters(): Partial<T> | null {
46
- if (!this.stateConfig) {
47
- return null;
48
- }
49
-
50
- const { parameters } = splitUserConfig(this.stateConfig);
51
- return parameters;
52
- }
53
-
54
-
55
20
  get allParameters(): Partial<T> {
56
- return { ...this.desiredParameters, ...this.stateParameters } as Partial<T>;
21
+ return { ...this.desiredConfig, ...this.stateConfig } as Partial<T>;
57
22
  }
58
23
 
59
24
  get allNonStatefulParameters(): Partial<T> {
@@ -19,9 +19,9 @@ describe('Resource tests for stateful plans', () => {
19
19
 
20
20
  const controller = new ResourceController(resource);
21
21
  const plan = await controller.plan(
22
+ { type: 'type' },
22
23
  null,
23
24
  {
24
- type: 'type',
25
25
  propA: 'propA',
26
26
  propB: 10,
27
27
  propC: 'propC',
@@ -67,8 +67,8 @@ describe('Resource tests for stateful plans', () => {
67
67
 
68
68
  const controller = new ResourceController(resource);
69
69
  const plan = await controller.plan(
70
+ { type: 'resource' },
70
71
  {
71
- type: 'resource',
72
72
  propA: 'propA',
73
73
  propB: 10,
74
74
  propC: 'propC',
@@ -119,6 +119,7 @@ describe('Resource tests for stateful plans', () => {
119
119
 
120
120
  const controller = new ResourceController(resource)
121
121
  const plan = await controller.plan(
122
+ { type: 'type' },
122
123
  {
123
124
  type: 'type',
124
125
  propA: 'propA',
@@ -191,15 +192,14 @@ describe('Resource tests for stateful plans', () => {
191
192
 
192
193
  const controller = new ResourceController(resource);
193
194
  const plan = await controller.plan(
195
+ { type: 'type' },
194
196
  {
195
- type: 'type',
196
197
  propA: 'propA',
197
198
  propB: 10,
198
199
  propC: 'propC',
199
200
  propD: 'propD'
200
201
  },
201
202
  {
202
- type: 'type',
203
203
  propA: 'propA',
204
204
  propC: 'propC'
205
205
  },