@codifycli/plugin-core 1.0.0-beta1
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/.eslintignore +2 -0
- package/.eslintrc.json +30 -0
- package/.github/workflows/release.yaml +19 -0
- package/.github/workflows/unit-test-ci.yaml +18 -0
- package/.prettierrc.json +1 -0
- package/bin/build.js +189 -0
- package/dist/bin/build.d.ts +1 -0
- package/dist/bin/build.js +80 -0
- package/dist/bin/deploy-plugin.d.ts +2 -0
- package/dist/bin/deploy-plugin.js +8 -0
- package/dist/common/errors.d.ts +8 -0
- package/dist/common/errors.js +24 -0
- package/dist/entities/change-set.d.ts +24 -0
- package/dist/entities/change-set.js +152 -0
- package/dist/entities/errors.d.ts +4 -0
- package/dist/entities/errors.js +7 -0
- package/dist/entities/plan-types.d.ts +25 -0
- package/dist/entities/plan-types.js +1 -0
- package/dist/entities/plan.d.ts +15 -0
- package/dist/entities/plan.js +127 -0
- package/dist/entities/plugin.d.ts +16 -0
- package/dist/entities/plugin.js +80 -0
- package/dist/entities/resource-options.d.ts +31 -0
- package/dist/entities/resource-options.js +76 -0
- package/dist/entities/resource-types.d.ts +11 -0
- package/dist/entities/resource-types.js +1 -0
- package/dist/entities/resource.d.ts +42 -0
- package/dist/entities/resource.js +303 -0
- package/dist/entities/stateful-parameter.d.ts +29 -0
- package/dist/entities/stateful-parameter.js +46 -0
- package/dist/entities/transform-parameter.d.ts +4 -0
- package/dist/entities/transform-parameter.js +2 -0
- package/dist/errors.d.ts +4 -0
- package/dist/errors.js +7 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +26 -0
- package/dist/messages/handlers.d.ts +14 -0
- package/dist/messages/handlers.js +134 -0
- package/dist/messages/sender.d.ts +11 -0
- package/dist/messages/sender.js +57 -0
- package/dist/plan/change-set.d.ts +53 -0
- package/dist/plan/change-set.js +153 -0
- package/dist/plan/plan-types.d.ts +23 -0
- package/dist/plan/plan-types.js +1 -0
- package/dist/plan/plan.d.ts +66 -0
- package/dist/plan/plan.js +328 -0
- package/dist/plugin/plugin.d.ts +24 -0
- package/dist/plugin/plugin.js +200 -0
- package/dist/pty/background-pty.d.ts +21 -0
- package/dist/pty/background-pty.js +127 -0
- package/dist/pty/index.d.ts +50 -0
- package/dist/pty/index.js +20 -0
- package/dist/pty/promise-queue.d.ts +5 -0
- package/dist/pty/promise-queue.js +26 -0
- package/dist/pty/seqeuntial-pty.d.ts +17 -0
- package/dist/pty/seqeuntial-pty.js +119 -0
- package/dist/pty/vitest.config.d.ts +2 -0
- package/dist/pty/vitest.config.js +11 -0
- package/dist/resource/config-parser.d.ts +11 -0
- package/dist/resource/config-parser.js +21 -0
- package/dist/resource/parsed-resource-settings.d.ts +47 -0
- package/dist/resource/parsed-resource-settings.js +196 -0
- package/dist/resource/resource-controller.d.ts +36 -0
- package/dist/resource/resource-controller.js +402 -0
- package/dist/resource/resource-settings.d.ts +303 -0
- package/dist/resource/resource-settings.js +147 -0
- package/dist/resource/resource.d.ts +144 -0
- package/dist/resource/resource.js +44 -0
- package/dist/resource/stateful-parameter.d.ts +165 -0
- package/dist/resource/stateful-parameter.js +94 -0
- package/dist/scripts/deploy.d.ts +1 -0
- package/dist/scripts/deploy.js +2 -0
- package/dist/stateful-parameter/stateful-parameter-controller.d.ts +21 -0
- package/dist/stateful-parameter/stateful-parameter-controller.js +81 -0
- package/dist/stateful-parameter/stateful-parameter.d.ts +144 -0
- package/dist/stateful-parameter/stateful-parameter.js +43 -0
- package/dist/test.d.ts +1 -0
- package/dist/test.js +5 -0
- package/dist/utils/codify-spawn.d.ts +29 -0
- package/dist/utils/codify-spawn.js +136 -0
- package/dist/utils/debug.d.ts +2 -0
- package/dist/utils/debug.js +10 -0
- package/dist/utils/file-utils.d.ts +23 -0
- package/dist/utils/file-utils.js +186 -0
- package/dist/utils/functions.d.ts +12 -0
- package/dist/utils/functions.js +74 -0
- package/dist/utils/index.d.ts +46 -0
- package/dist/utils/index.js +271 -0
- package/dist/utils/internal-utils.d.ts +12 -0
- package/dist/utils/internal-utils.js +74 -0
- package/dist/utils/load-resources.d.ts +1 -0
- package/dist/utils/load-resources.js +46 -0
- package/dist/utils/package-json-utils.d.ts +12 -0
- package/dist/utils/package-json-utils.js +34 -0
- package/dist/utils/pty-local-storage.d.ts +2 -0
- package/dist/utils/pty-local-storage.js +2 -0
- package/dist/utils/spawn-2.d.ts +5 -0
- package/dist/utils/spawn-2.js +7 -0
- package/dist/utils/spawn.d.ts +29 -0
- package/dist/utils/spawn.js +124 -0
- package/dist/utils/utils.d.ts +18 -0
- package/dist/utils/utils.js +86 -0
- package/dist/utils/verbosity-level.d.ts +5 -0
- package/dist/utils/verbosity-level.js +9 -0
- package/package.json +59 -0
- package/rollup.config.js +24 -0
- package/src/common/errors.test.ts +43 -0
- package/src/common/errors.ts +31 -0
- package/src/errors.ts +8 -0
- package/src/index.test.ts +6 -0
- package/src/index.ts +30 -0
- package/src/messages/handlers.test.ts +329 -0
- package/src/messages/handlers.ts +181 -0
- package/src/messages/sender.ts +69 -0
- package/src/plan/change-set.test.ts +280 -0
- package/src/plan/change-set.ts +236 -0
- package/src/plan/plan-types.ts +27 -0
- package/src/plan/plan.test.ts +413 -0
- package/src/plan/plan.ts +499 -0
- package/src/plugin/plugin.test.ts +533 -0
- package/src/plugin/plugin.ts +291 -0
- package/src/pty/background-pty.test.ts +69 -0
- package/src/pty/background-pty.ts +154 -0
- package/src/pty/index.test.ts +129 -0
- package/src/pty/index.ts +66 -0
- package/src/pty/promise-queue.ts +33 -0
- package/src/pty/seqeuntial-pty.ts +151 -0
- package/src/pty/sequential-pty.test.ts +194 -0
- package/src/resource/config-parser.ts +42 -0
- package/src/resource/parsed-resource-settings.test.ts +186 -0
- package/src/resource/parsed-resource-settings.ts +307 -0
- package/src/resource/resource-controller-stateful-mode.test.ts +253 -0
- package/src/resource/resource-controller.test.ts +1081 -0
- package/src/resource/resource-controller.ts +563 -0
- package/src/resource/resource-settings.test.ts +1213 -0
- package/src/resource/resource-settings.ts +545 -0
- package/src/resource/resource.ts +157 -0
- package/src/stateful-parameter/stateful-parameter-controller.test.ts +244 -0
- package/src/stateful-parameter/stateful-parameter-controller.ts +111 -0
- package/src/stateful-parameter/stateful-parameter.ts +160 -0
- package/src/utils/debug.ts +11 -0
- package/src/utils/file-utils.test.ts +7 -0
- package/src/utils/file-utils.ts +231 -0
- package/src/utils/functions.ts +103 -0
- package/src/utils/index.ts +340 -0
- package/src/utils/internal-utils.test.ts +52 -0
- package/src/utils/pty-local-storage.ts +3 -0
- package/src/utils/test-utils.test.ts +96 -0
- package/src/utils/verbosity-level.ts +11 -0
- package/tsconfig.json +26 -0
- package/tsconfig.test.json +9 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { Ajv, SchemaObject, ValidateFunction } from 'ajv';
|
|
2
|
+
import addFormats from 'ajv-formats';
|
|
3
|
+
import {
|
|
4
|
+
ApplyRequestDataSchema,
|
|
5
|
+
EmptyResponseDataSchema,
|
|
6
|
+
GetResourceInfoRequestDataSchema,
|
|
7
|
+
GetResourceInfoResponseDataSchema,
|
|
8
|
+
ImportRequestDataSchema,
|
|
9
|
+
ImportResponseDataSchema,
|
|
10
|
+
InitializeRequestDataSchema,
|
|
11
|
+
InitializeResponseDataSchema,
|
|
12
|
+
IpcMessage,
|
|
13
|
+
IpcMessageSchema,
|
|
14
|
+
IpcMessageV2,
|
|
15
|
+
IpcMessageV2Schema,
|
|
16
|
+
MatchRequestDataSchema,
|
|
17
|
+
MatchResponseDataSchema,
|
|
18
|
+
MessageStatus,
|
|
19
|
+
PlanRequestDataSchema,
|
|
20
|
+
PlanResponseDataSchema,
|
|
21
|
+
ResourceSchema,
|
|
22
|
+
SetVerbosityRequestDataSchema,
|
|
23
|
+
ValidateRequestDataSchema,
|
|
24
|
+
ValidateResponseDataSchema
|
|
25
|
+
} from 'codify-schemas';
|
|
26
|
+
|
|
27
|
+
import { SudoError } from '../errors.js';
|
|
28
|
+
import { Plugin } from '../plugin/plugin.js';
|
|
29
|
+
|
|
30
|
+
const SupportedRequests: Record<string, { handler: (plugin: Plugin, data: any) => Promise<unknown>; requestValidator: SchemaObject; responseValidator: SchemaObject }> = {
|
|
31
|
+
'initialize': {
|
|
32
|
+
handler: async (plugin: Plugin, data: any) => plugin.initialize(data),
|
|
33
|
+
requestValidator: InitializeRequestDataSchema,
|
|
34
|
+
responseValidator: InitializeResponseDataSchema
|
|
35
|
+
},
|
|
36
|
+
'validate': {
|
|
37
|
+
handler: async (plugin: Plugin, data: any) => plugin.validate(data),
|
|
38
|
+
requestValidator: ValidateRequestDataSchema,
|
|
39
|
+
responseValidator: ValidateResponseDataSchema
|
|
40
|
+
},
|
|
41
|
+
'getResourceInfo': {
|
|
42
|
+
handler: async (plugin: Plugin, data: any) => plugin.getResourceInfo(data),
|
|
43
|
+
requestValidator: GetResourceInfoRequestDataSchema,
|
|
44
|
+
responseValidator: GetResourceInfoResponseDataSchema
|
|
45
|
+
},
|
|
46
|
+
'setVerbosityLevel': {
|
|
47
|
+
async handler(plugin: Plugin, data: any) {
|
|
48
|
+
await plugin.setVerbosityLevel(data)
|
|
49
|
+
return null;
|
|
50
|
+
},
|
|
51
|
+
requestValidator: SetVerbosityRequestDataSchema,
|
|
52
|
+
responseValidator: EmptyResponseDataSchema,
|
|
53
|
+
},
|
|
54
|
+
'match': {
|
|
55
|
+
handler: async (plugin: Plugin, data: any) => plugin.match(data),
|
|
56
|
+
requestValidator: MatchRequestDataSchema,
|
|
57
|
+
responseValidator: MatchResponseDataSchema
|
|
58
|
+
},
|
|
59
|
+
'import': {
|
|
60
|
+
handler: async (plugin: Plugin, data: any) => plugin.import(data),
|
|
61
|
+
requestValidator: ImportRequestDataSchema,
|
|
62
|
+
responseValidator: ImportResponseDataSchema
|
|
63
|
+
},
|
|
64
|
+
'plan': {
|
|
65
|
+
handler: async (plugin: Plugin, data: any) => plugin.plan(data),
|
|
66
|
+
requestValidator: PlanRequestDataSchema,
|
|
67
|
+
responseValidator: PlanResponseDataSchema
|
|
68
|
+
},
|
|
69
|
+
'apply': {
|
|
70
|
+
async handler(plugin: Plugin, data: any) {
|
|
71
|
+
await plugin.apply(data);
|
|
72
|
+
return null;
|
|
73
|
+
},
|
|
74
|
+
requestValidator: ApplyRequestDataSchema,
|
|
75
|
+
responseValidator: EmptyResponseDataSchema
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export class MessageHandler {
|
|
80
|
+
private ajv: Ajv;
|
|
81
|
+
private readonly plugin: Plugin;
|
|
82
|
+
private messageSchemaValidatorV1: ValidateFunction;
|
|
83
|
+
private messageSchemaValidatorV2: ValidateFunction;
|
|
84
|
+
private requestValidators: Map<string, ValidateFunction>;
|
|
85
|
+
private responseValidators: Map<string, ValidateFunction>;
|
|
86
|
+
|
|
87
|
+
constructor(plugin: Plugin) {
|
|
88
|
+
this.ajv = new Ajv({ strict: true, strictRequired: false });
|
|
89
|
+
addFormats.default(this.ajv);
|
|
90
|
+
this.ajv.addSchema(ResourceSchema);
|
|
91
|
+
this.plugin = plugin;
|
|
92
|
+
|
|
93
|
+
this.messageSchemaValidatorV1 = this.ajv.compile(IpcMessageSchema);
|
|
94
|
+
this.messageSchemaValidatorV2 = this.ajv.compile(IpcMessageV2Schema);
|
|
95
|
+
|
|
96
|
+
this.requestValidators = new Map(
|
|
97
|
+
Object.entries(SupportedRequests)
|
|
98
|
+
.map(([k, v]) => [k, this.ajv.compile(v.requestValidator)])
|
|
99
|
+
)
|
|
100
|
+
this.responseValidators = new Map(
|
|
101
|
+
Object.entries(SupportedRequests)
|
|
102
|
+
.map(([k, v]) => [k, this.ajv.compile(v.responseValidator)])
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async onMessage(message: unknown): Promise<void> {
|
|
107
|
+
try {
|
|
108
|
+
if (!this.validateMessageV2(message) && !this.validateMessage(message)) {
|
|
109
|
+
throw new Error(`Plugin: ${this.plugin}. Message is malformed: ${JSON.stringify(this.messageSchemaValidatorV1.errors, null, 2)}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!this.requestValidators.has(message.cmd)) {
|
|
113
|
+
throw new Error(`Plugin: ${this.plugin}. Unsupported message: ${message.cmd}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const requestValidator = this.requestValidators.get(message.cmd)!;
|
|
117
|
+
if (!requestValidator(message.data)) {
|
|
118
|
+
throw new Error(`Plugin: ${this.plugin}. cmd: ${message.cmd}. Malformed message data: ${JSON.stringify(requestValidator.errors, null, 2)}`)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const result = await SupportedRequests[message.cmd].handler(this.plugin, message.data);
|
|
122
|
+
|
|
123
|
+
const responseValidator = this.responseValidators.get(message.cmd);
|
|
124
|
+
if (responseValidator && !responseValidator(result)) {
|
|
125
|
+
throw new Error(`Plugin: ${this.plugin.name}. Malformed response data: ${JSON.stringify(responseValidator.errors, null, 2)}. Received ${JSON.stringify(result, null, 2)}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
process.send!({
|
|
129
|
+
cmd: message.cmd + '_Response',
|
|
130
|
+
data: result,
|
|
131
|
+
// @ts-expect-error TS2239
|
|
132
|
+
requestId: message.requestId || undefined,
|
|
133
|
+
status: MessageStatus.SUCCESS,
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
} catch (error: unknown) {
|
|
137
|
+
this.handleErrors(message, error as Error);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private validateMessage(message: unknown): message is IpcMessage {
|
|
142
|
+
return this.messageSchemaValidatorV1(message);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private validateMessageV2(message: unknown): message is IpcMessageV2 {
|
|
146
|
+
return this.messageSchemaValidatorV2(message);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private handleErrors(message: unknown, e: Error) {
|
|
150
|
+
if (!message) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!message.hasOwnProperty('cmd')) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// @ts-expect-error TS2239
|
|
159
|
+
const cmd = message.cmd + '_Response';
|
|
160
|
+
|
|
161
|
+
if (e instanceof SudoError) {
|
|
162
|
+
return process.send?.({
|
|
163
|
+
cmd,
|
|
164
|
+
// @ts-expect-error TS2239
|
|
165
|
+
requestId: message.requestId || undefined,
|
|
166
|
+
data: `Plugin: '${this.plugin.name}'. Forbidden usage of sudo for command '${e.command}'. Please contact the plugin developer to fix this.`,
|
|
167
|
+
status: MessageStatus.ERROR,
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const isDebug = process.env.DEBUG?.includes('*') ?? false;
|
|
172
|
+
|
|
173
|
+
process.send?.({
|
|
174
|
+
cmd,
|
|
175
|
+
// @ts-expect-error TS2239
|
|
176
|
+
requestId: message.requestId || undefined,
|
|
177
|
+
data: isDebug ? e.stack : e.message,
|
|
178
|
+
status: MessageStatus.ERROR,
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Ajv } from 'ajv';
|
|
2
|
+
import { IpcMessageV2, IpcMessageV2Schema, MessageCmd, PressKeyToContinueRequestData } from 'codify-schemas';
|
|
3
|
+
import { nanoid } from 'nanoid';
|
|
4
|
+
|
|
5
|
+
const ajv = new Ajv({
|
|
6
|
+
strict: true,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Send requests to the Codify CLI
|
|
11
|
+
*/
|
|
12
|
+
class CodifyCliSenderImpl {
|
|
13
|
+
private readonly validateIpcMessageV2 = ajv.compile(IpcMessageV2Schema);
|
|
14
|
+
|
|
15
|
+
async requestPressKeyToContinuePrompt(message?: string): Promise<void> {
|
|
16
|
+
await this.sendAndWaitForResponse(<IpcMessageV2>{
|
|
17
|
+
cmd: MessageCmd.PRESS_KEY_TO_CONTINUE_REQUEST,
|
|
18
|
+
data: <PressKeyToContinueRequestData>{
|
|
19
|
+
promptMessage: message,
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async getCodifyCliCredentials(): Promise<string> {
|
|
25
|
+
const data = await this.sendAndWaitForResponse(<IpcMessageV2>{
|
|
26
|
+
cmd: MessageCmd.CODIFY_CREDENTIALS_REQUEST,
|
|
27
|
+
data: {},
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
if (typeof data.data !== 'string') {
|
|
31
|
+
throw new Error('Expected string back from credentials request');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return data.data;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private async sendAndWaitForResponse(message: IpcMessageV2): Promise<IpcMessageV2> {
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
const requestId = nanoid(8);
|
|
40
|
+
const listener = (data: IpcMessageV2) => {
|
|
41
|
+
if (data.requestId === requestId) {
|
|
42
|
+
process.removeListener('message', listener);
|
|
43
|
+
|
|
44
|
+
if (!this.validateIpcMessageV2(data)) {
|
|
45
|
+
throw new Error(`Invalid response for request.
|
|
46
|
+
Request:
|
|
47
|
+
${JSON.stringify(message, null, 2)}
|
|
48
|
+
Response:
|
|
49
|
+
${JSON.stringify(data, null, 2)}
|
|
50
|
+
Error:
|
|
51
|
+
${JSON.stringify(this.validateIpcMessageV2.errors, null, 2)}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
resolve(data);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
process.on('message', listener);
|
|
59
|
+
|
|
60
|
+
const ipcMessage = {
|
|
61
|
+
...message,
|
|
62
|
+
requestId,
|
|
63
|
+
}
|
|
64
|
+
process.send!(ipcMessage)
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const CodifyCliSender = new CodifyCliSenderImpl();
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { ChangeSet } from './change-set.js';
|
|
2
|
+
import { ParameterOperation, ResourceOperation } from 'codify-schemas';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
import { ParsedResourceSettings } from '../resource/parsed-resource-settings.js';
|
|
5
|
+
|
|
6
|
+
describe('Change set tests', () => {
|
|
7
|
+
it ('Correctly diffs two resource configs (modify)', () => {
|
|
8
|
+
const after = {
|
|
9
|
+
propA: 'before',
|
|
10
|
+
propB: 'before'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const before = {
|
|
14
|
+
propA: 'after',
|
|
15
|
+
propB: 'after'
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const cs = ChangeSet.calculateModification(after, before);
|
|
19
|
+
expect(cs.parameterChanges.length).to.eq(2);
|
|
20
|
+
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
21
|
+
expect(cs.parameterChanges[1].operation).to.eq(ParameterOperation.MODIFY);
|
|
22
|
+
expect(cs.operation).to.eq(ResourceOperation.RECREATE)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it ('Correctly diffs two resource configs (add)', () => {
|
|
26
|
+
const after = {
|
|
27
|
+
propA: 'before',
|
|
28
|
+
propB: 'after'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const before = {
|
|
32
|
+
propA: 'after',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const cs = ChangeSet.calculateModification(after, before);
|
|
36
|
+
expect(cs.parameterChanges.length).to.eq(2);
|
|
37
|
+
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
38
|
+
expect(cs.parameterChanges[1].operation).to.eq(ParameterOperation.ADD);
|
|
39
|
+
expect(cs.operation).to.eq(ResourceOperation.RECREATE)
|
|
40
|
+
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it ('Correctly diffs two resource configs (remove)', () => {
|
|
44
|
+
const after = {
|
|
45
|
+
propA: 'after',
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const before = {
|
|
49
|
+
propA: 'before',
|
|
50
|
+
propB: 'before'
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const cs = ChangeSet.calculateModification(after, before);
|
|
54
|
+
expect(cs.parameterChanges.length).to.eq(2);
|
|
55
|
+
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
56
|
+
expect(cs.parameterChanges[1].operation).to.eq(ParameterOperation.REMOVE);
|
|
57
|
+
expect(cs.operation).to.eq(ResourceOperation.RECREATE)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it ('Correctly diffs two resource configs (no-op)', () => {
|
|
61
|
+
const after = {
|
|
62
|
+
propA: 'prop',
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const before = {
|
|
66
|
+
propA: 'prop',
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const cs = ChangeSet.calculateModification(after, before);
|
|
70
|
+
expect(cs.parameterChanges.length).to.eq(1);
|
|
71
|
+
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.NOOP);
|
|
72
|
+
expect(cs.operation).to.eq(ResourceOperation.NOOP)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('Correctly diffs two resource configs (create)', () => {
|
|
76
|
+
const cs = ChangeSet.create({
|
|
77
|
+
propA: 'prop',
|
|
78
|
+
propB: 'propB'
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
expect(cs.parameterChanges.length).to.eq(2);
|
|
82
|
+
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.ADD);
|
|
83
|
+
expect(cs.parameterChanges[1].operation).to.eq(ParameterOperation.ADD);
|
|
84
|
+
expect(cs.operation).to.eq(ResourceOperation.CREATE)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('Correctly diffs two resource configs (destory)', () => {
|
|
88
|
+
const cs = ChangeSet.destroy({
|
|
89
|
+
propA: 'prop',
|
|
90
|
+
propB: 'propB',
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
expect(cs.parameterChanges.length).to.eq(2);
|
|
94
|
+
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.REMOVE);
|
|
95
|
+
expect(cs.parameterChanges[1].operation).to.eq(ParameterOperation.REMOVE);
|
|
96
|
+
expect(cs.operation).to.eq(ResourceOperation.DESTROY)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it ('handles simple arrays', () => {
|
|
100
|
+
const before = {
|
|
101
|
+
propA: ['a', 'b', 'c'],
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const after = {
|
|
105
|
+
propA: ['b', 'a', 'c'],
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
109
|
+
id: 'type',
|
|
110
|
+
parameterSettings: {
|
|
111
|
+
propA: { type: 'array' }
|
|
112
|
+
}
|
|
113
|
+
}).parameterSettings
|
|
114
|
+
|
|
115
|
+
const cs = ChangeSet.calculateModification(after, before, parameterSettings);
|
|
116
|
+
expect(cs.parameterChanges.length).to.eq(1);
|
|
117
|
+
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.NOOP);
|
|
118
|
+
expect(cs.operation).to.eq(ResourceOperation.NOOP)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('handles simple arrays 2', () => {
|
|
122
|
+
const after = {
|
|
123
|
+
propA: ['a', 'b', 'c'],
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const before = {
|
|
127
|
+
propA: ['b', 'a'],
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
131
|
+
id: 'type',
|
|
132
|
+
parameterSettings: {
|
|
133
|
+
propA: { type: 'array' }
|
|
134
|
+
}
|
|
135
|
+
}).parameterSettings
|
|
136
|
+
|
|
137
|
+
const cs = ChangeSet.calculateModification(after, before, parameterSettings);
|
|
138
|
+
expect(cs.parameterChanges.length).to.eq(1);
|
|
139
|
+
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
140
|
+
expect(cs.operation).to.eq(ResourceOperation.RECREATE)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('determines the order of operations with canModify 1', () => {
|
|
144
|
+
const after = {
|
|
145
|
+
propA: 'after',
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const before = {
|
|
149
|
+
propA: 'before',
|
|
150
|
+
propB: 'before'
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
154
|
+
id: 'type',
|
|
155
|
+
parameterSettings: {
|
|
156
|
+
propA: { canModify: true }
|
|
157
|
+
}
|
|
158
|
+
}).parameterSettings
|
|
159
|
+
|
|
160
|
+
const cs = ChangeSet.calculateModification(after, before, parameterSettings);
|
|
161
|
+
expect(cs.parameterChanges.length).to.eq(2);
|
|
162
|
+
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
163
|
+
expect(cs.parameterChanges[1].operation).to.eq(ParameterOperation.REMOVE);
|
|
164
|
+
expect(cs.operation).to.eq(ResourceOperation.RECREATE)
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it('determines the order of operations with canModify 2', () => {
|
|
168
|
+
const after = {
|
|
169
|
+
propA: 'after',
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const before = {
|
|
173
|
+
propA: 'before',
|
|
174
|
+
propB: 'before'
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
178
|
+
id: 'type',
|
|
179
|
+
parameterSettings: {
|
|
180
|
+
propA: { canModify: true },
|
|
181
|
+
propB: { canModify: true }
|
|
182
|
+
},
|
|
183
|
+
}).parameterSettings
|
|
184
|
+
|
|
185
|
+
const cs = ChangeSet.calculateModification<any>(after, before, parameterSettings);
|
|
186
|
+
expect(cs.parameterChanges.length).to.eq(2);
|
|
187
|
+
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
188
|
+
expect(cs.parameterChanges[1].operation).to.eq(ParameterOperation.REMOVE);
|
|
189
|
+
expect(cs.operation).to.eq(ResourceOperation.MODIFY)
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
it('correctly determines array equality', () => {
|
|
194
|
+
const arrA = ['a', 'b', 'd'];
|
|
195
|
+
const arrB = ['a', 'b', 'd'];
|
|
196
|
+
|
|
197
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
198
|
+
id: 'type',
|
|
199
|
+
parameterSettings: {
|
|
200
|
+
propA: { type: 'array' }
|
|
201
|
+
},
|
|
202
|
+
}).parameterSettings
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
const result = ChangeSet.calculateModification({ propA: arrA }, { propA: arrB }, parameterSettings)
|
|
206
|
+
|
|
207
|
+
expect(result.operation).to.eq(ResourceOperation.NOOP);
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it('correctly determines array equality 2', () => {
|
|
211
|
+
const arrA = ['a', 'b'];
|
|
212
|
+
const arrB = ['a', 'b', 'd'];
|
|
213
|
+
|
|
214
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
215
|
+
id: 'type',
|
|
216
|
+
parameterSettings: {
|
|
217
|
+
propA: { type: 'array' }
|
|
218
|
+
},
|
|
219
|
+
}).parameterSettings
|
|
220
|
+
|
|
221
|
+
const result = ChangeSet.calculateModification({ propA: arrA }, { propA: arrB }, parameterSettings)
|
|
222
|
+
|
|
223
|
+
expect(result.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it('correctly determines array equality 3', () => {
|
|
227
|
+
const arrA = ['b', 'a', 'd'];
|
|
228
|
+
const arrB = ['a', 'b', 'd'];
|
|
229
|
+
|
|
230
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
231
|
+
id: 'type',
|
|
232
|
+
parameterSettings: {
|
|
233
|
+
propA: { type: 'array' }
|
|
234
|
+
},
|
|
235
|
+
}).parameterSettings
|
|
236
|
+
|
|
237
|
+
const result = ChangeSet.calculateModification({ propA: arrA }, { propA: arrB }, parameterSettings)
|
|
238
|
+
|
|
239
|
+
expect(result.parameterChanges[0].operation).to.eq(ParameterOperation.NOOP);
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
it('correctly determines array equality 4', () => {
|
|
243
|
+
const arrA = [{ key1: 'a' }, { key1: 'a' }, { key1: 'a' }];
|
|
244
|
+
const arrB = [{ key1: 'a' }, { key1: 'a' }, { key1: 'b' }];
|
|
245
|
+
|
|
246
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
247
|
+
id: 'type',
|
|
248
|
+
parameterSettings: {
|
|
249
|
+
propA: {
|
|
250
|
+
type: 'array',
|
|
251
|
+
isElementEqual: (a, b) => a.key1 === b.key1
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
}).parameterSettings
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
const result = ChangeSet.calculateModification({ propA: arrA }, { propA: arrB }, parameterSettings)
|
|
258
|
+
|
|
259
|
+
expect(result.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it('correctly determines array equality 5', () => {
|
|
263
|
+
const arrA = [{ key1: 'b' }, { key1: 'a' }, { key1: 'a' }];
|
|
264
|
+
const arrB = [{ key1: 'a' }, { key1: 'a' }, { key1: 'b' }];
|
|
265
|
+
|
|
266
|
+
const parameterSettings = new ParsedResourceSettings({
|
|
267
|
+
id: 'type',
|
|
268
|
+
parameterSettings: {
|
|
269
|
+
propA: {
|
|
270
|
+
type: 'array',
|
|
271
|
+
isElementEqual: (a, b) => a.key1 === b.key1
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
}).parameterSettings
|
|
275
|
+
|
|
276
|
+
const result = ChangeSet.calculateModification({ propA: arrA }, { propA: arrB }, parameterSettings)
|
|
277
|
+
|
|
278
|
+
expect(result.parameterChanges[0].operation).to.eq(ParameterOperation.NOOP);
|
|
279
|
+
})
|
|
280
|
+
})
|