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.
- package/.eslintrc.json +11 -4
- package/.github/workflows/release.yaml +19 -0
- package/.github/workflows/unit-test-ci.yaml +19 -0
- package/dist/errors.d.ts +4 -0
- package/dist/errors.js +7 -0
- package/dist/index.d.ts +10 -10
- package/dist/index.js +9 -9
- package/dist/messages/handlers.d.ts +1 -1
- package/dist/messages/handlers.js +2 -1
- package/dist/plan/change-set.d.ts +37 -0
- package/dist/plan/change-set.js +146 -0
- package/dist/plan/plan-types.d.ts +23 -0
- package/dist/plan/plan-types.js +1 -0
- package/dist/plan/plan.d.ts +59 -0
- package/dist/plan/plan.js +228 -0
- package/dist/plugin/plugin.d.ts +17 -0
- package/dist/plugin/plugin.js +83 -0
- package/dist/resource/config-parser.d.ts +14 -0
- package/dist/resource/config-parser.js +48 -0
- package/dist/resource/parsed-resource-settings.d.ts +26 -0
- package/dist/resource/parsed-resource-settings.js +126 -0
- package/dist/resource/resource-controller.d.ts +30 -0
- package/dist/resource/resource-controller.js +247 -0
- package/dist/resource/resource-settings.d.ts +149 -0
- package/dist/resource/resource-settings.js +9 -0
- package/dist/resource/resource.d.ts +137 -0
- package/dist/resource/resource.js +44 -0
- package/dist/resource/stateful-parameter.d.ts +164 -0
- package/dist/resource/stateful-parameter.js +94 -0
- package/dist/utils/utils.d.ts +19 -3
- package/dist/utils/utils.js +52 -3
- package/package.json +5 -3
- package/src/index.ts +10 -11
- package/src/messages/handlers.test.ts +10 -37
- package/src/messages/handlers.ts +2 -2
- package/src/plan/change-set.test.ts +220 -0
- package/src/plan/change-set.ts +225 -0
- package/src/plan/plan-types.ts +27 -0
- package/src/{entities → plan}/plan.test.ts +35 -29
- package/src/plan/plan.ts +353 -0
- package/src/{entities → plugin}/plugin.test.ts +14 -13
- package/src/{entities → plugin}/plugin.ts +28 -24
- package/src/resource/config-parser.ts +77 -0
- package/src/{entities/resource-options.test.ts → resource/parsed-resource-settings.test.ts} +8 -7
- package/src/resource/parsed-resource-settings.ts +179 -0
- package/src/{entities/resource-stateful-mode.test.ts → resource/resource-controller-stateful-mode.test.ts} +36 -39
- package/src/{entities/resource.test.ts → resource/resource-controller.test.ts} +116 -176
- package/src/resource/resource-controller.ts +340 -0
- package/src/resource/resource-settings.test.ts +494 -0
- package/src/resource/resource-settings.ts +192 -0
- package/src/resource/resource.ts +149 -0
- package/src/resource/stateful-parameter.test.ts +93 -0
- package/src/resource/stateful-parameter.ts +217 -0
- package/src/utils/test-utils.test.ts +87 -0
- package/src/utils/utils.test.ts +2 -2
- package/src/utils/utils.ts +51 -5
- package/tsconfig.json +0 -1
- package/vitest.config.ts +10 -0
- package/src/entities/change-set.test.ts +0 -155
- package/src/entities/change-set.ts +0 -244
- package/src/entities/plan-types.ts +0 -44
- package/src/entities/plan.ts +0 -178
- package/src/entities/resource-options.ts +0 -155
- package/src/entities/resource-parameters.test.ts +0 -604
- package/src/entities/resource-types.ts +0 -31
- package/src/entities/resource.ts +0 -470
- package/src/entities/stateful-parameter.test.ts +0 -114
- package/src/entities/stateful-parameter.ts +0 -92
- package/src/entities/transform-parameter.ts +0 -13
- /package/src/{entities/errors.ts → errors.ts} +0 -0
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { ChangeSet } from './change-set.js';
|
|
2
|
-
import { ParameterOperation, ResourceOperation } from 'codify-schemas';
|
|
3
|
-
import { describe, expect, it } from 'vitest';
|
|
4
|
-
|
|
5
|
-
describe('Change set tests (stateful)', () => {
|
|
6
|
-
it ('Correctly diffs two resource configs (modify)', () => {
|
|
7
|
-
const after = {
|
|
8
|
-
propA: 'before',
|
|
9
|
-
propB: 'before'
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const before = {
|
|
13
|
-
propA: 'after',
|
|
14
|
-
propB: 'after'
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const cs = ChangeSet.calculateParameterChangeSet(after, before, { statefulMode: true });
|
|
18
|
-
expect(cs.length).to.eq(2);
|
|
19
|
-
expect(cs[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
20
|
-
expect(cs[1].operation).to.eq(ParameterOperation.MODIFY);
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
it ('Correctly diffs two resource configs (add)', () => {
|
|
24
|
-
const after = {
|
|
25
|
-
propA: 'before',
|
|
26
|
-
propB: 'after'
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const before = {
|
|
30
|
-
propA: 'after',
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const cs = ChangeSet.calculateParameterChangeSet(after, before, { statefulMode: true });
|
|
34
|
-
expect(cs.length).to.eq(2);
|
|
35
|
-
expect(cs[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
36
|
-
expect(cs[1].operation).to.eq(ParameterOperation.ADD);
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it ('Correctly diffs two resource configs (remove)', () => {
|
|
40
|
-
const after = {
|
|
41
|
-
propA: 'after',
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const before = {
|
|
45
|
-
propA: 'before',
|
|
46
|
-
propB: 'before'
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const cs = ChangeSet.calculateParameterChangeSet(after, before, { statefulMode: true });
|
|
50
|
-
expect(cs.length).to.eq(2);
|
|
51
|
-
expect(cs[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
52
|
-
expect(cs[1].operation).to.eq(ParameterOperation.REMOVE);
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it ('Correctly diffs two resource configs (no-op)', () => {
|
|
56
|
-
const after = {
|
|
57
|
-
propA: 'prop',
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const before = {
|
|
61
|
-
propA: 'prop',
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const cs = ChangeSet.calculateParameterChangeSet(after, before, { statefulMode: true });
|
|
65
|
-
expect(cs.length).to.eq(1);
|
|
66
|
-
expect(cs[0].operation).to.eq(ParameterOperation.NOOP);
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it ('handles simple arrays', () => {
|
|
70
|
-
const before = {
|
|
71
|
-
propA: ['a', 'b', 'c'],
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const after = {
|
|
75
|
-
propA: ['b', 'a', 'c'],
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const cs = ChangeSet.calculateParameterChangeSet(after, before, { statefulMode: true });
|
|
79
|
-
expect(cs.length).to.eq(1);
|
|
80
|
-
expect(cs[0].operation).to.eq(ParameterOperation.NOOP);
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it ('handles simple arrays', () => {
|
|
84
|
-
const after = {
|
|
85
|
-
propA: ['a', 'b', 'c'],
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const before = {
|
|
89
|
-
propA: ['b', 'a'],
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const cs = ChangeSet.calculateParameterChangeSet(after, before, { statefulMode: true });
|
|
93
|
-
expect(cs.length).to.eq(1);
|
|
94
|
-
expect(cs[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it ('determines the order of operations 1', () => {
|
|
98
|
-
const op1 = ResourceOperation.MODIFY;
|
|
99
|
-
const op2 = ResourceOperation.CREATE
|
|
100
|
-
|
|
101
|
-
const opResult = ChangeSet.combineResourceOperations(op1, op2);
|
|
102
|
-
expect(opResult).to.eq(ResourceOperation.CREATE);
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
it ('determines the order of operations 2', () => {
|
|
106
|
-
const op1 = ResourceOperation.NOOP;
|
|
107
|
-
const op2 = ResourceOperation.MODIFY
|
|
108
|
-
|
|
109
|
-
const opResult = ChangeSet.combineResourceOperations(op1, op2);
|
|
110
|
-
expect(opResult).to.eq(ResourceOperation.MODIFY);
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it ('determines the order of operations 3', () => {
|
|
114
|
-
const op1 = ResourceOperation.MODIFY;
|
|
115
|
-
const op2 = ResourceOperation.MODIFY
|
|
116
|
-
|
|
117
|
-
const opResult = ChangeSet.combineResourceOperations(op1, op2);
|
|
118
|
-
expect(opResult).to.eq(ResourceOperation.MODIFY);
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
it('correctly determines array equality', () => {
|
|
122
|
-
const arrA = ['a', 'b', 'd'];
|
|
123
|
-
const arrB = ['a', 'b', 'd'];
|
|
124
|
-
|
|
125
|
-
expect(ChangeSet.isSame(arrA, arrB)).to.be.true;
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
it('correctly determines array equality 2', () => {
|
|
129
|
-
const arrA = ['a', 'b'];
|
|
130
|
-
const arrB = ['a', 'b', 'd'];
|
|
131
|
-
|
|
132
|
-
expect(ChangeSet.isSame(arrA, arrB)).to.be.false;
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
it('correctly determines array equality 3', () => {
|
|
136
|
-
const arrA = ['b', 'a', 'd'];
|
|
137
|
-
const arrB = ['a', 'b', 'd'];
|
|
138
|
-
|
|
139
|
-
expect(ChangeSet.isSame(arrA, arrB)).to.be.true;
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
it('correctly determines array equality 4', () => {
|
|
143
|
-
const arrA = [{ key1: 'a' }, { key1: 'a' }, { key1: 'a' }];
|
|
144
|
-
const arrB = [{ key1: 'a' }, { key1: 'a' }, { key1: 'b' }];
|
|
145
|
-
|
|
146
|
-
expect(ChangeSet.isSame(arrA, arrB)).to.be.false;
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
it('correctly determines array equality 5', () => {
|
|
150
|
-
const arrA = [{ key1: 'b' }, { key1: 'a' }, { key1: 'a' }];
|
|
151
|
-
const arrB = [{ key1: 'a' }, { key1: 'a' }, { key1: 'b' }];
|
|
152
|
-
|
|
153
|
-
expect(ChangeSet.isSame(arrA, arrB)).to.be.false;
|
|
154
|
-
})
|
|
155
|
-
})
|
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import { ParameterOperation, ResourceOperation, StringIndexedObject } from 'codify-schemas';
|
|
2
|
-
import { ParameterOptions } from './plan-types.js';
|
|
3
|
-
|
|
4
|
-
export interface ParameterChange<T extends StringIndexedObject> {
|
|
5
|
-
name: keyof T & string;
|
|
6
|
-
operation: ParameterOperation;
|
|
7
|
-
previousValue: any | null;
|
|
8
|
-
newValue: any | null;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export class ChangeSet<T extends StringIndexedObject> {
|
|
12
|
-
operation: ResourceOperation
|
|
13
|
-
parameterChanges: Array<ParameterChange<T>>
|
|
14
|
-
|
|
15
|
-
constructor(
|
|
16
|
-
operation: ResourceOperation,
|
|
17
|
-
parameterChanges: Array<ParameterChange<T>>
|
|
18
|
-
) {
|
|
19
|
-
this.operation = operation;
|
|
20
|
-
this.parameterChanges = parameterChanges;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
get desiredParameters(): T {
|
|
24
|
-
return this.parameterChanges
|
|
25
|
-
.reduce((obj, pc) => ({
|
|
26
|
-
...obj,
|
|
27
|
-
[pc.name]: pc.newValue,
|
|
28
|
-
}), {}) as T;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
get currentParameters(): T {
|
|
32
|
-
return this.parameterChanges
|
|
33
|
-
.reduce((obj, pc) => ({
|
|
34
|
-
...obj,
|
|
35
|
-
[pc.name]: pc.previousValue,
|
|
36
|
-
}), {}) as T;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// static create<T extends Record<string, unknown>>(prev: T, next: T, options: {
|
|
40
|
-
// statefulMode: boolean,
|
|
41
|
-
// }): ChangeSet {
|
|
42
|
-
// const parameterChanges = ChangeSet.calculateParameterChangeSet(prev, prev, options);
|
|
43
|
-
// const operation = ChangeSet.combineResourceOperations(prev, );
|
|
44
|
-
// }
|
|
45
|
-
|
|
46
|
-
// static newCreate<T extends {}>(desiredConfig: T) {
|
|
47
|
-
// const parameterChangeSet = Object.entries(desiredConfig)
|
|
48
|
-
// .filter(([k,]) => k !== 'type' && k !== 'name')
|
|
49
|
-
// .map(([k, v]) => {
|
|
50
|
-
// return {
|
|
51
|
-
// name: k,
|
|
52
|
-
// operation: ParameterOperation.ADD,
|
|
53
|
-
// previousValue: null,
|
|
54
|
-
// newValue: v,
|
|
55
|
-
// }
|
|
56
|
-
// })
|
|
57
|
-
//
|
|
58
|
-
// return new ChangeSet(ResourceOperation.CREATE, parameterChangeSet);
|
|
59
|
-
// }
|
|
60
|
-
|
|
61
|
-
static calculateParameterChangeSet<T extends StringIndexedObject>(
|
|
62
|
-
desired: T | null,
|
|
63
|
-
current: T | null,
|
|
64
|
-
options: { statefulMode: boolean, parameterOptions?: Record<keyof T, ParameterOptions> },
|
|
65
|
-
): ParameterChange<T>[] {
|
|
66
|
-
if (options.statefulMode) {
|
|
67
|
-
return ChangeSet.calculateStatefulModeChangeSet(desired, current, options.parameterOptions);
|
|
68
|
-
} else {
|
|
69
|
-
return ChangeSet.calculateStatelessModeChangeSet(desired, current, options.parameterOptions);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
static combineResourceOperations(prev: ResourceOperation, next: ResourceOperation) {
|
|
74
|
-
const orderOfOperations = [
|
|
75
|
-
ResourceOperation.NOOP,
|
|
76
|
-
ResourceOperation.MODIFY,
|
|
77
|
-
ResourceOperation.RECREATE,
|
|
78
|
-
ResourceOperation.CREATE,
|
|
79
|
-
ResourceOperation.DESTROY,
|
|
80
|
-
]
|
|
81
|
-
|
|
82
|
-
const indexPrev = orderOfOperations.indexOf(prev);
|
|
83
|
-
const indexNext = orderOfOperations.indexOf(next);
|
|
84
|
-
|
|
85
|
-
return orderOfOperations[Math.max(indexPrev, indexNext)];
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
static isSame(
|
|
89
|
-
desired: unknown,
|
|
90
|
-
current: unknown,
|
|
91
|
-
options?: ParameterOptions,
|
|
92
|
-
): boolean {
|
|
93
|
-
if (options?.isEqual) {
|
|
94
|
-
return options.isEqual(desired, current);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (Array.isArray(desired) && Array.isArray(current)) {
|
|
98
|
-
const sortedDesired = desired.map((x) => x).sort();
|
|
99
|
-
const sortedCurrent = current.map((x) => x).sort();
|
|
100
|
-
|
|
101
|
-
if (sortedDesired.length !== sortedCurrent.length) {
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (options?.isElementEqual) {
|
|
106
|
-
return sortedDesired.every((value, index) =>
|
|
107
|
-
options.isElementEqual!(value, sortedCurrent[index])
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return JSON.stringify(sortedDesired) === JSON.stringify(sortedCurrent);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return desired === current;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Explanation: Stateful mode means that codify maintains a stateful to keep track of resources it has added.
|
|
118
|
-
// When a resource is removed from a stateful config, it will be deleted from the system.
|
|
119
|
-
private static calculateStatefulModeChangeSet<T extends StringIndexedObject>(
|
|
120
|
-
desired: T | null,
|
|
121
|
-
current: T | null,
|
|
122
|
-
parameterOptions?: Record<keyof T, ParameterOptions>,
|
|
123
|
-
): ParameterChange<T>[] {
|
|
124
|
-
const parameterChangeSet = new Array<ParameterChange<T>>();
|
|
125
|
-
|
|
126
|
-
const _desired = Object.fromEntries(Object.entries(desired ?? {}).filter(([, v]) => v != null));
|
|
127
|
-
const _current = Object.fromEntries(Object.entries(current ?? {}).filter(([, v]) => v != null));
|
|
128
|
-
|
|
129
|
-
this.addDefaultValues(_desired, parameterOptions);
|
|
130
|
-
|
|
131
|
-
for (const [k, v] of Object.entries(_current)) {
|
|
132
|
-
if (_desired[k] == null) {
|
|
133
|
-
parameterChangeSet.push({
|
|
134
|
-
name: k,
|
|
135
|
-
previousValue: v,
|
|
136
|
-
newValue: null,
|
|
137
|
-
operation: ParameterOperation.REMOVE,
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
delete _current[k];
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (!ChangeSet.isSame(_desired[k], _current[k], parameterOptions?.[k])) {
|
|
145
|
-
parameterChangeSet.push({
|
|
146
|
-
name: k,
|
|
147
|
-
previousValue: v,
|
|
148
|
-
newValue: _desired[k],
|
|
149
|
-
operation: ParameterOperation.MODIFY,
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
delete _current[k];
|
|
153
|
-
delete _desired[k];
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
parameterChangeSet.push({
|
|
158
|
-
name: k,
|
|
159
|
-
previousValue: v,
|
|
160
|
-
newValue: _desired[k],
|
|
161
|
-
operation: ParameterOperation.NOOP,
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
delete _current[k];
|
|
165
|
-
delete _desired[k];
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (Object.keys(_current).length !== 0) {
|
|
169
|
-
throw Error('Diff algorithm error');
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
for (const [k, v] of Object.entries(_desired)) {
|
|
173
|
-
parameterChangeSet.push({
|
|
174
|
-
name: k,
|
|
175
|
-
previousValue: null,
|
|
176
|
-
newValue: v,
|
|
177
|
-
operation: ParameterOperation.ADD,
|
|
178
|
-
})
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return parameterChangeSet;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Explanation: Stateful mode means that codify does not keep track of state. Resources in stateless mode can only
|
|
185
|
-
// be added by Codify and not destroyed.
|
|
186
|
-
private static calculateStatelessModeChangeSet<T extends StringIndexedObject>(
|
|
187
|
-
desired: T | null,
|
|
188
|
-
current: T | null,
|
|
189
|
-
parameterOptions?: Record<keyof T, ParameterOptions>,
|
|
190
|
-
): ParameterChange<T>[] {
|
|
191
|
-
const parameterChangeSet = new Array<ParameterChange<T>>();
|
|
192
|
-
|
|
193
|
-
const _desired = Object.fromEntries(Object.entries(desired ?? {}).filter(([, v]) => v != null));
|
|
194
|
-
const _current = Object.fromEntries(Object.entries(current ?? {}).filter(([, v]) => v != null));
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
this.addDefaultValues(_desired, parameterOptions);
|
|
198
|
-
|
|
199
|
-
for (const [k, v] of Object.entries(_desired)) {
|
|
200
|
-
if (_current[k] == null) {
|
|
201
|
-
parameterChangeSet.push({
|
|
202
|
-
name: k,
|
|
203
|
-
previousValue: null,
|
|
204
|
-
newValue: v,
|
|
205
|
-
operation: ParameterOperation.ADD,
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (!ChangeSet.isSame(_desired[k], _current[k], parameterOptions?.[k])) {
|
|
212
|
-
parameterChangeSet.push({
|
|
213
|
-
name: k,
|
|
214
|
-
previousValue: _current[k],
|
|
215
|
-
newValue: _desired[k],
|
|
216
|
-
operation: ParameterOperation.MODIFY,
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
parameterChangeSet.push({
|
|
223
|
-
name: k,
|
|
224
|
-
previousValue: v,
|
|
225
|
-
newValue: v,
|
|
226
|
-
operation: ParameterOperation.NOOP,
|
|
227
|
-
})
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return parameterChangeSet;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
private static addDefaultValues<T extends StringIndexedObject>(obj: Record<string, unknown>, options?: Record<keyof T, ParameterOptions>) {
|
|
234
|
-
Object.entries(options ?? {})
|
|
235
|
-
.filter(([, option]) => option.default !== undefined)
|
|
236
|
-
.map(([name, option]) => [name, option.default] as const)
|
|
237
|
-
.forEach(([key, defaultValue]) => {
|
|
238
|
-
if (obj[key] === undefined) {
|
|
239
|
-
obj[key] = defaultValue;
|
|
240
|
-
}
|
|
241
|
-
})
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { Plan } from './plan.js';
|
|
2
|
-
import { StringIndexedObject } from 'codify-schemas';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Customize properties for specific parameters. This will alter the way the library process changes to the parameter.
|
|
6
|
-
*/
|
|
7
|
-
export interface ParameterOptions {
|
|
8
|
-
/**
|
|
9
|
-
* Chose if the resource should be re-created or modified if this parameter is changed. Defaults to false (re-creates resource on change).
|
|
10
|
-
*/
|
|
11
|
-
modifyOnChange?: boolean;
|
|
12
|
-
/**
|
|
13
|
-
* Customize the equality comparison for a parameter.
|
|
14
|
-
* @param a
|
|
15
|
-
* @param b
|
|
16
|
-
*/
|
|
17
|
-
isEqual?: (desired: any, current: any) => boolean;
|
|
18
|
-
|
|
19
|
-
isElementEqual?: (desired: any, current: any) => boolean;
|
|
20
|
-
|
|
21
|
-
default?: unknown,
|
|
22
|
-
|
|
23
|
-
isStatefulParameter?: boolean;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface PlanOptions<T> {
|
|
27
|
-
statefulMode: boolean;
|
|
28
|
-
parameterOptions?: Record<keyof T, ParameterOptions>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface CreatePlan<T extends StringIndexedObject> extends Plan<T> {
|
|
32
|
-
desiredConfig: T;
|
|
33
|
-
currentConfig: null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface DestroyPlan<T extends StringIndexedObject> extends Plan<T> {
|
|
37
|
-
desiredConfig: null;
|
|
38
|
-
currentConfig: T;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface ModifyPlan<T extends StringIndexedObject> extends Plan<T> {
|
|
42
|
-
desiredConfig: T;
|
|
43
|
-
currentConfig: T;
|
|
44
|
-
}
|
package/src/entities/plan.ts
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { ChangeSet, ParameterChange } from './change-set.js';
|
|
2
|
-
import {
|
|
3
|
-
ApplyRequestData,
|
|
4
|
-
ParameterOperation,
|
|
5
|
-
PlanResponseData,
|
|
6
|
-
ResourceConfig,
|
|
7
|
-
ResourceOperation,
|
|
8
|
-
StringIndexedObject,
|
|
9
|
-
} from 'codify-schemas';
|
|
10
|
-
import { randomUUID } from 'crypto';
|
|
11
|
-
import { ParameterOptions, PlanOptions } from './plan-types.js';
|
|
12
|
-
|
|
13
|
-
export class Plan<T extends StringIndexedObject> {
|
|
14
|
-
id: string;
|
|
15
|
-
changeSet: ChangeSet<T>;
|
|
16
|
-
resourceMetadata: ResourceConfig
|
|
17
|
-
|
|
18
|
-
constructor(id: string, changeSet: ChangeSet<T>, resourceMetadata: ResourceConfig) {
|
|
19
|
-
this.id = id;
|
|
20
|
-
this.changeSet = changeSet;
|
|
21
|
-
this.resourceMetadata = resourceMetadata;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
static create<T extends StringIndexedObject>(
|
|
25
|
-
desiredParameters: Partial<T> | null,
|
|
26
|
-
currentParameters: Partial<T> | null,
|
|
27
|
-
resourceMetadata: ResourceConfig,
|
|
28
|
-
options: PlanOptions<T>
|
|
29
|
-
): Plan<T> {
|
|
30
|
-
const parameterOptions = options.parameterOptions ?? {} as Record<keyof T, ParameterOptions>;
|
|
31
|
-
const statefulParameterNames = new Set(
|
|
32
|
-
[...Object.entries(parameterOptions)]
|
|
33
|
-
.filter(([k, v]) => v.isStatefulParameter)
|
|
34
|
-
.map(([k, v]) => k)
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
// Explanation: This calculates the change set of the parameters between the
|
|
38
|
-
// two configs and then passes it to ChangeSet to calculate the overall
|
|
39
|
-
// operation for the resource
|
|
40
|
-
const parameterChangeSet = ChangeSet.calculateParameterChangeSet(
|
|
41
|
-
desiredParameters,
|
|
42
|
-
currentParameters,
|
|
43
|
-
{ statefulMode: options.statefulMode, parameterOptions }
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
let resourceOperation: ResourceOperation;
|
|
47
|
-
if (!currentParameters && desiredParameters) {
|
|
48
|
-
resourceOperation = ResourceOperation.CREATE;
|
|
49
|
-
} else if (currentParameters && !desiredParameters) {
|
|
50
|
-
resourceOperation = ResourceOperation.DESTROY;
|
|
51
|
-
} else {
|
|
52
|
-
resourceOperation = parameterChangeSet
|
|
53
|
-
.filter((change) => change.operation !== ParameterOperation.NOOP)
|
|
54
|
-
.reduce((operation: ResourceOperation, curr: ParameterChange<T>) => {
|
|
55
|
-
let newOperation: ResourceOperation;
|
|
56
|
-
if (statefulParameterNames.has(curr.name)) {
|
|
57
|
-
newOperation = ResourceOperation.MODIFY // All stateful parameters are modify only
|
|
58
|
-
} else if (parameterOptions[curr.name]?.modifyOnChange) {
|
|
59
|
-
newOperation = parameterOptions[curr.name].modifyOnChange ? ResourceOperation.MODIFY : ResourceOperation.RECREATE;
|
|
60
|
-
} else {
|
|
61
|
-
newOperation = ResourceOperation.RECREATE; // Default to Re-create. Should handle the majority of use cases
|
|
62
|
-
}
|
|
63
|
-
return ChangeSet.combineResourceOperations(operation, newOperation);
|
|
64
|
-
}, ResourceOperation.NOOP);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return new Plan(
|
|
68
|
-
randomUUID(),
|
|
69
|
-
new ChangeSet<T>(resourceOperation, parameterChangeSet),
|
|
70
|
-
resourceMetadata,
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
getResourceType(): string {
|
|
75
|
-
return this.resourceMetadata.type
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
static fromResponse<T extends ResourceConfig>(data: ApplyRequestData['plan'], defaultValues?: Partial<Record<keyof T, unknown>>): Plan<T> {
|
|
79
|
-
if (!data) {
|
|
80
|
-
throw new Error('Data is empty');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
addDefaultValues();
|
|
84
|
-
|
|
85
|
-
return new Plan(
|
|
86
|
-
randomUUID(),
|
|
87
|
-
new ChangeSet<T>(
|
|
88
|
-
data.operation,
|
|
89
|
-
data.parameters
|
|
90
|
-
),
|
|
91
|
-
{
|
|
92
|
-
type: data.resourceType,
|
|
93
|
-
name: data.resourceName,
|
|
94
|
-
},
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
function addDefaultValues(): void {
|
|
98
|
-
Object.entries(defaultValues ?? {})
|
|
99
|
-
.forEach(([key, defaultValue]) => {
|
|
100
|
-
const configValueExists = data!
|
|
101
|
-
.parameters
|
|
102
|
-
.some((p) => p.name === key);
|
|
103
|
-
|
|
104
|
-
// Only set default values if the value does not exist in the config
|
|
105
|
-
if (configValueExists) {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
switch (data!.operation) {
|
|
110
|
-
case ResourceOperation.CREATE: {
|
|
111
|
-
data!.parameters.push({
|
|
112
|
-
name: key,
|
|
113
|
-
operation: ParameterOperation.ADD,
|
|
114
|
-
previousValue: null,
|
|
115
|
-
newValue: defaultValue,
|
|
116
|
-
});
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
case ResourceOperation.DESTROY: {
|
|
121
|
-
data!.parameters.push({
|
|
122
|
-
name: key,
|
|
123
|
-
operation: ParameterOperation.REMOVE,
|
|
124
|
-
previousValue: defaultValue,
|
|
125
|
-
newValue: null,
|
|
126
|
-
});
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
case ResourceOperation.MODIFY:
|
|
131
|
-
case ResourceOperation.RECREATE:
|
|
132
|
-
case ResourceOperation.NOOP: {
|
|
133
|
-
data!.parameters.push({
|
|
134
|
-
name: key,
|
|
135
|
-
operation: ParameterOperation.NOOP,
|
|
136
|
-
previousValue: defaultValue,
|
|
137
|
-
newValue: defaultValue,
|
|
138
|
-
});
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
get desiredConfig(): T | null {
|
|
148
|
-
if (this.changeSet.operation === ResourceOperation.DESTROY) {
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return {
|
|
153
|
-
...this.resourceMetadata,
|
|
154
|
-
...this.changeSet.desiredParameters,
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
get currentConfig(): T | null {
|
|
159
|
-
if (this.changeSet.operation === ResourceOperation.CREATE) {
|
|
160
|
-
return null;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return {
|
|
164
|
-
...this.resourceMetadata,
|
|
165
|
-
...this.changeSet.currentParameters,
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
toResponse(): PlanResponseData {
|
|
170
|
-
return {
|
|
171
|
-
planId: this.id,
|
|
172
|
-
operation: this.changeSet.operation,
|
|
173
|
-
resourceName: this.resourceMetadata.name,
|
|
174
|
-
resourceType: this.resourceMetadata.type,
|
|
175
|
-
parameters: this.changeSet.parameterChanges,
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|