codify-plugin-lib 1.0.91 → 1.0.94
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/messages/handlers.js +6 -1
- package/dist/plugin/plugin.d.ts +2 -1
- package/dist/plugin/plugin.js +20 -1
- package/dist/resource/resource-controller.d.ts +2 -0
- package/dist/resource/resource-controller.js +29 -0
- package/dist/resource/resource-settings.d.ts +3 -0
- package/package.json +2 -2
- package/src/messages/handlers.ts +7 -0
- package/src/plugin/plugin.ts +29 -1
- package/src/resource/resource-controller.ts +42 -0
- package/src/resource/resource-settings.test.ts +16 -0
- package/src/resource/resource-settings.ts +4 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Ajv } from 'ajv';
|
|
2
2
|
import addFormats from 'ajv-formats';
|
|
3
|
-
import { ApplyRequestDataSchema, ApplyResponseDataSchema, GetResourceInfoRequestDataSchema, GetResourceInfoResponseDataSchema, InitializeRequestDataSchema, InitializeResponseDataSchema, IpcMessageSchema, MessageStatus, PlanRequestDataSchema, PlanResponseDataSchema, ResourceSchema, ValidateRequestDataSchema, ValidateResponseDataSchema } from 'codify-schemas';
|
|
3
|
+
import { ApplyRequestDataSchema, ApplyResponseDataSchema, GetResourceInfoRequestDataSchema, GetResourceInfoResponseDataSchema, ImportRequestDataSchema, ImportResponseDataSchema, InitializeRequestDataSchema, InitializeResponseDataSchema, IpcMessageSchema, MessageStatus, PlanRequestDataSchema, PlanResponseDataSchema, ResourceSchema, ValidateRequestDataSchema, ValidateResponseDataSchema } from 'codify-schemas';
|
|
4
4
|
import { SudoError } from '../errors.js';
|
|
5
5
|
const SupportedRequests = {
|
|
6
6
|
'initialize': {
|
|
@@ -18,6 +18,11 @@ const SupportedRequests = {
|
|
|
18
18
|
requestValidator: GetResourceInfoRequestDataSchema,
|
|
19
19
|
responseValidator: GetResourceInfoResponseDataSchema
|
|
20
20
|
},
|
|
21
|
+
'import': {
|
|
22
|
+
handler: async (plugin, data) => plugin.import(data),
|
|
23
|
+
requestValidator: ImportRequestDataSchema,
|
|
24
|
+
responseValidator: ImportResponseDataSchema
|
|
25
|
+
},
|
|
21
26
|
'plan': {
|
|
22
27
|
handler: async (plugin, data) => plugin.plan(data),
|
|
23
28
|
requestValidator: PlanRequestDataSchema,
|
package/dist/plugin/plugin.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ApplyRequestData, GetResourceInfoRequestData, GetResourceInfoResponseData, InitializeResponseData, PlanRequestData, PlanResponseData, ResourceConfig, ValidateRequestData, ValidateResponseData } from 'codify-schemas';
|
|
1
|
+
import { ApplyRequestData, GetResourceInfoRequestData, GetResourceInfoResponseData, ImportRequestData, ImportResponseData, InitializeResponseData, PlanRequestData, PlanResponseData, ResourceConfig, ValidateRequestData, ValidateResponseData } from 'codify-schemas';
|
|
2
2
|
import { Plan } from '../plan/plan.js';
|
|
3
3
|
import { Resource } from '../resource/resource.js';
|
|
4
4
|
import { ResourceController } from '../resource/resource-controller.js';
|
|
@@ -10,6 +10,7 @@ export declare class Plugin {
|
|
|
10
10
|
static create(name: string, resources: Resource<any>[]): Plugin;
|
|
11
11
|
initialize(): Promise<InitializeResponseData>;
|
|
12
12
|
getResourceInfo(data: GetResourceInfoRequestData): Promise<GetResourceInfoResponseData>;
|
|
13
|
+
import(data: ImportRequestData): Promise<ImportResponseData>;
|
|
13
14
|
validate(data: ValidateRequestData): Promise<ValidateResponseData>;
|
|
14
15
|
plan(data: PlanRequestData): Promise<PlanResponseData>;
|
|
15
16
|
apply(data: ApplyRequestData): Promise<void>;
|
package/dist/plugin/plugin.js
CHANGED
|
@@ -32,11 +32,30 @@ export class Plugin {
|
|
|
32
32
|
throw new Error(`Cannot get info for resource ${data.type}, resource doesn't exist`);
|
|
33
33
|
}
|
|
34
34
|
const resource = this.resourceControllers.get(data.type);
|
|
35
|
+
const schema = resource.settings.schema;
|
|
36
|
+
const requiredPropertyNames = (resource.settings.import?.requiredParameters
|
|
37
|
+
?? schema.required
|
|
38
|
+
?? null);
|
|
35
39
|
return {
|
|
36
40
|
plugin: this.name,
|
|
37
41
|
type: data.type,
|
|
38
42
|
dependencies: resource.dependencies,
|
|
39
|
-
schema:
|
|
43
|
+
schema: schema,
|
|
44
|
+
import: resource.settings.import ? {
|
|
45
|
+
requiredParameters: requiredPropertyNames,
|
|
46
|
+
} : undefined,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async import(data) {
|
|
50
|
+
if (!this.resourceControllers.has(data.config.type)) {
|
|
51
|
+
throw new Error(`Cannot get info for resource ${data.config.type}, resource doesn't exist`);
|
|
52
|
+
}
|
|
53
|
+
const result = await this.resourceControllers
|
|
54
|
+
.get(data.config.type)
|
|
55
|
+
?.import(data.config);
|
|
56
|
+
return {
|
|
57
|
+
request: data.config,
|
|
58
|
+
result: result ?? [],
|
|
40
59
|
};
|
|
41
60
|
}
|
|
42
61
|
async validate(data) {
|
|
@@ -17,6 +17,7 @@ export declare class ResourceController<T extends StringIndexedObject> {
|
|
|
17
17
|
validate(desiredConfig: Partial<T> & ResourceConfig): Promise<ValidateResponseData['resourceValidations'][0]>;
|
|
18
18
|
plan(desiredConfig: Partial<T> & ResourceConfig | null, stateConfig?: Partial<T> & ResourceConfig | null, statefulMode?: boolean): Promise<Plan<T>>;
|
|
19
19
|
apply(plan: Plan<T>): Promise<void>;
|
|
20
|
+
import(config: Partial<T> & ResourceConfig): Promise<(Partial<T> & ResourceConfig)[] | null>;
|
|
20
21
|
private applyCreate;
|
|
21
22
|
private applyModify;
|
|
22
23
|
private applyDestroy;
|
|
@@ -27,4 +28,5 @@ export declare class ResourceController<T extends StringIndexedObject> {
|
|
|
27
28
|
private refreshStatefulParameters;
|
|
28
29
|
private validatePlanInputs;
|
|
29
30
|
private getSortedStatefulParameterChanges;
|
|
31
|
+
private getAllParameterKeys;
|
|
30
32
|
}
|
|
@@ -130,6 +130,30 @@ export class ResourceController {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
+
async import(config) {
|
|
134
|
+
this.addDefaultValues(config);
|
|
135
|
+
await this.applyTransformParameters(config);
|
|
136
|
+
// Try to refresh as many parameters as possible here
|
|
137
|
+
const parametersToRefresh = {
|
|
138
|
+
...Object.fromEntries(this.getAllParameterKeys().map((k) => [k, null])),
|
|
139
|
+
...config,
|
|
140
|
+
};
|
|
141
|
+
// Parse data from the user supplied config
|
|
142
|
+
const parsedConfig = new ConfigParser(parametersToRefresh, null, this.parsedSettings.statefulParameters);
|
|
143
|
+
const { allNonStatefulParameters, allStatefulParameters, coreParameters, } = parsedConfig;
|
|
144
|
+
const currentParametersArray = await this.refreshNonStatefulParameters(allNonStatefulParameters);
|
|
145
|
+
if (currentParametersArray === null
|
|
146
|
+
|| currentParametersArray === undefined
|
|
147
|
+
|| this.settings.allowMultiple // Stateful parameters are not supported currently if allowMultiple is true
|
|
148
|
+
|| currentParametersArray.length === 0
|
|
149
|
+
|| currentParametersArray.filter(Boolean).length === 0) {
|
|
150
|
+
return currentParametersArray
|
|
151
|
+
?.map((r) => ({ ...coreParameters, ...r }))
|
|
152
|
+
?? null;
|
|
153
|
+
}
|
|
154
|
+
const statefulCurrentParameters = await this.refreshStatefulParameters(allStatefulParameters, parametersToRefresh);
|
|
155
|
+
return [{ ...coreParameters, ...currentParametersArray[0], ...statefulCurrentParameters }];
|
|
156
|
+
}
|
|
133
157
|
async applyCreate(plan) {
|
|
134
158
|
await this.resource.create(plan);
|
|
135
159
|
const statefulParameterChanges = this.getSortedStatefulParameterChanges(plan.changeSet.parameterChanges);
|
|
@@ -253,4 +277,9 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
253
277
|
.filter((pc) => this.parsedSettings.statefulParameters.has(pc.name))
|
|
254
278
|
.sort((a, b) => this.parsedSettings.statefulParameterOrder.get(a.name) - this.parsedSettings.statefulParameterOrder.get(b.name));
|
|
255
279
|
}
|
|
280
|
+
getAllParameterKeys() {
|
|
281
|
+
return this.settings.schema
|
|
282
|
+
? Object.keys(this.settings.schema?.properties)
|
|
283
|
+
: Object.keys(this.parsedSettings.parameterSettings);
|
|
284
|
+
}
|
|
256
285
|
}
|
|
@@ -52,6 +52,9 @@ export interface ResourceSettings<T extends StringIndexedObject> {
|
|
|
52
52
|
* @param desired
|
|
53
53
|
*/
|
|
54
54
|
inputTransformation?: (desired: Partial<T>) => Promise<unknown> | unknown;
|
|
55
|
+
import?: {
|
|
56
|
+
requiredParameters: Array<Partial<keyof T>>;
|
|
57
|
+
};
|
|
55
58
|
}
|
|
56
59
|
/**
|
|
57
60
|
* The type of parameter. This value is mainly used to determine a pre-set equality method for comparing the current
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codify-plugin-lib",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.94",
|
|
4
4
|
"description": "Library plugin library",
|
|
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.52",
|
|
18
18
|
"@npmcli/promise-spawn": "^7.0.1",
|
|
19
19
|
"uuid": "^10.0.0"
|
|
20
20
|
},
|
package/src/messages/handlers.ts
CHANGED
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
ApplyResponseDataSchema,
|
|
6
6
|
GetResourceInfoRequestDataSchema,
|
|
7
7
|
GetResourceInfoResponseDataSchema,
|
|
8
|
+
ImportRequestDataSchema,
|
|
9
|
+
ImportResponseDataSchema,
|
|
8
10
|
InitializeRequestDataSchema,
|
|
9
11
|
InitializeResponseDataSchema,
|
|
10
12
|
IpcMessage,
|
|
@@ -36,6 +38,11 @@ const SupportedRequests: Record<string, { handler: (plugin: Plugin, data: any) =
|
|
|
36
38
|
requestValidator: GetResourceInfoRequestDataSchema,
|
|
37
39
|
responseValidator: GetResourceInfoResponseDataSchema
|
|
38
40
|
},
|
|
41
|
+
'import': {
|
|
42
|
+
handler: async (plugin: Plugin, data: any) => plugin.import(data),
|
|
43
|
+
requestValidator: ImportRequestDataSchema,
|
|
44
|
+
responseValidator: ImportResponseDataSchema
|
|
45
|
+
},
|
|
39
46
|
'plan': {
|
|
40
47
|
handler: async (plugin: Plugin, data: any) => plugin.plan(data),
|
|
41
48
|
requestValidator: PlanRequestDataSchema,
|
package/src/plugin/plugin.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { JSONSchemaType } from 'ajv';
|
|
1
2
|
import {
|
|
2
3
|
ApplyRequestData,
|
|
3
4
|
GetResourceInfoRequestData,
|
|
4
5
|
GetResourceInfoResponseData,
|
|
6
|
+
ImportRequestData,
|
|
7
|
+
ImportResponseData,
|
|
5
8
|
InitializeResponseData,
|
|
6
9
|
PlanRequestData,
|
|
7
10
|
PlanResponseData,
|
|
@@ -56,11 +59,36 @@ export class Plugin {
|
|
|
56
59
|
|
|
57
60
|
const resource = this.resourceControllers.get(data.type)!;
|
|
58
61
|
|
|
62
|
+
const schema = resource.settings.schema as JSONSchemaType<any>;
|
|
63
|
+
const requiredPropertyNames = (
|
|
64
|
+
resource.settings.import?.requiredParameters
|
|
65
|
+
?? schema.required
|
|
66
|
+
?? null
|
|
67
|
+
) as null | string[];
|
|
68
|
+
|
|
59
69
|
return {
|
|
60
70
|
plugin: this.name,
|
|
61
71
|
type: data.type,
|
|
62
72
|
dependencies: resource.dependencies,
|
|
63
|
-
schema:
|
|
73
|
+
schema: schema as Record<string, unknown> | undefined,
|
|
74
|
+
import: resource.settings.import ? {
|
|
75
|
+
requiredParameters: requiredPropertyNames,
|
|
76
|
+
} : undefined,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async import(data: ImportRequestData): Promise<ImportResponseData> {
|
|
81
|
+
if (!this.resourceControllers.has(data.config.type)) {
|
|
82
|
+
throw new Error(`Cannot get info for resource ${data.config.type}, resource doesn't exist`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const result = await this.resourceControllers
|
|
86
|
+
.get(data.config.type!)
|
|
87
|
+
?.import(data.config);
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
request: data.config,
|
|
91
|
+
result: result ?? [],
|
|
64
92
|
}
|
|
65
93
|
}
|
|
66
94
|
|
|
@@ -185,6 +185,43 @@ export class ResourceController<T extends StringIndexedObject> {
|
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
async import(config: Partial<T> & ResourceConfig): Promise<(Partial<T> & ResourceConfig)[] | null> {
|
|
189
|
+
this.addDefaultValues(config);
|
|
190
|
+
await this.applyTransformParameters(config);
|
|
191
|
+
|
|
192
|
+
// Try to refresh as many parameters as possible here
|
|
193
|
+
const parametersToRefresh = {
|
|
194
|
+
...Object.fromEntries(
|
|
195
|
+
this.getAllParameterKeys().map((k) => [k, null])
|
|
196
|
+
),
|
|
197
|
+
...config,
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Parse data from the user supplied config
|
|
201
|
+
const parsedConfig = new ConfigParser(parametersToRefresh, null, this.parsedSettings.statefulParameters)
|
|
202
|
+
const {
|
|
203
|
+
allNonStatefulParameters,
|
|
204
|
+
allStatefulParameters,
|
|
205
|
+
coreParameters,
|
|
206
|
+
} = parsedConfig;
|
|
207
|
+
|
|
208
|
+
const currentParametersArray = await this.refreshNonStatefulParameters(allNonStatefulParameters);
|
|
209
|
+
|
|
210
|
+
if (currentParametersArray === null
|
|
211
|
+
|| currentParametersArray === undefined
|
|
212
|
+
|| this.settings.allowMultiple // Stateful parameters are not supported currently if allowMultiple is true
|
|
213
|
+
|| currentParametersArray.length === 0
|
|
214
|
+
|| currentParametersArray.filter(Boolean).length === 0
|
|
215
|
+
) {
|
|
216
|
+
return currentParametersArray
|
|
217
|
+
?.map((r) => ({ ...coreParameters, ...r }))
|
|
218
|
+
?? null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const statefulCurrentParameters = await this.refreshStatefulParameters(allStatefulParameters, parametersToRefresh);
|
|
222
|
+
return [{ ...coreParameters, ...currentParametersArray[0], ...statefulCurrentParameters }];
|
|
223
|
+
}
|
|
224
|
+
|
|
188
225
|
private async applyCreate(plan: Plan<T>): Promise<void> {
|
|
189
226
|
await this.resource.create(plan as CreatePlan<T>);
|
|
190
227
|
|
|
@@ -349,5 +386,10 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
349
386
|
)
|
|
350
387
|
}
|
|
351
388
|
|
|
389
|
+
private getAllParameterKeys(): string[] {
|
|
390
|
+
return this.settings.schema
|
|
391
|
+
? Object.keys((this.settings.schema as any)?.properties)
|
|
392
|
+
: Object.keys(this.parsedSettings.parameterSettings);
|
|
393
|
+
}
|
|
352
394
|
}
|
|
353
395
|
|
|
@@ -524,4 +524,20 @@ describe('Resource parameter tests', () => {
|
|
|
524
524
|
expect(plan.currentConfig?.propB).to.eq(10);
|
|
525
525
|
expect(plan.currentConfig?.propC).to.be.undefined;
|
|
526
526
|
})
|
|
527
|
+
|
|
528
|
+
it('Allows import required parameters customization', () => {
|
|
529
|
+
const resource = new class extends TestResource {
|
|
530
|
+
getSettings(): ResourceSettings<TestConfig> {
|
|
531
|
+
return {
|
|
532
|
+
id: 'resourceType',
|
|
533
|
+
import: {
|
|
534
|
+
requiredParameters: [
|
|
535
|
+
'propA',
|
|
536
|
+
'propB',
|
|
537
|
+
]
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
})
|
|
527
543
|
})
|
|
@@ -64,6 +64,10 @@ export interface ResourceSettings<T extends StringIndexedObject> {
|
|
|
64
64
|
* @param desired
|
|
65
65
|
*/
|
|
66
66
|
inputTransformation?: (desired: Partial<T>) => Promise<unknown> | unknown;
|
|
67
|
+
|
|
68
|
+
import?: {
|
|
69
|
+
requiredParameters: Array<Partial<keyof T>>;
|
|
70
|
+
}
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
/**
|