diff --git a/.talismanrc b/.talismanrc index 5ec469449..b8004aaf4 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,50 +1,4 @@ fileignoreconfig: - - filename: pnpm-lock.yaml - checksum: 8eb82c59ad8b81af64587af55c6788d09a34d1b651d030d1ef01dce472716f2a - - filename: packages/contentstack-branches/test/unit/helpers/stub-auth.ts - checksum: 8cafd5994d3ec13ba9af74c80b330bfd14721ea4e0359b456598964a6c2913ce - - filename: packages/contentstack-export/src/config/index.ts - checksum: 0219426b1873decef4d74bef5bfd50d1ed8f2567a2136122d869e4e53e4b4b99 - - filename: packages/contentstack-clone/README.md - checksum: fad666bf6290c980406ddd18caec2dd89d9c7a22b422010865199659956ab523 - - filename: packages/contentstack-migration/README.md - checksum: ceb7631888ee81711a32e2ac07762957bbf0f9c6c7f3f6bbc5d86326bd4352cc - - filename: packages/contentstack-external-migrate/test/commands/migrate/import.test.ts - checksum: 1d955eb34ab7e7e11cfad35cdbcb00692e39568bc690f46089fcbc0ca22a4852 - - filename: packages/contentstack-external-migrate/test/adapters/contentful/export.test.ts - checksum: 118cc140edf3b68191d1ef770c4142f9f5aa7af87a5a1832d6b3edee53d61c83 - - filename: packages/contentstack-cli-tsgen/test/unit/helper.test.ts - checksum: 146ff2a85a8f5ec463e51821f54c5f08143fa04209541a51017270e83b6ed46d - - filename: packages/contentstack-cli-cm-regex-validate/test/utils/connect-stack.test.ts - checksum: 018980aa2b919967b9ef9ab1bdf635d4867fe21593fba5890afa443f440228ff - - filename: packages/contentstack-bulk-operations/src/messages/index.ts - checksum: c8acefdd18f499a82d839e3cf99e34af9dd464f63f92282739411174ae7b7c37 - - filename: packages/contentstack-bulk-operations/src/utils/operation-flag-matrix.ts - checksum: 99a3c3eb422a17f73f4c8f15088004fa4c95df3545bdf510310c1f3a20e4c2c2 - - filename: packages/contentstack-bulk-operations/src/base-bulk-command.ts - checksum: cb1147ac666b607a093c4c827d143d0bd2de5b6e9d59973f1b7052451e82a89b - - filename: packages/contentstack-bulk-operations/src/commands/cm/stacks/bulk-assets.ts - checksum: 8bca423db4c3815c651ad922d986a53b6271cce3ea27f5987b66ee594151165e - - filename: packages/contentstack-bulk-operations/test/unit/commands/bulk-assets-init.test.ts - checksum: 590b1cfe42d46d0917ac90f363b1ccd05200b180bd9c58c770ffd1f12eb18327 - - filename: packages/contentstack-bulk-operations/test/unit/utils/operation-flag-matrix.test.ts - checksum: 35451ca4c03359b06531a8461091f4a3a45c4dea1f8853081fb53e4ce28c1cc3 - - filename: packages/contentstack-bulk-operations/test/unit/base-bulk-command.test.ts - checksum: ca699a9d73757d44ded4d9d27beb4f460f911a7c88a14551a9402a3ac0c69873 - - filename: packages/contentstack-external-migrate/src/lib/create-stack.ts - checksum: 68a9510db6f2746ac5006c091d276c1ba619a9e15c76a3edae3967e4f9c2dd4e - - filename: packages/contentstack-external-migrate/test/lib/create-stack.test.ts - checksum: 2dcbc359ee275e59e0536f3c325416eac8c43eb341b04da0d3757f5b5e556d9c - - filename: CHANGELOG.md - checksum: 88c7e1dee308fa4ae25e7815ead0842b1aac7ed669b02859cc8b25cba879595d - - filename: packages/contentstack-bulk-operations/test/unit/services/taxonomy-service.test.ts - checksum: abc5ac707341760cf59d5b8b1c4e13cf2c79955e2735c33e2db3ec6bc48eddb6 - - filename: packages/contentstack-import/src/import/modules/assets.ts - checksum: cda61a9c90bb39f27c09951b8a2623851296aefd0d3220d066032287a712d899 - - filename: packages/contentstack-asset-management/test/unit/utils/cs-assets-api-adapter.test.ts - checksum: 63c6bff4d51842d8fa3cce88545259d0a2c3cfe71df95d303d993f692cee883b - - filename: packages/contentstack-asset-management/src/utils/cs-assets-api-adapter.ts - checksum: bc4a53f96be6a10786e00133245c7bdc43c965c8a98b753e3879e1110cf9c601 - - filename: packages/contentstack-bulk-operations/test/unit/commands/bulk-assets-cs-assets.test.ts - checksum: 1b6b5b0302d3efd9508e2e5d4fe3783da97a110735ca3106ce829cfe93874150 +- filename: packages/contentstack-export/src/utils/export-config-handler.ts + checksum: ab7fd2fb63420e7a66856abace57965c1e9aa1033fc18dc8b194cf1d306f0bab version: '1.0' diff --git a/packages/contentstack-export/package.json b/packages/contentstack-export/package.json index 221252330..2e6af37f5 100644 --- a/packages/contentstack-export/package.json +++ b/packages/contentstack-export/package.json @@ -90,7 +90,10 @@ "csdxConfig": { "shortCommandName": { "cm:stacks:export": "EXPRT" - } + }, + "planProtectedFeatures": [ + "amAssets" + ] }, "repository": { "type": "git", diff --git a/packages/contentstack-export/src/commands/cm/stacks/export.ts b/packages/contentstack-export/src/commands/cm/stacks/export.ts index 8a2fc359a..5a769cfad 100644 --- a/packages/contentstack-export/src/commands/cm/stacks/export.ts +++ b/packages/contentstack-export/src/commands/cm/stacks/export.ts @@ -111,7 +111,7 @@ export default class ExportCommand extends Command { let exportDir: string = pathValidator('logs'); try { const { flags } = await this.parse(ExportCommand); - const exportConfig = await setupExportConfig(flags); + const exportConfig = await setupExportConfig(flags, this.context); // Prepare the context object const context = this.createExportContext(exportConfig.apiKey, exportConfig.authenticationMethod); exportConfig.context = { ...context }; diff --git a/packages/contentstack-export/src/export/modules/assets.ts b/packages/contentstack-export/src/export/modules/assets.ts index 5dfb193c8..cca23f75a 100644 --- a/packages/contentstack-export/src/export/modules/assets.ts +++ b/packages/contentstack-export/src/export/modules/assets.ts @@ -20,11 +20,12 @@ import { handleAndLogError, messageHandler, CLIProgressManager, + FEATURE, } from '@contentstack/cli-utilities'; import { PATH_CONSTANTS } from '../../constants'; import config from '../../config'; -import { ModuleClassParams } from '../../types'; +import { ModuleClassParams, GlobalSummary } from '../../types'; import BaseClass, { CustomPromiseHandler, CustomPromiseHandlerInput } from './base-class'; import { ExportSpaces, type AssetExportCounts } from '@contentstack/cli-asset-management'; import { @@ -57,24 +58,10 @@ export default class ExportAssets extends BaseClass { }; } - /** - * Bug 3 — push real CS Assets entity counts into the final EXPORT summary: override the ASSETS - * module to count downloaded binaries only, and add dedicated ASSET TYPES / FIELDS / FOLDERS rows. - * Drives the global summary directly (no cli-utilities change); the live multibar is unaffected. - * The ASSETS strategy is set to Default so applyStrategyCorrections does not overwrite these. - */ - private applyAssetSummaryCounts(counts: AssetExportCounts): void { - type SummaryModule = { successCount: number; failureCount: number }; - type GlobalSummary = { - getModules(): Map; - registerModule(name: string, totalItems?: number): void; - startModule(name: string): void; - completeModule(name: string, success?: boolean): void; - }; - // globalSummary is runtime-accessible but typed private; reach it via a structural cast. + // globalSummary is runtime-accessible but typed private; feature-detect the shape and return null + // so callers degrade instead of throwing if a future cli-utilities version changes it. + private getGlobalSummary(): GlobalSummary | null { const gs = (CLIProgressManager as unknown as { globalSummary?: GlobalSummary | null }).globalSummary; - // We reach into cli-utilities' summary internals, so feature-detect the shape and DEGRADE - // (skip the count overrides) instead of throwing if a future version changes it. if ( !gs || typeof gs.getModules !== 'function' || @@ -82,6 +69,20 @@ export default class ExportAssets extends BaseClass { typeof gs.startModule !== 'function' || typeof gs.completeModule !== 'function' ) { + return null; + } + return gs; + } + + /** + * Bug 3 — push real CS Assets entity counts into the final EXPORT summary: override the ASSETS + * module to count downloaded binaries only, and add dedicated ASSET TYPES / FIELDS / FOLDERS rows. + * Drives the global summary directly (no cli-utilities change); the live multibar is unaffected. + * The ASSETS strategy is set to Default so applyStrategyCorrections does not overwrite these. + */ + private applyAssetSummaryCounts(counts: AssetExportCounts): void { + const gs = this.getGlobalSummary(); + if (!gs) { log.debug('Global summary shape unavailable; skipping CS Assets summary count overrides', this.exportConfig.context); return; } @@ -116,7 +117,44 @@ export default class ExportAssets extends BaseClass { } } + // Records the skip in the final summary via the failure channel, which is the only per-module + // slot carrying a message. createNestedProgress is intentionally not used: it would render an + // empty "ASSETS:" live section. + private markAssetsSkippedInSummary(reason: string): void { + const gs = this.getGlobalSummary(); + if (!gs) { + log.debug('Global summary shape unavailable; skipping ASSETS skip row', this.exportConfig.context); + return; + } + + try { + const name = this.currentModuleName.toUpperCase(); + gs.registerModule(name); + gs.startModule(name); + const module = gs.getModules().get(name); + if (module) { + module.failures.push({ item: reason, error: reason }); + module.status = 'failed'; + module.endTime = Date.now(); + } + } catch (e) { + log.debug(`Failed to mark ASSETS as skipped in summary: ${e}`, this.exportConfig.context); + } + } + async start(): Promise { + const csAssetsInPlan = this.exportConfig.planStatus?.[FEATURE.ASSET_MANAGEMENT]?.is_part_of_plan; + if (csAssetsInPlan && this.exportConfig.management_token) { + const warning = + 'Skipping Contentstack Assets export: management token authentication is not supported by the Assets APIs. ' + + 'Entry-to-asset references will NOT resolve in the exported content. ' + + 'Re-run the export with a logged-in session (auth token or OAuth) to export Contentstack Assets.'; + cliux.print(`\nWARNING!!! ${warning}`, { color: 'yellow' }); + log.error(warning, this.exportConfig.context); + this.markAssetsSkippedInSummary(warning); + return; + } + const linkedWorkspaces = this.exportConfig.linkedWorkspaces ?? []; if (linkedWorkspaces.length > 0) { diff --git a/packages/contentstack-export/src/types/export-config.ts b/packages/contentstack-export/src/types/export-config.ts index 893e2dc8e..33cf163c0 100644 --- a/packages/contentstack-export/src/types/export-config.ts +++ b/packages/contentstack-export/src/types/export-config.ts @@ -1,3 +1,4 @@ +import { FeatureStatus } from '@contentstack/cli-utilities'; import { Context, Modules, Region } from '.'; import DefaultConfig from './default-config'; @@ -36,6 +37,7 @@ export default interface ExportConfig extends DefaultConfig { skipDependencies?: boolean; authenticationMethod?: string; linkedWorkspaces?: Array<{ uid: string; space_uid: string; is_default: boolean }>; + planStatus?: Record; } type branch = { diff --git a/packages/contentstack-export/src/types/index.ts b/packages/contentstack-export/src/types/index.ts index 605129e48..9694b46fd 100644 --- a/packages/contentstack-export/src/types/index.ts +++ b/packages/contentstack-export/src/types/index.ts @@ -180,6 +180,21 @@ export interface Context { authenticationMethod?: string; } +export interface SummaryModule { + status: string; + successCount: number; + failureCount: number; + failures: Array<{ item: string; error: string }>; + endTime?: number; +} + +export interface GlobalSummary { + getModules(): Map; + registerModule(name: string, totalItems?: number): void; + startModule(name: string): void; + completeModule(name: string, success?: boolean): void; +} + export { default as DefaultConfig } from './default-config'; export { default as ExportConfig } from './export-config'; export * from './marketplace-app'; diff --git a/packages/contentstack-export/src/utils/export-config-handler.ts b/packages/contentstack-export/src/utils/export-config-handler.ts index 36c803e31..04321613d 100644 --- a/packages/contentstack-export/src/utils/export-config-handler.ts +++ b/packages/contentstack-export/src/utils/export-config-handler.ts @@ -1,6 +1,14 @@ import merge from 'merge'; import * as path from 'path'; -import { configHandler, isAuthenticated, cliux, sanitizePath, log } from '@contentstack/cli-utilities'; +import { + configHandler, + isAuthenticated, + cliux, + sanitizePath, + log, + isFeatureEnabled, + FeatureCtx, +} from '@contentstack/cli-utilities'; import defaultConfig from '../config'; import { readFile, isDirectoryNonEmpty } from './file-helper'; import { askExportDir, askAPIKey } from './interactive'; @@ -8,7 +16,7 @@ import login from './basic-login'; import { filter, includes } from 'lodash'; import { ExportConfig } from '../types'; -const setupConfig = async (exportCmdFlags: any): Promise => { +const setupConfig = async (exportCmdFlags: any, context: any): Promise => { // Set progress supported module FIRST, before any log calls // This ensures the logger respects the showConsoleLogs setting correctly configHandler.set('log.progressSupportedModule', 'export'); @@ -152,6 +160,32 @@ const setupConfig = async (exportCmdFlags: any): Promise => { config.authenticationMethod = authenticationMethod; log.debug('Export configuration setup completed.', { ...config }); + // Deferred plan check — credentials now available after setupExportConfig + const deferredFeatures: string[] = context?.planCheckRequired ?? []; + if (deferredFeatures.length > 0) { + const planCtx: FeatureCtx = { + apiKey: config.apiKey, + managementToken: config.management_token, + authToken: config.auth_token, + }; + for (const featureUid of deferredFeatures) { + try { + const status = await isFeatureEnabled(featureUid, planCtx); + if (context) { + context.planStatus[featureUid] = status; + } + + log.debug(`[export] Deferred plan status fetched for "${featureUid}".`); + } catch (error) { + log.warn(`[export] Could not fetch deferred plan status for "${featureUid}": ${(error as Error).message}`); + } + } + } + + if (context?.planStatus) { + config.planStatus = context.planStatus; + } + return config; };