codify-plugin-lib 1.0.44 → 1.0.45

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.
@@ -14,7 +14,7 @@ export class Plugin {
14
14
  resourceDefinitions: [...this.resources.values()]
15
15
  .map((r) => ({
16
16
  type: r.typeId,
17
- dependencies: r.getDependencyTypeIds(),
17
+ dependencies: r.dependencies,
18
18
  }))
19
19
  };
20
20
  }
@@ -1,6 +1,5 @@
1
1
  import { StatefulParameter } from './stateful-parameter.js';
2
2
  import { ResourceOperation, StringIndexedObject } from 'codify-schemas';
3
- import { Resource } from './resource.js';
4
3
  export type ErrorMessage = string;
5
4
  export interface ResourceParameterConfiguration {
6
5
  planOperation?: ResourceOperation.MODIFY | ResourceOperation.RECREATE;
@@ -9,7 +8,7 @@ export interface ResourceParameterConfiguration {
9
8
  export interface ResourceConfiguration<T extends StringIndexedObject> {
10
9
  type: string;
11
10
  callStatefulParameterRemoveOnDestroy?: boolean;
12
- dependencies?: Resource<any>[];
11
+ dependencies?: string[];
13
12
  statefulParameters?: Array<StatefulParameter<T, T[keyof T]>>;
14
13
  parameterConfigurations?: Partial<Record<keyof T, ResourceParameterConfiguration>>;
15
14
  }
@@ -6,11 +6,10 @@ import { ParameterConfiguration } from './plan-types.js';
6
6
  export declare abstract class Resource<T extends StringIndexedObject> {
7
7
  readonly typeId: string;
8
8
  readonly statefulParameters: Map<keyof T, StatefulParameter<T, T[keyof T]>>;
9
- readonly dependencies: Resource<any>[];
9
+ readonly dependencies: string[];
10
10
  readonly parameterConfigurations: Record<keyof T, ParameterConfiguration>;
11
- private readonly options;
11
+ readonly configuration: ResourceConfiguration<T>;
12
12
  protected constructor(configuration: ResourceConfiguration<T>);
13
- getDependencyTypeIds(): string[];
14
13
  onInitialize(): Promise<void>;
15
14
  plan(desiredConfig: Partial<T> & ResourceConfig): Promise<Plan<T>>;
16
15
  apply(plan: Plan<T>): Promise<void>;
@@ -6,17 +6,14 @@ export class Resource {
6
6
  statefulParameters;
7
7
  dependencies;
8
8
  parameterConfigurations;
9
- options;
9
+ configuration;
10
10
  constructor(configuration) {
11
11
  this.validateResourceConfiguration(configuration);
12
12
  this.typeId = configuration.type;
13
13
  this.statefulParameters = new Map(configuration.statefulParameters?.map((sp) => [sp.name, sp]));
14
14
  this.parameterConfigurations = this.generateParameterConfigurations(configuration);
15
15
  this.dependencies = configuration.dependencies ?? [];
16
- this.options = configuration;
17
- }
18
- getDependencyTypeIds() {
19
- return this.dependencies.map((d) => d.typeId);
16
+ this.configuration = configuration;
20
17
  }
21
18
  async onInitialize() { }
22
19
  async plan(desiredConfig) {
@@ -115,7 +112,7 @@ export class Resource {
115
112
  }
116
113
  }
117
114
  async _applyDestroy(plan) {
118
- if (this.options.callStatefulParameterRemoveOnDestroy) {
115
+ if (this.configuration.callStatefulParameterRemoveOnDestroy) {
119
116
  const statefulParameterChanges = plan.changeSet.parameterChanges
120
117
  .filter((pc) => this.statefulParameters.has(pc.name));
121
118
  for (const parameterChange of statefulParameterChanges) {
@@ -146,7 +143,7 @@ export class Resource {
146
143
  validateResourceConfiguration(data) {
147
144
  if (data.parameterConfigurations && data.statefulParameters) {
148
145
  const parameters = [...Object.keys(data.parameterConfigurations)];
149
- const statefulParameterSet = new Set(Object.keys(data.statefulParameters));
146
+ const statefulParameterSet = new Set(data.statefulParameters.map((sp) => sp.name));
150
147
  const intersection = parameters.some((p) => statefulParameterSet.has(p));
151
148
  if (intersection) {
152
149
  throw new Error(`Resource ${this.typeId} cannot declare a parameter as both stateful and non-stateful`);
@@ -159,7 +156,7 @@ export class Resource {
159
156
  }
160
157
  const refreshKeys = new Set(Object.keys(refresh));
161
158
  if (!setsEqual(desiredKeys, refreshKeys)) {
162
- throw new Error(`Resource ${this.options.type}
159
+ throw new Error(`Resource ${this.configuration.type}
163
160
  refresh() must return back exactly the keys that were provided
164
161
  Missing: ${[...desiredKeys].filter((k) => !refreshKeys.has(k))};
165
162
  Additional: ${[...refreshKeys].filter(k => !desiredKeys.has(k))};`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codify-plugin-lib",
3
- "version": "1.0.44",
3
+ "version": "1.0.45",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -126,7 +126,6 @@ export class ChangeSet<T extends StringIndexedObject> {
126
126
  const _desired = { ...desired };
127
127
  const _current = { ...current };
128
128
 
129
-
130
129
  for (const [k, v] of Object.entries(_current)) {
131
130
  if (_desired[k] == null) {
132
131
  parameterChangeSet.push({
@@ -34,10 +34,6 @@ export class Plan<T extends StringIndexedObject> {
34
34
  .map(([k, v]) => k)
35
35
  );
36
36
 
37
-
38
- // TODO: After adding in state files, need to calculate deletes here
39
- // Where current config exists and state config exists but desired config doesn't
40
-
41
37
  // Explanation: This calculates the change set of the parameters between the
42
38
  // two configs and then passes it to ChangeSet to calculate the overall
43
39
  // operation for the resource
@@ -28,7 +28,7 @@ export class Plugin {
28
28
  resourceDefinitions: [...this.resources.values()]
29
29
  .map((r) => ({
30
30
  type: r.typeId,
31
- dependencies: r.getDependencyTypeIds(),
31
+ dependencies: r.dependencies,
32
32
  }))
33
33
  }
34
34
  }
@@ -1,6 +1,5 @@
1
1
  import { StatefulParameter } from './stateful-parameter.js';
2
2
  import { ResourceOperation, StringIndexedObject } from 'codify-schemas';
3
- import { Resource } from './resource.js';
4
3
 
5
4
  export type ErrorMessage = string;
6
5
 
@@ -30,7 +29,7 @@ export interface ResourceConfiguration<T extends StringIndexedObject> {
30
29
  * Defaults to false.
31
30
  */
32
31
  callStatefulParameterRemoveOnDestroy?: boolean,
33
- dependencies?: Resource<any>[];
32
+ dependencies?: string[];
34
33
  statefulParameters?: Array<StatefulParameter<T, T[keyof T]>>;
35
34
  parameterConfigurations?: Partial<Record<keyof T, ResourceParameterConfiguration>>
36
35
  }
@@ -4,6 +4,7 @@ import { spy } from 'sinon';
4
4
  import { Plan } from './plan.js';
5
5
  import { describe, expect, it } from 'vitest'
6
6
  import { ResourceConfiguration, ValidationResult } from './resource-types.js';
7
+ import { StatefulParameter } from './stateful-parameter.js';
7
8
 
8
9
  export interface TestConfig extends StringIndexedObject {
9
10
  propA: string;
@@ -40,7 +41,8 @@ export class TestResource extends Resource<TestConfig> {
40
41
  }
41
42
 
42
43
  describe('Resource tests', () => {
43
- it('plans correctly', async () => {
44
+
45
+ it('Plans successfully', async () => {
44
46
  const resource = new class extends TestResource {
45
47
  constructor() {
46
48
  super({ type: 'type' });
@@ -212,4 +214,83 @@ describe('Resource tests', () => {
212
214
 
213
215
  expect(resourceSpy.applyModify.calledTwice).to.be.true;
214
216
  })
217
+
218
+ it('Validates the resource configuration correct (pass)', () => {
219
+ const parameter = new class extends StatefulParameter<TestConfig, string> {
220
+ constructor() {
221
+ super({
222
+ name: 'propC',
223
+ });
224
+ }
225
+
226
+ async refresh(): Promise<string | null> {
227
+ return null;
228
+ }
229
+ applyAdd(valueToAdd: string, plan: Plan<TestConfig>): Promise<void> {
230
+ throw new Error('Method not implemented.');
231
+ }
232
+ applyModify(newValue: string, previousValue: string, allowDeletes: boolean, plan: Plan<TestConfig>): Promise<void> {
233
+ throw new Error('Method not implemented.');
234
+ }
235
+ applyRemove(valueToRemove: string, plan: Plan<TestConfig>): Promise<void> {
236
+ throw new Error('Method not implemented.');
237
+ }
238
+ }
239
+
240
+ expect(() => new class extends TestResource {
241
+ constructor() {
242
+ super({
243
+ type: 'type',
244
+ dependencies: ['homebrew', 'python'],
245
+ statefulParameters: [
246
+ parameter
247
+ ],
248
+ parameterConfigurations: {
249
+ propA: { planOperation: ResourceOperation.MODIFY },
250
+ propC: { isEqual: (a, b) => true },
251
+ }
252
+ });
253
+ }
254
+ }).to.not.throw;
255
+ })
256
+
257
+ it('Validates the resource configuration correct (fail)', () => {
258
+ const parameter = new class extends StatefulParameter<TestConfig, string> {
259
+ constructor() {
260
+ super({
261
+ name: 'propC',
262
+ });
263
+ }
264
+
265
+ async refresh(): Promise<string | null> {
266
+ return null;
267
+ }
268
+ applyAdd(valueToAdd: string, plan: Plan<TestConfig>): Promise<void> {
269
+ throw new Error('Method not implemented.');
270
+ }
271
+ applyModify(newValue: string, previousValue: string, allowDeletes: boolean, plan: Plan<TestConfig>): Promise<void> {
272
+ throw new Error('Method not implemented.');
273
+ }
274
+ applyRemove(valueToRemove: string, plan: Plan<TestConfig>): Promise<void> {
275
+ throw new Error('Method not implemented.');
276
+ }
277
+ }
278
+
279
+ expect(() => new class extends TestResource {
280
+ constructor() {
281
+ super({
282
+ type: 'type',
283
+ dependencies: ['homebrew', 'python'],
284
+ statefulParameters: [
285
+ parameter
286
+ ],
287
+ parameterConfigurations: {
288
+ propA: { planOperation: ResourceOperation.MODIFY },
289
+ propC: { isEqual: (a, b) => true },
290
+ }
291
+ });
292
+ }
293
+ }).to.not.throw;
294
+ })
295
+
215
296
  });
@@ -17,10 +17,9 @@ export abstract class Resource<T extends StringIndexedObject> {
17
17
 
18
18
  readonly typeId: string;
19
19
  readonly statefulParameters: Map<keyof T, StatefulParameter<T, T[keyof T]>>;
20
- readonly dependencies: Resource<any>[]; // TODO: Change this to a string
20
+ readonly dependencies: string[]; // TODO: Change this to a string
21
21
  readonly parameterConfigurations: Record<keyof T, ParameterConfiguration>
22
-
23
- private readonly options: ResourceConfiguration<T>;
22
+ readonly configuration: ResourceConfiguration<T>;
24
23
 
25
24
  protected constructor(configuration: ResourceConfiguration<T>) {
26
25
  this.validateResourceConfiguration(configuration);
@@ -30,11 +29,7 @@ export abstract class Resource<T extends StringIndexedObject> {
30
29
  this.parameterConfigurations = this.generateParameterConfigurations(configuration);
31
30
 
32
31
  this.dependencies = configuration.dependencies ?? [];
33
- this.options = configuration;
34
- }
35
-
36
- getDependencyTypeIds(): string[] {
37
- return this.dependencies.map((d) => d.typeId)
32
+ this.configuration = configuration;
38
33
  }
39
34
 
40
35
  async onInitialize(): Promise<void> {}
@@ -176,7 +171,7 @@ export abstract class Resource<T extends StringIndexedObject> {
176
171
  private async _applyDestroy(plan: Plan<T>): Promise<void> {
177
172
  // If this option is set (defaults to false), then stateful parameters need to be destroyed
178
173
  // as well. This means that the stateful parameter wouldn't have been normally destroyed with applyDestroy()
179
- if (this.options.callStatefulParameterRemoveOnDestroy) {
174
+ if (this.configuration.callStatefulParameterRemoveOnDestroy) {
180
175
  const statefulParameterChanges = plan.changeSet.parameterChanges
181
176
  .filter((pc: ParameterChange<T>) => this.statefulParameters.has(pc.name))
182
177
  for (const parameterChange of statefulParameterChanges) {
@@ -215,16 +210,18 @@ export abstract class Resource<T extends StringIndexedObject> {
215
210
  }
216
211
 
217
212
  private validateResourceConfiguration(data: ResourceConfiguration<T>) {
218
- // A parameter cannot be both stateful and stateless
213
+ // Stateful parameters are configured within the object not in the resource.
219
214
  if (data.parameterConfigurations && data.statefulParameters) {
220
215
  const parameters = [...Object.keys(data.parameterConfigurations)];
221
- const statefulParameterSet = new Set(Object.keys(data.statefulParameters));
216
+ const statefulParameterSet = new Set(data.statefulParameters.map((sp) => sp.name));
222
217
 
223
218
  const intersection = parameters.some((p) => statefulParameterSet.has(p));
224
219
  if (intersection) {
225
220
  throw new Error(`Resource ${this.typeId} cannot declare a parameter as both stateful and non-stateful`);
226
221
  }
227
222
  }
223
+
224
+
228
225
  }
229
226
 
230
227
  private validateRefreshResults(refresh: Partial<T> | null, desiredKeys: Set<keyof T>) {
@@ -236,7 +233,7 @@ export abstract class Resource<T extends StringIndexedObject> {
236
233
 
237
234
  if (!setsEqual(desiredKeys, refreshKeys)) {
238
235
  throw new Error(
239
- `Resource ${this.options.type}
236
+ `Resource ${this.configuration.type}
240
237
  refresh() must return back exactly the keys that were provided
241
238
  Missing: ${[...desiredKeys].filter((k) => !refreshKeys.has(k))};
242
239
  Additional: ${[...refreshKeys].filter(k => !desiredKeys.has(k))};`