@axway/axway-central-cli 3.7.0 → 3.8.0

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.
@@ -28,7 +28,8 @@ const action = async ({
28
28
  region,
29
29
  cache,
30
30
  yes,
31
- language
31
+ language,
32
+ subresource
32
33
  } = argv;
33
34
  let isCmdError = false;
34
35
 
@@ -38,17 +39,7 @@ const action = async ({
38
39
  if (!file) throw new Error('File name is required, please provide -f, --file [path] option');
39
40
  log(`verifying file: ${file}`);
40
41
  (0, _utils.verifyFile)(file);
41
- let results = {
42
- created: {
43
- success: [],
44
- error: [],
45
- warning: []
46
- },
47
- updated: {
48
- success: [],
49
- error: []
50
- }
51
- };
42
+ let results = [];
52
43
  const render = new _Renderer.default(console, output).startSpin('Creating or updating resource(s)');
53
44
  const client = new _ApiServerClient.ApiServerClient({
54
45
  baseUrl,
@@ -75,15 +66,18 @@ const action = async ({
75
66
  render.startSpin('Creating or updating resource(s)');
76
67
  }
77
68
  const sortedKindsMap = defsManager.getSortedKindsMap();
78
- results = await client.bulkCreateOrUpdate(docs, sortedKindsMap, language);
79
- render.bulkCreateOrUpdateResult(results, 'has successfully been created.', 'has successfully been updated.', 'was created with an autogenerated logical name.');
80
- isCmdError = results.created.error.length > 0 || results.updated.error.length > 0;
69
+ results = await client.bulkCreateOrUpdate(docs, sortedKindsMap, language, subresource);
70
+ render.bulkCreateOrUpdateResult(results);
71
+ isCmdError = results.some(nextResult => {
72
+ var _nextResult$error$len, _nextResult$error;
73
+ return (_nextResult$error$len = (_nextResult$error = nextResult.error) === null || _nextResult$error === void 0 ? void 0 : _nextResult$error.length) !== null && _nextResult$error$len !== void 0 ? _nextResult$error$len : 0 > 0;
74
+ });
81
75
  } catch (e) {
82
76
  log('command error', e);
83
77
  isCmdError = true;
84
- // if some calls completed, rendering the result
85
- if (results.created.success.length || results.updated.success.length) {
86
- render.bulkCreateOrUpdateResult(results, 'has successfully been created.', 'has successfully been updated.', 'was created with an autogenerated logical name.');
78
+ if (results.some(nextResult => nextResult.data)) {
79
+ // Render the results that have completed.
80
+ render.bulkCreateOrUpdateResult(results);
87
81
  }
88
82
  render.anyError(e);
89
83
  } finally {
@@ -109,6 +103,10 @@ const apply = exports.apply = {
109
103
  '--language=[langCode]': {
110
104
  desc: `Language Codes. One of: Comma Separated values of ${_types.LanguageTypes.French} | ${_types.LanguageTypes.US} | ${_types.LanguageTypes.German} | ${_types.LanguageTypes.Portugese}`,
111
105
  type: 'string'
106
+ },
107
+ '--subresource=[name]': {
108
+ desc: 'Name of the 1 subresource to update. Will prevent main resource and all other subresources from being updated.',
109
+ type: 'string'
112
110
  }
113
111
  }
114
112
  };
@@ -130,6 +130,7 @@ class ApiServerClient {
130
130
  * @param {Object} args function expects arguments as an object
131
131
  * @param {GenericResource} args.resource resource input (not the APIs response)
132
132
  * @param {string} args.resourceName resource name
133
+ * @param {string} args.subResourceName subresource name
133
134
  * @param {ResourceDefinition} args.resourceDef resource definition
134
135
  * @param {string} [args.scopeName] scope name
135
136
  * @param {ResourceDefinition} [args.scopeDef] scope definition
@@ -140,6 +141,7 @@ class ApiServerClient {
140
141
  async generateSubResourcesRequests({
141
142
  resource,
142
143
  resourceName,
144
+ subResourceName,
143
145
  resourceDef,
144
146
  scopeDef,
145
147
  scopeName,
@@ -162,7 +164,12 @@ class ApiServerClient {
162
164
  version
163
165
  });
164
166
  const knownSubResourcesNames = (_resourceDef$spec$sub = (_resourceDef$spec$sub2 = resourceDef.spec.subResources) === null || _resourceDef$spec$sub2 === void 0 ? void 0 : _resourceDef$spec$sub2.names) !== null && _resourceDef$spec$sub !== void 0 ? _resourceDef$spec$sub : [];
165
- const foundSubResources = (0, _pickBy.default)(resource, (_, key) => key.startsWith('x-') || knownSubResourcesNames.includes(key));
167
+ const foundSubResources = (0, _pickBy.default)(resource, (_, key) => {
168
+ if (key.startsWith('x-') || knownSubResourcesNames.includes(key)) {
169
+ return !subResourceName || subResourceName === key;
170
+ }
171
+ return false;
172
+ });
166
173
  if (language) {
167
174
  const langSubResourcesNames = (0, _utils.createLanguageSubresourceNames)(language);
168
175
  langSubResourcesNames.forEach(name => {
@@ -186,14 +193,15 @@ class ApiServerClient {
186
193
  });
187
194
  }
188
195
  return (0, _isEmpty.default)(foundSubResources) ? null : Object.keys(foundSubResources).map(key => {
189
- return () => service.put(`${baseUrl}/${key}?fields=${key}`, {
190
- [key]: foundSubResources[key]
191
- })
192
- // note: "catch" will not be needed if APIs will return the sub-resource name in error response
193
- .catch(err => Promise.reject({
196
+ return {
194
197
  name: key,
195
- requestError: err
196
- }));
198
+ operation: () => service.put(`${baseUrl}/${key}?fields=${key}`, {
199
+ [key]: foundSubResources[key]
200
+ }).catch(err => Promise.reject({
201
+ name: key,
202
+ requestError: err
203
+ }))
204
+ };
197
205
  });
198
206
  }
199
207
 
@@ -207,34 +215,44 @@ class ApiServerClient {
207
215
  */
208
216
  async resolveSubResourcesRequests(mainResourceResponse, pendingCalls) {
209
217
  var _result$error2, _result$error3;
210
- if (!pendingCalls) return {
211
- data: mainResourceResponse,
212
- error: null
213
- };
218
+ if (!pendingCalls) {
219
+ return {
220
+ data: mainResourceResponse,
221
+ error: null
222
+ };
223
+ }
214
224
  log(`resolving sub-resources, pending calls = ${pendingCalls.length}.`);
215
225
  // note: errors set to an empty array initially, will reset to null if no errors found
216
226
  const result = {
217
227
  data: null,
228
+ updatedSubResourceNames: [],
218
229
  error: []
219
230
  };
220
- const subResourcesCombined = (await Promise.allSettled(pendingCalls.map(call => call()))).reduce((a, c) => {
221
- if (c.status === 'fulfilled') return {
222
- ...a,
223
- ...c.value
224
- };else {
225
- var _c$reason$requestErro;
226
- // expecting only a valid ApiServer error response here
227
- // re-throw if something different, so it should be handled by command's catch block.
228
- if ((_c$reason$requestErro = c.reason.requestError) !== null && _c$reason$requestErro !== void 0 && _c$reason$requestErro.errors && Array.isArray(c.reason.requestError.errors)) {
229
- var _result$error;
230
- // note: if APIs are going to return more details this details override will not be needed, just push as in other methods
231
- (_result$error = result.error) === null || _result$error === void 0 ? void 0 : _result$error.push(...c.reason.requestError.errors.map(e => ({
232
- ...e,
233
- detail: `sub-resource "${c.reason.name}" ${e.detail}`
234
- })));
235
- } else throw c.reason;
231
+ const subResourcesCombined = (await Promise.allSettled(pendingCalls.map(async next => {
232
+ var _result$updatedSubRes;
233
+ const opResult = await next.operation();
234
+ (_result$updatedSubRes = result.updatedSubResourceNames) === null || _result$updatedSubRes === void 0 ? void 0 : _result$updatedSubRes.push(next.name);
235
+ return opResult;
236
+ }))).reduce((a, c) => {
237
+ var _c$reason$requestErro;
238
+ if (c.status === 'fulfilled') {
239
+ return {
240
+ ...a,
241
+ ...c.value
242
+ };
243
+ }
244
+ // expecting only a valid ApiServer error response here
245
+ // re-throw if something different, so it should be handled by command's catch block.
246
+ if ((_c$reason$requestErro = c.reason.requestError) !== null && _c$reason$requestErro !== void 0 && _c$reason$requestErro.errors && Array.isArray(c.reason.requestError.errors)) {
247
+ var _result$error;
248
+ // note: if APIs are going to return more details this details override will not be needed, just push as in other methods
249
+ (_result$error = result.error) === null || _result$error === void 0 ? void 0 : _result$error.push(...c.reason.requestError.errors.map(e => ({
250
+ ...e,
251
+ detail: `sub-resource "${c.reason.name}" ${e.detail}`
252
+ })));
236
253
  return a;
237
254
  }
255
+ throw c.reason;
238
256
  }, {});
239
257
  result.data = (0, _assign.default)(mainResourceResponse, subResourcesCombined);
240
258
  if (!((_result$error2 = result.error) !== null && _result$error2 !== void 0 && _result$error2.length)) result.error = null; // reset errors to null if none encountered
@@ -245,8 +263,8 @@ class ApiServerClient {
245
263
  /**
246
264
  * Check if resources are deleted by making a fetch call for the resources
247
265
  */
248
- checkForResources(sortedResources, sortedDefsArray) {
249
- return Promise.all(sortedResources.map(resource => {
266
+ checkForResources(resources, sortedDefsArray) {
267
+ return Promise.all(resources.map(resource => {
250
268
  var _resource$metadata2, _resource$metadata3, _resource$metadata3$s;
251
269
  const resourceDef = sortedDefsArray.find(def => {
252
270
  var _def$spec$scope, _resource$metadata, _resource$metadata$sc;
@@ -282,7 +300,7 @@ class ApiServerClient {
282
300
  withSubResources = true,
283
301
  language
284
302
  }) {
285
- log(`createResource, spec.kind = ${resourceDef.spec.kind}, name = ${resource.name}, withSubResources = ${withSubResources}`);
303
+ log(`createResource, spec.kind = ${resourceDef.spec.kind}, name = ${resource.name}`);
286
304
  const result = {
287
305
  data: null,
288
306
  error: null,
@@ -337,7 +355,9 @@ class ApiServerClient {
337
355
  result.error = e.errors;
338
356
  } else throw e;
339
357
  }
340
- if (!!result.data) result.data = (0, _utils.sanitizeMetadata)(result.data);
358
+ if (!!result.data) {
359
+ result.data = (0, _utils.sanitizeMetadata)(result.data);
360
+ }
341
361
  return result;
342
362
  }
343
363
 
@@ -351,7 +371,7 @@ class ApiServerClient {
351
371
  scopeDef,
352
372
  scopeName,
353
373
  version = ApiServerVersions.v1alpha1,
354
- withSubResources = true,
374
+ subResourceName,
355
375
  language
356
376
  }) {
357
377
  log(`updateResource, spec.kind = ${resourceDef.spec.kind}, name = ${resource.name}`);
@@ -360,32 +380,15 @@ class ApiServerClient {
360
380
  error: null,
361
381
  pending: null
362
382
  };
363
- try {
364
- const service = await (0, _dataService.dataService)({
365
- baseUrl: this.baseUrl,
366
- region: this.region,
367
- account: this.account,
368
- team: this.team
369
- });
370
- let pendingSubResources;
371
- if (language) {
372
- pendingSubResources = await this.generateSubResourcesRequests({
373
- resource,
374
- resourceName: resource.name,
375
- resourceDef,
376
- scopeDef,
377
- scopeName,
378
- version,
379
- createAction: false,
380
- language
381
- });
382
- result.data = (0, _utils.buildGenericResource)({
383
- resourceName: resource.name,
384
- resourceDef: resourceDef,
385
- scopeName: scopeName
383
+ const canUpdateMainResource = !language && !subResourceName;
384
+ if (canUpdateMainResource) {
385
+ try {
386
+ const service = await (0, _dataService.dataService)({
387
+ baseUrl: this.baseUrl,
388
+ region: this.region,
389
+ account: this.account,
390
+ team: this.team
386
391
  });
387
- result.pending = pendingSubResources;
388
- } else {
389
392
  const url = this.buildResourceBaseUrl({
390
393
  resourceDef,
391
394
  resourceName: resource.name,
@@ -393,37 +396,46 @@ class ApiServerClient {
393
396
  scopeName,
394
397
  version
395
398
  });
396
- const response = await service.put(url, (0, _utils.sanitizeMetadata)(resource));
397
- pendingSubResources = await this.generateSubResourcesRequests({
398
- resource,
399
- resourceName: response.name,
400
- resourceDef,
401
- scopeDef,
402
- scopeName,
403
- createAction: false,
404
- version
405
- });
406
- if (withSubResources) {
407
- const {
408
- data: subResData,
409
- error: subResError
410
- } = await this.resolveSubResourcesRequests(response, pendingSubResources);
411
- result.data = subResData;
412
- result.error = subResError;
399
+ result.data = await service.put(url, (0, _utils.sanitizeMetadata)(resource));
400
+ } catch (e) {
401
+ log('updateResource, error', e);
402
+ // expecting only a valid ApiServer error response here
403
+ // re-throw if something different, so it should be handled by command's catch block.
404
+ if (e.errors && Array.isArray(e.errors)) {
405
+ result.error = e.errors;
413
406
  } else {
414
- result.data = response;
415
- result.pending = pendingSubResources;
407
+ throw e;
416
408
  }
409
+ ;
417
410
  }
418
- } catch (e) {
419
- log('updateResource, error', e);
420
- // expecting only a valid ApiServer error response here
421
- // re-throw if something different, so it should be handled by command's catch block.
422
- if (e.errors && Array.isArray(e.errors)) {
423
- result.error = e.errors;
424
- } else throw e;
425
411
  }
426
- if (!!result.data) result.data = (0, _utils.sanitizeMetadata)(result.data);
412
+ result.pending = await this.generateSubResourcesRequests({
413
+ resource,
414
+ resourceName: resource.name,
415
+ subResourceName,
416
+ resourceDef,
417
+ scopeDef,
418
+ scopeName,
419
+ version,
420
+ createAction: false,
421
+ language
422
+ });
423
+ if (!result.data && !result.pending && subResourceName) {
424
+ result.error = [{
425
+ status: 0,
426
+ title: '',
427
+ detail: `sub-resource "${subResourceName}" not found.`,
428
+ meta: {
429
+ instanceId: '',
430
+ tenantId: '',
431
+ authenticatedUserId: '',
432
+ transactionId: ''
433
+ }
434
+ }];
435
+ }
436
+ if (result.data) {
437
+ result.data = (0, _utils.sanitizeMetadata)(result.data);
438
+ }
427
439
  return result;
428
440
  }
429
441
 
@@ -730,16 +742,14 @@ class ApiServerClient {
730
742
  */
731
743
  async bulkCreate(resources, sortedDefsMap, version) {
732
744
  log(`bulk create`);
733
- // sort() is modifying the existing array so cloning it before use.
734
745
  const sortedDefsArray = Array.from(sortedDefsMap.values());
735
- const sortedResources = [...resources].sort((0, _utils.compareResourcesByKindAsc)(sortedDefsArray));
736
746
  const pendingSubResources = [];
737
747
  const bulkResult = {
738
748
  success: [],
739
749
  error: [],
740
750
  warning: []
741
751
  };
742
- for (const resource of sortedResources) {
752
+ for (const resource of resources) {
743
753
  var _resource$metadata7, _resource$metadata8, _resource$metadata8$s;
744
754
  const resourceDef = sortedDefsArray.find(def => {
745
755
  var _def$spec$scope2, _resource$metadata4, _resource$metadata4$s;
@@ -768,8 +778,7 @@ class ApiServerClient {
768
778
  resourceDef,
769
779
  scopeDef,
770
780
  scopeName,
771
- version,
772
- withSubResources: false
781
+ version
773
782
  });
774
783
  if (res.data && !res.error) {
775
784
  // note: bulk operation requires creation of sub-resources after all main resources created
@@ -821,35 +830,19 @@ class ApiServerClient {
821
830
  * sorting of the array of resources with "compareResourcesByKindAsc".
822
831
  * @param resources array of resources to create
823
832
  */
824
- async bulkCreateOrUpdate(resources, sortedDefsMap, language, version) {
833
+ async bulkCreateOrUpdate(resources, sortedDefsMap, language, subResourceName, version) {
825
834
  log(`bulk create or update`);
826
- // sort() is modifying the existing array so cloning it before use.
827
835
  const sortedDefsArray = Array.from(sortedDefsMap.values());
828
- const sortedResources = [...resources].sort((0, _utils.compareResourcesByKindAsc)(sortedDefsArray));
829
- const bulkResult = {
830
- created: {
831
- success: [],
832
- error: [],
833
- warning: []
834
- },
835
- updated: {
836
- success: [],
837
- error: []
838
- }
839
- };
840
- const pendingSubResources = {
841
- created: [],
842
- updated: []
843
- };
844
- for (const resource of sortedResources) {
845
- var _resource$metadata12, _resource$metadata13, _resource$metadata13$;
836
+ const applyResults = [];
837
+ for (const resource of resources) {
838
+ var _resource$metadata12, _resource$metadata13, _resource$metadata13$, _resource$name2, _singleResult$error, _applyResult$error3;
846
839
  const resourceDef = sortedDefsArray.find(def => {
847
840
  var _def$spec$scope3, _resource$metadata9, _resource$metadata9$s;
848
841
  return def.spec.kind === resource.kind && ((_def$spec$scope3 = def.spec.scope) === null || _def$spec$scope3 === void 0 ? void 0 : _def$spec$scope3.kind) === ((_resource$metadata9 = resource.metadata) === null || _resource$metadata9 === void 0 ? void 0 : (_resource$metadata9$s = _resource$metadata9.scope) === null || _resource$metadata9$s === void 0 ? void 0 : _resource$metadata9$s.kind);
849
842
  });
850
843
  // the check below is already happening when loading the specs but checking again just in case.
851
844
  if (!resourceDef) {
852
- var _resource$metadata10, _resource$metadata10$;
845
+ var _resource$metadata10, _resource$metadata10$, _resource$name;
853
846
  let errorMessage = `No resource definition found for "kind/${resource.kind}"`;
854
847
  if (!!((_resource$metadata10 = resource.metadata) !== null && _resource$metadata10 !== void 0 && (_resource$metadata10$ = _resource$metadata10.scope) !== null && _resource$metadata10$ !== void 0 && _resource$metadata10$.kind)) {
855
848
  var _resource$metadata11, _resource$metadata11$;
@@ -857,15 +850,18 @@ class ApiServerClient {
857
850
  } else {
858
851
  errorMessage += ' with no scope.';
859
852
  }
860
- bulkResult.created.error.push({
861
- name: resource.name || 'Unknown name',
862
- kind: resource.kind,
863
- error: new Error(errorMessage)
853
+ applyResults.push({
854
+ error: [{
855
+ name: (_resource$name = resource.name) !== null && _resource$name !== void 0 ? _resource$name : 'Unknown name',
856
+ kind: resource.kind,
857
+ error: new Error(errorMessage)
858
+ }]
864
859
  });
865
860
  continue;
866
861
  }
867
862
  const scopeDef = !!((_resource$metadata12 = resource.metadata) !== null && _resource$metadata12 !== void 0 && _resource$metadata12.scope) ? sortedDefsArray.find(def => def.spec.kind === resource.metadata.scope.kind && !def.spec.scope) : undefined;
868
863
  const scopeName = (_resource$metadata13 = resource.metadata) === null || _resource$metadata13 === void 0 ? void 0 : (_resource$metadata13$ = _resource$metadata13.scope) === null || _resource$metadata13$ === void 0 ? void 0 : _resource$metadata13$.name;
864
+ const resourceName = (_resource$name2 = resource.name) !== null && _resource$name2 !== void 0 ? _resource$name2 : 'Unknown name';
869
865
 
870
866
  // only making getResource call if resource has a name
871
867
  let getResult = resource.name ? await this.getResourceByName({
@@ -876,73 +872,29 @@ class ApiServerClient {
876
872
  }) : null;
877
873
 
878
874
  // Create new resources first
879
- if (!getResult || getResult !== null && getResult !== void 0 && getResult.error && getResult.error[0].status === 404) {
880
- // Resource is not found, do the create
881
-
882
- const res = await this.createResource({
875
+ let singleResult;
876
+ const shouldCreate = !getResult || !!(getResult !== null && getResult !== void 0 && getResult.error) && getResult.error[0].status === 404;
877
+ if (shouldCreate) {
878
+ // Resource not found. Create a new resource.
879
+ singleResult = await this.createResource({
883
880
  resource,
884
881
  resourceDef,
885
882
  scopeDef,
886
883
  scopeName,
887
884
  version,
888
- withSubResources: false,
889
885
  language
890
886
  });
891
- if (res.data && !res.error) {
892
- // note: bulk operation requires creation of sub-resources after all main resources created
893
- // since a sub-resource might have a reference to another resource.
894
- if (!!res.pending) {
895
- var _res$warning2;
896
- pendingSubResources.created.push({
897
- mainResult: res.data,
898
- pendingCalls: res.pending,
899
- withWarning: (_res$warning2 = res.warning) !== null && _res$warning2 !== void 0 ? _res$warning2 : false
900
- });
901
- } else {
902
- var _bulkResult$created$w;
903
- if (res.warning) (_bulkResult$created$w = bulkResult.created.warning) === null || _bulkResult$created$w === void 0 ? void 0 : _bulkResult$created$w.push(res.data);else bulkResult.created.success.push(res.data);
904
- }
905
- } else if (res.error) {
906
- for (const nextError of res.error) {
907
- bulkResult.created.error.push({
908
- name: resource.name || 'Unknown name',
909
- kind: resource.kind,
910
- error: nextError
911
- });
912
- }
913
- }
914
887
  } else if (getResult.data) {
915
- // Resource found, do the update
916
- const res = await this.updateResource({
888
+ // Resource found. Update the existing resource.
889
+ singleResult = await this.updateResource({
917
890
  resource: resource,
918
- //we know that the resource exists and has a name if we've gotten to this point in th control flow
919
891
  resourceDef,
920
892
  scopeDef,
921
893
  scopeName,
922
894
  version,
923
- withSubResources: false,
924
- language
895
+ language,
896
+ subResourceName
925
897
  });
926
- if (res.data && !res.error) {
927
- if (!!res.pending) {
928
- var _res$warning3;
929
- pendingSubResources.updated.push({
930
- mainResult: res.data,
931
- pendingCalls: res.pending,
932
- withWarning: (_res$warning3 = res.warning) !== null && _res$warning3 !== void 0 ? _res$warning3 : false
933
- });
934
- } else {
935
- bulkResult.updated.success.push(res.data);
936
- }
937
- } else if (res.error) {
938
- for (const nextError of res.error) {
939
- bulkResult.updated.error.push({
940
- name: resource.name,
941
- kind: resource.kind,
942
- error: nextError
943
- });
944
- }
945
- }
946
898
  } else {
947
899
  // Something is going wrong - more than one error in api server response, re-throw in the same
948
900
  // structure as ApiServerErrorResponse so renderer.anyError can pick this up.
@@ -950,40 +902,54 @@ class ApiServerClient {
950
902
  errors: getResult.error
951
903
  };
952
904
  }
953
- }
954
905
 
955
- // creating sub-resources
956
- for (const p of pendingSubResources.created) {
957
- const subResResult = await this.resolveSubResourcesRequests(p.mainResult, p.pendingCalls);
958
- if (subResResult.data && !subResResult.error) {
959
- var _bulkResult$created$w2;
960
- if (p.withWarning) (_bulkResult$created$w2 = bulkResult.created.warning) === null || _bulkResult$created$w2 === void 0 ? void 0 : _bulkResult$created$w2.push(subResResult.data);else bulkResult.created.success.push(subResResult.data);
961
- } else if (subResResult.error) {
962
- for (const nextError of subResResult.error) {
963
- bulkResult.created.error.push({
964
- name: p.mainResult.name,
965
- kind: p.mainResult.kind,
966
- error: nextError
967
- });
906
+ // Store the results of the above create/update.
907
+ const applyResult = {
908
+ data: singleResult.data,
909
+ wasCreated: shouldCreate && !!singleResult.data,
910
+ wasAutoNamed: shouldCreate && singleResult.warning,
911
+ wasMainResourceChanged: !!singleResult.data,
912
+ error: []
913
+ };
914
+ (_singleResult$error = singleResult.error) === null || _singleResult$error === void 0 ? void 0 : _singleResult$error.forEach(nextError => {
915
+ var _applyResult$error;
916
+ return (_applyResult$error = applyResult.error) === null || _applyResult$error === void 0 ? void 0 : _applyResult$error.push({
917
+ name: resourceName,
918
+ kind: resource.kind,
919
+ error: nextError
920
+ });
921
+ });
922
+ applyResults.push(applyResult);
923
+
924
+ // Create or update any pending subresources.
925
+ if (singleResult.pending) {
926
+ var _singleResult$data, _subResResult$error;
927
+ const pendingData = (_singleResult$data = singleResult.data) !== null && _singleResult$data !== void 0 ? _singleResult$data : (0, _utils.sanitizeMetadata)((0, _utils.buildGenericResource)({
928
+ resourceName: resourceName,
929
+ resourceDef: resourceDef,
930
+ scopeName: scopeName
931
+ }));
932
+ const subResResult = await this.resolveSubResourcesRequests(pendingData, singleResult.pending);
933
+ if (subResResult.data) {
934
+ applyResult.data = subResResult.data;
968
935
  }
969
- }
970
- }
971
- // creating sub-resources
972
- for (const p of pendingSubResources.updated) {
973
- const subResResult = await this.resolveSubResourcesRequests(p.mainResult, p.pendingCalls);
974
- if (subResResult.data && !subResResult.error) {
975
- bulkResult.updated.success.push(subResResult.data);
976
- } else if (subResResult.error) {
977
- for (const nextError of subResResult.error) {
978
- bulkResult.created.error.push({
979
- name: p.mainResult.name,
980
- kind: p.mainResult.kind,
981
- error: nextError
936
+ applyResult.updatedSubResourceNames = subResResult.updatedSubResourceNames;
937
+ (_subResResult$error = subResResult.error) === null || _subResResult$error === void 0 ? void 0 : _subResResult$error.forEach(error => {
938
+ var _applyResult$error2;
939
+ return (_applyResult$error2 = applyResult.error) === null || _applyResult$error2 === void 0 ? void 0 : _applyResult$error2.push({
940
+ name: resourceName,
941
+ kind: resource.kind,
942
+ error: error
982
943
  });
983
- }
944
+ });
945
+ }
946
+
947
+ // Delete the result's error array if it is empty.
948
+ if (!((_applyResult$error3 = applyResult.error) !== null && _applyResult$error3 !== void 0 && _applyResult$error3.length)) {
949
+ delete applyResult.error;
984
950
  }
985
951
  }
986
- return bulkResult;
952
+ return applyResults;
987
953
  }
988
954
 
989
955
  /**
@@ -993,14 +959,12 @@ class ApiServerClient {
993
959
  */
994
960
  async bulkDelete(resources, sortedDefsMap, wait, forceDelete, version) {
995
961
  log(`bulk delete`);
996
- // sort() is modifying the existing array so cloning it before use.
997
962
  const sortedDefsArray = Array.from(sortedDefsMap.values());
998
- const sortedResources = [...resources].sort((0, _utils.compareResourcesByKindDesc)(sortedDefsArray));
999
963
  const bulkResult = {
1000
964
  success: [],
1001
965
  error: []
1002
966
  };
1003
- for (const resource of sortedResources) {
967
+ for (const resource of resources) {
1004
968
  try {
1005
969
  var _resource$metadata15, _resource$metadata16, _resource$metadata16$;
1006
970
  const resourceDef = sortedDefsArray.find(def => {
@@ -1064,11 +1028,11 @@ class ApiServerClient {
1064
1028
  }
1065
1029
  if (wait) {
1066
1030
  let pendingResources = [];
1067
- pendingResources = await this.checkForResources(sortedResources, sortedDefsArray);
1031
+ pendingResources = await this.checkForResources(resources, sortedDefsArray);
1068
1032
  const pendingDeletingResource = pendingResources.some(res => res === null || res === void 0 ? void 0 : res.data);
1069
1033
  if (pendingDeletingResource) {
1070
1034
  setTimeout(async () => {
1071
- pendingResources = await this.checkForResources(sortedResources, sortedDefsArray);
1035
+ pendingResources = await this.checkForResources(resources, sortedDefsArray);
1072
1036
  }, _types.WAIT_TIMEOUT);
1073
1037
  const stillPending = pendingResources.some(res => res === null || res === void 0 ? void 0 : res.data);
1074
1038
  if (stillPending) {
@@ -118,6 +118,22 @@ class Renderer {
118
118
  return `"${resource.kind}/${resource.name}"${!!((_resource$metadata = resource.metadata) !== null && _resource$metadata !== void 0 && _resource$metadata.scope) ? ` in the scope "${resource.metadata.scope.kind}/${resource.metadata.scope.name}"` : ``}`;
119
119
  }
120
120
 
121
+ /**
122
+ * A helper returning `"<kind>/<name>" subresource "<subResourceNaem>" in the scope "<scopeKind>/<scopeName>"`
123
+ * string used to print bulk results (in "bulkResult" or "bulkCreateOrUpdateResult") or individually (see the "delete" cmd)
124
+ * @param {GenericResource} resource resource for witch the string should be created
125
+ * @param {string} subResourceName of the subresource that was updated
126
+ * @returns {string}
127
+ */
128
+ subResourceAndScopeKinds(resource, subResourceName) {
129
+ var _resource$metadata2;
130
+ let message = `"${resource.kind}/${resource.name}" subresource "${subResourceName}"`;
131
+ if ((_resource$metadata2 = resource.metadata) !== null && _resource$metadata2 !== void 0 && _resource$metadata2.scope) {
132
+ message += ` in the scope "${resource.metadata.scope.kind}/${resource.metadata.scope.name}"`;
133
+ }
134
+ return message;
135
+ }
136
+
121
137
  /**
122
138
  * Render bulk call result.
123
139
  * If error is happening - render as simple output (even if "output" param has been provided)
@@ -147,35 +163,35 @@ class Renderer {
147
163
  /**
148
164
  * Render bulk "apply" result (with different success messages).
149
165
  * If error is happening - render as simple output (even if "output" param has been provided)
150
- * @param bulkResult bulk response from createOrUpdate ApiServerClient
151
- * @param createSuccessMsg message to display for each created "kind/name"
152
- * @param updateSuccessMsg message to display for each updated "kind/name"
166
+ * @param results array of responses from createOrUpdate ApiServerClient
153
167
  */
154
- bulkCreateOrUpdateResult(bulkResult, createSuccessMsg, updateSuccessMsg, createWarningMsg) {
155
- // if array passed, combine in a single ApiServerClientBulkResult, else use as-is
156
- const bulkResultCombined = {
157
- success: [...bulkResult.created.success, ...bulkResult.updated.success],
158
- error: [...bulkResult.created.error, ...bulkResult.updated.error],
159
- warning: [bulkResult.created.warning]
160
- };
161
- if (bulkResultCombined.error.length) {
162
- var _bulkResult$created$w;
163
- (_bulkResult$created$w = bulkResult.created.warning) === null || _bulkResult$created$w === void 0 ? void 0 : _bulkResult$created$w.forEach(r => this.warning(`${this.resourceAndScopeKinds(r)} ${createWarningMsg}`));
164
- bulkResult.created.success.forEach(r => this.success(`${this.resourceAndScopeKinds(r)} ${createSuccessMsg}`));
165
- bulkResult.updated.success.forEach(r => this.success(`${this.resourceAndScopeKinds(r)} ${updateSuccessMsg}`));
166
- bulkResultCombined.error.forEach(r => this.anyError(r.error, `"${r.kind}/${r.name}" `, true));
167
- } else if (this.output) {
168
- var _bulkResult$created$w2;
169
- let results = bulkResultCombined.success;
170
- if ((_bulkResult$created$w2 = bulkResult.created.warning) !== null && _bulkResult$created$w2 !== void 0 && _bulkResult$created$w2.length) {
171
- results = bulkResult.created.warning.concat(results);
172
- }
173
- (0, _resultsRenderers.renderResponse)(this._console, results, this.output);
168
+ bulkCreateOrUpdateResult(results) {
169
+ if (results.every(r => {
170
+ var _r$error$length, _r$error;
171
+ return ((_r$error$length = (_r$error = r.error) === null || _r$error === void 0 ? void 0 : _r$error.length) !== null && _r$error$length !== void 0 ? _r$error$length : 0) === 0;
172
+ }) && this.output) {
173
+ // Output responses as JSON/YAML, but only if no error responses were received.
174
+ const dataArray = results.map(r => r.data).filter(r => r != null);
175
+ (0, _resultsRenderers.renderResponse)(this._console, dataArray, this.output);
174
176
  } else {
175
- var _bulkResult$created$w3;
176
- (_bulkResult$created$w3 = bulkResult.created.warning) === null || _bulkResult$created$w3 === void 0 ? void 0 : _bulkResult$created$w3.forEach(r => this.warning(`${this.resourceAndScopeKinds(r)} ${createWarningMsg}`));
177
- bulkResult.created.success.forEach(r => this.success(`${this.resourceAndScopeKinds(r)} ${createSuccessMsg}`));
178
- bulkResult.updated.success.forEach(r => this.success(`${this.resourceAndScopeKinds(r)} ${updateSuccessMsg}`));
177
+ // Log results.
178
+ for (const result of results) {
179
+ var _result$error;
180
+ if (result.data) {
181
+ if (result.wasAutoNamed) {
182
+ this.warning(this.resourceAndScopeKinds(result.data) + ' was created with an autogenerated logical name.');
183
+ } else if (result.wasCreated) {
184
+ this.success(this.resourceAndScopeKinds(result.data) + ' has successfully been created.');
185
+ } else if (result.wasMainResourceChanged) {
186
+ this.success(this.resourceAndScopeKinds(result.data) + ' has successfully been updated.');
187
+ }
188
+ }
189
+ (_result$error = result.error) === null || _result$error === void 0 ? void 0 : _result$error.forEach(r => this.anyError(r.error, `"${r.kind}/${r.name}" `, true));
190
+ if (!result.wasMainResourceChanged && result.data) {
191
+ var _result$updatedSubRes;
192
+ (_result$updatedSubRes = result.updatedSubResourceNames) === null || _result$updatedSubRes === void 0 ? void 0 : _result$updatedSubRes.forEach(name => this.success(this.subResourceAndScopeKinds(result.data, name) + ' has successfully been updated.'));
193
+ }
194
+ }
179
195
  }
180
196
  }
181
197
  renderGetResults(bulkResultsArray, successMsg, langDef) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axway/axway-central-cli",
3
- "version": "3.7.0",
3
+ "version": "3.8.0",
4
4
  "description": "Manage APIs, services and publish to the Amplify Marketplace",
5
5
  "homepage": "https://platform.axway.com",
6
6
  "author": {