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.
- package/dist/entities/plugin.js +1 -1
- package/dist/entities/resource-types.d.ts +1 -2
- package/dist/entities/resource.d.ts +2 -3
- package/dist/entities/resource.js +5 -8
- package/package.json +1 -1
- package/src/entities/change-set.ts +0 -1
- package/src/entities/plan.ts +0 -4
- package/src/entities/plugin.ts +1 -1
- package/src/entities/resource-types.ts +1 -2
- package/src/entities/resource.test.ts +82 -1
- package/src/entities/resource.ts +9 -12
package/dist/entities/plugin.js
CHANGED
|
@@ -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?:
|
|
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:
|
|
9
|
+
readonly dependencies: string[];
|
|
10
10
|
readonly parameterConfigurations: Record<keyof T, ParameterConfiguration>;
|
|
11
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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(
|
|
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.
|
|
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
package/src/entities/plan.ts
CHANGED
|
@@ -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
|
package/src/entities/plugin.ts
CHANGED
|
@@ -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?:
|
|
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
|
-
|
|
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
|
});
|
package/src/entities/resource.ts
CHANGED
|
@@ -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:
|
|
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.
|
|
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.
|
|
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
|
-
//
|
|
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(
|
|
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.
|
|
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))};`
|