Skip to content

Commit 20a3e9c

Browse files
committed
refactored taxonomy publish import
1 parent 68c32c7 commit 20a3e9c

5 files changed

Lines changed: 211 additions & 173 deletions

File tree

packages/contentstack-import/src/import/modules/taxonomies.ts

Lines changed: 15 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,17 @@ import { log, handleAndLogError, CLIProgressManager } from '@contentstack/cli-ut
55
import { PATH_CONSTANTS } from '../../constants';
66

77
import BaseClass, { ApiOptions } from './base-class';
8-
import { fsUtil, fileHelper, MODULE_CONTEXTS, MODULE_NAMES, PROCESS_STATUS, PROCESS_NAMES } from '../../utils';
8+
import {
9+
fsUtil,
10+
fileHelper,
11+
MODULE_CONTEXTS,
12+
MODULE_NAMES,
13+
PROCESS_STATUS,
14+
PROCESS_NAMES,
15+
readEnvUidMapperSync,
16+
warnIfEnvMapperEmpty,
17+
serializePublishTaxonomies,
18+
} from '../../utils';
919
import { ModuleClassParams, TaxonomiesConfig } from '../../types';
1020

1121
export default class ImportTaxonomies extends BaseClass {
@@ -20,7 +30,6 @@ export default class ImportTaxonomies extends BaseClass {
2030
private termsFailsPath: string;
2131
private localesFilePath: string;
2232
private envUidMapperPath: string;
23-
private envUidMapper: Record<string, string> = {};
2433
private isLocaleBasedStructure: boolean = false;
2534
public createdTaxonomies: Record<string, unknown> = {};
2635
public failedTaxonomies: Record<string, unknown> = {};
@@ -387,30 +396,6 @@ export default class ImportTaxonomies extends BaseClass {
387396

388397
// --- Publish ---
389398

390-
/**
391-
* Reads source env UID → destination stack env UID map produced during environments import.
392-
*/
393-
private readEnvUidMapperSync(): Record<string, string> {
394-
if (!fileHelper.fileExistsSync(this.envUidMapperPath)) {
395-
log.debug(`Environment UID mapper not found at ${this.envUidMapperPath}`, this.importConfig.context);
396-
return {};
397-
}
398-
399-
try {
400-
const raw = fsUtil.readFile(this.envUidMapperPath, true) as Record<string, unknown>;
401-
const out: Record<string, string> = {};
402-
for (const [k, v] of Object.entries(raw || {})) {
403-
if (v !== undefined && v !== null && String(v).trim() !== '') {
404-
out[k] = String(v);
405-
}
406-
}
407-
return out;
408-
} catch {
409-
log.debug('Failed to read environment UID mapper', this.importConfig.context);
410-
return {};
411-
}
412-
}
413-
414399
private countPublishEligibleTaxonomies(envMapper: Record<string, string>): number {
415400
let count = 0;
416401
for (const key of Object.keys(this.taxonomies || {})) {
@@ -454,18 +439,9 @@ export default class ImportTaxonomies extends BaseClass {
454439
return jobs;
455440
}
456441

457-
private loadEnvUidMapper(): void {
458-
this.envUidMapper = this.readEnvUidMapperSync();
459-
if (isEmpty(this.envUidMapper)) {
460-
log.warn(
461-
'Environment UID mapper is empty; taxonomy publishing is skipped. Import environments first or ensure mapper/environments/uid-mapping.json exists.',
462-
this.importConfig.context,
463-
);
464-
}
465-
}
466-
467442
async processTaxonomyPublishing(): Promise<void> {
468-
this.loadEnvUidMapper();
443+
const envUidMapper = readEnvUidMapperSync(this.envUidMapperPath, this.importConfig.context);
444+
warnIfEnvMapperEmpty(envUidMapper, this.importConfig.context);
469445
const jobs = this.collectTaxonomyPublishJobs();
470446

471447
if (jobs.length === 0) {
@@ -506,7 +482,7 @@ export default class ImportTaxonomies extends BaseClass {
506482
apiContent: jobs as unknown as Record<string, any>[],
507483
processName: 'publish taxonomies',
508484
apiParams: {
509-
serializeData: this.serializePublishTaxonomies.bind(this),
485+
serializeData: (opts: ApiOptions) => serializePublishTaxonomies(opts, envUidMapper),
510486
reject: onReject,
511487
resolve: onSuccess,
512488
entity: 'publish-taxonomies',
@@ -519,43 +495,6 @@ export default class ImportTaxonomies extends BaseClass {
519495
);
520496
}
521497

522-
/**
523-
* Builds taxonomy publish payload: destination env UIDs from mapper, locales from taxonomy.locale, items: [{ uid }].
524-
*/
525-
serializePublishTaxonomies(apiOptions: ApiOptions): ApiOptions {
526-
const job = apiOptions.apiData as { taxonomy?: Record<string, any> };
527-
const taxonomy = job?.taxonomy;
528-
529-
if (!taxonomy?.publish_details?.length || !taxonomy?.locale) {
530-
apiOptions.apiData = undefined;
531-
return apiOptions;
532-
}
533-
534-
const environments: string[] = [];
535-
for (const pub of taxonomy.publish_details as any[]) {
536-
const sourceEnvUid = pub?.environment;
537-
if (!sourceEnvUid) continue;
538-
const destUid = this.envUidMapper[String(sourceEnvUid)];
539-
if (destUid && !environments.includes(destUid)) {
540-
environments.push(destUid);
541-
}
542-
}
543-
544-
if (environments.length === 0) {
545-
apiOptions.apiData = undefined;
546-
return apiOptions;
547-
}
548-
549-
const locales = [String(taxonomy.locale)];
550-
apiOptions.apiData = {
551-
environments,
552-
locales,
553-
items: [{ uid: taxonomy.uid }],
554-
};
555-
556-
return apiOptions;
557-
}
558-
559498
// --- Mapper output ---
560499

561500
/**
@@ -631,7 +570,7 @@ export default class ImportTaxonomies extends BaseClass {
631570
this.isLocaleBasedStructure = this.detectAndScanLocaleStructure();
632571

633572
const taxonomyCount = Object.keys(this.taxonomies || {}).length;
634-
const envMapper = this.readEnvUidMapperSync();
573+
const envMapper = readEnvUidMapperSync(this.envUidMapperPath, this.importConfig.context);
635574
const publishJobCount = this.countPublishEligibleTaxonomies(envMapper);
636575

637576
log.debug(

packages/contentstack-import/src/utils/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,9 @@ export {
3131
} from './entries-helper';
3232
export * from './common-helper';
3333
export { lookUpTaxonomy, lookUpTerms } from './taxonomies-helper';
34+
export {
35+
readEnvUidMapperSync,
36+
warnIfEnvMapperEmpty,
37+
serializePublishTaxonomies,
38+
} from './taxonomy-publish-utils';
3439
export { MODULE_CONTEXTS, MODULE_NAMES, PROCESS_NAMES, PROCESS_STATUS } from './constants';
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import isEmpty from 'lodash/isEmpty';
2+
import { log } from '@contentstack/cli-utilities';
3+
import { ApiOptions } from '../import/modules/base-class';
4+
import type { Context } from '../types';
5+
import { fsUtil, fileExistsSync } from './file-helper';
6+
7+
/**
8+
* Reads source env UID → destination stack env UID map produced during environments import.
9+
*/
10+
export function readEnvUidMapperSync(envUidMapperPath: string, context: Context): Record<string, string> {
11+
if (!fileExistsSync(envUidMapperPath)) {
12+
log.debug(`Environment UID mapper not found at ${envUidMapperPath}`, context);
13+
return {};
14+
}
15+
16+
try {
17+
const raw = fsUtil.readFile(envUidMapperPath, true) as Record<string, unknown>;
18+
const out: Record<string, string> = {};
19+
for (const [k, v] of Object.entries(raw || {})) {
20+
if (v !== undefined && v !== null && String(v).trim() !== '') {
21+
out[k] = String(v);
22+
}
23+
}
24+
return out;
25+
} catch {
26+
log.debug('Failed to read environment UID mapper', context);
27+
return {};
28+
}
29+
}
30+
31+
export function warnIfEnvMapperEmpty(envUidMapper: Record<string, string>, context: Context): void {
32+
if (isEmpty(envUidMapper)) {
33+
log.warn(
34+
'Environment UID mapper is empty; taxonomy publishing is skipped. Import environments first or ensure mapper/environments/uid-mapping.json exists.',
35+
context,
36+
);
37+
}
38+
}
39+
40+
/**
41+
* Builds taxonomy publish payload: destination env UIDs from mapper, locales from taxonomy.locale, items: [{ uid }].
42+
*/
43+
export function serializePublishTaxonomies(
44+
apiOptions: ApiOptions,
45+
envUidMapper: Record<string, string>,
46+
): ApiOptions {
47+
const job = apiOptions.apiData as { taxonomy?: Record<string, any> };
48+
const taxonomy = job?.taxonomy;
49+
50+
if (!taxonomy?.publish_details?.length || !taxonomy?.locale) {
51+
apiOptions.apiData = undefined;
52+
return apiOptions;
53+
}
54+
55+
const environments: string[] = [];
56+
for (const pub of taxonomy.publish_details as any[]) {
57+
const sourceEnvUid = pub?.environment;
58+
if (!sourceEnvUid) continue;
59+
const destUid = envUidMapper[String(sourceEnvUid)];
60+
if (destUid && !environments.includes(destUid)) {
61+
environments.push(destUid);
62+
}
63+
}
64+
65+
if (environments.length === 0) {
66+
apiOptions.apiData = undefined;
67+
return apiOptions;
68+
}
69+
70+
const locales = [String(taxonomy.locale)];
71+
apiOptions.apiData = {
72+
environments,
73+
locales,
74+
items: [{ uid: taxonomy.uid }],
75+
};
76+
77+
return apiOptions;
78+
}

packages/contentstack-import/test/unit/import/modules/taxonomies.test.ts

Lines changed: 0 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -396,103 +396,6 @@ describe('ImportTaxonomies', () => {
396396
});
397397
});
398398

399-
describe('serializePublishTaxonomies', () => {
400-
it('maps source environment UIDs to destination UIDs and sets items to uid only', () => {
401-
(importTaxonomies as any).envUidMapper = { bltSrc: 'bltDest' };
402-
const apiOptions: any = {
403-
entity: 'publish-taxonomies',
404-
apiData: {
405-
taxonomy: {
406-
uid: 'tax1',
407-
locale: 'en-us',
408-
publish_details: [{ environment: 'bltSrc', time: '', user: '' }],
409-
},
410-
},
411-
resolve: sandbox.stub(),
412-
reject: sandbox.stub(),
413-
};
414-
415-
const result = (importTaxonomies as any).serializePublishTaxonomies(apiOptions);
416-
417-
expect(result.apiData).to.deep.equal({
418-
environments: ['bltDest'],
419-
locales: ['en-us'],
420-
items: [{ uid: 'tax1' }],
421-
});
422-
});
423-
424-
it('dedupes multiple publish_details environments', () => {
425-
(importTaxonomies as any).envUidMapper = { e1: 'd1', e2: 'd2' };
426-
const apiOptions: any = {
427-
entity: 'publish-taxonomies',
428-
apiData: {
429-
taxonomy: {
430-
uid: 'tax2',
431-
locale: 'fr-fr',
432-
publish_details: [{ environment: 'e1' }, { environment: 'e2' }, { environment: 'e1' }],
433-
},
434-
},
435-
resolve: sandbox.stub(),
436-
reject: sandbox.stub(),
437-
};
438-
439-
const result = (importTaxonomies as any).serializePublishTaxonomies(apiOptions);
440-
441-
expect(result.apiData.environments).to.deep.equal(['d1', 'd2']);
442-
expect(result.apiData.locales).to.deep.equal(['fr-fr']);
443-
expect(result.apiData.items).to.deep.equal([{ uid: 'tax2' }]);
444-
});
445-
446-
it('returns undefined when publish_details empty', () => {
447-
(importTaxonomies as any).envUidMapper = { x: 'y' };
448-
const apiOptions: any = {
449-
entity: 'publish-taxonomies',
450-
apiData: {
451-
taxonomy: { uid: 't', locale: 'en-us', publish_details: [] },
452-
},
453-
resolve: sandbox.stub(),
454-
reject: sandbox.stub(),
455-
};
456-
457-
expect((importTaxonomies as any).serializePublishTaxonomies(apiOptions).apiData).to.be.undefined;
458-
});
459-
460-
it('returns undefined when no env mapping resolves', () => {
461-
(importTaxonomies as any).envUidMapper = {};
462-
const apiOptions: any = {
463-
entity: 'publish-taxonomies',
464-
apiData: {
465-
taxonomy: {
466-
uid: 'tax1',
467-
locale: 'en-us',
468-
publish_details: [{ environment: 'missing' }],
469-
},
470-
},
471-
resolve: sandbox.stub(),
472-
reject: sandbox.stub(),
473-
};
474-
475-
expect((importTaxonomies as any).serializePublishTaxonomies(apiOptions).apiData).to.be.undefined;
476-
});
477-
478-
it('returns undefined when taxonomy.locale missing', () => {
479-
(importTaxonomies as any).envUidMapper = { e: 'd' };
480-
const apiOptions: any = {
481-
entity: 'publish-taxonomies',
482-
apiData: {
483-
taxonomy: {
484-
uid: 'tax1',
485-
publish_details: [{ environment: 'e' }],
486-
},
487-
},
488-
resolve: sandbox.stub(),
489-
reject: sandbox.stub(),
490-
};
491-
492-
expect((importTaxonomies as any).serializePublishTaxonomies(apiOptions).apiData).to.be.undefined;
493-
});
494-
});
495-
496399
describe('createSuccessAndFailedFile', () => {
497400
it('should write all four files when data exists', () => {
498401
(importTaxonomies as any).createSuccessAndFailedFile.restore();

0 commit comments

Comments
 (0)