codify-plugin-lib 1.0.37 → 1.0.39
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/change-set.d.ts +17 -9
- package/dist/entities/change-set.js +91 -36
- package/dist/entities/plan-types.d.ts +11 -0
- package/dist/entities/plan-types.js +1 -0
- package/dist/entities/plan.d.ts +10 -7
- package/dist/entities/plan.js +53 -8
- package/dist/entities/plugin.js +9 -8
- package/dist/entities/resource-types.d.ts +24 -0
- package/dist/entities/resource-types.js +1 -0
- package/dist/entities/resource.d.ts +20 -15
- package/dist/entities/resource.js +137 -62
- package/dist/entities/stateful-parameter.d.ts +22 -8
- package/dist/entities/stateful-parameter.js +33 -0
- package/dist/entities/test.d.ts +1 -0
- package/dist/entities/test.js +22 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/utils/common-types.d.ts +3 -0
- package/dist/utils/common-types.js +1 -0
- package/dist/utils/utils.d.ts +6 -0
- package/dist/utils/utils.js +15 -0
- package/package.json +2 -2
- package/src/entities/change-set.test.ts +24 -36
- package/src/entities/change-set.ts +138 -47
- package/src/entities/plan-types.ts +26 -0
- package/src/entities/plan.ts +87 -16
- package/src/entities/plugin.ts +11 -9
- package/src/entities/resource-parameters.test.ts +159 -0
- package/src/entities/resource-types.ts +47 -0
- package/src/entities/resource.test.ts +77 -215
- package/src/entities/resource.ts +203 -91
- package/src/entities/stateful-parameter.ts +56 -8
- package/src/index.ts +3 -0
- package/src/utils/utils.ts +21 -0
|
@@ -1,87 +1,162 @@
|
|
|
1
|
-
import { ParameterOperation, ResourceOperation } from 'codify-schemas';
|
|
2
|
-
import { ChangeSet } from './change-set.js';
|
|
1
|
+
import { ParameterOperation, ResourceOperation, } from 'codify-schemas';
|
|
3
2
|
import { Plan } from './plan.js';
|
|
3
|
+
import { setsEqual, splitUserConfig } from '../utils/utils.js';
|
|
4
4
|
export class Resource {
|
|
5
|
+
typeId;
|
|
6
|
+
statefulParameters;
|
|
5
7
|
dependencies;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
parameterConfigurations;
|
|
9
|
+
options;
|
|
10
|
+
constructor(configuration) {
|
|
11
|
+
this.validateResourceConfiguration(configuration);
|
|
12
|
+
this.typeId = configuration.type;
|
|
13
|
+
this.statefulParameters = new Map(configuration.statefulParameters?.map((sp) => [sp.name, sp]));
|
|
14
|
+
this.parameterConfigurations = this.generateParameterConfigurations(configuration);
|
|
15
|
+
this.dependencies = configuration.dependencies ?? [];
|
|
16
|
+
this.options = configuration;
|
|
9
17
|
}
|
|
10
18
|
getDependencyTypeIds() {
|
|
11
|
-
return this.dependencies.map((d) => d.
|
|
19
|
+
return this.dependencies.map((d) => d.typeId);
|
|
12
20
|
}
|
|
13
21
|
async onInitialize() { }
|
|
14
22
|
async plan(desiredConfig) {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
23
|
+
const planConfiguration = {
|
|
24
|
+
statefulMode: false,
|
|
25
|
+
parameterConfigurations: this.parameterConfigurations,
|
|
26
|
+
};
|
|
27
|
+
const { resourceMetadata, parameters: desiredParameters } = splitUserConfig(desiredConfig);
|
|
28
|
+
const resourceParameters = Object.fromEntries([
|
|
29
|
+
...Object.entries(desiredParameters).filter(([key]) => !this.statefulParameters.has(key)),
|
|
30
|
+
]);
|
|
31
|
+
const statefulParameters = [...this.statefulParameters.values()]
|
|
32
|
+
.filter((sp) => desiredParameters[sp.name] !== undefined);
|
|
33
|
+
const keysToRefresh = new Set(Object.keys(resourceParameters));
|
|
34
|
+
const currentParameters = await this.refresh(keysToRefresh);
|
|
35
|
+
if (currentParameters == null && statefulParameters.length === 0) {
|
|
36
|
+
return Plan.create(desiredConfig, null, planConfiguration);
|
|
18
37
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
for (const statefulParameter of
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
38
|
+
this.validateRefreshResults(currentParameters, keysToRefresh);
|
|
39
|
+
const currentStatefulParameters = {};
|
|
40
|
+
for (const statefulParameter of statefulParameters) {
|
|
41
|
+
const desiredValue = desiredParameters[statefulParameter.name];
|
|
42
|
+
let currentValue = await statefulParameter.refresh(desiredValue ?? null) ?? undefined;
|
|
43
|
+
if (Array.isArray(currentValue) && Array.isArray(desiredValue) && !planConfiguration.statefulMode) {
|
|
44
|
+
currentValue = currentValue.filter((p) => desiredValue?.includes(p));
|
|
25
45
|
}
|
|
46
|
+
currentStatefulParameters[statefulParameter.name] = currentValue;
|
|
26
47
|
}
|
|
27
|
-
|
|
28
|
-
const resourceOperation = parameterChangeSet
|
|
29
|
-
.filter((change) => change.operation !== ParameterOperation.NOOP)
|
|
30
|
-
.reduce((operation, curr) => {
|
|
31
|
-
const newOperation = !this.statefulParameters.has(curr.name)
|
|
32
|
-
? this.calculateOperation(curr)
|
|
33
|
-
: ResourceOperation.MODIFY;
|
|
34
|
-
return ChangeSet.combineResourceOperations(operation, newOperation);
|
|
35
|
-
}, ResourceOperation.NOOP);
|
|
36
|
-
return Plan.create(new ChangeSet(resourceOperation, parameterChangeSet), desiredConfig);
|
|
48
|
+
return Plan.create(desiredConfig, { ...currentParameters, ...currentStatefulParameters, ...resourceMetadata }, planConfiguration);
|
|
37
49
|
}
|
|
38
50
|
async apply(plan) {
|
|
39
|
-
if (plan.getResourceType() !== this.
|
|
40
|
-
throw new Error(`Internal error: Plan set to wrong resource during apply. Expected ${this.
|
|
51
|
+
if (plan.getResourceType() !== this.typeId) {
|
|
52
|
+
throw new Error(`Internal error: Plan set to wrong resource during apply. Expected ${this.typeId} but got: ${plan.getResourceType()}`);
|
|
41
53
|
}
|
|
42
54
|
switch (plan.changeSet.operation) {
|
|
55
|
+
case ResourceOperation.CREATE: {
|
|
56
|
+
return this._applyCreate(plan);
|
|
57
|
+
}
|
|
43
58
|
case ResourceOperation.MODIFY: {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
59
|
+
return this._applyModify(plan);
|
|
60
|
+
}
|
|
61
|
+
case ResourceOperation.RECREATE: {
|
|
62
|
+
await this._applyDestroy(plan);
|
|
63
|
+
return this._applyCreate(plan);
|
|
64
|
+
}
|
|
65
|
+
case ResourceOperation.DESTROY: {
|
|
66
|
+
return this._applyDestroy(plan);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async _applyCreate(plan) {
|
|
71
|
+
await this.applyCreate(plan);
|
|
72
|
+
const statefulParameterChanges = plan.changeSet.parameterChanges
|
|
73
|
+
.filter((pc) => this.statefulParameters.has(pc.name));
|
|
74
|
+
for (const parameterChange of statefulParameterChanges) {
|
|
75
|
+
const statefulParameter = this.statefulParameters.get(parameterChange.name);
|
|
76
|
+
await statefulParameter.applyAdd(parameterChange.newValue, plan);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async _applyModify(plan) {
|
|
80
|
+
const parameterChanges = plan
|
|
81
|
+
.changeSet
|
|
82
|
+
.parameterChanges
|
|
83
|
+
.filter((c) => c.operation !== ParameterOperation.NOOP);
|
|
84
|
+
const statelessParameterChanges = parameterChanges
|
|
85
|
+
.filter((pc) => !this.statefulParameters.has(pc.name));
|
|
86
|
+
for (const pc of statelessParameterChanges) {
|
|
87
|
+
await this.applyModify(pc.name, pc.newValue, pc.previousValue, false, plan);
|
|
88
|
+
}
|
|
89
|
+
const statefulParameterChanges = parameterChanges
|
|
90
|
+
.filter((pc) => this.statefulParameters.has(pc.name));
|
|
91
|
+
for (const parameterChange of statefulParameterChanges) {
|
|
92
|
+
const statefulParameter = this.statefulParameters.get(parameterChange.name);
|
|
93
|
+
switch (parameterChange.operation) {
|
|
94
|
+
case ParameterOperation.ADD: {
|
|
95
|
+
await statefulParameter.applyAdd(parameterChange.newValue, plan);
|
|
96
|
+
break;
|
|
49
97
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
case ParameterOperation.MODIFY: {
|
|
59
|
-
await statefulParameter.applyModify(parameterChange, plan);
|
|
60
|
-
break;
|
|
61
|
-
}
|
|
62
|
-
case ParameterOperation.REMOVE: {
|
|
63
|
-
await statefulParameter.applyRemove(parameterChange, plan);
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
98
|
+
case ParameterOperation.MODIFY: {
|
|
99
|
+
await statefulParameter.applyModify(parameterChange.newValue, parameterChange.previousValue, false, plan);
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case ParameterOperation.REMOVE: {
|
|
103
|
+
await statefulParameter.applyRemove(parameterChange.previousValue, plan);
|
|
104
|
+
break;
|
|
67
105
|
}
|
|
68
|
-
return;
|
|
69
106
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async _applyDestroy(plan) {
|
|
110
|
+
if (this.options.callStatefulParameterRemoveOnDestroy) {
|
|
111
|
+
const statefulParameterChanges = plan.changeSet.parameterChanges
|
|
112
|
+
.filter((pc) => this.statefulParameters.has(pc.name));
|
|
113
|
+
for (const parameterChange of statefulParameterChanges) {
|
|
114
|
+
const statefulParameter = this.statefulParameters.get(parameterChange.name);
|
|
115
|
+
await statefulParameter.applyRemove(parameterChange.previousValue, plan);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
await this.applyDestroy(plan);
|
|
119
|
+
}
|
|
120
|
+
generateParameterConfigurations(resourceConfiguration) {
|
|
121
|
+
const resourceParameters = Object.fromEntries(Object.entries(resourceConfiguration.parameterConfigurations ?? {})
|
|
122
|
+
?.map(([name, value]) => ([name, { ...value, isStatefulParameter: false }])));
|
|
123
|
+
const statefulParameters = resourceConfiguration.statefulParameters
|
|
124
|
+
?.reduce((obj, sp) => {
|
|
125
|
+
return {
|
|
126
|
+
...obj,
|
|
127
|
+
[sp.name]: {
|
|
128
|
+
...sp.configuration,
|
|
129
|
+
isStatefulParameter: true,
|
|
77
130
|
}
|
|
78
|
-
|
|
131
|
+
};
|
|
132
|
+
}, {}) ?? {};
|
|
133
|
+
return {
|
|
134
|
+
...resourceParameters,
|
|
135
|
+
...statefulParameters,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
validateResourceConfiguration(data) {
|
|
139
|
+
if (data.parameterConfigurations && data.statefulParameters) {
|
|
140
|
+
const parameters = [...Object.keys(data.parameterConfigurations)];
|
|
141
|
+
const statefulParameterSet = new Set(Object.keys(data.statefulParameters));
|
|
142
|
+
const intersection = parameters.some((p) => statefulParameterSet.has(p));
|
|
143
|
+
if (intersection) {
|
|
144
|
+
throw new Error(`Resource ${this.typeId} cannot declare a parameter as both stateful and non-stateful`);
|
|
79
145
|
}
|
|
80
|
-
case ResourceOperation.RECREATE: return this.applyRecreate(plan);
|
|
81
|
-
case ResourceOperation.DESTROY: return this.applyDestroy(plan);
|
|
82
146
|
}
|
|
83
147
|
}
|
|
84
|
-
|
|
85
|
-
|
|
148
|
+
validateRefreshResults(refresh, desiredKeys) {
|
|
149
|
+
if (!refresh) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const refreshKeys = new Set(Object.keys(refresh));
|
|
153
|
+
if (!setsEqual(desiredKeys, refreshKeys)) {
|
|
154
|
+
throw new Error(`Resource ${this.options.type}
|
|
155
|
+
refresh() must return back exactly the keys that were provided
|
|
156
|
+
Missing: ${[...desiredKeys].filter((k) => !refreshKeys.has(k))};
|
|
157
|
+
Additional: ${[...refreshKeys].filter(k => !desiredKeys.has(k))};`);
|
|
158
|
+
}
|
|
86
159
|
}
|
|
160
|
+
async applyModify(parameterName, newValue, previousValue, allowDeletes, plan) { }
|
|
161
|
+
;
|
|
87
162
|
}
|
|
@@ -1,10 +1,24 @@
|
|
|
1
|
-
import { ParameterChange } from './change-set.js';
|
|
2
1
|
import { Plan } from './plan.js';
|
|
3
|
-
import {
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
import { StringIndexedObject } from 'codify-schemas';
|
|
3
|
+
export interface StatefulParameterConfiguration<T> {
|
|
4
|
+
name: keyof T;
|
|
5
|
+
isEqual?: (a: any, b: any) => boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare abstract class StatefulParameter<T extends StringIndexedObject, V extends T[keyof T]> {
|
|
8
|
+
readonly name: keyof T;
|
|
9
|
+
readonly configuration: StatefulParameterConfiguration<T>;
|
|
10
|
+
protected constructor(configuration: StatefulParameterConfiguration<T>);
|
|
11
|
+
abstract refresh(previousValue: V | null): Promise<V | null>;
|
|
12
|
+
abstract applyAdd(valueToAdd: V, plan: Plan<T>): Promise<void>;
|
|
13
|
+
abstract applyModify(newValue: V, previousValue: V, allowDeletes: boolean, plan: Plan<T>): Promise<void>;
|
|
14
|
+
abstract applyRemove(valueToRemove: V, plan: Plan<T>): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare abstract class ArrayStatefulParameter<T extends StringIndexedObject, V> extends StatefulParameter<T, any> {
|
|
17
|
+
protected constructor(configuration: StatefulParameterConfiguration<T>);
|
|
18
|
+
applyAdd(valuesToAdd: V[], plan: Plan<T>): Promise<void>;
|
|
19
|
+
applyModify(newValues: V[], previousValues: V[], allowDeletes: boolean, plan: Plan<T>): Promise<void>;
|
|
20
|
+
applyRemove(valuesToRemove: V[], plan: Plan<T>): Promise<void>;
|
|
21
|
+
abstract refresh(previousValue: V[] | null): Promise<V[] | null>;
|
|
22
|
+
abstract applyAddItem(item: V, plan: Plan<T>): Promise<void>;
|
|
23
|
+
abstract applyRemoveItem(item: V, plan: Plan<T>): Promise<void>;
|
|
10
24
|
}
|
|
@@ -1,2 +1,35 @@
|
|
|
1
1
|
export class StatefulParameter {
|
|
2
|
+
name;
|
|
3
|
+
configuration;
|
|
4
|
+
constructor(configuration) {
|
|
5
|
+
this.name = configuration.name;
|
|
6
|
+
this.configuration = configuration;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class ArrayStatefulParameter extends StatefulParameter {
|
|
10
|
+
constructor(configuration) {
|
|
11
|
+
super(configuration);
|
|
12
|
+
}
|
|
13
|
+
async applyAdd(valuesToAdd, plan) {
|
|
14
|
+
for (const value of valuesToAdd) {
|
|
15
|
+
await this.applyAddItem(value, plan);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async applyModify(newValues, previousValues, allowDeletes, plan) {
|
|
19
|
+
const valuesToAdd = newValues.filter((n) => !previousValues.includes(n));
|
|
20
|
+
const valuesToRemove = previousValues.filter((n) => !newValues.includes(n));
|
|
21
|
+
for (const value of valuesToAdd) {
|
|
22
|
+
await this.applyAddItem(value, plan);
|
|
23
|
+
}
|
|
24
|
+
if (allowDeletes) {
|
|
25
|
+
for (const value of valuesToRemove) {
|
|
26
|
+
await this.applyRemoveItem(value, plan);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async applyRemove(valuesToRemove, plan) {
|
|
31
|
+
for (const value of valuesToRemove) {
|
|
32
|
+
await this.applyRemoveItem(value, plan);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
2
35
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Resource } from './resource.js';
|
|
2
|
+
class Test extends Resource {
|
|
3
|
+
validate(config) {
|
|
4
|
+
throw new Error('Method not implemented.');
|
|
5
|
+
}
|
|
6
|
+
async refresh(keys) {
|
|
7
|
+
const result = {};
|
|
8
|
+
if (keys.has('propA')) {
|
|
9
|
+
result['propA'] = 'abc';
|
|
10
|
+
}
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
applyCreate(plan) {
|
|
14
|
+
throw new Error('Method not implemented.');
|
|
15
|
+
}
|
|
16
|
+
applyModify(parameterName, newValue, previousValue, plan) {
|
|
17
|
+
throw new Error('Method not implemented.');
|
|
18
|
+
}
|
|
19
|
+
applyDestroy(plan) {
|
|
20
|
+
throw new Error('Method not implemented.');
|
|
21
|
+
}
|
|
22
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Plugin } from './entities/plugin.js';
|
|
2
2
|
export * from './entities/resource.js';
|
|
3
|
+
export * from './entities/resource-types.js';
|
|
3
4
|
export * from './entities/plugin.js';
|
|
4
5
|
export * from './entities/change-set.js';
|
|
5
6
|
export * from './entities/plan.js';
|
|
7
|
+
export * from './entities/plan-types.js';
|
|
6
8
|
export * from './entities/stateful-parameter.js';
|
|
7
9
|
export * from './utils/test-utils.js';
|
|
8
10
|
export * from './utils/utils.js';
|
|
9
11
|
export declare function runPlugin(plugin: Plugin): Promise<void>;
|
|
12
|
+
export { ErrorMessage } from './entities/resource-types.js';
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { MessageHandler } from './messages/handlers.js';
|
|
2
2
|
export * from './entities/resource.js';
|
|
3
|
+
export * from './entities/resource-types.js';
|
|
3
4
|
export * from './entities/plugin.js';
|
|
4
5
|
export * from './entities/change-set.js';
|
|
5
6
|
export * from './entities/plan.js';
|
|
7
|
+
export * from './entities/plan-types.js';
|
|
6
8
|
export * from './entities/stateful-parameter.js';
|
|
7
9
|
export * from './utils/test-utils.js';
|
|
8
10
|
export * from './utils/utils.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/utils/utils.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
import { SpawnOptions } from 'child_process';
|
|
3
|
+
import { ResourceConfig, StringIndexedObject } from 'codify-schemas';
|
|
3
4
|
export declare enum SpawnStatus {
|
|
4
5
|
SUCCESS = "success",
|
|
5
6
|
ERROR = "error"
|
|
@@ -16,4 +17,9 @@ export declare function codifySpawn(cmd: string, args?: string[], opts?: Omit<Co
|
|
|
16
17
|
throws?: boolean;
|
|
17
18
|
}, extras?: Record<any, any>): Promise<SpawnResult>;
|
|
18
19
|
export declare function isDebug(): boolean;
|
|
20
|
+
export declare function splitUserConfig<T extends StringIndexedObject>(config: T & ResourceConfig): {
|
|
21
|
+
parameters: T;
|
|
22
|
+
resourceMetadata: ResourceConfig;
|
|
23
|
+
};
|
|
24
|
+
export declare function setsEqual(set1: Set<unknown>, set2: Set<unknown>): boolean;
|
|
19
25
|
export {};
|
package/dist/utils/utils.js
CHANGED
|
@@ -36,3 +36,18 @@ export async function codifySpawn(cmd, args, opts, extras) {
|
|
|
36
36
|
export function isDebug() {
|
|
37
37
|
return process.env.DEBUG != null && process.env.DEBUG.includes('codify');
|
|
38
38
|
}
|
|
39
|
+
export function splitUserConfig(config) {
|
|
40
|
+
const resourceMetadata = {
|
|
41
|
+
type: config.type,
|
|
42
|
+
...(config.name && { name: config.name }),
|
|
43
|
+
...(config.dependsOn && { dependsOn: config.dependsOn }),
|
|
44
|
+
};
|
|
45
|
+
const { type, name, dependsOn, ...parameters } = config;
|
|
46
|
+
return {
|
|
47
|
+
parameters: parameters,
|
|
48
|
+
resourceMetadata,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function setsEqual(set1, set2) {
|
|
52
|
+
return set1.size === set2.size && [...set1].every((v) => set2.has(v));
|
|
53
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codify-plugin-lib",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.39",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"ajv": "^8.12.0",
|
|
16
16
|
"ajv-formats": "^2.1.1",
|
|
17
|
-
"codify-schemas": "1.0.
|
|
17
|
+
"codify-schemas": "1.0.32",
|
|
18
18
|
"@npmcli/promise-spawn": "^7.0.1"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
@@ -1,107 +1,95 @@
|
|
|
1
|
-
import { ChangeSet } from './change-set';
|
|
1
|
+
import { ChangeSet } from './change-set.js';
|
|
2
2
|
import { ParameterOperation, ResourceOperation } from 'codify-schemas';
|
|
3
|
-
import { describe,
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
4
|
|
|
5
|
-
describe('Change set tests', () => {
|
|
5
|
+
describe('Change set tests (stateful)', () => {
|
|
6
6
|
it ('Correctly diffs two resource configs (modify)', () => {
|
|
7
|
-
const
|
|
8
|
-
type: 'config',
|
|
7
|
+
const after = {
|
|
9
8
|
propA: 'before',
|
|
10
9
|
propB: 'before'
|
|
11
10
|
}
|
|
12
11
|
|
|
13
|
-
const
|
|
14
|
-
type: 'config',
|
|
12
|
+
const before = {
|
|
15
13
|
propA: 'after',
|
|
16
14
|
propB: 'after'
|
|
17
15
|
}
|
|
18
16
|
|
|
19
|
-
const cs = ChangeSet.calculateParameterChangeSet(before,
|
|
17
|
+
const cs = ChangeSet.calculateParameterChangeSet(after, before, { statefulMode: true });
|
|
20
18
|
expect(cs.length).to.eq(2);
|
|
21
19
|
expect(cs[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
22
20
|
expect(cs[1].operation).to.eq(ParameterOperation.MODIFY);
|
|
23
21
|
})
|
|
24
22
|
|
|
25
23
|
it ('Correctly diffs two resource configs (add)', () => {
|
|
26
|
-
const
|
|
27
|
-
type: 'config',
|
|
24
|
+
const after = {
|
|
28
25
|
propA: 'before',
|
|
26
|
+
propB: 'after'
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
const
|
|
32
|
-
type: 'config',
|
|
29
|
+
const before = {
|
|
33
30
|
propA: 'after',
|
|
34
|
-
propB: 'after'
|
|
35
31
|
}
|
|
36
32
|
|
|
37
|
-
const cs = ChangeSet.calculateParameterChangeSet(before,
|
|
33
|
+
const cs = ChangeSet.calculateParameterChangeSet(after, before, { statefulMode: true });
|
|
38
34
|
expect(cs.length).to.eq(2);
|
|
39
35
|
expect(cs[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
40
36
|
expect(cs[1].operation).to.eq(ParameterOperation.ADD);
|
|
41
37
|
})
|
|
42
38
|
|
|
43
39
|
it ('Correctly diffs two resource configs (remove)', () => {
|
|
40
|
+
const after = {
|
|
41
|
+
propA: 'after',
|
|
42
|
+
}
|
|
43
|
+
|
|
44
44
|
const before = {
|
|
45
|
-
type: 'config',
|
|
46
45
|
propA: 'before',
|
|
47
46
|
propB: 'before'
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
const
|
|
51
|
-
type: 'config',
|
|
52
|
-
propA: 'after',
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const cs = ChangeSet.calculateParameterChangeSet(before, after);
|
|
49
|
+
const cs = ChangeSet.calculateParameterChangeSet(after, before, { statefulMode: true });
|
|
56
50
|
expect(cs.length).to.eq(2);
|
|
57
51
|
expect(cs[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
58
52
|
expect(cs[1].operation).to.eq(ParameterOperation.REMOVE);
|
|
59
53
|
})
|
|
60
54
|
|
|
61
55
|
it ('Correctly diffs two resource configs (no-op)', () => {
|
|
62
|
-
const
|
|
63
|
-
type: 'config',
|
|
56
|
+
const after = {
|
|
64
57
|
propA: 'prop',
|
|
65
58
|
}
|
|
66
59
|
|
|
67
|
-
const
|
|
68
|
-
type: 'config',
|
|
60
|
+
const before = {
|
|
69
61
|
propA: 'prop',
|
|
70
62
|
}
|
|
71
63
|
|
|
72
|
-
const cs = ChangeSet.calculateParameterChangeSet(before,
|
|
64
|
+
const cs = ChangeSet.calculateParameterChangeSet(after, before, { statefulMode: true });
|
|
73
65
|
expect(cs.length).to.eq(1);
|
|
74
66
|
expect(cs[0].operation).to.eq(ParameterOperation.NOOP);
|
|
75
67
|
})
|
|
76
68
|
|
|
77
69
|
it ('handles simple arrays', () => {
|
|
78
70
|
const before = {
|
|
79
|
-
type: 'config',
|
|
80
71
|
propA: ['a', 'b', 'c'],
|
|
81
72
|
}
|
|
82
73
|
|
|
83
74
|
const after = {
|
|
84
|
-
type: 'config',
|
|
85
75
|
propA: ['b', 'a', 'c'],
|
|
86
76
|
}
|
|
87
77
|
|
|
88
|
-
const cs = ChangeSet.calculateParameterChangeSet(before,
|
|
78
|
+
const cs = ChangeSet.calculateParameterChangeSet(after, before, { statefulMode: true });
|
|
89
79
|
expect(cs.length).to.eq(1);
|
|
90
80
|
expect(cs[0].operation).to.eq(ParameterOperation.NOOP);
|
|
91
81
|
})
|
|
92
82
|
|
|
93
83
|
it ('handles simple arrays', () => {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
propA: ['a', 'b'],
|
|
84
|
+
const after = {
|
|
85
|
+
propA: ['a', 'b', 'c'],
|
|
97
86
|
}
|
|
98
87
|
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
propA: ['b', 'a', 'c'],
|
|
88
|
+
const before = {
|
|
89
|
+
propA: ['b', 'a'],
|
|
102
90
|
}
|
|
103
91
|
|
|
104
|
-
const cs = ChangeSet.calculateParameterChangeSet(before,
|
|
92
|
+
const cs = ChangeSet.calculateParameterChangeSet(after, before, { statefulMode: true });
|
|
105
93
|
expect(cs.length).to.eq(1);
|
|
106
94
|
expect(cs[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
107
95
|
})
|