@axway/axway-central-cli 3.8.0 → 3.9.0-rc.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.
package/README.md CHANGED
@@ -450,20 +450,26 @@ Update resources from a file
450
450
 
451
451
  APPLY OPTIONS:
452
452
  --account [value] Override your default account config
453
- --no-cache Do not use cache when communicating with the server
454
453
  -f, --file [path] Filename to use to create or update the resources. One of: yaml | json
454
+ --language [langCode] Only update language portion. One of: fr-fr | en-us | de-de | pt-br
455
+ --no-cache Do not use cache when communicating with the server
455
456
  -o, --output [value] Additional output formats. One of: yaml | json
456
457
  --region [value] Override your region config
458
+ --subresource [name] Name of the 1 subresource to update. Will prevent main resource and all other subresources from being updated.
457
459
  -y, --yes Automatically reply "yes" to any command prompts.
458
460
  ```
459
461
 
460
462
  ### apply examples
461
463
 
462
464
  ```bash
463
- # create multiple resources from file
465
+ # create or update multiple resources from file
464
466
  axway central apply -f ./some/folder/resources.yaml
465
- # create multiple resources from file and output results in YAML format
467
+ # create or update multiple resources from file and output results in YAML format
466
468
  axway central apply -f ./some/folder/resources.json -o yaml
469
+ # only update 1 language "en-us" for multiple resources from file
470
+ axway central apply -f ./some/folder/resources.yaml --language en-us
471
+ # only update 1 subresource named "state" for multiple resources from file
472
+ axway central apply -f ./some/folder/resources.yaml --subresource state
467
473
  ```
468
474
 
469
475
  ---
@@ -16,14 +16,15 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
16
16
  const {
17
17
  log
18
18
  } = (0, _snooplogg.default)('central: get');
19
- const getListOrByName = async (resourceDef, client, scopeName, resourceName, scopeDef, query, progressListener, expand, langDef) => {
19
+ const getListOrByName = async (resourceDef, client, scopeName, resourceName, scopeDef, query, progressListener, expand, langDef, fieldSet) => {
20
20
  return resourceName ? await client.getResourceByName({
21
21
  resourceDef,
22
22
  resourceName,
23
23
  scopeDef,
24
24
  scopeName,
25
25
  expand,
26
- langDef
26
+ langDef,
27
+ fieldSet
27
28
  }) : await client.getResourcesList({
28
29
  resourceDef,
29
30
  scopeDef,
@@ -31,7 +32,8 @@ const getListOrByName = async (resourceDef, client, scopeName, resourceName, sco
31
32
  query,
32
33
  progressListener,
33
34
  expand,
34
- langDef
35
+ langDef,
36
+ fieldSet
35
37
  });
36
38
  };
37
39
  const get = exports.get = {
@@ -159,7 +161,7 @@ ${defsManager.getDefsTableForHelpMsg()}`);
159
161
  */
