@contentstack/cli-cm-branches 1.0.10 → 1.0.12

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
@@ -37,7 +37,7 @@ $ npm install -g @contentstack/cli-cm-branches
37
37
  $ csdx COMMAND
38
38
  running command...
39
39
  $ csdx (--version)
40
- @contentstack/cli-cm-branches/1.0.10 linux-x64 node-v18.17.0
40
+ @contentstack/cli-cm-branches/1.0.12 linux-x64 node-v18.17.1
41
41
  $ csdx --help [COMMAND]
42
42
  USAGE
43
43
  $ csdx COMMAND
@@ -5,7 +5,6 @@ const path_1 = tslib_1.__importDefault(require("path"));
5
5
  const forEach_1 = tslib_1.__importDefault(require("lodash/forEach"));
6
6
  const cli_utilities_1 = require("@contentstack/cli-utilities");
7
7
  const utils_1 = require("../utils");
8
- const enableEntryExp = false;
9
8
  class MergeHandler {
10
9
  constructor(options) {
11
10
  this.stackAPIKey = options.stackAPIKey;
@@ -42,6 +41,14 @@ class MergeHandler {
42
41
  else if (this.executeOption === 'export') {
43
42
  await this.exportSummary(mergePayload);
44
43
  }
44
+ else if (this.executeOption === 'merge_n_scripts') {
45
+ this.enableEntryExp = true;
46
+ await this.executeMerge(mergePayload);
47
+ }
48
+ else if (this.executeOption === 'summary_n_scripts') {
49
+ this.enableEntryExp = true;
50
+ await this.exportSummary(mergePayload);
51
+ }
45
52
  else {
46
53
  await this.exportSummary(mergePayload);
47
54
  await this.executeMerge(mergePayload);
@@ -183,6 +190,9 @@ class MergeHandler {
183
190
  };
184
191
  await (0, utils_1.writeFile)(path_1.default.join(this.exportSummaryPath, 'merge-summary.json'), summary);
185
192
  cli_utilities_1.cliux.success('Exported the summary successfully');
193
+ if (this.enableEntryExp) {
194
+ this.executeEntryExpFlow(this.stackAPIKey, mergePayload);
195
+ }
186
196
  }
187
197
  async executeMerge(mergePayload) {
188
198
  let spinner;
@@ -204,11 +214,52 @@ class MergeHandler {
204
214
  cli_utilities_1.cliux.error('Failed to merge the changes', error.message || error);
205
215
  }
206
216
  }
207
- executeEntryExpFlow(mergeJobUID, mergePayload) {
208
- let scriptFolderPath = (0, utils_1.generateMergeScripts)(this.mergeSettings.mergeContent, mergeJobUID);
217
+ async executeEntryExpFlow(mergeJobUID, mergePayload) {
218
+ const { mergeContent } = this.mergeSettings;
219
+ let mergePreference = await (0, utils_1.selectContentMergePreference)();
220
+ let selectedMergePreference;
221
+ const updateEntryMergeStrategy = (items, mergeStrategy) => {
222
+ items &&
223
+ items.forEach((item) => {
224
+ item.entry_merge_strategy = mergeStrategy;
225
+ });
226
+ };
227
+ switch (mergePreference) {
228
+ case 'existing_new':
229
+ selectedMergePreference = 'merge_existing_new';
230
+ updateEntryMergeStrategy(mergeContent.content_types.added, selectedMergePreference);
231
+ updateEntryMergeStrategy(mergeContent.content_types.modified, selectedMergePreference);
232
+ break;
233
+ case 'new':
234
+ selectedMergePreference = 'merge_new';
235
+ updateEntryMergeStrategy(mergeContent.content_types.added, selectedMergePreference);
236
+ break;
237
+ case 'existing':
238
+ selectedMergePreference = 'merge_existing';
239
+ updateEntryMergeStrategy(mergeContent.content_types.modified, selectedMergePreference);
240
+ break;
241
+ case 'ask_preference':
242
+ selectedMergePreference = 'custom';
243
+ const selectedMergeItems = await (0, utils_1.selectContentMergeCustomPreferences)(mergeContent.content_types);
244
+ mergeContent.content_types = {
245
+ added: [],
246
+ modified: [],
247
+ deleted: [],
248
+ };
249
+ selectedMergeItems.forEach((item) => {
250
+ mergeContent.content_types[item.status].push(item.value);
251
+ });
252
+ break;
253
+ default:
254
+ cli_utilities_1.cliux.error(`error: Invalid preference ${mergePreference}`);
255
+ process.exit(1);
256
+ }
257
+ let scriptFolderPath = (0, utils_1.generateMergeScripts)(mergeContent.content_types, mergeJobUID);
209
258
  if (scriptFolderPath !== undefined) {
210
259
  cli_utilities_1.cliux.success(`\nSuccess! We have generated entry migration files in the folder ${scriptFolderPath}`);
211
- cli_utilities_1.cliux.print(`\nKindly follow the steps in the guide "https://www.contentstack.com/docs/developers/cli/migrate-branch-entries" to update the migration scripts, and then run the command \n\ncsdx cm:stacks:migration --multiple --file-path ./${scriptFolderPath} --config compare-branch:${mergePayload.compare_branch} --branch ${mergePayload.base_branch} --stack-api-key ${this.stackAPIKey}`, { color: 'blue' });
260
+ cli_utilities_1.cliux.print('\nWARNING!!! Migration is not intended to be run more than once. Migrated(entries/assets) will be duplicated if run more than once', { color: 'yellow' });
261
+ const migrationCommand = `csdx cm:stacks:migration --multiple --file-path ./${scriptFolderPath} --config {compare-branch:${mergePayload.compare_branch},file-path:./${scriptFolderPath}} --branch ${mergePayload.base_branch} --stack-api-key ${this.stackAPIKey}`;
262
+ cli_utilities_1.cliux.print(`\nKindly follow the steps in the guide "https://www.contentstack.com/docs/developers/cli/migrate-branch-entries" to update the migration scripts, and then run the command:\n\n${migrationCommand}`, { color: 'blue' });
212
263
  }
213
264
  }
214
265
  async restartMergeProcess() {
@@ -35,7 +35,7 @@ class BranchMergeCommand extends cli_command_1.Command {
35
35
  exportSummaryPath: branchMergeFlags['export-summary-path'],
36
36
  mergeSummary: branchMergeFlags.mergeSummary,
37
37
  host: this.cmaHost,
38
- enableEntryExp: true,
38
+ enableEntryExp: false,
39
39
  }).start();
40
40
  }
41
41
  catch (error) {
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assetFolderCreateScript = void 0;
4
+ function assetFolderCreateScript(contentType) {
5
+ return `
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ module.exports = async ({ migration, stackSDKInstance, managementAPIClient, config, branch, apiKey }) => {
9
+ let filePath = config['file-path'] || process.cwd();
10
+ let compareBranch = config['compare-branch'];
11
+ let folderMapper = {};
12
+ let folderBucket = [];
13
+
14
+ const getAssetCount = async function (branchName, isDir = false) {
15
+ const queryParam = {
16
+ asc: 'created_at',
17
+ include_count: true,
18
+ skip: 10 ** 100,
19
+ };
20
+
21
+ if (isDir) queryParam.query = { is_dir: true };
22
+
23
+ return await managementAPIClient
24
+ .stack({ api_key: stackSDKInstance.api_key, branch_uid: branchName })
25
+ .asset()
26
+ .query(queryParam)
27
+ .count()
28
+ .then(({ assets }) => assets)
29
+ .catch((error) => {});
30
+ };
31
+
32
+ async function getFolderJSON(skip, fCount, branchName, folderData = []) {
33
+ const queryRequestObj = {
34
+ skip,
35
+ include_folders: true,
36
+ query: { is_dir: true },
37
+ };
38
+
39
+ return await managementAPIClient
40
+ .stack({ api_key: stackSDKInstance.api_key, branch_uid: branchName })
41
+ .asset()
42
+ .query(queryRequestObj)
43
+ .find()
44
+ .then(async (response) => {
45
+ skip += 100;
46
+ folderData = [...folderData, ...response.items];
47
+ if (skip >= fCount) {
48
+ return folderData;
49
+ }
50
+ return await getFolderJSON(skip, fCount, branchName, folderData);
51
+ })
52
+ .catch((error) => {});
53
+ }
54
+
55
+ function buildTree(coll) {
56
+ let tree = {};
57
+ for (let i = 0; i < coll.length; i++) {
58
+ if (coll[i].parent_uid === null || !coll[i].hasOwnProperty('parent_uid')) {
59
+ tree[coll[i].uid] = {};
60
+ }
61
+ }
62
+ findBranches(tree, Object.keys(tree), coll);
63
+ return tree;
64
+ }
65
+
66
+ function findBranches(tree, branches, coll) {
67
+ branches.forEach((branch) => {
68
+ for (const element of coll) {
69
+ if (branch === element.parent_uid) {
70
+ let childUid = element.uid;
71
+ tree[branch][childUid] = {};
72
+ return findBranches(tree[branch], [childUid], coll);
73
+ }
74
+ }
75
+ });
76
+ }
77
+
78
+ function buildFolderReqObjs(baseFolderUIDs, compareAssetsFolder, tree, parent_uid) {
79
+ for (let leaf in tree) {
80
+ //folder doesn't exists
81
+ if (baseFolderUIDs.indexOf(leaf) === -1) {
82
+ let folderObj = compareAssetsFolder.filter((folder) => folder.uid === leaf);
83
+ if (folderObj && folderObj.length) {
84
+ let requestOption = {
85
+ folderReq: {
86
+ asset: {
87
+ name: folderObj[0].name,
88
+ parent_uid: parent_uid || null,
89
+ },
90
+ },
91
+ oldUid: leaf,
92
+ };
93
+ folderBucket.push(requestOption);
94
+ }
95
+ }
96
+ if (Object.keys(tree[leaf]).length > 0) {
97
+ buildFolderReqObjs(baseFolderUIDs, compareAssetsFolder, tree[leaf], leaf, folderBucket);
98
+ }
99
+ }
100
+ }
101
+
102
+ async function createFolder(payload) {
103
+ if (folderMapper.hasOwnProperty(payload.folderReq.asset.parent_uid)) {
104
+ // replace old uid with new
105
+ payload.folderReq.asset.parent_uid = folderMapper[payload.folderReq.asset.parent_uid];
106
+ }
107
+ await managementAPIClient
108
+ .stack({ api_key: apiKey, branch_uid: branch })
109
+ .asset()
110
+ .folder()
111
+ .create(payload.folderReq)
112
+ .then((res) => {
113
+ folderMapper[payload.oldUid] = res.uid;
114
+ })
115
+ .catch((err) => console.log(err));
116
+ }
117
+
118
+ const createAssetTask = () => {
119
+ return {
120
+ title: 'Create Assets Folder',
121
+ successTitle: 'Assets folder Created Successfully',
122
+ failedTitle: 'Failed to create assets folder',
123
+ task: async () => {
124
+ try {
125
+ const baseAssetsFolderCount = await getAssetCount(branch, true);
126
+ const compareAssetsFolderCount = await getAssetCount(compareBranch, true);
127
+ const baseAssetsFolder = await getFolderJSON(0, baseAssetsFolderCount, branch);
128
+ const compareAssetsFolder = await getFolderJSON(0, compareAssetsFolderCount, compareBranch);
129
+ if (Array.isArray(compareAssetsFolder) && Array.isArray(baseAssetsFolder)) {
130
+ const baseAssetUIDs = baseAssetsFolder.map((bAsset) => bAsset.uid);
131
+ //create new asset folder in base branch and update it in mapper
132
+ const tree = buildTree(compareAssetsFolder);
133
+ buildFolderReqObjs(baseAssetUIDs, compareAssetsFolder, tree, null);
134
+ for (let i = 0; i < folderBucket.length; i++) {
135
+ await createFolder(folderBucket[i]);
136
+ }
137
+ fs.writeFileSync(path.resolve(filePath, 'folder-mapper.json'), JSON.stringify(folderMapper));
138
+ }
139
+ } catch (error) {
140
+ throw error;
141
+ }
142
+ },
143
+ };
144
+ };
145
+ if (compareBranch && branch.length !== 0 && apiKey.length !== 0) {
146
+ migration.addTask(createAssetTask());
147
+ } else {
148
+ if (apiKey.length === 0) {
149
+ console.error('Please provide api key using --stack-api-key flag');
150
+ }
151
+ if (!compareBranch) {
152
+ console.error('Please provide compare branch through --config compare-branch:<value> flag');
153
+ }
154
+ if (branch.length === 0) {
155
+ console.error('Please provide branch name through --branch flag');
156
+ }
157
+ }
158
+ }
159
+ `;
160
+ }
161
+ exports.assetFolderCreateScript = assetFolderCreateScript;
@@ -1,26 +1,49 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createMergeScripts = exports.getContentypeMergeStatus = exports.generateMergeScripts = void 0;
3
+ exports.createMergeScripts = exports.getContentTypeMergeStatus = exports.generateMergeScripts = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const fs_1 = tslib_1.__importDefault(require("fs"));
6
+ const cli_utilities_1 = require("@contentstack/cli-utilities");
6
7
  const entry_create_script_1 = require("./entry-create-script");
7
8
  const entry_update_script_1 = require("./entry-update-script");
9
+ const entry_create_update_script_1 = require("./entry-create-update-script");
10
+ const asset_folder_create_script_1 = require("./asset-folder-create-script");
8
11
  function generateMergeScripts(mergeSummary, mergeJobUID) {
9
- var _a, _b, _c;
10
12
  try {
11
13
  let scriptFolderPath;
12
- if (mergeSummary.content_types.modified && ((_a = mergeSummary.content_types.modified) === null || _a === void 0 ? void 0 : _a.length) !== 0) {
13
- mergeSummary.content_types.modified.map((contentType) => {
14
- let data = (0, entry_update_script_1.entryUpdateScript)(contentType.uid);
15
- scriptFolderPath = createMergeScripts(contentType, data, mergeJobUID);
16
- });
17
- }
18
- if (mergeSummary.content_types.added && ((_b = mergeSummary.content_types.added) === null || _b === void 0 ? void 0 : _b.length) !== 0) {
19
- (_c = mergeSummary.content_types.added) === null || _c === void 0 ? void 0 : _c.map((contentType) => {
20
- let data = (0, entry_create_script_1.entryCreateScript)(contentType.uid);
21
- scriptFolderPath = createMergeScripts(contentType, data, mergeJobUID);
22
- });
23
- }
14
+ const processContentType = (contentType, scriptFunction) => {
15
+ let data;
16
+ if (contentType.uid) {
17
+ data = scriptFunction(contentType.uid);
18
+ }
19
+ else {
20
+ data = scriptFunction();
21
+ }
22
+ scriptFolderPath = createMergeScripts(contentType, mergeJobUID, data);
23
+ };
24
+ const mergeStrategies = {
25
+ asset_create_folder: asset_folder_create_script_1.assetFolderCreateScript,
26
+ merge_existing_new: entry_create_update_script_1.entryCreateUpdateScript,
27
+ merge_existing: entry_update_script_1.entryUpdateScript,
28
+ merge_new: entry_create_script_1.entryCreateScript,
29
+ ignore: entry_create_update_script_1.entryCreateUpdateScript,
30
+ };
31
+ const processContentTypes = (contentTypes, messageType) => {
32
+ if (contentTypes && contentTypes.length > 0) {
33
+ processContentType({ type: 'assets', uid: '', entry_merge_strategy: '' }, mergeStrategies['asset_create_folder']);
34
+ contentTypes.forEach((contentType) => {
35
+ const mergeStrategy = contentType.entry_merge_strategy;
36
+ if (mergeStrategies.hasOwnProperty(mergeStrategy)) {
37
+ processContentType(contentType, mergeStrategies[mergeStrategy]);
38
+ }
39
+ });
40
+ }
41
+ else {
42
+ cli_utilities_1.cliux.print(`No ${messageType} entries selected for merge`, { color: 'yellow' });
43
+ }
44
+ };
45
+ processContentTypes(mergeSummary.modified, 'Modified');
46
+ processContentTypes(mergeSummary.added, 'New');
24
47
  return scriptFolderPath;
25
48
  }
26
49
  catch (error) {
@@ -28,19 +51,22 @@ function generateMergeScripts(mergeSummary, mergeJobUID) {
28
51
  }
29
52
  }
30
53
  exports.generateMergeScripts = generateMergeScripts;
31
- function getContentypeMergeStatus(status) {
32
- if (status === 'modified') {
54
+ function getContentTypeMergeStatus(status) {
55
+ if (status === 'merge_existing') {
33
56
  return 'updated';
34
57
  }
35
- else if (status === 'compare_only') {
58
+ else if (status === 'merge_new') {
36
59
  return 'created';
37
60
  }
61
+ else if (status === 'merge_existing_new') {
62
+ return 'created_updated';
63
+ }
38
64
  else {
39
65
  return '';
40
66
  }
41
67
  }
42
- exports.getContentypeMergeStatus = getContentypeMergeStatus;
43
- function createMergeScripts(contentType, content, mergeJobUID) {
68
+ exports.getContentTypeMergeStatus = getContentTypeMergeStatus;
69
+ function createMergeScripts(contentType, mergeJobUID, content) {
44
70
  const date = new Date();
45
71
  const rootFolder = 'merge_scripts';
46
72
  const fileCreatedAt = `${date.getFullYear()}${date.getMonth().toString.length === 1 ? `0${date.getMonth() + 1}` : date.getMonth() + 1}${date.getUTCDate()}${date.getHours()}${date.getMinutes()}${date.getSeconds()}`;
@@ -56,7 +82,14 @@ function createMergeScripts(contentType, content, mergeJobUID) {
56
82
  if (!fs_1.default.existsSync(fullPath)) {
57
83
  fs_1.default.mkdirSync(fullPath);
58
84
  }
59
- fs_1.default.writeFileSync(`${fullPath}/${fileCreatedAt}_${getContentypeMergeStatus(contentType.status)}_${contentType.uid}.js`, content, 'utf-8');
85
+ let filePath;
86
+ if (contentType.type === 'assets') {
87
+ filePath = `${fullPath}/${fileCreatedAt}_create_assets_folder.js`;
88
+ }
89
+ else {
90
+ filePath = `${fullPath}/${fileCreatedAt}_${getContentTypeMergeStatus(contentType.entry_merge_strategy)}_${contentType.uid}.js`;
91
+ }
92
+ fs_1.default.writeFileSync(filePath, content, 'utf-8');
60
93
  }
61
94
  return fullPath;
62
95
  }