@contrail/cli 2.2.5 → 2.2.7
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 +1 -1
- package/dist/commands/types/uploadOptionSetHierarchies.js +1 -1
- package/dist/commands/types/uploadTypePolicies.js +2 -1
- package/dist/commands/types/uploadTypePropertyPolicies.d.ts +1 -0
- package/dist/commands/types/uploadTypePropertyPolicies.js +90 -49
- package/dist/commands/types/uploadUsageInfo.js +1 -1
- package/dist/helpers/app/app-config-validators.js +3 -1
- package/dist/helpers/app/app-config-validators.spec.js +38 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
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/2.2.
|
|
20
|
+
@contrail/cli/2.2.7 darwin-arm64 node-v18.13.0
|
|
21
21
|
$ contrail --help [COMMAND]
|
|
22
22
|
USAGE
|
|
23
23
|
$ contrail COMMAND
|
|
@@ -178,7 +178,7 @@ async function uploadOSHLinks(reducedOSHLinks) {
|
|
|
178
178
|
if (!foundType ||
|
|
179
179
|
!foundOSH ||
|
|
180
180
|
foundTPSlugs.length !== currentLink.hierarchyTypePropertyIds.length) {
|
|
181
|
-
logger_1.default.info(`skipping unhashable, invalid type option set hierarchy link: ${currentLink}`);
|
|
181
|
+
logger_1.default.info(`skipping unhashable, invalid type option set hierarchy link: ${JSON.stringify(currentLink, null, 2)}`);
|
|
182
182
|
}
|
|
183
183
|
// don't mutate original array
|
|
184
184
|
const sortedFoundTPSlugs = [...foundTPSlugs].sort();
|
|
@@ -165,7 +165,7 @@ async function uploadTypePolicyLinks(reducedTypePolicyLinks) {
|
|
|
165
165
|
const foundType = types.find((type) => type.id === currentLink.typeId);
|
|
166
166
|
const foundTypePolicy = currentTypePolicies.find((tp) => tp.id === currentLink.typePolicyId);
|
|
167
167
|
if (!foundType || !foundTypePolicy) {
|
|
168
|
-
logger_1.default.info(`skipping unhashable, invalid policy link: ${currentLink}`);
|
|
168
|
+
logger_1.default.info(`skipping unhashable, invalid policy link: ${JSON.stringify(currentLink, null, 2)}`);
|
|
169
169
|
}
|
|
170
170
|
const hash = `${foundType.slug}|${foundTypePolicy.identifier}`;
|
|
171
171
|
currentLinksHashes[hash] = currentLink;
|
|
@@ -182,6 +182,7 @@ async function uploadTypePolicyLinks(reducedTypePolicyLinks) {
|
|
|
182
182
|
if (!transformReducedLink(loadedTPLink, types, currentTypePolicies)) {
|
|
183
183
|
continue;
|
|
184
184
|
}
|
|
185
|
+
logger_1.default.info(`Creating: ${loadedTPLink.typeSlug}|${loadedTPLink.typePolicyIdentifier}`);
|
|
185
186
|
await new sdk_1.Entities().create({
|
|
186
187
|
entityName: 'type-policy-link',
|
|
187
188
|
object: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.uploadTypePropertyPolicies = void 0;
|
|
3
|
+
exports.findAllOccurrences = exports.uploadTypePropertyPolicies = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const sdk_1 = require("@contrail/sdk");
|
|
6
6
|
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
@@ -13,6 +13,7 @@ const users_1 = require("../../api/users");
|
|
|
13
13
|
const basecommand_1 = require("../../basecommand");
|
|
14
14
|
const logger_1 = tslib_1.__importDefault(require("../../logger"));
|
|
15
15
|
const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
|
|
16
|
+
const _ = tslib_1.__importStar(require("lodash"));
|
|
16
17
|
class UploadTypePropertyPolicies extends basecommand_1.BaseCommand {
|
|
17
18
|
async run() {
|
|
18
19
|
const { flags } = await this.parse(UploadTypePropertyPolicies);
|
|
@@ -172,75 +173,115 @@ async function uploadTypePropertyPolicyLinks(reducedTypePropertyPolicyLinks) {
|
|
|
172
173
|
const currentTPPLinks = await new sdk_1.Entities().get({
|
|
173
174
|
entityName: 'type-property-policy-link',
|
|
174
175
|
});
|
|
176
|
+
logger_1.default.info(`found ${currentTPPLinks.length} current type property policy links`);
|
|
177
|
+
logger_1.default.info(`found ${reducedTypePropertyPolicyLinks.length} type property policy links to load`);
|
|
175
178
|
const currentLinksHashes = {};
|
|
176
179
|
for (const currentLink of currentTPPLinks) {
|
|
177
|
-
const
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
const foundTPs = findAllOccurrences(typeProperties, (tp) => tp.id === currentLink.typePropertyId);
|
|
181
|
+
for (const foundTP of foundTPs) {
|
|
182
|
+
const foundTPP = currentTPPs.find((tpp) => tpp.id === currentLink.typePropertyPolicyId);
|
|
183
|
+
if (!foundTP || !foundTPP) {
|
|
184
|
+
logger_1.default.info(`skipping unhashable, invalid policy link: ${JSON.stringify(currentLink, null, 2)}`);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const hash = `${foundTP.typeSlug}|${foundTP.slug}|${foundTPP.identifier}`;
|
|
188
|
+
currentLinksHashes[hash] = currentLink;
|
|
182
189
|
}
|
|
183
|
-
const hash = `${foundTypeProperty.typeSlug}${foundTypeProperty.slug}|${foundTPP.identifier}`;
|
|
184
|
-
currentLinksHashes[hash] = currentLink;
|
|
185
190
|
}
|
|
191
|
+
logger_1.default.debug(`current links hashes: ${JSON.stringify(currentLinksHashes, null, 2)}`);
|
|
186
192
|
const reducedLinksByHashes = {};
|
|
187
193
|
for (const loadedLink of reducedTypePropertyPolicyLinks) {
|
|
188
194
|
const hash = `${loadedLink.typeSlug}|${loadedLink.typePropertySlug}|${loadedLink.typePropertyPolicyIdentifier}`;
|
|
189
195
|
reducedLinksByHashes[hash] = loadedLink;
|
|
190
196
|
}
|
|
191
|
-
|
|
197
|
+
const toCreate = Object.keys(reducedLinksByHashes)
|
|
198
|
+
.filter((x) => !currentLinksHashes[x])
|
|
199
|
+
.map((x) => {
|
|
200
|
+
return {
|
|
201
|
+
[x]: reducedLinksByHashes[x],
|
|
202
|
+
};
|
|
203
|
+
})
|
|
204
|
+
.reduce((a, b) => Object.assign(a, b), {});
|
|
205
|
+
const toDelete = _.uniqBy(Object.keys(currentLinksHashes)
|
|
206
|
+
.filter((x) => !reducedLinksByHashes[x])
|
|
207
|
+
.map((x) => {
|
|
208
|
+
return {
|
|
209
|
+
[x]: currentLinksHashes[x],
|
|
210
|
+
};
|
|
211
|
+
}), 'id').reduce((a, b) => Object.assign(a, b), {});
|
|
212
|
+
logger_1.default.debug(`reduced links hashes: ${JSON.stringify(reducedLinksByHashes, null, 2)}`);
|
|
213
|
+
logger_1.default.info(`found ${Object.keys(toCreate).length} type property policy links to create`);
|
|
214
|
+
logger_1.default.info(`found ${Object.keys(toDelete).length} type property policy links to delete`);
|
|
215
|
+
logger_1.default.debug(`to create: ${JSON.stringify(toCreate, null, 2)}`);
|
|
216
|
+
logger_1.default.debug(`to delete: ${JSON.stringify(toDelete, null, 2)}`);
|
|
217
|
+
logger_1.default.debug(`current links hashes to delete: ${JSON.stringify(Object.keys(currentLinksHashes).filter((x) => !reducedLinksByHashes[x]), null, 2)}`);
|
|
218
|
+
// fs.writeFileSync('toCreate.json', JSON.stringify(toCreate, null, 2));
|
|
219
|
+
// fs.writeFileSync('toDelete.json', JSON.stringify(toDelete, null, 2));
|
|
220
|
+
// fs.writeFileSync('currentLinksHashes.json', JSON.stringify(currentLinksHashes, null, 2));
|
|
221
|
+
// fs.writeFileSync('reducedLinksByHashes.json', JSON.stringify(reducedLinksByHashes, null, 2));
|
|
222
|
+
// fs.writeFileSync(
|
|
223
|
+
// 'current_link_hashes_to_delete.json',
|
|
224
|
+
// JSON.stringify(
|
|
225
|
+
// Object.keys(currentLinksHashes).filter((x) => !reducedLinksByHashes[x]),
|
|
226
|
+
// null,
|
|
227
|
+
// 2,
|
|
228
|
+
// ),
|
|
229
|
+
// );
|
|
230
|
+
// return;
|
|
231
|
+
for (const [hash, link] of Object.entries(toCreate)) {
|
|
192
232
|
try {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if (!transformReducedLink(loadedTPPLink, typeProperties, currentTPPs)) {
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
await new sdk_1.Entities().create({
|
|
199
|
-
entityName: 'type-property-policy-link',
|
|
200
|
-
object: {
|
|
201
|
-
typePropertyPolicyId: loadedTPPLink.typePropertyPolicyId,
|
|
202
|
-
typePropertyId: loadedTPPLink.typePropertyId,
|
|
203
|
-
},
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
if (!transformReducedLink(loadedTPPLink, typeProperties, currentTPPs)) {
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
233
|
+
if (!transformReducedLink(link, typeProperties, currentTPPs)) {
|
|
234
|
+
continue;
|
|
210
235
|
}
|
|
236
|
+
logger_1.default.info(`Creating: ${hash}: ${JSON.stringify(link, null, 2)}`);
|
|
237
|
+
await new sdk_1.Entities().create({
|
|
238
|
+
entityName: 'type-property-policy-link',
|
|
239
|
+
object: {
|
|
240
|
+
typePropertyPolicyId: link.typePropertyPolicyId,
|
|
241
|
+
typePropertyId: link.typePropertyId,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
211
244
|
}
|
|
212
245
|
catch (err) {
|
|
213
246
|
logger_1.default.error(`Error Uploading type property policy links: ${err}`);
|
|
214
247
|
}
|
|
215
248
|
}
|
|
216
|
-
for (const [
|
|
249
|
+
for (const [hash, link] of Object.entries(toDelete)) {
|
|
217
250
|
try {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
id: currentLink['id'],
|
|
224
|
-
});
|
|
225
|
-
}
|
|
251
|
+
logger_1.default.info(`Deleting: ${hash}`);
|
|
252
|
+
await new sdk_1.Entities().delete({
|
|
253
|
+
entityName: 'type-property-policy-link',
|
|
254
|
+
id: link['id'],
|
|
255
|
+
});
|
|
226
256
|
}
|
|
227
257
|
catch (err) {
|
|
228
258
|
logger_1.default.error(`Error Deleting type property policy link: ${err}`);
|
|
229
259
|
}
|
|
230
260
|
}
|
|
261
|
+
function transformReducedLink(TPPLink, typeProperties, typePropertyPolicies) {
|
|
262
|
+
const foundTP = typeProperties.find((tp) => tp.slug === TPPLink.typePropertySlug && tp.typeSlug === TPPLink.typeSlug);
|
|
263
|
+
if (!foundTP) {
|
|
264
|
+
logger_1.default.error(`Could not find type property with slug ${TPPLink.typePropertySlug} `);
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
TPPLink.typePropertyId = foundTP.id;
|
|
268
|
+
const foundTPP = typePropertyPolicies.find((tpp) => tpp.identifier === TPPLink.typePropertyPolicyIdentifier);
|
|
269
|
+
if (!foundTPP) {
|
|
270
|
+
logger_1.default.error(`Could not find type property policy with identifier ${TPPLink.typePropertyPolicyIdentifier} `);
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
TPPLink.typePropertyPolicyId = foundTPP.id;
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
231
276
|
}
|
|
232
|
-
function
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
logger_1.default.error(`Could not find type property policy with identifier ${TPPLink.typePropertyPolicyIdentifier}`);
|
|
242
|
-
return false;
|
|
243
|
-
}
|
|
244
|
-
TPPLink.typePropertyPolicyId = foundTPP.id;
|
|
245
|
-
return true;
|
|
277
|
+
function findAllOccurrences(array, evaluator) {
|
|
278
|
+
const found = [];
|
|
279
|
+
for (let i = 0; i < array.length; i++) {
|
|
280
|
+
const element = array[i];
|
|
281
|
+
if (evaluator(element)) {
|
|
282
|
+
found.push(element);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return found;
|
|
246
286
|
}
|
|
287
|
+
exports.findAllOccurrences = findAllOccurrences;
|
|
@@ -70,7 +70,7 @@ async function uploadUsageInfoObjects(loadedUsageInfo) {
|
|
|
70
70
|
const foundType = typesWithProperties.find((t) => t.id === currentUI.typeId);
|
|
71
71
|
const foundTypeProperty = typeProperties.find((tp) => tp.id === currentUI.typePropertyId);
|
|
72
72
|
if (!foundType || !foundTypeProperty) {
|
|
73
|
-
logger_1.default.info(`skipping unhashable, invalid usage info: ${currentUI}`);
|
|
73
|
+
logger_1.default.info(`skipping unhashable, invalid usage info: ${JSON.stringify(currentUI, null, 2)}`);
|
|
74
74
|
continue;
|
|
75
75
|
}
|
|
76
76
|
const hash = `${foundType.slug}|${foundTypeProperty.slug}`;
|
|
@@ -40,7 +40,9 @@ function visibilityValidator(appDeclaration) {
|
|
|
40
40
|
error: 'Invalid visibility. Visibility must be "public" or "private".',
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
-
if (appDeclaration.visibility === 'private' &&
|
|
43
|
+
if (appDeclaration.visibility === 'private' &&
|
|
44
|
+
Object.prototype.hasOwnProperty.call(appDeclaration, 'hidden') &&
|
|
45
|
+
appDeclaration.hidden === true) {
|
|
44
46
|
return {
|
|
45
47
|
error: 'Apps can not be private and hidden.',
|
|
46
48
|
};
|
|
@@ -65,3 +65,41 @@ it('should return an error if app version has invalid format', () => {
|
|
|
65
65
|
const validationResult = (0, app_config_validators_1.appVersionValidator)(appDeclaration);
|
|
66
66
|
expect(validationResult).toEqual(expectedError);
|
|
67
67
|
});
|
|
68
|
+
describe('visibilityValidator', () => {
|
|
69
|
+
it('should return an error if visibility is neither "public" nor "private"', () => {
|
|
70
|
+
const appDeclaration = {
|
|
71
|
+
visibility: 'invalidVisibility',
|
|
72
|
+
};
|
|
73
|
+
const expectedError = {
|
|
74
|
+
error: 'Invalid visibility. Visibility must be "public" or "private".',
|
|
75
|
+
};
|
|
76
|
+
const validationResult = (0, app_config_validators_1.visibilityValidator)(appDeclaration);
|
|
77
|
+
expect(validationResult).toEqual(expectedError);
|
|
78
|
+
});
|
|
79
|
+
it('should return an error if app is private and not hidden', () => {
|
|
80
|
+
const appDeclaration = {
|
|
81
|
+
visibility: 'private',
|
|
82
|
+
hidden: true,
|
|
83
|
+
};
|
|
84
|
+
const expectedError = {
|
|
85
|
+
error: 'Apps can not be private and hidden.',
|
|
86
|
+
};
|
|
87
|
+
const validationResult = (0, app_config_validators_1.visibilityValidator)(appDeclaration);
|
|
88
|
+
expect(validationResult).toEqual(expectedError);
|
|
89
|
+
});
|
|
90
|
+
it('should not return an error if visibility is "public"', () => {
|
|
91
|
+
const appDeclaration = {
|
|
92
|
+
visibility: 'public',
|
|
93
|
+
};
|
|
94
|
+
const validationResult = (0, app_config_validators_1.visibilityValidator)(appDeclaration);
|
|
95
|
+
expect(validationResult).toBeUndefined();
|
|
96
|
+
});
|
|
97
|
+
it('should not return an error if app is private and hidden', () => {
|
|
98
|
+
const appDeclaration = {
|
|
99
|
+
visibility: 'private',
|
|
100
|
+
hidden: false,
|
|
101
|
+
};
|
|
102
|
+
const validationResult = (0, app_config_validators_1.visibilityValidator)(appDeclaration);
|
|
103
|
+
expect(validationResult).toBeUndefined();
|
|
104
|
+
});
|
|
105
|
+
});
|
package/oclif.manifest.json
CHANGED