160
162
  if (scope) {
161
163
  const results = await Promise.all(defs.filter(defs => !scope.kind || !defs.scope || defs.scope.spec.kind === scope.kind).map(async defs => ({
162
- response: await getListOrByName(defs.resource, client, scope.name, resourceName, defs.scope, query, progressListener, languageExpand, languageDefinition),
164
+ response: await getListOrByName(defs.resource, client, scope.name, resourceName, defs.scope, query, progressListener, languageExpand, languageDefinition, argv.output ? undefined : getFieldSetFromDefinitionColumns(defs)),
163
165
  cli: defs.cli
164
166
  })));
165
167
  results.forEach(({
@@ -179,7 +181,7 @@ ${defsManager.getDefsTableForHelpMsg()}`);
179
181
  }
180
182
  });
181
183
  const results = await Promise.all(Object.values(defsMatchingGroup).map(async defs => ({
182
- response: await getListOrByName(defs.resource, client, undefined, resourceName, undefined, query, progressListener, languageExpand, languageDefinition),
184
+ response: await getListOrByName(defs.resource, client, undefined, resourceName, undefined, query, progressListener, languageExpand, languageDefinition, argv.output ? undefined : getFieldSetFromDefinitionColumns(defs)),
183
185
  cli: defs.cli
184
186
  })));
185
187
  results.forEach(({
@@ -248,4 +250,23 @@ ${defsManager.getDefsTableForHelpMsg()}`);
248
250
  desc: `Show the language definition constraint of the returned object. One of: Comma Separated values of ${_types.LanguageTypes.French} | ${_types.LanguageTypes.US} | ${_types.LanguageTypes.German} | ${_types.LanguageTypes.Portugese}`
249
251
  }
250
252
  }
251
- };
253
+ };
254
+
255
+ /**
256
+ * Gets the resource field names to be shown when outputting the resource as a table.
257
+ * These names are to be assigned to the api-server HTTP GET request's "fields" query param.
258
+ * @param def The resource definition providing the columns to be shown in the outputed table.
259
+ * @returns Returns a set set of field names.
260
+ */
261
+ function getFieldSetFromDefinitionColumns(def) {
262
+ var _def$cli, _def$cli$spec, _def$cli$spec$columns;
263
+ const fieldSet = new Set();
264
+ (_def$cli = def.cli) === null || _def$cli === void 0 ? void 0 : (_def$cli$spec = _def$cli.spec) === null || _def$cli$spec === void 0 ? void 0 : (_def$cli$spec$columns = _def$cli$spec.columns) === null || _def$cli$spec$columns === void 0 ? void 0 : _def$cli$spec$columns.forEach(column => {
265
+ let fieldName = column.jsonPath;
266
+ if (fieldName.startsWith('.')) {
267
+ fieldName = fieldName.substring(1);
268
+ }
269
+ fieldSet.add(fieldName);
270
+ });
271
+ return fieldSet;
272
+ }
@@ -59,8 +59,9 @@ class ApiServerClient {
59
59
  /**
60
60
  * Build resource url based on its ResourceDefinition and passed scope def and name.
61
61
  * Note that for scope url part both name and def needed.
62
+ * The returned URL path is expected to be appended to the base URL.
62
63
  */
63
- buildResourceBaseUrl({
64
+ buildResourceUrlPath({
64
65
  resourceDef,
65
66
  resourceName,
66
67
  scopeDef,
@@ -68,60 +69,51 @@ class ApiServerClient {
68
69
  version = ApiServerVersions.v1alpha1,
69
70
  forceDelete = false,
70
71
  expand,
71
- langDef
72
+ langDef,
73
+ fieldSet
72
74
  }) {
73
75
  const groupUrl = `/${resourceDef.metadata.scope.name}/${version}`;
74
76
  const scopeUrl = scopeName && scopeDef ? `/${scopeDef.spec.plural}/${encodeURIComponent(scopeName)}` : '';
75
77
  const resourceUrl = `/${resourceDef.spec.plural}`;
76
78
  const nameUrl = resourceName ? `/${encodeURIComponent(resourceName)}` : '';
77
- const expandUrl = expand ? `?expand=${expand}` : '';
78
- const langDefUrl = langDef ? this.buildLanguageDefinitionUrl({
79
- langCode: langDef
80
- }) : '';
81
- const forceDeleteUrl = forceDelete ? `?forceDelete=${forceDelete}` : '';
82
- if (expand) {
83
- return `${groupUrl}${scopeUrl}${resourceUrl}${nameUrl}${expandUrl}`;
84
- } else if (langDef) {
85
- return `${groupUrl}${scopeUrl}${resourceUrl}${nameUrl}${langDefUrl}`;
86
- } else {
87
- return `${groupUrl}${scopeUrl}${resourceUrl}${nameUrl}${forceDeleteUrl}`;
88
- }
89
- }
90
-
91
- /**
92
- * Build language definition url based on the language code.
93
- */
94
- buildLanguageDefinitionUrl({
95
- langCode
96
- }) {
97
- let langDefUrl = '';
98
- let i = 0;
99
- let embed = '?embed=';
100
- let expand = '&expand=languages,';
101
- let fields = '&fields=languages,group,apiVersion,name,kind,metadata,';
102
- const langCodeArr = langCode.split(',');
103
- let languageTypesArr = [];
104
- Object.keys(_types.LanguageTypes).forEach(key => languageTypesArr.push((0, _utils.ValueFromKey)(_types.LanguageTypes, key)));
105
- langCodeArr.forEach(code => {
106
- if (code.trim() != '') {
107
- if (!languageTypesArr.includes(code)) {
79
+ const embedSet = new Set();
80
+ const expandSet = new Set(expand === null || expand === void 0 ? void 0 : expand.split(','));
81
+ if (langDef) {
82
+ var _fieldSet;
83
+ (_fieldSet = fieldSet) !== null && _fieldSet !== void 0 ? _fieldSet : fieldSet = new Set();
84
+ fieldSet.add('languages').add('group').add('apiVersion').add('name').add('kind').add('metadata');
85
+ expandSet.add('languages');
86
+ let languageTypesArr = [];
87
+ Object.keys(_types.LanguageTypes).forEach(key => languageTypesArr.push((0, _utils.ValueFromKey)(_types.LanguageTypes, key)));
88
+ langDef.split(',').forEach(code => {
89
+ if (languageTypesArr.includes(code)) {
90
+ embedSet.add(`languages-${code.trim()}.resource`);
91
+ expandSet.add(`languages-${code.trim()}`);
92
+ fieldSet.add(`languages-${code.trim()}.values`);
93
+ } else if (code.trim().length > 0) {
108
94
  console.log(_chalk.default.yellow(`\n\'${code}\' language code is not supported. Allowed language codes: ${_types.LanguageTypes.French} | ${_types.LanguageTypes.German} | ${_types.LanguageTypes.US} | ${_types.LanguageTypes.Portugese}.'`));
109
- } else {
110
- if (i < langCodeArr.length - 1) {
111
- embed = embed + `languages-${code.trim()}.resource` + ",";
112
- expand = expand + `languages-${code.trim()}` + ",";
113
- fields = fields + `languages-${code.trim()}.values` + ",";
114
- } else {
115
- embed = embed + `languages-${code.trim()}.resource`;
116
- expand = expand + `languages-${code.trim()}`;
117
- fields = fields + `languages-${code.trim()}.values`;
118
- }
119
95
  }
96
+ });
97
+ }
98
+ let url = `${groupUrl}${scopeUrl}${resourceUrl}${nameUrl}`;
99
+ if (forceDelete || embedSet.size || expandSet.size || fieldSet) {
100
+ const queryParams = [];
101
+ if (forceDelete) {
102
+ queryParams.push('forceDelete=true');
120
103
  }
121
- i++;
122
- });
123
- langDefUrl = `${embed}${expand}${fields}`;
124
- return langDefUrl;
104
+ if (embedSet.size) {
105
+ queryParams.push('embed=' + [...embedSet].join(','));
106
+ }
107
+ if (expandSet.size) {
108
+ queryParams.push('expand=' + [...expandSet].join(','));
109
+ }
110
+ if (fieldSet) {
111
+ // If field set is empty, then return no fields. This is intentional.
112
+ queryParams.push('fields=' + [...fieldSet].join(','));
113
+ }
114
+ url += '?' + queryParams.join('&');
115
+ }
116
+ return url;
125
117
  }
126
118
 
127
119
  /**
@@ -156,7 +148,7 @@ class ApiServerClient {
156
148
  account: this.account,
157
149
  team: this.team
158
150
  });
159
- const baseUrl = this.buildResourceBaseUrl({
151
+ const urlPath = this.buildResourceUrlPath({
160
152
  resourceDef,
161
153
  resourceName,
162
154
  scopeDef,
@@ -195,7 +187,7 @@ class ApiServerClient {
195
187
  return (0, _isEmpty.default)(foundSubResources) ? null : Object.keys(foundSubResources).map(key => {
196
188
  return {
197
189
  name: key,
198
- operation: () => service.put(`${baseUrl}/${key}?fields=${key}`, {
190
+ operation: () => service.put(`${urlPath}/${key}?fields=${key}`, {
199
191
  [key]: foundSubResources[key]
200
192
  }).catch(err => Promise.reject({
201
193
  name: key,
@@ -314,13 +306,13 @@ class ApiServerClient {
314
306
  account: this.account,
315
307
  team: this.team
316
308
  });
317
- const url = this.buildResourceBaseUrl({
309
+ const urlPath = this.buildResourceUrlPath({
318
310
  resourceDef,
319
311
  scopeDef,
320
312
  scopeName,
321
313
  version
322
314
  });
323
- const response = await service.post(url, (0, _utils.sanitizeMetadata)(resource));
315
+ const response = await service.post(urlPath, (0, _utils.sanitizeMetadata)(resource));
324
316
  if (!resource.name) {
325
317
  log('createResource, resource does not have a logical name');
326
318
  result.warning = true;
@@ -389,14 +381,14 @@ class ApiServerClient {
389
381
  account: this.account,
390
382
  team: this.team
391
383
  });
392
- const url = this.buildResourceBaseUrl({
384
+ const urlPath = this.buildResourceUrlPath({
393
385
  resourceDef,
394
386
  resourceName: resource.name,
395
387
  scopeDef,
396
388
  scopeName,
397
389
  version
398
390
  });
399
- result.data = await service.put(url, (0, _utils.sanitizeMetadata)(resource));
391
+ result.data = await service.put(urlPath, (0, _utils.sanitizeMetadata)(resource));
400
392
  } catch (e) {
401
393
  log('updateResource, error', e);
402
394
  // expecting only a valid ApiServer error response here
@@ -469,14 +461,14 @@ class ApiServerClient {
469
461
  const knownSubResourcesNames = (_resourceDef$spec$sub3 = (_resourceDef$spec$sub4 = resourceDef.spec.subResources) === null || _resourceDef$spec$sub4 === void 0 ? void 0 : _resourceDef$spec$sub4.names) !== null && _resourceDef$spec$sub3 !== void 0 ? _resourceDef$spec$sub3 : [];
470
462
  const foundSubResources = (0, _pickBy.default)(resource, (_, key) => subResourceName == key && knownSubResourcesNames.includes(key));
471
463
  const resourceName = resource.name;
472
- const baseUrl = this.buildResourceBaseUrl({
464
+ const urlPath = this.buildResourceUrlPath({
473
465
  resourceDef,
474
466
  resourceName,
475
467
  scopeDef,
476
468
  scopeName,
477
469
  version
478
470
  });
479
- service.put(`${baseUrl}/${subResourceName}?fields=${subResourceName}`, {
471
+ service.put(`${urlPath}/${subResourceName}?fields=${subResourceName}`, {
480
472
  [subResourceName]: foundSubResources[subResourceName]
481
473
  });
482
474
  } catch (e) {
@@ -523,7 +515,7 @@ class ApiServerClient {
523
515
  account: this.account,
524
516
  team: this.team
525
517
  });
526
- const url = this.buildResourceBaseUrl({
518
+ const urlPath = this.buildResourceUrlPath({
527
519
  resourceDef,
528
520
  resourceName,
529
521
  scopeDef,
@@ -531,7 +523,7 @@ class ApiServerClient {
531
523
  version,
532
524
  forceDelete
533
525
  });
534
- const response = await service.delete(url);
526
+ const response = await service.delete(urlPath);
535
527
  // note: delete "response" value from api-server is translated to an empty string currently.
536
528
  // If its true, constructing a simple representation from provided data (definition, name, scope name)
537
529
  // and manually set it as the "data" key.
@@ -589,7 +581,8 @@ class ApiServerClient {
589
581
  query,
590
582
  progressListener,
591
583
  expand,
592
- langDef
584
+ langDef,
585
+ fieldSet
593
586
  }) {
594
587
  log(`getResourcesList, spec.kind = ${resourceDef.spec.kind}`);
595
588
  const result = {
@@ -603,15 +596,16 @@ class ApiServerClient {
603
596
  account: this.account,
604
597
  team: this.team
605
598
  });
606
- const url = this.buildResourceBaseUrl({
599
+ const urlPath = this.buildResourceUrlPath({
607
600
  resourceDef,
608
601
  scopeDef,
609
602
  scopeName,
610
603
  version,
611
604
  expand,
612
- langDef
605
+ langDef,
606
+ fieldSet
613
607
  });
614
- const response = await service.getWithPagination(url, query, 50, {}, progressListener);
608
+ const response = await service.getWithPagination(urlPath, query, 50, {}, progressListener);
615
609
  result.data = response;
616
610
  } catch (e) {
617
611
  log('getResourcesList, error: ', e);
@@ -641,7 +635,8 @@ class ApiServerClient {
641
635
  scopeName,
642
636
  version = ApiServerVersions.v1alpha1,
643
637
  expand,
644
- langDef
638
+ langDef,
639
+ fieldSet
645
640
  }) {
646
641
  log(`getResourceByName, spec.kind = ${resourceDef.spec.kind}, name = ${resourceName}`);
647
642
  const result = {
@@ -655,16 +650,17 @@ class ApiServerClient {
655
650
  account: this.account,
656
651
  team: this.team
657
652
  });
658
- const url = this.buildResourceBaseUrl({
653
+ const urlPath = this.buildResourceUrlPath({
659
654
  resourceDef,
660
655
  resourceName,
661
656
  scopeDef,
662
657
  scopeName,
663
658
  version,
664
659
  expand,
665
- langDef
660
+ langDef,
661
+ fieldSet
666
662
  });
667
- const response = await service.get(url);
663
+ const response = await service.get(urlPath);
668
664
  result.data = response;
669
665
  } catch (e) {
670
666
  log('getResourceByName, error: ', e);
@@ -126,7 +126,7 @@ const dataService = async ({
126
126
  clientId,
127
127
  team
128
128
  });
129
- const url = await getBaseUrl(baseUrl, basePath, region, orgRegion);
129
+ baseUrl = await getBaseUrl(baseUrl, basePath, region, orgRegion);
130
130
  const defaultHeaders = getDefaultHeaders({
131
131
  orgId,
132
132
  token
@@ -158,8 +158,8 @@ const dataService = async ({
158
158
  };
159
159
  return {
160
160
  postFormData: (route, body, headers = {}) => {
161
- log(`POST (from data): ${url + route}`);
162
- return fetch('post', url + route, {
161
+ log(`POST (from data): ${baseUrl + route}`);
162
+ return fetch('post', baseUrl + route, {
163
163
  headers: {
164
164
  ...defaultHeaders,
165
165
  ...body.getHeaders(),
@@ -169,9 +169,9 @@ const dataService = async ({
169
169
  }).then(handleResponse);
170
170
  },
171
171
  post: (route, data, headers = {}) => {
172
- log(`POST: ${url + route}`);
172
+ log(`POST: ${baseUrl + route}`);
173
173
  log(data);
174
- return fetch('post', url + route, {
174
+ return fetch('post', baseUrl + route, {
175
175
  headers: {
176
176
  ...defaultHeaders,
177
177
  ...headers
@@ -180,8 +180,8 @@ const dataService = async ({
180
180
  }).then(handleResponse);
181
181
  },
182
182
  put: (route, data, headers = {}) => {
183
- log(`PUT: ${url + route}`);
184
- return fetch('put', url + route, {
183
+ log(`PUT: ${baseUrl + route}`);
184
+ return fetch('put', baseUrl + route, {
185
185
  headers: {
186
186
  ...defaultHeaders,
187
187
  ...headers
@@ -194,8 +194,8 @@ const dataService = async ({
194
194
  ...defaultHeaders,
195
195
  ...headers
196
196
  };
197
- log(`GET: ${url + route}`, h);
198
- return fetch('get', url + route, {
197
+ log(`GET: ${baseUrl + route}`, h);
198
+ return fetch('get', baseUrl + route, {
199
199
  headers: h
200
200
  }).then(handleResponse);
201
201
  },
@@ -210,7 +210,10 @@ const dataService = async ({
210
210
  * @param progressListener invoked multiple times where argument is assigned progress value 0-100
211
211
  */
212
212
  getWithPagination: async function (route, queryParams = '', pageSize = 50, headers = {}, progressListener) {
213
- const fullUrl = queryParams ? new _url.URL(url + route + '?query=' + queryParams) : new _url.URL(url + route);
213
+ const fullUrl = new _url.URL(baseUrl + route);
214
+ if (queryParams) {
215
+ fullUrl.searchParams.set('query', queryParams);
216
+ }
214
217
  fullUrl.searchParams.set('pageSize', `${pageSize}`);
215
218
  log(`GET (with auto-pagination): ${fullUrl.href}`);
216
219
  const response = await fetch('get', fullUrl.toString(), {
@@ -241,9 +244,9 @@ const dataService = async ({
241
244
  for (let pageIndex = 1; pageIndex < totalPages; pageIndex++) {
242
245
  const thisPageIndex = pageIndex;
243
246
  fullUrl.searchParams.set('page', `${thisPageIndex + 1}`);
244
- const thisPageUrl = `${route}?${fullUrl.searchParams.toString()}`;
247
+ const nextRoute = fullUrl.href.substring(baseUrl.length);
245
248
  otherPagesCalls.push(limit(async () => {
246
- allPages[thisPageIndex] = await this.get(thisPageUrl, headers);
249
+ allPages[thisPageIndex] = await this.get(nextRoute, headers);
247
250
  pageDownloadCount++;
248
251
  updateProgress();
249
252
  }));
@@ -253,8 +256,8 @@ const dataService = async ({
253
256
  return (0, _flatten.default)(allPages);
254
257
  },
255
258
  delete: (route, headers = {}) => {
256
- log(`DELETE: ${url + route}`);
257
- return fetch('delete', url + route, {
259
+ log(`DELETE: ${baseUrl + route}`);
260
+ return fetch('delete', baseUrl + route, {
258
261
  headers: {
259
262
  ...defaultHeaders,
260
263
  ...headers
@@ -264,8 +267,8 @@ const dataService = async ({
264
267
  download: async route => {
265
268
  try {
266
269
  return await new Promise((resolve, reject) => {
267
- log(`DOWNLOAD: ${url + route}`);
268
- const stream = got.stream(url + route, {
270
+ log(`DOWNLOAD: ${baseUrl + route}`);
271
+ const stream = got.stream(baseUrl + route, {
269
272
  retry: 0,
270
273
  timeout: _types.ABORT_TIMEOUT
271
274
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axway/axway-central-cli",
3
- "version": "3.8.0",
3
+ "version": "3.9.0-rc.0",
4
4
  "description": "Manage APIs, services and publish to the Amplify Marketplace",
5
5
  "homepage": "https://platform.axway.com",
6
6
  "author": {