codify-plugin-lib 1.0.43 → 1.0.44

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.
@@ -39,8 +39,17 @@ export class Resource {
39
39
  for (const statefulParameter of statefulParameters) {
40
40
  const desiredValue = desiredParameters[statefulParameter.name];
41
41
  let currentValue = await statefulParameter.refresh() ?? undefined;
42
- if (Array.isArray(currentValue) && Array.isArray(desiredValue) && !planConfiguration.statefulMode) {
43
- currentValue = currentValue.filter((p) => desiredValue?.includes(p));
42
+ if (Array.isArray(currentValue)
43
+ && Array.isArray(desiredValue)
44
+ && !planConfiguration.statefulMode
45
+ && !statefulParameter.configuration.disableStatelessModeArrayFiltering) {
46
+ currentValue = currentValue.filter((c) => desiredValue?.some((d) => {
47
+ const pc = planConfiguration?.parameterConfigurations?.[statefulParameter.name];
48
+ if (pc && pc.isElementEqual) {
49
+ return pc.isElementEqual(d, c);
50
+ }
51
+ return d === c;
52
+ }));
44
53
  }
45
54
  currentParameters[statefulParameter.name] = currentValue;
46
55
  }
@@ -3,6 +3,7 @@ import { StringIndexedObject } from 'codify-schemas';
3
3
  export interface StatefulParameterConfiguration<T> {
4
4
  name: keyof T;
5
5
  isEqual?: (desired: any, current: any) => boolean;
6
+ disableStatelessModeArrayFiltering?: boolean;
6
7
  }
7
8
  export interface ArrayStatefulParameterConfiguration<T> extends StatefulParameterConfiguration<T> {
8
9
  isEqual?: (desired: any[], current: any[]) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codify-plugin-lib",
3
- "version": "1.0.43",
3
+ "version": "1.0.44",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { StatefulParameter, StatefulParameterConfiguration } from './stateful-parameter.js';
2
+ import { ArrayStatefulParameter, StatefulParameter, StatefulParameterConfiguration } from './stateful-parameter.js';
3
3
  import { Plan } from './plan.js';
4
4
  import { spy } from 'sinon';
5
5
  import { ResourceOperation } from 'codify-schemas';
@@ -157,4 +157,45 @@ describe('Resource parameters tests', () => {
157
157
  }
158
158
  })
159
159
  })
160
+
161
+ it('Uses isElementEqual for stateless mode filtering if available', async () => {
162
+ const statefulParameter = new class extends ArrayStatefulParameter<TestConfig, string> {
163
+ constructor() {
164
+ super({
165
+ name: 'propA',
166
+ isElementEqual: (desired, current) => current.includes(desired),
167
+ });
168
+ }
169
+
170
+ async refresh(): Promise<any | null> {
171
+ return ['3.11.9']
172
+ }
173
+
174
+ async applyAddItem(item: string, plan: Plan<TestConfig>): Promise<void> {}
175
+ async applyRemoveItem(item: string, plan: Plan<TestConfig>): Promise<void> {}
176
+ }
177
+
178
+ const statefulParameterSpy = spy(statefulParameter);
179
+
180
+ const resource = new class extends TestResource {
181
+ constructor() {
182
+ super({
183
+ type: 'resource',
184
+ statefulParameters: [statefulParameterSpy],
185
+ });
186
+ }
187
+
188
+ async refresh(): Promise<Partial<TestConfig> | null> {
189
+ return {};
190
+ }
191
+ }
192
+
193
+ const plan = await resource.plan({ type: 'resource', propA: ['3.11'] } as any)
194
+
195
+ expect(plan).toMatchObject({
196
+ changeSet: {
197
+ operation: ResourceOperation.NOOP,
198
+ }
199
+ })
200
+ })
160
201
  })
@@ -79,8 +79,18 @@ export abstract class Resource<T extends StringIndexedObject> {
79
79
  let currentValue = await statefulParameter.refresh() ?? undefined;
80
80
 
81
81
  // In stateless mode, filter the refreshed parameters by the desired to ensure that no deletes happen
82
- if (Array.isArray(currentValue) && Array.isArray(desiredValue) && !planConfiguration.statefulMode) {
83
- currentValue = currentValue.filter((p) => desiredValue?.includes(p)) as any;
82
+ if (Array.isArray(currentValue)
83
+ && Array.isArray(desiredValue)
84
+ && !planConfiguration.statefulMode
85
+ && !statefulParameter.configuration.disableStatelessModeArrayFiltering
86
+ ) {
87
+ currentValue = currentValue.filter((c) => desiredValue?.some((d) => {
88
+ const pc = planConfiguration?.parameterConfigurations?.[statefulParameter.name];
89
+ if (pc && pc.isElementEqual) {
90
+ return pc.isElementEqual(d, c);
91
+ }
92
+ return d === c;
93
+ })) as any;
84
94
  }
85
95
 
86
96
  currentParameters[statefulParameter.name] = currentValue;
@@ -4,6 +4,17 @@ import { StringIndexedObject } from 'codify-schemas';
4
4
  export interface StatefulParameterConfiguration<T> {
5
5
  name: keyof T;
6
6
  isEqual?: (desired: any, current: any) => boolean;
7
+
8
+ /**
9
+ * In stateless mode, array refresh results (current) will be automatically filtered by the user config (desired).
10
+ * This is done to ensure that for modify operations, stateless mode will not try to delete existing resources.
11
+ *
12
+ * Ex: System has python 3.11.9 and 3.12.7 installed (current). Desired is 3.11. Without filtering 3.12.7 will be deleted
13
+ * in the next modify
14
+ *
15
+ * Set this flag to true to disable this behaviour
16
+ */
17
+ disableStatelessModeArrayFiltering?: boolean;
7
18
  }
8
19
 
9
20
  export interface ArrayStatefulParameterConfiguration<T> extends StatefulParameterConfiguration<T> {