@contrail/cli 3.0.0 → 3.0.2-alpha.1
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/README.md
CHANGED
|
@@ -17,7 +17,7 @@ $ npm install -g @contrail/cli
|
|
|
17
17
|
$ contrail COMMAND
|
|
18
18
|
running command...
|
|
19
19
|
$ contrail (--version)
|
|
20
|
-
@contrail/cli/3.0.
|
|
20
|
+
@contrail/cli/3.0.2-alpha.1 darwin-x64 node-v18.17.1
|
|
21
21
|
$ contrail --help [COMMAND]
|
|
22
22
|
USAGE
|
|
23
23
|
$ contrail COMMAND
|
|
@@ -64,7 +64,7 @@ function loadOptionSets(fromDir) {
|
|
|
64
64
|
function parseOptionSetValuesToString(optionSet) {
|
|
65
65
|
return (0, lodash_1.cloneDeepWith)(optionSet, (value) => {
|
|
66
66
|
// If the value is an object or array, let cloneDeepWith handle it
|
|
67
|
-
if ((0, lodash_1.isObject)(value) || (0, lodash_1.isArray)(value)) {
|
|
67
|
+
if ((0, lodash_1.isObject)(value) || (0, lodash_1.isArray)(value) || typeof value === 'boolean') {
|
|
68
68
|
return undefined;
|
|
69
69
|
}
|
|
70
70
|
// Otherwise, convert the value to string
|
|
@@ -74,6 +74,7 @@ function parseOptionSetValuesToString(optionSet) {
|
|
|
74
74
|
exports.parseOptionSetValuesToString = parseOptionSetValuesToString;
|
|
75
75
|
async function uploadOS(dir) {
|
|
76
76
|
const optionSets = loadOptionSets(dir);
|
|
77
|
+
validateOptionSets(optionSets);
|
|
77
78
|
const currentOptionSets = await new sdk_1.Entities().get({
|
|
78
79
|
entityName: 'type-property-option-set',
|
|
79
80
|
});
|
|
@@ -126,6 +127,18 @@ async function uploadOS(dir) {
|
|
|
126
127
|
logger_1.default.error(`Error Uploading OptionSets: ${err}`);
|
|
127
128
|
}
|
|
128
129
|
}
|
|
130
|
+
function validateOptionSets(optionSets) {
|
|
131
|
+
optionSets.forEach((optionSet) => {
|
|
132
|
+
optionSet.optionSet.forEach((option) => {
|
|
133
|
+
validateOption(option, optionSet.slug);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function validateOption(option, slug) {
|
|
138
|
+
if (typeof option.disabled !== 'boolean') {
|
|
139
|
+
throw new Error(`Invalid type for "disabled" property: expected a boolean but received "${typeof option.disabled}" for Option Set with slug "${slug}" and value "${option.value}".`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
129
142
|
// for (const currentOptionSet of currentOptionSets) {
|
|
130
143
|
// try {
|
|
131
144
|
// const found = newOptionSetsBySlug[currentOptionSet.slug];
|
|
@@ -23,14 +23,17 @@ class LoadValidators {
|
|
|
23
23
|
if (!config?.federatedMappings?.name) {
|
|
24
24
|
errors.push('"name" is required in the config file');
|
|
25
25
|
}
|
|
26
|
-
if (
|
|
27
|
-
errors.push('Conditional columns with "toProperty": "typePath" and "default": "color" properties are required in the config file');
|
|
28
|
-
}
|
|
29
|
-
if (config?.conditionalColumns &&
|
|
26
|
+
if (config?.conditionalColumns?.length &&
|
|
30
27
|
config?.conditionalColumns[0].toProperty === 'typePath' &&
|
|
31
28
|
config?.conditionalColumns[0].default !== 'color') {
|
|
32
29
|
errors.push('"typePath" must be "color" in the config file');
|
|
33
30
|
}
|
|
31
|
+
else if (csvHeaders.includes('typePath')) {
|
|
32
|
+
const hasCorrectTypePath = colorsData.every((row) => row.typePath === 'color');
|
|
33
|
+
if (!hasCorrectTypePath) {
|
|
34
|
+
errors.push('"typePath" must be "color" in each row in the csv file');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
34
37
|
if (!csvHeaders.includes(config?.federatedMappings?.federatedId)) {
|
|
35
38
|
errors.push(`Federated ID column (${config?.federatedMappings?.federatedId}) not found in the CSV file`);
|
|
36
39
|
}
|
|
@@ -74,9 +77,6 @@ class LoadValidators {
|
|
|
74
77
|
if (!config?.federatedMappings?.name) {
|
|
75
78
|
errors.push('"name" is required in the config file');
|
|
76
79
|
}
|
|
77
|
-
if (!config?.conditionalColumns?.length) {
|
|
78
|
-
errors.push('"typePath" is required in the config file');
|
|
79
|
-
}
|
|
80
80
|
if (!csvHeaders.includes(config?.federatedMappings?.federatedId)) {
|
|
81
81
|
errors.push(`Federated ID column (${config?.federatedMappings?.federatedId}) not found in the CSV file`);
|
|
82
82
|
}
|
|
@@ -87,6 +87,23 @@ class LoadValidators {
|
|
|
87
87
|
if (duplicateFederatedIdErrors.length) {
|
|
88
88
|
errors.push(`Duplicate FederatedIds found: ${duplicateFederatedIdErrors.join(', ')}`);
|
|
89
89
|
}
|
|
90
|
+
if (Array.isArray(config?.conditionalColumns) && config.conditionalColumns.length) {
|
|
91
|
+
const hasRequiredConditionalColumn = config.conditionalColumns.some((column) => column.toProperty === 'typePath' &&
|
|
92
|
+
column.default?.startsWith('custom-entity:') &&
|
|
93
|
+
column.default?.split(':')[1]?.length > 0);
|
|
94
|
+
if (!hasRequiredConditionalColumn) {
|
|
95
|
+
errors.push('"typePath" must be "custom-entity:<subtypepath>" in the config file');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (csvHeaders.includes('typePath')) {
|
|
99
|
+
const hasCorrectTypePath = customEntityData.every((row) => row.typePath?.startsWith('custom-entity:') && row.typePath?.split(':')[1]?.length > 0);
|
|
100
|
+
if (!hasCorrectTypePath) {
|
|
101
|
+
errors.push('"typePath" must be "custom-entity:<subtypepath>" in each row in the csv file');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
errors.push('Missing "typePath" column in the csv file or config file');
|
|
106
|
+
}
|
|
90
107
|
return { errors, warnings };
|
|
91
108
|
}
|
|
92
109
|
static ValidateLineSheetLoadFile(lineSheetData, config) {
|
|
@@ -3,14 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const validators_1 = require("./validators");
|
|
4
4
|
describe('LoadValidators', () => {
|
|
5
5
|
describe('ValidateColorsLoadFile', () => {
|
|
6
|
-
it('should return multiple errors if properties are missing in the config file', () => {
|
|
7
|
-
const colorsData = [{ id: 1, name: 'Red', hex: '#FF0000' }];
|
|
8
|
-
const config = { federatedMappings: { name: 'Colors' } };
|
|
9
|
-
const result = validators_1.LoadValidators.ValidateColorsLoadFile(colorsData, config);
|
|
10
|
-
expect(result.errors).toContain('"federatedId" is required in the config file');
|
|
11
|
-
expect(result.errors).toContain('"loadType" is required in the config file');
|
|
12
|
-
expect(result.errors).toContain('Conditional columns with "toProperty": "typePath" and "default": "color" properties are required in the config file');
|
|
13
|
-
});
|
|
14
6
|
it('should return errors if Federated ID is missing in the config file', () => {
|
|
15
7
|
const colorsData = [{ id: 1, name: 'Red', hex: '#FF0000' }];
|
|
16
8
|
const config = {
|
|
@@ -116,6 +108,38 @@ describe('LoadValidators', () => {
|
|
|
116
108
|
const result = validators_1.LoadValidators.ValidateColorsLoadFile(colorsData, config);
|
|
117
109
|
expect(result.errors).toContain('Duplicate FederatedIds found: 1');
|
|
118
110
|
});
|
|
111
|
+
it('should throw error if typePath is present in the csv header but have incorrect typePath', () => {
|
|
112
|
+
const colorsData = [{ name: 'color1', typePath: 'color1' }];
|
|
113
|
+
const config = {
|
|
114
|
+
loadType: ['COLOR'],
|
|
115
|
+
conditionalColumns: [],
|
|
116
|
+
federatedMappings: {
|
|
117
|
+
red: 'red',
|
|
118
|
+
green: 'green',
|
|
119
|
+
blue: 'blue',
|
|
120
|
+
name: 'Colors',
|
|
121
|
+
federatedId: 'id',
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
const result = validators_1.LoadValidators.ValidateColorsLoadFile(colorsData, config);
|
|
125
|
+
expect(result.errors).toContain('"typePath" must be "color" in each row in the csv file');
|
|
126
|
+
});
|
|
127
|
+
it('should not throw error if typepath is present in the csv header and have correct typePath', () => {
|
|
128
|
+
const colorsData = [{ name: 'color1', typePath: 'color' }];
|
|
129
|
+
const config = {
|
|
130
|
+
loadType: ['COLOR'],
|
|
131
|
+
conditionalColumns: [],
|
|
132
|
+
federatedMappings: {
|
|
133
|
+
red: 'red',
|
|
134
|
+
green: 'green',
|
|
135
|
+
blue: 'blue',
|
|
136
|
+
name: 'name',
|
|
137
|
+
federatedId: 'name',
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
const result = validators_1.LoadValidators.ValidateColorsLoadFile(colorsData, config);
|
|
141
|
+
expect(result.errors).toHaveLength(0);
|
|
142
|
+
});
|
|
119
143
|
});
|
|
120
144
|
describe('ValidateCustomEntityLoadFile', () => {
|
|
121
145
|
it('should return error if config is null', () => {
|
|
@@ -150,24 +174,24 @@ describe('LoadValidators', () => {
|
|
|
150
174
|
const result = validators_1.LoadValidators.ValidateCustomEntityLoadFile(customEntityData, config);
|
|
151
175
|
expect(result.errors).toContain('"name" is required in the config file');
|
|
152
176
|
});
|
|
153
|
-
it('should return error if
|
|
154
|
-
const customEntityData = [{
|
|
177
|
+
it('should return error if federatedId column is missing in CSV', () => {
|
|
178
|
+
const customEntityData = [{ name: 'Test' }];
|
|
155
179
|
const config = {
|
|
156
180
|
loadType: ['CUSTOM_ENTITY'],
|
|
157
181
|
federatedMappings: { federatedId: 'id', name: 'name' },
|
|
182
|
+
conditionalColumns: ['typePath'],
|
|
158
183
|
};
|
|
159
184
|
const result = validators_1.LoadValidators.ValidateCustomEntityLoadFile(customEntityData, config);
|
|
160
|
-
expect(result.errors).toContain('
|
|
185
|
+
expect(result.errors).toContain('Federated ID column (id) not found in the CSV file');
|
|
161
186
|
});
|
|
162
|
-
it('should return error if
|
|
163
|
-
const customEntityData = [{ name: 'Test' }];
|
|
187
|
+
it('should return error if conditionalColumns is missing in config', () => {
|
|
188
|
+
const customEntityData = [{ id: 1, name: 'Test' }];
|
|
164
189
|
const config = {
|
|
165
190
|
loadType: ['CUSTOM_ENTITY'],
|
|
166
191
|
federatedMappings: { federatedId: 'id', name: 'name' },
|
|
167
|
-
conditionalColumns: ['typePath'],
|
|
168
192
|
};
|
|
169
193
|
const result = validators_1.LoadValidators.ValidateCustomEntityLoadFile(customEntityData, config);
|
|
170
|
-
expect(result.errors).toContain('
|
|
194
|
+
expect(result.errors).toContain('Missing "typePath" column in the csv file or config file');
|
|
171
195
|
});
|
|
172
196
|
it('should return error if name column is missing in CSV', () => {
|
|
173
197
|
const customEntityData = [{ id: 1 }];
|
|
@@ -184,7 +208,7 @@ describe('LoadValidators', () => {
|
|
|
184
208
|
const config = {
|
|
185
209
|
loadType: ['CUSTOM_ENTITY'],
|
|
186
210
|
federatedMappings: { federatedId: 'id', name: 'name' },
|
|
187
|
-
conditionalColumns: [{ toProperty: 'typePath', default: 'custom-entity' }],
|
|
211
|
+
conditionalColumns: [{ toProperty: 'typePath', default: 'custom-entity:material' }],
|
|
188
212
|
};
|
|
189
213
|
const result = validators_1.LoadValidators.ValidateCustomEntityLoadFile(customEntityData, config);
|
|
190
214
|
expect(result.errors).toHaveLength(0);
|
|
@@ -203,6 +227,26 @@ describe('LoadValidators', () => {
|
|
|
203
227
|
const result = validators_1.LoadValidators.ValidateCustomEntityLoadFile(customEntityData, config);
|
|
204
228
|
expect(result.errors).toContain('Duplicate FederatedIds found: 1');
|
|
205
229
|
});
|
|
230
|
+
it('should throw error if typepath is present in the csv header but have incorrect typePath', () => {
|
|
231
|
+
const customEntityData = [{ name: 'custom-entity1', typePath: 'custom-entity1' }];
|
|
232
|
+
const config = {
|
|
233
|
+
loadType: ['CUSTOM_ENTITY'],
|
|
234
|
+
federatedMappings: { federatedId: 'name', name: 'name' },
|
|
235
|
+
conditionalColumns: [],
|
|
236
|
+
};
|
|
237
|
+
const result = validators_1.LoadValidators.ValidateCustomEntityLoadFile(customEntityData, config);
|
|
238
|
+
expect(result.errors).toContain('"typePath" must be "custom-entity:<subtypepath>" in each row in the csv file');
|
|
239
|
+
});
|
|
240
|
+
it('should not throw error if typepath is present in the csv header but have correct typePath', () => {
|
|
241
|
+
const customEntityData = [{ name: 'custom-entity1', typePath: 'custom-entity:material' }];
|
|
242
|
+
const config = {
|
|
243
|
+
loadType: ['CUSTOM_ENTITY'],
|
|
244
|
+
federatedMappings: { federatedId: 'name', name: 'name' },
|
|
245
|
+
conditionalColumns: [],
|
|
246
|
+
};
|
|
247
|
+
const result = validators_1.LoadValidators.ValidateCustomEntityLoadFile(customEntityData, config);
|
|
248
|
+
expect(result.errors).toHaveLength(0);
|
|
249
|
+
});
|
|
206
250
|
});
|
|
207
251
|
describe('ValidateLineSheetLoadFile', () => {
|
|
208
252
|
it('should return an error if config is empty', () => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const uploadOptionSets_1 = require("../../commands/types/uploadOptionSets");
|
|
4
4
|
describe('parseOptionSetValuesToString', () => {
|
|
5
|
-
it('should convert all option set values to strings', () => {
|
|
5
|
+
it('should convert all option set values to strings except for booleans', () => {
|
|
6
6
|
const input = {
|
|
7
7
|
value1: 123,
|
|
8
8
|
value2: true,
|
|
@@ -10,7 +10,7 @@ describe('parseOptionSetValuesToString', () => {
|
|
|
10
10
|
};
|
|
11
11
|
const expectedOutput = {
|
|
12
12
|
value1: '123',
|
|
13
|
-
value2:
|
|
13
|
+
value2: true,
|
|
14
14
|
value3: { nested: 'object' },
|
|
15
15
|
};
|
|
16
16
|
const result = (0, uploadOptionSets_1.parseOptionSetValuesToString)(input);
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrail/cli",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2-alpha.1",
|
|
4
4
|
"description": "VibeIQ's Contrail Platform CLI.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"contrail-cli": "./bin/run",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@contrail/entity-types": "^1.1.17",
|
|
26
|
-
"@contrail/org-config-migration": "
|
|
26
|
+
"@contrail/org-config-migration": "1.1.1-alpha.1",
|
|
27
27
|
"@contrail/sdk": "^1.4.6",
|
|
28
28
|
"@contrail/types": "^3.0.48",
|
|
29
29
|
"@contrail/util": "^1.0.41",
|
|
@@ -141,4 +141,4 @@
|
|
|
141
141
|
"coverageDirectory": "../coverage",
|
|
142
142
|
"testEnvironment": "node"
|
|
143
143
|
}
|
|
144
|
-
}
|
|
144
|
+
}
|