Skip to content

Commit a42caae

Browse files
authored
Merge pull request #2133 from contentstack/fix/DX-3561-count-issue
fix: Progress Manager shows duplicate module counts and inaccurate personalize stats in --show-console output
2 parents 78314ad + 9af0152 commit a42caae

File tree

4 files changed

+91
-27
lines changed

4 files changed

+91
-27
lines changed

packages/contentstack-export/src/export/modules/personalize.ts

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,48 @@ export default class ExportPersonalize extends BaseClass {
4242
try {
4343
log.debug('Starting personalize export process...', this.exportConfig.context);
4444

45-
const [canProceed, moduleCount] = await this.withLoadingSpinner(
46-
'PERSONALIZE: Analyzing personalization configuration...',
45+
const [canProceed, projectCount, moduleCount] = await this.withLoadingSpinner(
46+
'PERSONALIZE: Analyzing personalization configuration and connectivity...',
4747
async () => {
48-
const canProceed = this.validatePersonalizeSetup();
49-
const moduleCount = canProceed ? this.getPersonalizeModuleCount() : 0;
48+
// Step 1: Basic validation (URL, tokens)
49+
const basicValidation = this.validatePersonalizeSetup();
50+
if (!basicValidation) {
51+
return [false, 0, 0];
52+
}
53+
54+
// Step 2: Check actual project connectivity
55+
const projectCount = await this.validateProjectConnectivity();
56+
if (projectCount === 0) {
57+
log.info('No Personalize Project connected with the given stack', this.exportConfig.context);
58+
this.exportConfig.personalizationEnabled = false;
59+
return [false, 0, 0];
60+
}
61+
62+
// Step 3: Get module count only if projects exist
63+
const moduleCount = this.getPersonalizeModuleCount();
5064

5165
log.debug(
52-
`Personalize validation - canProceed: ${canProceed}, moduleCount: ${moduleCount}`,
66+
`Personalize validation - canProceed: true, projectCount: ${projectCount}, moduleCount: ${moduleCount}`,
5367
this.exportConfig.context,
5468
);
5569

56-
return [canProceed, moduleCount];
70+
// Enable personalization since we have connected projects
71+
this.exportConfig.personalizationEnabled = true;
72+
return [true, projectCount, moduleCount];
5773
},
5874
);
5975

6076
if (!canProceed) {
61-
log.debug('Personalization setup validation failed, exiting', this.exportConfig.context);
6277
return;
6378
}
6479

65-
log.debug(`Creating personalize progress with moduleCount: ${moduleCount}`, this.exportConfig.context);
80+
log.debug(
81+
`Creating personalize progress with projectCount: ${projectCount}, moduleCount: ${moduleCount}`,
82+
this.exportConfig.context,
83+
);
6684
const progress = this.createNestedProgress(this.currentModuleName);
6785

68-
this.addProjectProcess(progress);
86+
this.addProjectProcess(progress, projectCount);
6987
this.addModuleProcesses(progress, moduleCount);
7088

7189
try {
@@ -118,15 +136,35 @@ export default class ExportPersonalize extends BaseClass {
118136
return true;
119137
}
120138

139+
private async validateProjectConnectivity(): Promise<number> {
140+
try {
141+
// Create a temporary ExportProjects instance to check connectivity
142+
const tempProjectsExporter = new ExportProjects(this.exportConfig);
143+
144+
// Initialize and fetch projects
145+
await tempProjectsExporter.init();
146+
// talisman-ignore-line
147+
const projectsData = await tempProjectsExporter.projects({ connectedStackApiKey: this.exportConfig.apiKey });
148+
149+
const projectCount = projectsData?.length || 0;
150+
log.debug(`Found ${projectCount} connected projects`, this.exportConfig.context);
151+
152+
return projectCount;
153+
} catch (error) {
154+
log.debug(`Error checking project connectivity: ${error}`, this.exportConfig.context);
155+
return 0;
156+
}
157+
}
158+
121159
private getPersonalizeModuleCount(): number {
122160
const order = this.exportConfig.modules?.personalize?.exportOrder;
123161
return Array.isArray(order) ? order.length : 0;
124162
}
125163

126-
private addProjectProcess(progress: CLIProgressManager) {
127-
progress.addProcess(PROCESS_NAMES.PERSONALIZE_PROJECTS, 1);
164+
private addProjectProcess(progress: CLIProgressManager, projectCount: number) {
165+
progress.addProcess(PROCESS_NAMES.PERSONALIZE_PROJECTS, projectCount);
128166
log.debug(
129-
`Added ${PROCESS_NAMES.PERSONALIZE_PROJECTS} process to personalize progress`,
167+
`Added ${PROCESS_NAMES.PERSONALIZE_PROJECTS} process with count: ${projectCount}`,
130168
this.exportConfig.context,
131169
);
132170
}
@@ -153,10 +191,7 @@ export default class ExportPersonalize extends BaseClass {
153191
private async exportProjects(progress: CLIProgressManager) {
154192
progress
155193
.startProcess(PROCESS_NAMES.PERSONALIZE_PROJECTS)
156-
.updateStatus(
157-
PROCESS_STATUS[PROCESS_NAMES.PERSONALIZE_PROJECTS].EXPORTING,
158-
PROCESS_NAMES.PERSONALIZE_PROJECTS,
159-
);
194+
.updateStatus(PROCESS_STATUS[PROCESS_NAMES.PERSONALIZE_PROJECTS].EXPORTING, PROCESS_NAMES.PERSONALIZE_PROJECTS);
160195
log.debug('Starting projects export for personalization...', this.exportConfig.context);
161196

162197
const projectsExporter = new ExportProjects(this.exportConfig);
@@ -188,10 +223,7 @@ export default class ExportPersonalize extends BaseClass {
188223
if (ModuleClass) {
189224
progress
190225
.startProcess(processName)
191-
.updateStatus(
192-
(PROCESS_STATUS as any)[processName]?.EXPORTING || `Exporting ${module}...`,
193-
processName,
194-
);
226+
.updateStatus((PROCESS_STATUS as any)[processName]?.EXPORTING || `Exporting ${module}...`, processName);
195227
log.debug(`Starting export for module: ${module}`, this.exportConfig.context);
196228

197229
if (this.exportConfig.personalizationEnabled) {

packages/contentstack-export/src/utils/progress-strategy-registry.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,33 @@ import {
1414

1515
ProgressStrategyRegistry.register(MODULE_NAMES[MODULE_CONTEXTS.CONTENT_TYPES], new DefaultProgressStrategy());
1616

17-
// Register strategy for Assets - use Asset Metadata as primary process
17+
// Register strategy for Assets - custom strategy to avoid double counting
1818
ProgressStrategyRegistry.register(
1919
MODULE_NAMES[MODULE_CONTEXTS.ASSETS],
20-
new PrimaryProcessStrategy(PROCESS_NAMES.ASSET_METADATA),
20+
new CustomProgressStrategy((processes) => {
21+
// Both ASSET_METADATA and ASSET_DOWNLOADS represent the same assets
22+
// Count only the downloads process to avoid double counting in summary
23+
const downloadsProcess = processes.get(PROCESS_NAMES.ASSET_DOWNLOADS);
24+
if (downloadsProcess) {
25+
return {
26+
total: downloadsProcess.total,
27+
success: downloadsProcess.successCount,
28+
failures: downloadsProcess.failureCount,
29+
};
30+
}
31+
32+
// Fallback to metadata process if downloads don't exist
33+
const metadataProcess = processes.get(PROCESS_NAMES.ASSET_METADATA);
34+
if (metadataProcess) {
35+
return {
36+
total: metadataProcess.total,
37+
success: metadataProcess.successCount,
38+
failures: metadataProcess.failureCount,
39+
};
40+
}
41+
42+
return null; // Fall back to default aggregation
43+
}),
2144
);
2245

2346
ProgressStrategyRegistry.register(MODULE_NAMES[MODULE_CONTEXTS.GLOBAL_FIELDS], new DefaultProgressStrategy());

packages/contentstack-import/src/utils/progress-strategy-registry.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,18 @@ ProgressStrategyRegistry.register(
2121
// Register strategy for Assets - use Asset Upload as primary process
2222
ProgressStrategyRegistry.register(
2323
MODULE_NAMES[MODULE_CONTEXTS.ASSETS],
24-
new PrimaryProcessStrategy(PROCESS_NAMES.ASSET_UPLOAD),
24+
new CustomProgressStrategy((processes) => {
25+
const uploadsProcess = processes.get(PROCESS_NAMES.ASSET_UPLOAD);
26+
if (uploadsProcess) {
27+
return {
28+
total: uploadsProcess.total,
29+
success: uploadsProcess.successCount,
30+
failures: uploadsProcess.failureCount,
31+
};
32+
}
33+
34+
return null; // Fall back to default aggregation
35+
}),
2536
);
2637

2738
// Register strategy for Entries - use Entry Creation as primary process

packages/contentstack-variants/src/export/projects.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ export default class ExportProjects extends PersonalizationAdapter<ExportConfig>
3333
log.debug('Starting projects export process...', this.exportConfig.context);
3434
log.info('Starting projects export', this.exportConfig.context);
3535

36-
// Set project personalization config before starting
37-
this.exportConfig.personalizationEnabled = false;
38-
3936
// Initial setup with loading spinner
4037
await this.withLoadingSpinner('PROJECTS: Initializing export and fetching data...', async () => {
4138
log.debug('Initializing personalization adapter...', this.exportConfig.context);
@@ -69,7 +66,8 @@ export default class ExportProjects extends PersonalizationAdapter<ExportConfig>
6966
if (this.parentProgressManager) {
7067
progress = this.parentProgressManager;
7168
this.progressManager = this.parentProgressManager;
72-
progress.updateProcessTotal(PROCESS_NAMES.PROJECTS, this.projectsData?.length);
69+
// Parent already has correct count, just update status
70+
progress.updateStatus(EXPORT_PROCESS_STATUS[PROCESS_NAMES.PROJECTS].EXPORTING, PROCESS_NAMES.PROJECTS);
7371
} else {
7472
progress = this.createNestedProgress(PROCESS_NAMES.PROJECTS);
7573
progress.addProcess(PROCESS_NAMES.PROJECTS, this.projectsData?.length);

0 commit comments

Comments
 (0)