@contentstack/cli-cm-export-to-csv 1.9.1 → 1.10.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/package.json +2 -2
- package/src/commands/cm/export-to-csv.js +77 -45
- package/src/util/index.js +71 -14
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentstack/cli-cm-export-to-csv",
|
|
3
3
|
"description": "Export entities to csv",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.10.0",
|
|
5
5
|
"author": "Abhinav Gupta @abhinav-from-contentstack",
|
|
6
6
|
"bugs": "https://github.com/contentstack/cli/issues",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@contentstack/cli-command": "~1.6.1",
|
|
9
|
-
"@contentstack/cli-utilities": "~1.14.
|
|
9
|
+
"@contentstack/cli-utilities": "~1.14.4",
|
|
10
10
|
"@oclif/core": "^4.3.0",
|
|
11
11
|
"@oclif/plugin-help": "^6.2.32",
|
|
12
12
|
"fast-csv": "^4.3.6",
|
|
@@ -7,7 +7,6 @@ const {
|
|
|
7
7
|
cliux,
|
|
8
8
|
doesBranchExist,
|
|
9
9
|
isManagementTokenValid,
|
|
10
|
-
log
|
|
11
10
|
} = require('@contentstack/cli-utilities');
|
|
12
11
|
const util = require('../../util');
|
|
13
12
|
const config = require('../../util/config');
|
|
@@ -18,7 +17,8 @@ class ExportToCsvCommand extends Command {
|
|
|
18
17
|
required: false,
|
|
19
18
|
multiple: false,
|
|
20
19
|
options: ['entries', 'users', 'teams', 'taxonomies'],
|
|
21
|
-
description:
|
|
20
|
+
description:
|
|
21
|
+
'Option to export data (entries, users, teams, taxonomies). <options: entries|users|teams|taxonomies>',
|
|
22
22
|
}),
|
|
23
23
|
alias: flags.string({
|
|
24
24
|
char: 'a',
|
|
@@ -67,12 +67,22 @@ class ExportToCsvCommand extends Command {
|
|
|
67
67
|
'taxonomy-uid': flags.string({
|
|
68
68
|
description: 'Provide the taxonomy UID of the related terms you want to export.',
|
|
69
69
|
}),
|
|
70
|
+
'include-fallback': flags.boolean({
|
|
71
|
+
description:
|
|
72
|
+
"[Optional] Include fallback locale data when exporting taxonomies. When enabled, if a taxonomy term doesn't exist in the specified locale, it will fallback to the hierarchy defined in the branch settings.",
|
|
73
|
+
default: false,
|
|
74
|
+
}),
|
|
75
|
+
'fallback-locale': flags.string({
|
|
76
|
+
description:
|
|
77
|
+
"[Optional] Specify a specific fallback locale for taxonomy export. This locale will be used when a taxonomy term doesn't exist in the primary locale. Takes priority over branch fallback hierarchy when both are specified.",
|
|
78
|
+
required: false,
|
|
79
|
+
}),
|
|
70
80
|
delimiter: flags.string({
|
|
71
|
-
description:
|
|
81
|
+
description:
|
|
82
|
+
"[optional] Provide a delimiter to separate individual data fields within the CSV file. For example: cm:export-to-csv --delimiter '|'",
|
|
72
83
|
default: ',',
|
|
73
84
|
}),
|
|
74
|
-
};
|
|
75
|
-
|
|
85
|
+
};
|
|
76
86
|
async run() {
|
|
77
87
|
try {
|
|
78
88
|
let action, managementAPIClient;
|
|
@@ -87,9 +97,11 @@ class ExportToCsvCommand extends Command {
|
|
|
87
97
|
'content-type': contentTypesFlag,
|
|
88
98
|
alias: managementTokenAlias,
|
|
89
99
|
branch: branchUid,
|
|
90
|
-
|
|
100
|
+
'team-uid': teamUid,
|
|
91
101
|
'taxonomy-uid': taxonomyUID,
|
|
92
|
-
|
|
102
|
+
'include-fallback': includeFallback,
|
|
103
|
+
'fallback-locale': fallbackLocale,
|
|
104
|
+
delimiter,
|
|
93
105
|
},
|
|
94
106
|
} = await this.parse(ExportToCsvCommand);
|
|
95
107
|
|
|
@@ -127,7 +139,12 @@ class ExportToCsvCommand extends Command {
|
|
|
127
139
|
}
|
|
128
140
|
|
|
129
141
|
stackAPIClient = this.getStackClient(managementAPIClient, stack);
|
|
130
|
-
stackAPIClient = await this.checkAndUpdateBranchDetail(
|
|
142
|
+
stackAPIClient = await this.checkAndUpdateBranchDetail(
|
|
143
|
+
branchUid,
|
|
144
|
+
stack,
|
|
145
|
+
stackAPIClient,
|
|
146
|
+
managementAPIClient,
|
|
147
|
+
);
|
|
131
148
|
|
|
132
149
|
const contentTypeCount = await util.getContentTypeCount(stackAPIClient);
|
|
133
150
|
|
|
@@ -223,15 +240,15 @@ class ExportToCsvCommand extends Command {
|
|
|
223
240
|
}
|
|
224
241
|
case config.exportTeams:
|
|
225
242
|
case 'teams': {
|
|
226
|
-
try{
|
|
243
|
+
try {
|
|
227
244
|
let organization;
|
|
228
245
|
if (org) {
|
|
229
246
|
organization = { uid: org, name: orgName || org };
|
|
230
247
|
} else {
|
|
231
248
|
organization = await util.chooseOrganization(managementAPIClient, action); // prompt for organization
|
|
232
249
|
}
|
|
233
|
-
|
|
234
|
-
await util.exportTeams(managementAPIClient,organization,teamUid, delimiter);
|
|
250
|
+
|
|
251
|
+
await util.exportTeams(managementAPIClient, organization, teamUid, delimiter);
|
|
235
252
|
} catch (error) {
|
|
236
253
|
if (error.message || error.errorMessage) {
|
|
237
254
|
cliux.error(util.formatError(error));
|
|
@@ -242,7 +259,11 @@ class ExportToCsvCommand extends Command {
|
|
|
242
259
|
case config.exportTaxonomies:
|
|
243
260
|
case 'taxonomies': {
|
|
244
261
|
let stack;
|
|
262
|
+
let language;
|
|
245
263
|
let stackAPIClient;
|
|
264
|
+
let finalIncludeFallback = includeFallback;
|
|
265
|
+
let finalFallbackLocale = fallbackLocale;
|
|
266
|
+
|
|
246
267
|
if (managementTokenAlias) {
|
|
247
268
|
const { stackDetails, apiClient } = await this.getAliasDetails(managementTokenAlias, stackName);
|
|
248
269
|
managementAPIClient = apiClient;
|
|
@@ -252,7 +273,27 @@ class ExportToCsvCommand extends Command {
|
|
|
252
273
|
}
|
|
253
274
|
|
|
254
275
|
stackAPIClient = this.getStackClient(managementAPIClient, stack);
|
|
255
|
-
|
|
276
|
+
if (locale) {
|
|
277
|
+
language = { code: locale };
|
|
278
|
+
} else {
|
|
279
|
+
language = await util.chooseLanguage(stackAPIClient);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// if (includeFallback === undefined || fallbackLocale === undefined) {
|
|
283
|
+
// const fallbackOptions = await util.chooseFallbackOptions(stackAPIClient);
|
|
284
|
+
// }
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
if (fallbackLocale !== undefined) {
|
|
288
|
+
finalFallbackLocale = fallbackLocale;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
await this.createTaxonomyAndTermCsvFile(stackAPIClient, stackName, stack, taxonomyUID, delimiter, {
|
|
292
|
+
locale: language.code,
|
|
293
|
+
branch: branchUid,
|
|
294
|
+
include_fallback: finalIncludeFallback,
|
|
295
|
+
fallback_locale: finalFallbackLocale,
|
|
296
|
+
});
|
|
256
297
|
break;
|
|
257
298
|
}
|
|
258
299
|
}
|
|
@@ -287,7 +328,7 @@ class ExportToCsvCommand extends Command {
|
|
|
287
328
|
.query()
|
|
288
329
|
.find()
|
|
289
330
|
.then(({ items }) => (items !== undefined ? items : []))
|
|
290
|
-
.catch((
|
|
331
|
+
.catch(() => {});
|
|
291
332
|
}
|
|
292
333
|
|
|
293
334
|
/**
|
|
@@ -335,9 +376,14 @@ class ExportToCsvCommand extends Command {
|
|
|
335
376
|
let apiClient, stackDetails;
|
|
336
377
|
const listOfTokens = configHandler.get('tokens');
|
|
337
378
|
if (managementTokenAlias && listOfTokens[managementTokenAlias]) {
|
|
338
|
-
const checkManagementTokenValidity = await isManagementTokenValid(
|
|
339
|
-
|
|
340
|
-
|
|
379
|
+
const checkManagementTokenValidity = await isManagementTokenValid(
|
|
380
|
+
listOfTokens[managementTokenAlias].apiKey,
|
|
381
|
+
listOfTokens[managementTokenAlias].token,
|
|
382
|
+
);
|
|
383
|
+
if (Object.prototype.hasOwnProperty.call(checkManagementTokenValidity, 'message')) {
|
|
384
|
+
throw checkManagementTokenValidity.valid === 'failedToCheck'
|
|
385
|
+
? checkManagementTokenValidity.message
|
|
386
|
+
: `error: Management token or stack API key is invalid. ${checkManagementTokenValidity.message}`;
|
|
341
387
|
}
|
|
342
388
|
apiClient = await managementSDKClient({
|
|
343
389
|
host: this.cmaHost,
|
|
@@ -393,13 +439,12 @@ class ExportToCsvCommand extends Command {
|
|
|
393
439
|
* @param {object} stack
|
|
394
440
|
* @param {string} taxUID
|
|
395
441
|
*/
|
|
396
|
-
async createTaxonomyAndTermCsvFile(stackAPIClient, stackName, stack, taxUID, delimiter) {
|
|
397
|
-
//TODO: Temp variable to export taxonomies in importable format will replaced with flag once decided
|
|
398
|
-
const importableCSV = true;
|
|
442
|
+
async createTaxonomyAndTermCsvFile(stackAPIClient, stackName, stack, taxUID, delimiter, localeOptions = {}) {
|
|
399
443
|
const payload = {
|
|
400
444
|
stackAPIClient,
|
|
401
445
|
type: '',
|
|
402
446
|
limit: config.limit || 100,
|
|
447
|
+
...localeOptions, // Spread locale, branch, include_fallback, fallback_locale
|
|
403
448
|
};
|
|
404
449
|
//check whether the taxonomy is valid or not
|
|
405
450
|
let taxonomies = [];
|
|
@@ -411,36 +456,13 @@ class ExportToCsvCommand extends Command {
|
|
|
411
456
|
taxonomies = await util.getAllTaxonomies(payload);
|
|
412
457
|
}
|
|
413
458
|
|
|
414
|
-
if (!
|
|
415
|
-
|
|
416
|
-
if (formattedTaxonomiesData?.length) {
|
|
417
|
-
const fileName = `${stackName ? stackName : stack.name}_taxonomies.csv`;
|
|
418
|
-
util.write(this, formattedTaxonomiesData, fileName, 'taxonomies', delimiter);
|
|
419
|
-
} else {
|
|
420
|
-
cliux.print('info: No taxonomies found! Please provide a valid stack.', { color: 'blue' });
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
for (let index = 0; index < taxonomies?.length; index++) {
|
|
424
|
-
const taxonomy = taxonomies[index];
|
|
425
|
-
const taxonomyUID = taxonomy?.uid;
|
|
426
|
-
if (taxonomyUID) {
|
|
427
|
-
payload['taxonomyUID'] = taxonomyUID;
|
|
428
|
-
const terms = await util.getAllTermsOfTaxonomy(payload);
|
|
429
|
-
const formattedTermsData = util.formatTermsOfTaxonomyData(terms, taxonomyUID);
|
|
430
|
-
const taxonomyName = taxonomy?.name ?? '';
|
|
431
|
-
const termFileName = `${stackName ?? stack.name}_${taxonomyName}_${taxonomyUID}_terms.csv`;
|
|
432
|
-
if (formattedTermsData?.length) {
|
|
433
|
-
util.write(this, formattedTermsData, termFileName, 'terms', delimiter);
|
|
434
|
-
} else {
|
|
435
|
-
cliux.print(`info: No terms found for the taxonomy UID - '${taxonomyUID}'!`, { color: 'blue' });
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
}
|
|
459
|
+
if (!taxonomies?.length) {
|
|
460
|
+
cliux.print('info: No taxonomies found!', { color: 'blue' });
|
|
439
461
|
} else {
|
|
440
462
|
const fileName = `${stackName ?? stack.name}_taxonomies.csv`;
|
|
441
463
|
const { taxonomiesData, headers } = await util.createImportableCSV(payload, taxonomies);
|
|
442
464
|
if (taxonomiesData?.length) {
|
|
443
|
-
util.write(this, taxonomiesData, fileName, 'taxonomies',delimiter, headers);
|
|
465
|
+
util.write(this, taxonomiesData, fileName, 'taxonomies', delimiter, headers);
|
|
444
466
|
}
|
|
445
467
|
}
|
|
446
468
|
}
|
|
@@ -486,6 +508,16 @@ ExportToCsvCommand.examples = [
|
|
|
486
508
|
'',
|
|
487
509
|
'Exporting taxonomies and respective terms to a .CSV file with a delimiter',
|
|
488
510
|
'csdx cm:export-to-csv --action <taxonomies> --alias <management-token-alias> --delimiter <delimiter>',
|
|
511
|
+
'',
|
|
512
|
+
'Exporting taxonomies with specific locale',
|
|
513
|
+
'csdx cm:export-to-csv --action <taxonomies> --alias <management-token-alias> --locale <locale>',
|
|
514
|
+
'',
|
|
515
|
+
'Exporting taxonomies with fallback locale support',
|
|
516
|
+
'csdx cm:export-to-csv --action <taxonomies> --alias <management-token-alias> --locale <locale> --include-fallback',
|
|
517
|
+
'',
|
|
518
|
+
'Exporting taxonomies with custom fallback locale',
|
|
519
|
+
'csdx cm:export-to-csv --action <taxonomies> --alias <management-token-alias> --locale <locale> --include-fallback --fallback-locale <fallback-locale>',
|
|
520
|
+
'',
|
|
489
521
|
];
|
|
490
522
|
|
|
491
523
|
module.exports = ExportToCsvCommand;
|
package/src/util/index.js
CHANGED
|
@@ -485,6 +485,50 @@ function startupQuestions() {
|
|
|
485
485
|
});
|
|
486
486
|
}
|
|
487
487
|
|
|
488
|
+
function chooseFallbackOptions(stackAPIClient) {
|
|
489
|
+
return new Promise(async (resolve, reject) => {
|
|
490
|
+
try {
|
|
491
|
+
const questions = [
|
|
492
|
+
{
|
|
493
|
+
type: 'confirm',
|
|
494
|
+
name: 'includeFallback',
|
|
495
|
+
message: 'Include fallback locale data when exporting taxonomies?',
|
|
496
|
+
default: false,
|
|
497
|
+
},
|
|
498
|
+
];
|
|
499
|
+
|
|
500
|
+
const { includeFallback } = await inquirer.prompt(questions);
|
|
501
|
+
|
|
502
|
+
let fallbackLocale = null;
|
|
503
|
+
|
|
504
|
+
if (includeFallback) {
|
|
505
|
+
// Get available languages for fallback locale selection
|
|
506
|
+
const languages = await getLanguages(stackAPIClient);
|
|
507
|
+
const languagesList = Object.keys(languages);
|
|
508
|
+
|
|
509
|
+
const fallbackQuestion = [
|
|
510
|
+
{
|
|
511
|
+
type: 'list',
|
|
512
|
+
name: 'selectedFallbackLocale',
|
|
513
|
+
message: 'Choose fallback locale',
|
|
514
|
+
choices: languagesList,
|
|
515
|
+
},
|
|
516
|
+
];
|
|
517
|
+
|
|
518
|
+
const { selectedFallbackLocale } = await inquirer.prompt(fallbackQuestion);
|
|
519
|
+
fallbackLocale = languages[selectedFallbackLocale];
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
resolve({
|
|
523
|
+
includeFallback,
|
|
524
|
+
fallbackLocale,
|
|
525
|
+
});
|
|
526
|
+
} catch (error) {
|
|
527
|
+
reject(error);
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
|
|
488
532
|
function getOrgUsers(managementAPIClient, orgUid) {
|
|
489
533
|
return new Promise((resolve, reject) => {
|
|
490
534
|
managementAPIClient
|
|
@@ -1080,11 +1124,17 @@ async function getTaxonomy(payload) {
|
|
|
1080
1124
|
* @returns {*} Promise<any>
|
|
1081
1125
|
*/
|
|
1082
1126
|
async function taxonomySDKHandler(payload, skip) {
|
|
1083
|
-
const { stackAPIClient, taxonomyUID, type, format } = payload;
|
|
1127
|
+
const { stackAPIClient, taxonomyUID, type, format, locale, branch, include_fallback, fallback_locale } = payload;
|
|
1084
1128
|
|
|
1085
1129
|
const queryParams = { include_count: true, limit: payload.limit };
|
|
1086
1130
|
if (skip >= 0) queryParams['skip'] = skip || 0;
|
|
1087
1131
|
|
|
1132
|
+
// Add locale and branch parameters if provided
|
|
1133
|
+
if (locale) queryParams['locale'] = locale;
|
|
1134
|
+
if (branch) queryParams['branch'] = branch;
|
|
1135
|
+
if (include_fallback !== undefined) queryParams['include_fallback'] = include_fallback;
|
|
1136
|
+
if (fallback_locale) queryParams['fallback_locale'] = fallback_locale;
|
|
1137
|
+
|
|
1088
1138
|
switch (type) {
|
|
1089
1139
|
case 'taxonomies':
|
|
1090
1140
|
return await stackAPIClient
|
|
@@ -1109,9 +1159,15 @@ async function taxonomySDKHandler(payload, skip) {
|
|
|
1109
1159
|
.then((data) => data)
|
|
1110
1160
|
.catch((err) => handleTaxonomyErrorMsg(err));
|
|
1111
1161
|
case 'export-taxonomies':
|
|
1162
|
+
const exportParams = { format };
|
|
1163
|
+
if (locale) exportParams.locale = locale;
|
|
1164
|
+
if (branch) exportParams.branch = branch;
|
|
1165
|
+
if (include_fallback !== undefined) exportParams.include_fallback = include_fallback;
|
|
1166
|
+
if (fallback_locale) exportParams.fallback_locale = fallback_locale;
|
|
1167
|
+
|
|
1112
1168
|
return await stackAPIClient
|
|
1113
1169
|
.taxonomy(taxonomyUID)
|
|
1114
|
-
.export(
|
|
1170
|
+
.export(exportParams)
|
|
1115
1171
|
.then((data) => data)
|
|
1116
1172
|
.catch((err) => handleTaxonomyErrorMsg(err));
|
|
1117
1173
|
default:
|
|
@@ -1176,20 +1232,20 @@ function handleTaxonomyErrorMsg(err) {
|
|
|
1176
1232
|
* @returns
|
|
1177
1233
|
*/
|
|
1178
1234
|
async function createImportableCSV(payload, taxonomies) {
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
}
|
|
1235
|
+
let taxonomiesData = [];
|
|
1236
|
+
let headers = [];
|
|
1237
|
+
payload['type'] = 'export-taxonomies';
|
|
1238
|
+
payload['format'] = 'csv';
|
|
1239
|
+
for (const taxonomy of taxonomies) {
|
|
1240
|
+
if (taxonomy?.uid) {
|
|
1241
|
+
payload['taxonomyUID'] = taxonomy?.uid;
|
|
1242
|
+
const data = await taxonomySDKHandler(payload);
|
|
1243
|
+
const taxonomies = await csvParse(data, headers);
|
|
1244
|
+
taxonomiesData.push(...taxonomies);
|
|
1190
1245
|
}
|
|
1246
|
+
}
|
|
1191
1247
|
|
|
1192
|
-
|
|
1248
|
+
return { taxonomiesData, headers };
|
|
1193
1249
|
}
|
|
1194
1250
|
|
|
1195
1251
|
/**
|
|
@@ -1224,6 +1280,7 @@ module.exports = {
|
|
|
1224
1280
|
chooseBranch: chooseBranch,
|
|
1225
1281
|
chooseContentType: chooseContentType,
|
|
1226
1282
|
chooseLanguage: chooseLanguage,
|
|
1283
|
+
chooseFallbackOptions: chooseFallbackOptions,
|
|
1227
1284
|
getEntries: getEntries,
|
|
1228
1285
|
getEnvironments: getEnvironments,
|
|
1229
1286
|
cleanEntries: cleanEntries,
|