@contentstack/cli-cm-export-query 1.0.0-beta.2 → 1.0.0-beta.4

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.
@@ -65,6 +65,11 @@ ExportQueryCommand.flags = {
65
65
  }),
66
66
  branch: cli_utilities_1.flags.string({
67
67
  description: 'Branch name to export from',
68
+ exclusive: ['branch-alias'],
69
+ }),
70
+ 'branch-alias': cli_utilities_1.flags.string({
71
+ description: 'Alias of Branch to export from',
72
+ exclusive: ['branch'],
68
73
  }),
69
74
  query: cli_utilities_1.flags.string({
70
75
  required: true,
@@ -225,19 +225,97 @@ class QueryExporter {
225
225
  async exportReferencedAssets() {
226
226
  (0, logger_1.log)(this.exportQueryConfig, 'Starting export of referenced assets...', 'info');
227
227
  try {
228
+ const assetsDir = path.join((0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.exportDir), (0, cli_utilities_1.sanitizePath)(this.exportQueryConfig.branchName || ''), 'assets');
229
+ const metadataFilePath = path.join(assetsDir, 'metadata.json');
230
+ const assetFilePath = path.join(assetsDir, 'assets.json');
231
+ // Define temp file paths
232
+ const tempMetadataFilePath = path.join(assetsDir, 'metadata_temp.json');
233
+ const tempAssetFilePath = path.join(assetsDir, 'assets_temp.json');
228
234
  const assetHandler = new utils_4.AssetReferenceHandler(this.exportQueryConfig);
229
235
  // Extract referenced asset UIDs from all entries
230
236
  const assetUIDs = assetHandler.extractReferencedAssets();
231
237
  if (assetUIDs.length > 0) {
232
- (0, logger_1.log)(this.exportQueryConfig, `Exporting ${assetUIDs.length} referenced assets...`, 'info');
233
- const query = {
234
- modules: {
235
- assets: {
236
- uid: { $in: assetUIDs },
238
+ (0, logger_1.log)(this.exportQueryConfig, `Found ${assetUIDs.length} referenced assets to export`, 'info');
239
+ // Define batch size - can be configurable through exportQueryConfig
240
+ const batchSize = this.exportQueryConfig.assetBatchSize || 100;
241
+ if (assetUIDs.length <= batchSize) {
242
+ const query = {
243
+ modules: {
244
+ assets: {
245
+ uid: { $in: assetUIDs },
246
+ },
237
247
  },
238
- },
239
- };
240
- await this.moduleExporter.exportModule('assets', { query });
248
+ };
249
+ await this.moduleExporter.exportModule('assets', { query });
250
+ }
251
+ // if asset size is bigger than batch size, then we need to export in batches
252
+ // Calculate number of batches
253
+ const totalBatches = Math.ceil(assetUIDs.length / batchSize);
254
+ (0, logger_1.log)(this.exportQueryConfig, `Processing assets in ${totalBatches} batches of ${batchSize}`, 'info');
255
+ // Process assets in batches
256
+ for (let i = 0; i < totalBatches; i++) {
257
+ const start = i * batchSize;
258
+ const end = Math.min(start + batchSize, assetUIDs.length);
259
+ const batchAssetUIDs = assetUIDs.slice(start, end);
260
+ (0, logger_1.log)(this.exportQueryConfig, `Exporting batch ${i + 1}/${totalBatches} (${batchAssetUIDs.length} assets)...`, 'info');
261
+ const query = {
262
+ modules: {
263
+ assets: {
264
+ uid: { $in: batchAssetUIDs },
265
+ },
266
+ },
267
+ };
268
+ await this.moduleExporter.exportModule('assets', { query });
269
+ // Read the current batch's metadata.json and assets.json files
270
+ const currentMetadata = utils_2.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(metadataFilePath));
271
+ const currentAssets = utils_2.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(assetFilePath));
272
+ // Check if this is the first batch
273
+ if (i === 0) {
274
+ // For first batch, initialize temp files with current content
275
+ utils_2.fsUtil.writeFile((0, cli_utilities_1.sanitizePath)(tempMetadataFilePath), currentMetadata);
276
+ utils_2.fsUtil.writeFile((0, cli_utilities_1.sanitizePath)(tempAssetFilePath), currentAssets);
277
+ (0, logger_1.log)(this.exportQueryConfig, `Initialized temporary files with first batch data`, 'info');
278
+ }
279
+ else {
280
+ // For subsequent batches, append to temp files with incremented keys
281
+ // Handle metadata (which contains arrays of asset info)
282
+ const tempMetadata = utils_2.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(tempMetadataFilePath)) || {};
283
+ // Merge metadata by combining arrays
284
+ if (currentMetadata) {
285
+ Object.keys(currentMetadata).forEach((key) => {
286
+ if (!tempMetadata[key]) {
287
+ tempMetadata[key] = currentMetadata[key];
288
+ }
289
+ });
290
+ }
291
+ // Write updated metadata back to temp file
292
+ utils_2.fsUtil.writeFile((0, cli_utilities_1.sanitizePath)(tempMetadataFilePath), tempMetadata);
293
+ // Handle assets (which is an object with numeric keys)
294
+ const tempAssets = utils_2.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(tempAssetFilePath)) || {};
295
+ let nextIndex = Object.keys(tempAssets).length + 1;
296
+ // Add current assets with incremented keys
297
+ Object.values(currentAssets).forEach((value) => {
298
+ tempAssets[nextIndex.toString()] = value;
299
+ nextIndex++;
300
+ });
301
+ utils_2.fsUtil.writeFile((0, cli_utilities_1.sanitizePath)(tempAssetFilePath), tempAssets);
302
+ (0, logger_1.log)(this.exportQueryConfig, `Updated temporary files with batch ${i + 1} data`, 'info');
303
+ }
304
+ // Optional: Add delay between batches to avoid rate limiting
305
+ if (i < totalBatches - 1 && this.exportQueryConfig.batchDelayMs) {
306
+ await new Promise((resolve) => setTimeout(resolve, this.exportQueryConfig.batchDelayMs));
307
+ }
308
+ }
309
+ // After all batches are processed, copy temp files back to original files
310
+ const finalMetadata = utils_2.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(tempMetadataFilePath));
311
+ const finalAssets = utils_2.fsUtil.readFile((0, cli_utilities_1.sanitizePath)(tempAssetFilePath));
312
+ utils_2.fsUtil.writeFile((0, cli_utilities_1.sanitizePath)(metadataFilePath), finalMetadata);
313
+ utils_2.fsUtil.writeFile((0, cli_utilities_1.sanitizePath)(assetFilePath), finalAssets);
314
+ (0, logger_1.log)(this.exportQueryConfig, `Final data written back to original files`, 'info');
315
+ // Clean up temp files
316
+ utils_2.fsUtil.removeFile((0, cli_utilities_1.sanitizePath)(tempMetadataFilePath));
317
+ utils_2.fsUtil.removeFile((0, cli_utilities_1.sanitizePath)(tempAssetFilePath));
318
+ (0, logger_1.log)(this.exportQueryConfig, `Temporary files cleaned up`, 'info');
241
319
  (0, logger_1.log)(this.exportQueryConfig, 'Referenced assets exported successfully', 'success');
242
320
  }
243
321
  else {
@@ -136,10 +136,14 @@ export interface QueryExportConfig extends DefaultConfig {
136
136
  stackApiKey: string;
137
137
  managementToken?: string;
138
138
  branchName: string;
139
+ branchAlias?: string;
139
140
  securedAssets: boolean;
140
141
  logsPath: string;
141
142
  dataPath: string;
142
143
  exportDelayMs?: number;
144
+ batchDelayMs?: number;
145
+ assetBatchSize?: number;
146
+ assetBatchDelayMs?: number;
143
147
  }
144
148
  export interface QueryMetadata {
145
149
  query: any;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.setupBranches = void 0;
4
+ const cli_utilities_1 = require("@contentstack/cli-utilities");
4
5
  const logger_1 = require("./logger");
5
6
  /**
6
7
  * Validates and sets up branch configuration for the stack
@@ -14,6 +15,10 @@ const setupBranches = async (config, stackAPIClient) => {
14
15
  throw new Error('Invalid config to setup the branch');
15
16
  }
16
17
  try {
18
+ if (config.branchAlias) {
19
+ config.branchName = await (0, cli_utilities_1.getBranchFromAlias)(stackAPIClient, config.branchAlias);
20
+ return;
21
+ }
17
22
  if (config.branchName) {
18
23
  // Check if the specified branch exists
19
24
  (0, logger_1.log)(config, `Validating branch: ${config.branchName}`, 'info');
@@ -12,6 +12,13 @@ async function setupQueryExportConfig(flags) {
12
12
  const exportQueryConfig = Object.assign(Object.assign({}, config_1.default), { exportDir, stackApiKey: flags['stack-api-key'] || '', managementToken: flags.alias ? (_a = cli_utilities_1.configHandler.get(`tokens.${flags.alias}`)) === null || _a === void 0 ? void 0 : _a.token : undefined, query: flags.query, skipReferences: flags['skip-references'] || false, skipDependencies: flags['skip-dependencies'] || false, branchName: flags.branch, securedAssets: flags['secured-assets'] || false, isQueryBasedExport: true, logsPath: exportDir, dataPath: exportDir,
13
13
  // Todo: accept the path of the config file from the user
14
14
  externalConfigPath: path.join(__dirname, '../config/export-config.json') });
15
+ if (flags['branch-alias']) {
16
+ exportQueryConfig.branchAlias = flags['branch-alias'];
17
+ }
18
+ // override the external config path if the user provides a config file
19
+ if (flags.config) {
20
+ exportQueryConfig.externalConfigPath = (0, cli_utilities_1.sanitizePath)(flags['config']);
21
+ }
15
22
  // Handle authentication
16
23
  if (flags.alias) {
17
24
  const { token, apiKey } = cli_utilities_1.configHandler.get(`tokens.${flags.alias}`) || {};
@@ -45,11 +45,24 @@
45
45
  },
46
46
  "branch": {
47
47
  "description": "Branch name to export from",
48
+ "exclusive": [
49
+ "branch-alias"
50
+ ],
48
51
  "name": "branch",
49
52
  "hasDynamicHelp": false,
50
53
  "multiple": false,
51
54
  "type": "option"
52
55
  },
56
+ "branch-alias": {
57
+ "description": "Alias of Branch to export from",
58
+ "exclusive": [
59
+ "branch"
60
+ ],
61
+ "name": "branch-alias",
62
+ "hasDynamicHelp": false,
63
+ "multiple": false,
64
+ "type": "option"
65
+ },
53
66
  "query": {
54
67
  "description": "Query as JSON string or file path",
55
68
  "name": "query",
@@ -102,5 +115,5 @@
102
115
  ]
103
116
  }
104
117
  },
105
- "version": "1.0.0-beta.2"
118
+ "version": "1.0.0-beta.4"
106
119
  }
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@contentstack/cli-cm-export-query",
3
3
  "description": "Contentstack CLI plugin to export content from stack",
4
- "version": "1.0.0-beta.2",
4
+ "version": "1.0.0-beta.4",
5
5
  "author": "Contentstack",
6
6
  "bugs": "https://github.com/contentstack/cli/issues",
7
7
  "dependencies": {
8
- "@contentstack/cli-cm-export": "~1.18.0",
9
- "@contentstack/cli-command": "~1.6.0",
10
- "@contentstack/cli-utilities": "~1.13.0",
8
+ "@contentstack/cli-cm-export": "~1.20.2",
9
+ "@contentstack/cli-command": "~1.6.1",
10
+ "@contentstack/cli-utilities": "~1.14.1",
11
11
  "@oclif/core": "^4.3.0",
12
12
  "async": "^3.2.6",
13
13
  "big-json": "^3.2.0",
@@ -21,21 +21,21 @@
21
21
  "winston": "^3.17.0"
22
22
  },
23
23
  "devDependencies": {
24
- "@contentstack/cli-dev-dependencies": "~1.3.0",
25
- "@oclif/plugin-help": "^6.2.28",
26
- "@oclif/test": "^4.1.13",
24
+ "@contentstack/cli-dev-dependencies": "~1.3.1",
25
+ "@oclif/plugin-help": "^6.2.33",
26
+ "@oclif/test": "^4.1.14",
27
27
  "@types/big-json": "^3.2.5",
28
28
  "@types/chai": "^4.3.20",
29
29
  "@types/mkdirp": "^1.0.2",
30
30
  "@types/mocha": "^10.0.10",
31
- "@types/node": "^20.19.8",
31
+ "@types/node": "^20.19.17",
32
32
  "@types/progress-stream": "^2.0.5",
33
33
  "@types/sinon": "^17.0.4",
34
34
  "chai": "^4.5.0",
35
- "dotenv": "^16.5.0",
35
+ "dotenv": "^16.6.1",
36
36
  "dotenv-expand": "^9.0.0",
37
37
  "eslint": "^8.57.1",
38
- "eslint-config-oclif": "^6.0.62",
38
+ "eslint-config-oclif": "^6.0.104",
39
39
  "husky": "^9.1.7",
40
40
  "mocha": "10.8.2",
41
41
  "nyc": "^15.1.0",