From 39c5acc4b847eb4dec24f9eec1240cda95f27ab2 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 6 Aug 2025 16:33:04 +0530 Subject: [PATCH] feat: Added export draft and export latest published --- .talismanrc | 4 +++ package-lock.json | 30 ++++++++--------- .../src/commands/cm/stacks/export.ts | 11 ++++++- .../src/export/modules/assets.ts | 4 +-- .../src/export/modules/entries.ts | 33 +++++++++++++++++-- .../src/types/default-config.ts | 3 ++ .../src/utils/export-config-handler.ts | 13 ++++++++ .../src/export/variant-entries.ts | 1 + .../src/types/export-config.ts | 1 + .../src/types/variant-api-adapter.ts | 2 +- .../src/utils/variant-api-adapter.ts | 15 ++++++++- 11 files changed, 95 insertions(+), 22 deletions(-) diff --git a/.talismanrc b/.talismanrc index e69de29bb2..6d52386cce 100644 --- a/.talismanrc +++ b/.talismanrc @@ -0,0 +1,4 @@ +fileignoreconfig: +- filename: package-lock.json + checksum: ff392396cc7545f985afdf0282d387b538371011e5cd5feed4424dfc7d368376 +version: "" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f02f9b854a..16adb440bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5670,9 +5670,9 @@ "license": "MIT" }, "node_modules/@types/inquirer": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.8.tgz", - "integrity": "sha512-CgPD5kFGWsb8HJ5K7rfWlifao87m4ph8uioU7OTncJevmE/VLIqAAjfQtko578JZg7/f69K4FgqYym3gNr7DeA==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.9.tgz", + "integrity": "sha512-/mWx5136gts2Z2e5izdoRCo46lPp5TMs9R15GTSsgg/XnZyxDWVqoVU3R9lWnccKpqwsJLvRoxbCjoJtZB7DSw==", "dev": true, "license": "MIT", "dependencies": { @@ -9372,9 +9372,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.195", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.195.tgz", - "integrity": "sha512-URclP0iIaDUzqcAyV1v2PgduJ9N0IdXmWsnPzPfelvBmjmZzEy6xJcjb1cXj+TbYqXgtLrjHEoaSIdTYhw4ezg==", + "version": "1.5.197", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.197.tgz", + "integrity": "sha512-m1xWB3g7vJ6asIFz+2pBUbq3uGmfmln1M9SSvBe4QIFWYrRHylP73zL/3nMjDmwz8V+1xAXQDfBd6+HPW0WvDQ==", "dev": true, "license": "ISC" }, @@ -12401,9 +12401,9 @@ "license": "MIT" }, "node_modules/fs-extra": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -20605,9 +20605,9 @@ } }, "node_modules/oclif": { - "version": "4.22.5", - "resolved": "https://registry.npmjs.org/oclif/-/oclif-4.22.5.tgz", - "integrity": "sha512-1TViD9V+y3zLnnBzV3cNsKzXxMY7doEcxwny7eqiW4OHDU3PNTPWngG/aidzlKLDXGbajTdjtUpX69UXF78Ahw==", + "version": "4.22.6", + "resolved": "https://registry.npmjs.org/oclif/-/oclif-4.22.6.tgz", + "integrity": "sha512-TsFZfPdhOKtBRv3YKnJMUVbL/JTw5IDs4DoWekpn7c+jBDw/snp0STCe48YYW4hotULwfy2yPbKr0KyzDQ7gjw==", "dev": true, "license": "MIT", "dependencies": { @@ -24459,9 +24459,9 @@ } }, "node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz", + "integrity": "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ==", "license": "MIT", "engines": { "node": ">=14.14" diff --git a/packages/contentstack-export/src/commands/cm/stacks/export.ts b/packages/contentstack-export/src/commands/cm/stacks/export.ts index 2b1602069a..3abd54fc2d 100644 --- a/packages/contentstack-export/src/commands/cm/stacks/export.ts +++ b/packages/contentstack-export/src/commands/cm/stacks/export.ts @@ -30,10 +30,11 @@ export default class ExportCommand extends Command { 'csdx cm:stacks:export --alias --config ', 'csdx cm:stacks:export --module ', 'csdx cm:stacks:export --branch [optional] branch name', + 'csdx cm:stacks:export --skip-publish-details', ]; static usage: string = - 'cm:stacks:export [-c ] [-k ] [-d ] [-a ] [--module ] [--content-types ] [--branch ] [--secured-assets]'; + 'cm:stacks:export [-c ] [-k ] [-d ] [-a ] [--module ] [--content-types ] [--branch ] [--secured-assets] [--skip-publish-details]'; static flags: FlagInput = { config: flags.string({ @@ -106,6 +107,14 @@ export default class ExportCommand extends Command { description: '[optional] Query object (inline JSON or file path) to filter module exports.', hidden: true, }), + 'skip-publish-details': flags.boolean({ + description: '[optional] Skip publish details when exporting entries, assets, and variants.', + default: false, + }), + 'latest-publish-details': flags.boolean({ + description: '[optional] Only include publish details for the latest version of entries.', + default: false, + }), }; static aliases: string[] = ['cm:export']; diff --git a/packages/contentstack-export/src/export/modules/assets.ts b/packages/contentstack-export/src/export/modules/assets.ts index 1a95d5f257..fa0722914b 100644 --- a/packages/contentstack-export/src/export/modules/assets.ts +++ b/packages/contentstack-export/src/export/modules/assets.ts @@ -134,7 +134,7 @@ export default class ExportAssets extends BaseClass { const queryParam = { ...this.commonQueryParam, - include_publish_details: true, + include_publish_details: this.assetConfig.includePublishDetails !== false, except: { BASE: this.assetConfig.invalidKeys }, }; this.applyQueryFilters(queryParam, 'assets'); @@ -203,7 +203,7 @@ export default class ExportAssets extends BaseClass { const queryParam = { ...this.commonQueryParam, - include_publish_details: true, + include_publish_details: this.assetConfig.includePublishDetails !== false, except: { BASE: this.assetConfig.invalidKeys }, }; diff --git a/packages/contentstack-export/src/export/modules/entries.ts b/packages/contentstack-export/src/export/modules/entries.ts index 9bdf10784d..f5fcd014bb 100644 --- a/packages/contentstack-export/src/export/modules/entries.ts +++ b/packages/contentstack-export/src/export/modules/entries.ts @@ -20,6 +20,8 @@ export default class EntriesExport extends BaseClass { chunkFileSize?: number; batchLimit?: number; exportVersions: boolean; + includePublishDetails?: boolean; + latestPublishDetails?: boolean; }; private variantEntries!: any; private entriesDirPath: string; @@ -85,7 +87,22 @@ export default class EntriesExport extends BaseClass { log.debug(`Found project with ID: ${project_id}, enabling variant entry export`, this.exportConfig.context); } - this.variantEntries = new Export.VariantEntries(Object.assign(this.exportConfig, { project_id })); + // Ensure variant entry config respects publish details flag + const variantConfig = { + ...this.exportConfig, + project_id, + modules: { + ...this.exportConfig.modules, + variantEntry: { + ...this.exportConfig.modules.variantEntry, + query: { + ...this.exportConfig.modules.variantEntry.query, + include_publish_details: this.entriesConfig.includePublishDetails !== false + } + } + } + }; + this.variantEntries = new Export.VariantEntries(variantConfig); } catch (error) { handleAndLogError(error, { ...this.exportConfig.context }); } @@ -158,7 +175,7 @@ export default class EntriesExport extends BaseClass { skip: options.skip, limit: this.entriesConfig.limit, include_count: true, - include_publish_details: true, + include_publish_details: this.entriesConfig.includePublishDetails !== false, query: { locale: options.locale, }, @@ -208,6 +225,18 @@ export default class EntriesExport extends BaseClass { log.debug('Initialized FsUtility for writing entries', this.exportConfig.context); } + // Filter publish details if latestPublishDetails is enabled + if (this.entriesConfig.latestPublishDetails && this.entriesConfig.includePublishDetails !== false) { + entriesSearchResponse.items = entriesSearchResponse.items.map(entry => { + if (entry.publish_details) { + entry.publish_details = entry.publish_details.filter( + (detail: any) => detail.version === entry._version + ); + } + return entry; + }); + } + log.debug(`Writing ${entriesSearchResponse.items.length} entries to file`, this.exportConfig.context); this.entriesFileHelper.writeIntoFile(entriesSearchResponse.items, { mapKeyVal: true }); diff --git a/packages/contentstack-export/src/types/default-config.ts b/packages/contentstack-export/src/types/default-config.ts index c70a1de2dc..d1d6db8e65 100644 --- a/packages/contentstack-export/src/types/default-config.ts +++ b/packages/contentstack-export/src/types/default-config.ts @@ -95,6 +95,7 @@ export default interface DefaultConfig { displayExecutionTime: boolean; enableDownloadStatus: boolean; includeVersionedAssets: boolean; + includePublishDetails?: boolean; dependencies?: Modules[]; }; content_types: { @@ -123,6 +124,8 @@ export default interface DefaultConfig { limit: number; dependencies?: Modules[]; exportVersions: boolean; + includePublishDetails?: boolean; + latestPublishDetails?: boolean; }; personalize: { dirName: string; diff --git a/packages/contentstack-export/src/utils/export-config-handler.ts b/packages/contentstack-export/src/utils/export-config-handler.ts index eced22ef10..a88ab6f8b4 100644 --- a/packages/contentstack-export/src/utils/export-config-handler.ts +++ b/packages/contentstack-export/src/utils/export-config-handler.ts @@ -130,6 +130,19 @@ const setupConfig = async (exportCmdFlags: any): Promise => { } } + // Handle publish details flags + if (exportCmdFlags['skip-publish-details']) { + log.debug('Skipping publish details in export'); + config.modules.entries.includePublishDetails = false; + config.modules.assets.includePublishDetails = false; + config.modules.variantEntry.query.include_publish_details = false; + } + + if (exportCmdFlags['latest-publish-details']) { + log.debug('Only including latest publish details in export'); + config.modules.entries.latestPublishDetails = true; + } + // Add authentication details to config for context tracking config.authenticationMethod = authenticationMethod; log.debug('Export configuration setup completed', { ...config }); diff --git a/packages/contentstack-variants/src/export/variant-entries.ts b/packages/contentstack-variants/src/export/variant-entries.ts index 50904b7a19..2a46ae4576 100644 --- a/packages/contentstack-variants/src/export/variant-entries.ts +++ b/packages/contentstack-variants/src/export/variant-entries.ts @@ -95,6 +95,7 @@ export default class VariantEntries extends VariantAdapter[]) => void; } & AnyProperty; diff --git a/packages/contentstack-variants/src/utils/variant-api-adapter.ts b/packages/contentstack-variants/src/utils/variant-api-adapter.ts index d668a67796..1dda322822 100644 --- a/packages/contentstack-variants/src/utils/variant-api-adapter.ts +++ b/packages/contentstack-variants/src/utils/variant-api-adapter.ts @@ -93,7 +93,7 @@ export class VariantHttpClient extends AdapterHelper implement limit = variantConfig.query.limit || 100, include_variant = variantConfig.query.include_variant || true, include_count = variantConfig.query.include_count || true, - include_publish_details = variantConfig.query.include_publish_details || true, + include_publish_details = variantConfig.query.include_publish_details !== false, } = options; log.debug(`Fetching variant entries for content type: ${content_type_uid}, entry: ${entry_uid}, locale: ${locale}`, this.exportConfig?.context ); @@ -159,6 +159,19 @@ export class VariantHttpClient extends AdapterHelper implement if (response?.entries?.length) { log.debug(`Received ${response.entries?.length} variant entries out of total ${response.count}`, this.exportConfig?.context ); + + // Filter publish details if latestPublishDetails is enabled + const variantConfig = (this.config as ExportConfig).modules.variantEntry; + if (variantConfig.query.include_publish_details && ((this.config as any).modules.entries.latestPublishDetails)) { + response.entries = response.entries.map(entry => { + if (entry.publish_details) { + entry.publish_details = entry.publish_details.filter( + (detail: any) => detail.version === entry._version + ); + } + return entry; + }); + } } if (callback) {