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.
@@ -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,
@@ -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>;
@@ -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: resource.settings.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.91",
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.49",
17
+ "codify-schemas": "1.0.52",
18
18
  "@npmcli/promise-spawn": "^7.0.1",
19
19
  "uuid": "^10.0.0"
20
20
  },
@@ -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,
@@ -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: resource.settings.schema as Record<string, unknown> | undefined
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
  /**