Skip to content

Commit

Permalink
Merge pull request #1128 from contentstack/feat/CS-38078-taxonomy
Browse files Browse the repository at this point in the history
Feat: taxonomy
  • Loading branch information
aman19K authored Oct 27, 2023
2 parents b58f291 + 2b9e01c commit 5bc7977
Show file tree
Hide file tree
Showing 42 changed files with 2,174 additions and 448 deletions.
420 changes: 354 additions & 66 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/contentstack-bootstrap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ $ npm install -g @contentstack/cli-cm-bootstrap
$ csdx COMMAND
running command...
$ csdx (--version)
@contentstack/cli-cm-bootstrap/1.6.0 darwin-arm64 node-v20.8.0
@contentstack/cli-cm-bootstrap/1.6.1 darwin-arm64 node-v20.8.0
$ csdx --help [COMMAND]
USAGE
$ csdx COMMAND
Expand Down
4 changes: 2 additions & 2 deletions packages/contentstack-bootstrap/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@contentstack/cli-cm-bootstrap",
"description": "Bootstrap contentstack apps",
"version": "1.6.0",
"version": "1.6.1",
"author": "Contentstack",
"bugs": "https://github.com/contentstack/cli/issues",
"scripts": {
Expand All @@ -17,7 +17,7 @@
"test:report": "nyc --reporter=lcov mocha \"test/**/*.test.js\""
},
"dependencies": {
"@contentstack/cli-cm-seed": "~1.6.0",
"@contentstack/cli-cm-seed": "~1.6.1",
"@contentstack/cli-command": "~1.2.14",
"@contentstack/cli-utilities": "~1.5.4",
"inquirer": "8.2.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/contentstack-clone/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ $ npm install -g @contentstack/cli-cm-clone
$ csdx COMMAND
running command...
$ csdx (--version)
@contentstack/cli-cm-clone/1.6.0 darwin-arm64 node-v20.8.0
@contentstack/cli-cm-clone/1.7.0 darwin-arm64 node-v20.8.0
$ csdx --help [COMMAND]
USAGE
$ csdx COMMAND
Expand Down
6 changes: 3 additions & 3 deletions packages/contentstack-clone/package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "@contentstack/cli-cm-clone",
"description": "Contentstack stack clone plugin",
"version": "1.6.0",
"version": "1.7.0",
"author": "Contentstack",
"bugs": "https://github.com/rohitmishra209/cli-cm-clone/issues",
"dependencies": {
"@contentstack/cli-cm-export": "~1.9.0",
"@contentstack/cli-cm-import": "~1.10.0",
"@contentstack/cli-cm-export": "~1.10.0",
"@contentstack/cli-cm-import": "~1.11.0",
"@contentstack/cli-command": "~1.2.14",
"@contentstack/cli-utilities": "~1.5.4",
"@colors/colors": "^1.5.0",
Expand Down
14 changes: 9 additions & 5 deletions packages/contentstack-export-to-csv/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@contentstack/cli-cm-export-to-csv",
"description": "Export entities to csv",
"version": "1.4.4",
"version": "1.5.0",
"author": "Abhinav Gupta @abhinav-from-contentstack",
"bugs": "https://github.com/contentstack/cli/issues",
"dependencies": {
Expand All @@ -15,12 +15,15 @@
},
"devDependencies": {
"@oclif/test": "^2.2.10",
"chai": "^4.2.0",
"@types/chai": "^4.3.6",
"@types/mocha": "^10.0.1",
"chai": "^4.3.8",
"debug": "^4.3.1",
"dotenv": "^16.3.1",
"eslint": "^7.32.0",
"eslint-config-oclif": "^4.0.0",
"globby": "^10.0.2",
"mocha": "^10.0.0",
"mocha": "^10.2.0",
"nyc": "^15.1.0",
"oclif": "^3.8.1"
},
Expand All @@ -44,7 +47,8 @@
"postpack": "rm -f oclif.manifest.json",
"prepack": "oclif manifest && oclif readme",
"test": "nyc mocha --forbid-only \"test/**/*.test.js\"",
"test:unit": "nyc mocha --timeout 10000 --forbid-only \"test/unit/**/*.test.js\"",
"test:unit": "mocha --timeout 10000 --forbid-only \"test/unit/**/*.test.js\" \"test/util/common-utils.test.js\"",
"test:unit:report": "nyc --extension .js mocha --forbid-only \"test/unit/**/*.test.js\" \"test/util/common-utils.test.js\"",
"version": "oclif readme && git add README.md",
"clean": "rm -rf ./node_modules tsconfig.build.tsbuildinfo"
},
Expand All @@ -61,4 +65,4 @@
}
},
"repository": "https://github.com/contentstack/cli"
}
}
234 changes: 173 additions & 61 deletions packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class ExportToCsvCommand extends Command {
action: flags.string({
required: false,
multiple: false,
options: ['entries', 'users'],
options: ['entries', 'users', 'taxonomies'],
description: `Option to export data (entries, users)`,
}),
alias: flags.string({
Expand Down Expand Up @@ -59,6 +59,9 @@ class ExportToCsvCommand extends Command {
multiple: false,
required: false,
}),
'taxonomy-uid': flags.string({
description: 'Provide the taxonomy UID of the related terms you want to export',
}),
};

async run() {
Expand All @@ -75,6 +78,7 @@ class ExportToCsvCommand extends Command {
'content-type': contentTypesFlag,
alias: managementTokenAlias,
branch: branchUid,
'taxonomy-uid': taxonomyUID,
},
} = await this.parse(ExportToCsvCommand);

Expand All @@ -96,69 +100,17 @@ class ExportToCsvCommand extends Command {
let stackAPIClient;
let language;
let contentTypes = [];
let stackBranches;
const listOfTokens = configHandler.get('tokens');

if (managementTokenAlias && listOfTokens[managementTokenAlias]) {
managementAPIClient = await managementSDKClient({
host: this.cmaHost,
management_token: listOfTokens[managementTokenAlias].token,
});
stack = {
name: stackName || managementTokenAlias,
apiKey: listOfTokens[managementTokenAlias].apiKey,
token: listOfTokens[managementTokenAlias].token,
};
} else if (managementTokenAlias) {
this.error('Provided management token alias not found in your config.!');
if (managementTokenAlias) {
const { stackDetails, apiClient } = await this.getAliasDetails(managementTokenAlias, stackName);
managementAPIClient = apiClient;
stack = stackDetails;
} else {
let organization;

if (!isAuthenticated()) {
this.error(config.CLI_EXPORT_CSV_ENTRIES_ERROR, {
exit: 2,
suggestions: ['https://www.contentstack.com/docs/developers/cli/authentication/'],
});
}

if (org) {
organization = { uid: org };
} else {
organization = await util.chooseOrganization(managementAPIClient); // prompt for organization
}
if (!stackAPIKey) {
stack = await util.chooseStack(managementAPIClient, organization.uid); // prompt for stack
} else {
stack = await util.chooseStack(managementAPIClient, organization.uid, stackAPIKey);
}
stack = await this.getStackDetails(managementAPIClient, stackAPIKey, org);
}

stackAPIClient = this.getStackClient(managementAPIClient, stack);

if (branchUid) {
try {
const branchExists = await doesBranchExist(stackAPIClient, branchUid);
if (branchExists?.errorCode) {
throw new Error(branchExists.errorMessage);
}
stack.branch_uid = branchUid;
stackAPIClient = this.getStackClient(managementAPIClient, stack);
} catch (error) {
if (error.message || error.errorMessage) {
cliux.error(util.formatError(error));
this.exit();
}
}
} else {
stackBranches = await this.getStackBranches(stackAPIClient);
if (stackBranches === undefined) {
stackAPIClient = this.getStackClient(managementAPIClient, stack);
} else {
const { branch } = await util.chooseBranch(stackBranches);
stack.branch_uid = branch;
stackAPIClient = this.getStackClient(managementAPIClient, stack);
}
}
await this.checkAndUpdateBranchDetail(branchUid, stack, stackAPIClient, managementAPIClient);

const contentTypeCount = await util.getContentTypeCount(stackAPIClient);

Expand Down Expand Up @@ -258,6 +210,22 @@ class ExportToCsvCommand extends Command {
}
break;
}
case config.exportTaxonomies:
case 'taxonomies': {
let stack;
let stackAPIClient;
if (managementTokenAlias) {
const { stackDetails, apiClient } = await this.getAliasDetails(managementTokenAlias, stackName);
managementAPIClient = apiClient;
stack = stackDetails;
} else {
stack = await this.getStackDetails(managementAPIClient, stackAPIKey, org);
}

stackAPIClient = this.getStackClient(managementAPIClient, stack);
await this.createTaxonomyAndTermCsvFile(stackAPIClient, stackName, stack, taxonomyUID);
break;
}
}
} catch (error) {
if (error.message || error.errorMessage) {
Expand All @@ -273,8 +241,8 @@ class ExportToCsvCommand extends Command {
getStackClient(managementAPIClient, stack) {
const stackInit = {
api_key: stack.apiKey,
branch_uid: stack.branch_uid,
};
if(stack?.branch_uid) stackInit['branch_uid'] = stack.branch_uid;
if (stack.token) {
return managementAPIClient.stack({
...stackInit,
Expand All @@ -292,9 +260,149 @@ class ExportToCsvCommand extends Command {
.then(({ items }) => (items !== undefined ? items : []))
.catch((_err) => {});
}

/**
* check whether branch enabled org or not and update branch details
* @param {string} branchUid
* @param {object} stack
* @param {*} stackAPIClient
* @param {*} managementAPIClient
*/
async checkAndUpdateBranchDetail(branchUid, stack, stackAPIClient, managementAPIClient) {
if (branchUid) {
try {
const branchExists = await doesBranchExist(stackAPIClient, branchUid);
if (branchExists?.errorCode) {
throw new Error(branchExists.errorMessage);
}
stack.branch_uid = branchUid;
stackAPIClient = this.getStackClient(managementAPIClient, stack);
} catch (error) {
if (error?.message || error?.errorMessage) {
cliux.error(util.formatError(error));
this.exit();
}
}
} else {
const stackBranches = await this.getStackBranches(stackAPIClient);
if (stackBranches === undefined) {
stackAPIClient = this.getStackClient(managementAPIClient, stack);
} else {
const { branch } = await util.chooseBranch(stackBranches);
stack.branch_uid = branch;
stackAPIClient = this.getStackClient(managementAPIClient, stack);
}
}
}

/**
* fetch stack details from alias token
* @param {string} managementTokenAlias
* @param {string} stackName
* @returns
*/
async getAliasDetails(managementTokenAlias, stackName) {
let apiClient, stackDetails;
const listOfTokens = configHandler.get('tokens');
if (managementTokenAlias && listOfTokens[managementTokenAlias]) {
apiClient = await managementSDKClient({
host: this.cmaHost,
management_token: listOfTokens[managementTokenAlias].token,
});
stackDetails = {
name: stackName || managementTokenAlias,
apiKey: listOfTokens[managementTokenAlias].apiKey,
token: listOfTokens[managementTokenAlias].token,
};
} else if (managementTokenAlias) {
this.error('Provided management token alias not found in your config.!');
}
return {
apiClient,
stackDetails,
};
}

/**
* fetch stack details on basis of the selected org and stack
* @param {*} managementAPIClient
* @param {string} stackAPIKey
* @param {string} org
* @returns
*/
async getStackDetails(managementAPIClient, stackAPIKey, org) {
let organization, stackDetails;

if (!isAuthenticated()) {
this.error(config.CLI_EXPORT_CSV_ENTRIES_ERROR, {
exit: 2,
suggestions: ['https://www.contentstack.com/docs/developers/cli/authentication/'],
});
}

if (org) {
organization = { uid: org };
} else {
organization = await util.chooseOrganization(managementAPIClient); // prompt for organization
}
if (!stackAPIKey) {
stackDetails = await util.chooseStack(managementAPIClient, organization.uid); // prompt for stack
} else {
stackDetails = await util.chooseStack(managementAPIClient, organization.uid, stackAPIKey);
}
return stackDetails;
}

/**
* Create a taxonomies csv file for stack and a terms csv file for associated taxonomies
* @param {string} stackName
* @param {object} stack
* @param {string} taxUID
*/
async createTaxonomyAndTermCsvFile(stackAPIClient, stackName, stack, taxUID) {
const payload = {
stackAPIClient,
type: '',
limit: config.limit || 100
};
//check whether the taxonomy is valid or not
let taxonomies = [];
if (taxUID) {
payload['taxonomyUID'] = taxUID;
const taxonomy = await util.getTaxonomy(payload);
taxonomies.push(taxonomy);
} else {
taxonomies = await util.getAllTaxonomies(payload);
}

const formattedTaxonomiesData = util.formatTaxonomiesData(taxonomies);
if (formattedTaxonomiesData?.length) {
const fileName = `${stackName ? stackName : stack.name}_taxonomies.csv`;
util.write(this, formattedTaxonomiesData, fileName, 'taxonomies');
} else {
cliux.print('info: No taxonomies found! Please provide a valid stack.', { color: 'blue' });
}

for (let index = 0; index < taxonomies?.length; index++) {
const taxonomy = taxonomies[index];
const taxonomyUID = taxonomy?.uid;
if (taxonomyUID) {
payload['taxonomyUID'] = taxonomyUID;
const terms = await util.getAllTermsOfTaxonomy(payload);
const formattedTermsData = util.formatTermsOfTaxonomyData(terms, taxonomyUID);
const taxonomyName = taxonomy?.name ?? '';
const termFileName = `${stackName ?? stack.name}_${taxonomyName}_${taxonomyUID}_terms.csv`;
if (formattedTermsData?.length) {
util.write(this, formattedTermsData, termFileName, 'terms');
} else {
cliux.print(`info: No terms found for the taxonomy UID - '${taxonomyUID}'!`, { color: 'blue' });
}
}
}
}
}

ExportToCsvCommand.description = `Export entries or organization users to csv using this command`;
ExportToCsvCommand.description = `Export entries, taxonomies, terms or organization users to csv using this command`;

ExportToCsvCommand.examples = [
'csdx cm:export-to-csv',
Expand All @@ -310,6 +418,10 @@ ExportToCsvCommand.examples = [
'',
'Exporting organization users to csv with organization name provided',
'csdx cm:export-to-csv --action <users> --org <org-uid> --org-name <org-name>',
'Exporting taxonomies and related terms to a .CSV file with the provided taxonomy UID',
'csdx cm:export-to-csv --action <taxonomies> --alias <management-token-alias> --taxonomy-uid <taxonomy-uid>',
'Exporting taxonomies and respective terms to a .CSV file',
'csdx cm:export-to-csv --action <taxonomies> --alias <management-token-alias>',
];

module.exports = ExportToCsvCommand;
Loading

0 comments on commit 5bc7977

Please sign in to comment.