Skip to content

Commit

Permalink
feat:replaced taxonomy & terms create api with import api in migratio…
Browse files Browse the repository at this point in the history
…n utility
  • Loading branch information
aman19K committed Feb 14, 2024
1 parent a8dc20e commit afb3890
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 100 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions packages/contentstack-import/src/import/modules/taxonomies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,12 @@ export default class ImportTaxonomies extends BaseClass {
};

const onReject = ({ error, apiData }: any) => {
const err = error?.message ? JSON.parse(error.message) : error;
const taxonomyUID = apiData?.taxonomy?.uid;
if (err?.errors?.taxonomy) {
log(this.importConfig, `Taxonomy '${taxonomyUID}' failed to be import! ${err.errors.taxonomy}`, 'error');
if (error?.errorMessage) {
log(this.importConfig, `Taxonomy '${taxonomyUID}' failed to be import! ${error?.errorMessage}`, 'error');
} else if (error?.message) {
const errorMsg = error?.errors?.taxonomy || error?.errors?.term || error?.message;
log(this.importConfig, `Taxonomy '${taxonomyUID}' failed to be import! ${errorMsg}`, 'error');
} else {
log(this.importConfig, `Taxonomy '${taxonomyUID}' failed to be import! ${formatError(error)}`, 'error');
}
Expand Down
2 changes: 1 addition & 1 deletion packages/contentstack-migration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ $ npm install -g @contentstack/cli-migration
$ csdx COMMAND
running command...
$ csdx (--version)
@contentstack/cli-migration/1.4.2 darwin-arm64 node-v20.8.0
@contentstack/cli-migration/1.5.0 darwin-arm64 node-v20.8.0
$ csdx --help [COMMAND]
USAGE
$ csdx COMMAND
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const fs = require('fs');
const path = require('path');
const fastcsv = require('fast-csv');
const find = require('lodash/find');

module.exports = ({ migration, stackSDKInstance, managementAPIClient, config }) => {
const dataDir = config['data-dir'];
Expand All @@ -10,34 +10,31 @@ module.exports = ({ migration, stackSDKInstance, managementAPIClient, config })
let stack;
let depth = 1,
parentUID = null;
let taxonomies = {};

const stackClient = () => {
return managementAPIClient.stack({ api_key: stackSDKInstance.api_key });
};

const createTaxonomy = async (apiData) => {
await stack
.taxonomy()
.create({ taxonomy: apiData })
.catch((err) => handleErrorMsg(err));
const pushTaxonomyDetails = async (apiData) => {
if (!taxonomies[apiData?.uid]) taxonomies[apiData?.uid] = { taxonomy: apiData };
};

const createTerm = async (apiData) => {
await stack
.taxonomy(apiData.taxonomy_uid)
.terms()
.create({ term: apiData })
.catch((err) => handleErrorMsg(err));
const pushTermDetails = async (apiData) => {
if (taxonomies[apiData?.taxonomy_uid]) {
const terms = (taxonomies[apiData.taxonomy_uid].terms ||= []);
terms.push({ uid: apiData.uid, name: apiData.name, parent_uid: apiData.parent_uid });
}
};

function handleErrorMsg(err) {
let errMsg = 'Something went wrong! Please try again';
let errMsg;
if (err?.errorMessage) {
errMsg = err.errorMessage;
} else if (err?.message) {
errMsg = err?.errors?.taxonomy || err?.errors?.term || JSON.stringify(err?.errors) || err?.message;
}
throw errMsg;
throw errMsg ?? err;
}

const readCsv = (path, options) => {
Expand All @@ -55,6 +52,23 @@ module.exports = ({ migration, stackSDKInstance, managementAPIClient, config })
});
};

const importTaxonomies = async () => {
for (const taxonomyUID in taxonomies) {
const filePath = path.resolve(process.cwd(), `${taxonomyUID}.json`);
if (!fs.existsSync(filePath)) {
fs.writeFileSync(filePath, JSON.stringify(taxonomies[taxonomyUID]));
}
await stack
.taxonomy()
.import({ taxonomy: filePath })
.then(() => console.log(`Taxonomy ${taxonomyUID} migrated successfully!`))
.catch((err) => {
handleErrorMsg(err);
});
fs.unlinkSync(filePath);
}
};

const toSnakeCase = (str) =>
str
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
Expand All @@ -69,74 +83,54 @@ module.exports = ({ migration, stackSDKInstance, managementAPIClient, config })
task: async (params) => {
try {
stack = stackClient();
if (!fs.existsSync(dataDir)) {
throw new Error(`No such file or directory - ${dataDir}`);
}
if (!fs.existsSync(dataDir)) throw new Error(`No such file or directory - ${dataDir}`);
const taxonomies = await readCsv(dataDir, { headers: true, delimiter });

if (!taxonomies?.length) {
throw new Error('No Taxonomies found!');
}
if (!taxonomies?.length) throw new Error('No Taxonomies found!');

for (let row = 0; row < taxonomies?.length; row++) {
const taxDetails = taxonomies[row];
for (const taxDetails of taxonomies) {
const taxonomyName = taxDetails['Taxonomy Name'] ?? '';
const taxonomyUID = taxDetails['Taxonomy Uid'] ?? '';
const taxonomyDesc = taxDetails['Taxonomy Description'] ?? '';
//taxonomy name required
if (taxDetails['Taxonomy Name']?.length) {
const taxonomyName = taxDetails['Taxonomy Name'];
const taxonomyUID = taxDetails['Taxonomy UID'] ?? '';
const taxonomyDesc = taxDetails['Taxonomy Description'] ?? '';
if (taxonomyName) {
const reqTaxonomyObj = {
name: taxonomyName,
uid: taxonomyUID?.length ? taxonomyUID : toSnakeCase(taxonomyName),
uid: taxonomyUID ?? toSnakeCase(taxonomyName),
description: taxonomyDesc,
};
parentDetails = {};
parentDetails['taxonomy_uid'] = reqTaxonomyObj.uid;
await createTaxonomy(reqTaxonomyObj);
} else if (!taxDetails['Taxonomy Name']?.length && parentDetails['taxonomy_uid']) {
const column = find(Object.keys(taxDetails), (col) => {
if (taxDetails[col] !== '') {
return col;
}
});
const termLevel = column?.split(' ')?.[1] ?? ''; // Output:- Level1/Level2
const termDepth = +termLevel.replace(/[^0-9]/g, ''); // fetch depth from header
const termName = taxDetails[`Term ${termLevel} Name`] ?? '';
parentDetails = { taxonomy_uid: reqTaxonomyObj.uid };
await pushTaxonomyDetails(reqTaxonomyObj);
} else if (!taxonomyName && parentDetails['taxonomy_uid']) {
const column = Object.keys(taxDetails).find((col) => taxDetails[col] !== '');
if (!column) continue;

const termLevel = (column.match(/Level \d+/) || [''])[0]; // Output:- Level 1/Level 2
const termDepth = +termLevel.replace(/\D/g, ''); // fetch depth from header
const termName = taxDetails[`${termLevel} Term Name`] ?? '';

//term name required field
if (termName?.length && termDepth) {
const termUID = taxDetails[`Term ${termLevel} UID`]?.length
? taxDetails[`Term ${termLevel} UID`]
: toSnakeCase(termName);
if (termDepth > depth) {
//child term case
parentUID = parentDetails[termDepth - 1] || null;
depth = termDepth;
parentDetails[depth] = termUID;
} else if (termDepth === 1) {
//parent term case
depth = 1;
parentUID = null;
parentDetails[depth] = termUID;
} else if (termDepth === depth) {
//sibling term case
parentUID = parentDetails[termDepth - 1];
} else if (termDepth < depth) {
//diff parent term case
parentUID = parentDetails[termDepth - 1] || null;
depth = termDepth;
parentDetails[depth] = termUID;
}
//term name required field to generate term uid
if (termName && termDepth) {
const termUID = taxDetails[`${termLevel} Term Uid`] || toSnakeCase(termName);
//Handled cases
//1.child term case 2.sibling term 3.different parent term parentUID = parentDetails[termDepth - 1] || null
//4.parent term -> parentUID = null & depth=1
parentUID = parentDetails[termDepth - 1] || (termDepth === 1 ? null : parentUID);
depth = termDepth;
parentDetails[depth] = termUID;
const reqTermObj = {
uid: termUID,
name: termName,
parent_uid: parentUID,
taxonomy_uid: parentDetails['taxonomy_uid'],
};
await createTerm(reqTermObj);
await pushTermDetails(reqTermObj);
}
}
}

// create json file & remove it after migrating taxonomy
await importTaxonomies();
} catch (error) {
throw error;
}
Expand All @@ -146,6 +140,6 @@ module.exports = ({ migration, stackSDKInstance, managementAPIClient, config })
if (config?.['data-dir']) {
migration.addTask(createTaxonomyTask());
} else {
console.error('Please provide config using --config data-dir: "<file-path>"');
console.error('Please provide config using --config data-dir:"<file-path>"');
}
};
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
Taxonomy Name,Taxonomy UID,Taxonomy Description,Term Level1 Name,Term Level1 UID,Term Level2 Name,Term Level2 UID,Term Level3 Name,Term Level3 UID,Term Level4 Name,Term Level4 UID
name taxonomy,name_taxonomy,,,,,,,,,
,,,term 2,term_2,,,,,,
,,,,,term 8,term_8,,,,
,,,,,,,term 9,term_9,,
,,,,,,,,,term 10,term_10
,,,term 1,term_1,,,,,,
,,,,,term 4,term_4,,,,
,,,,,,,term 5,term_5,,
,,,,,,,,,term 7,term_7
,,,,,term 3,term_3,,,,
,,,,,,,term 6,term_6,,
taxonomy1,taxonomy1,,,,,,,,,
,,,May,may,,,,,,
,,,,,Summer 2023,summer_2023,,,,
,,,December,december,,,,,,
,,,,,Winter 2022,winter_2022,,,,
clothes,clothes,clothes taxonomy,,,,,,,,
,,,fdshfgadf,fdshfgadf,,,,,,
,,,jeans,jeans,,,,,,
,,,shirt,shirt,,,,,,
,,,,,dfgdshfga,dfgdshfga,,,,
Taxonomy Name,Taxonomy Uid,Taxonomy Description,Level 1 Term Name,Level 1 Term Uid,Level 2 Term Name,Level 2 Term Uid,Level 3 Term Name,Level 3 Term Uid,Level 4 Term Name,Level 4 Term Uid,Level 5 Term Name,Level 5 Term Uid,Level 6 Term Name,Level 6 Term Uid,Level 7 Term Name,Level 7 Term Uid,Level 8 Term Name,Level 8 Term Uid,Level 9 Term Name,Level 9 Term Uid,Level 10 Term Name,Level 10 Term Uid
Regions,regions,A Taxonomy which focuses on the categorization of various regions & it's sub regions,,,,,,,,,,,,,,,,,,,,
,,,EMEA,emea,,,,,,,,,,,,,,,,,,
,,,,,Europe,europe,,,,,,,,,,,,,,,,
,,,,,Middle East,middle_east,,,,,,,,,,,,,,,,
,,,,,Africa,africa,,,,,,,,,,,,,,,,
,,,APAC,apac,,,,,,,,,,,,,,,,,,
,,,,,Asia,asia,,,,,,,,,,,,,,,,
,,,,,,,Northeastern Asia,northeastern_asia,,,,,,,,,,,,,,
,,,,,,,Central and South Asia,central_and_south_asia,,,,,,,,,,,,,,
,,,,,,,,,Central Asia,central_asia,,,,,,,,,,,,
,,,,,,,,,South Asia,south_asia,,,,,,,,,,,,
,,,,,,,,,,,India,india,,,,,,,,,,
,,,,,,,,,,,,,Maharashtra,maharashtra,,,,,,,,
,,,,,,,,,,,,,,,Mumbai,mumbai,,,,,,
,,,,,,,Southeastern Asia,southeastern_asia,,,,,,,,,,,,,,
,,,,,Pacific,pacific,,,,,,,,,,,,,,,,
clothes,clothes,categorization of various clothes,,,,,,,,,,,,,,,,,,,,
,,,Casual wear,casual,,,,,,,,,,,,,,,,,,
,,,Formal wear,formal,,,,,,,,,,,,,,,,,,
,,,Sports wear,sports,,,,,,,,,,,,,,,,,,
2 changes: 1 addition & 1 deletion packages/contentstack-migration/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@contentstack/cli-migration",
"version": "1.4.2",
"version": "1.5.0",
"author": "@contentstack",
"bugs": "https://github.com/contentstack/cli/issues",
"dependencies": {
Expand Down
10 changes: 6 additions & 4 deletions packages/contentstack-migration/src/utils/error-helper.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { highlight } = require('cardinal');
const { keys } = Object;
const chalk = require('chalk');
const isEmpty = require('lodash/isEmpty')

const { readFile } = require('./fs-helper');
const groupBy = require('./group-by');
Expand Down Expand Up @@ -50,10 +51,11 @@ module.exports = (errors) => {

messages.push(`${fileErrorsMessage}${errorMessages}`);
}
// eslint-disable-next-line
// console.error(chalk`{red.bold Validation failed}\n\n`);
// eslint-disable-next-line
console.log(messages.join('\n'));
if (isEmpty(messages) && errors?.length) {
console.error('Migration error---', errors);
} else {
console.log(messages.join('\n'));
}
// eslint-disable-next-line
console.log(chalk`{bold.red Migration unsuccessful}`);
};
2 changes: 1 addition & 1 deletion packages/contentstack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"@contentstack/cli-command": "~1.2.17",
"@contentstack/cli-config": "~1.6.2",
"@contentstack/cli-launch": "~1.0.16",
"@contentstack/cli-migration": "~1.4.2",
"@contentstack/cli-migration": "~1.5.0",
"@contentstack/cli-utilities": "~1.5.12",
"@contentstack/management": "~1.15.2",
"@oclif/core": "^2.9.3",
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit afb3890

Please sign in to comment.