@contentstack/cli-variants 1.2.2 → 1.3.0
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.
- package/lib/export/attributes.js +27 -10
- package/lib/export/audiences.js +28 -10
- package/lib/export/events.js +28 -10
- package/lib/export/experiences.js +48 -13
- package/lib/export/projects.js +24 -6
- package/lib/export/variant-entries.js +25 -4
- package/lib/import/attribute.d.ts +2 -3
- package/lib/import/attribute.js +16 -8
- package/lib/import/audiences.d.ts +2 -3
- package/lib/import/audiences.js +21 -8
- package/lib/import/events.d.ts +3 -4
- package/lib/import/events.js +16 -9
- package/lib/import/experiences.d.ts +2 -3
- package/lib/import/experiences.js +60 -17
- package/lib/import/project.d.ts +2 -3
- package/lib/import/project.js +11 -6
- package/lib/import/variant-entries.js +62 -25
- package/lib/types/export-config.d.ts +2 -1
- package/lib/types/utils.d.ts +11 -0
- package/lib/utils/attributes-helper.js +17 -1
- package/lib/utils/audiences-helper.js +37 -6
- package/lib/utils/events-helper.js +17 -4
- package/lib/utils/personalization-api-adapter.d.ts +2 -1
- package/lib/utils/personalization-api-adapter.js +119 -27
- package/lib/utils/variant-api-adapter.d.ts +4 -1
- package/lib/utils/variant-api-adapter.js +91 -17
- package/package.json +5 -2
- package/src/export/attributes.ts +34 -10
- package/src/export/audiences.ts +35 -7
- package/src/export/events.ts +35 -7
- package/src/export/experiences.ts +74 -24
- package/src/export/projects.ts +31 -7
- package/src/export/variant-entries.ts +47 -12
- package/src/import/attribute.ts +22 -9
- package/src/import/audiences.ts +28 -10
- package/src/import/events.ts +21 -10
- package/src/import/experiences.ts +74 -20
- package/src/import/project.ts +22 -8
- package/src/import/variant-entries.ts +116 -40
- package/src/types/export-config.ts +2 -1
- package/src/types/utils.ts +12 -0
- package/src/utils/attributes-helper.ts +21 -2
- package/src/utils/audiences-helper.ts +41 -1
- package/src/utils/events-helper.ts +19 -1
- package/src/utils/personalization-api-adapter.ts +95 -19
- package/src/utils/variant-api-adapter.ts +79 -8
package/src/export/attributes.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import omit from 'lodash/omit';
|
|
2
2
|
import { resolve as pResolve } from 'node:path';
|
|
3
|
-
import { sanitizePath } from '@contentstack/cli-utilities';
|
|
4
|
-
import {
|
|
3
|
+
import { sanitizePath, log, handleAndLogError } from '@contentstack/cli-utilities';
|
|
4
|
+
import {fsUtil, PersonalizationAdapter } from '../utils';
|
|
5
5
|
import { PersonalizeConfig, ExportConfig, AttributesConfig, AttributeStruct } from '../types';
|
|
6
6
|
|
|
7
7
|
export default class ExportAttributes extends PersonalizationAdapter<ExportConfig> {
|
|
@@ -16,6 +16,7 @@ export default class ExportAttributes extends PersonalizationAdapter<ExportConfi
|
|
|
16
16
|
baseURL: exportConfig.modules.personalize.baseURL[exportConfig.region.name],
|
|
17
17
|
headers: { 'X-Project-Uid': exportConfig.project_id },
|
|
18
18
|
});
|
|
19
|
+
this.exportConfig = exportConfig;
|
|
19
20
|
this.personalizeConfig = exportConfig.modules.personalize;
|
|
20
21
|
this.attributesConfig = exportConfig.modules.attributes;
|
|
21
22
|
this.attributesFolderPath = pResolve(
|
|
@@ -25,28 +26,46 @@ export default class ExportAttributes extends PersonalizationAdapter<ExportConfi
|
|
|
25
26
|
sanitizePath(this.attributesConfig.dirName),
|
|
26
27
|
);
|
|
27
28
|
this.attributes = [];
|
|
29
|
+
this.exportConfig.context.module = 'attributes';
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
async start() {
|
|
31
33
|
try {
|
|
32
|
-
log(
|
|
34
|
+
log.info('Starting attributes export', this.exportConfig.context);
|
|
35
|
+
|
|
36
|
+
log.debug('Initializing personalization adapter...', this.exportConfig.context);
|
|
33
37
|
await this.init();
|
|
38
|
+
log.debug('Personalization adapter initialized successfully', this.exportConfig.context);
|
|
39
|
+
|
|
40
|
+
log.debug(`Creating attributes directory at: ${this.attributesFolderPath}`, this.exportConfig.context);
|
|
34
41
|
await fsUtil.makeDirectory(this.attributesFolderPath);
|
|
42
|
+
log.debug('Attributes directory created successfully', this.exportConfig.context);
|
|
43
|
+
|
|
44
|
+
log.debug('Fetching attributes from personalization API...', this.exportConfig.context);
|
|
35
45
|
this.attributes = (await this.getAttributes()) as AttributeStruct[];
|
|
46
|
+
log.debug(`Fetched ${this.attributes?.length || 0} attributes`, this.exportConfig.context);
|
|
36
47
|
|
|
37
48
|
if (!this.attributes?.length) {
|
|
38
|
-
log(
|
|
49
|
+
log.debug('No attributes found, completing export', this.exportConfig.context);
|
|
50
|
+
log.info('No Attributes found with the given project!', this.exportConfig.context);
|
|
39
51
|
} else {
|
|
52
|
+
log.debug(`Processing ${this.attributes.length} attributes`, this.exportConfig.context);
|
|
40
53
|
this.sanitizeAttribs();
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
54
|
+
log.debug('Attributes sanitization completed', this.exportConfig.context);
|
|
55
|
+
|
|
56
|
+
const attributesFilePath = pResolve(sanitizePath(this.attributesFolderPath), sanitizePath(this.attributesConfig.fileName));
|
|
57
|
+
log.debug(`Writing attributes to: ${attributesFilePath}`, this.exportConfig.context);
|
|
58
|
+
fsUtil.writeFile(attributesFilePath, this.attributes);
|
|
59
|
+
|
|
60
|
+
log.debug('Attributes export completed successfully', this.exportConfig.context);
|
|
61
|
+
log.success(
|
|
62
|
+
`Attributes exported successfully! Total attributes: ${this.attributes.length}`,
|
|
63
|
+
this.exportConfig.context,
|
|
44
64
|
);
|
|
45
|
-
log(this.exportConfig, 'All the attributes have been exported successfully!', 'success');
|
|
46
65
|
}
|
|
47
66
|
} catch (error) {
|
|
48
|
-
log(
|
|
49
|
-
|
|
67
|
+
log.debug(`Error occurred during attributes export: ${error}`, this.exportConfig.context);
|
|
68
|
+
handleAndLogError(error, { ...this.exportConfig.context });
|
|
50
69
|
}
|
|
51
70
|
}
|
|
52
71
|
|
|
@@ -54,6 +73,11 @@ export default class ExportAttributes extends PersonalizationAdapter<ExportConfi
|
|
|
54
73
|
* function to remove invalid keys from attributes object
|
|
55
74
|
*/
|
|
56
75
|
sanitizeAttribs() {
|
|
76
|
+
log.debug(`Sanitizing ${this.attributes?.length || 0} attributes`, this.exportConfig.context);
|
|
77
|
+
log.debug(`Invalid keys to remove: ${JSON.stringify(this.attributesConfig.invalidKeys)}`, this.exportConfig.context);
|
|
78
|
+
|
|
57
79
|
this.attributes = this.attributes?.map((audience) => omit(audience, this.attributesConfig.invalidKeys)) || [];
|
|
80
|
+
|
|
81
|
+
log.debug(`Sanitization complete. Total attributes after sanitization: ${this.attributes.length}`, this.exportConfig.context);
|
|
58
82
|
}
|
|
59
83
|
}
|
package/src/export/audiences.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import omit from 'lodash/omit';
|
|
2
2
|
import { resolve as pResolve } from 'node:path';
|
|
3
|
+
import { log, handleAndLogError } from '@contentstack/cli-utilities';
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
+
import { fsUtil, PersonalizationAdapter } from '../utils';
|
|
5
6
|
import { PersonalizeConfig, ExportConfig, AudienceStruct, AudiencesConfig } from '../types';
|
|
6
7
|
|
|
7
8
|
export default class ExportAudiences extends PersonalizationAdapter<ExportConfig> {
|
|
@@ -25,27 +26,49 @@ export default class ExportAudiences extends PersonalizationAdapter<ExportConfig
|
|
|
25
26
|
this.audiencesConfig.dirName,
|
|
26
27
|
);
|
|
27
28
|
this.audiences = [];
|
|
29
|
+
this.exportConfig.context.module = 'audiences';
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
async start() {
|
|
31
33
|
try {
|
|
32
|
-
log(
|
|
34
|
+
log.debug('Starting audiences export process...', this.exportConfig.context);
|
|
35
|
+
log.info('Starting audiences export', this.exportConfig.context);
|
|
36
|
+
|
|
37
|
+
log.debug('Initializing personalization adapter...', this.exportConfig.context);
|
|
33
38
|
await this.init();
|
|
39
|
+
log.debug('Personalization adapter initialized successfully', this.exportConfig.context);
|
|
40
|
+
|
|
41
|
+
log.debug(`Creating audiences directory at: ${this.audiencesFolderPath}`, this.exportConfig.context);
|
|
34
42
|
await fsUtil.makeDirectory(this.audiencesFolderPath);
|
|
43
|
+
log.debug('Audiences directory created successfully', this.exportConfig.context);
|
|
44
|
+
|
|
45
|
+
log.debug('Fetching audiences from personalization API...', this.exportConfig.context);
|
|
35
46
|
this.audiences = (await this.getAudiences()) as AudienceStruct[];
|
|
47
|
+
log.debug(`Fetched ${this.audiences?.length || 0} audiences`, this.exportConfig.context);
|
|
36
48
|
|
|
37
49
|
if (!this.audiences?.length) {
|
|
38
|
-
log(
|
|
50
|
+
log.debug('No audiences found, completing export', this.exportConfig.context);
|
|
51
|
+
log.info('No Audiences found with the given project!', this.exportConfig.context);
|
|
39
52
|
return;
|
|
40
53
|
} else {
|
|
54
|
+
log.debug(`Processing ${this.audiences.length} audiences`, this.exportConfig.context);
|
|
41
55
|
this.sanitizeAttribs();
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
log.debug('Audiences sanitization completed', this.exportConfig.context);
|
|
57
|
+
|
|
58
|
+
const audiencesFilePath = pResolve(this.audiencesFolderPath, this.audiencesConfig.fileName);
|
|
59
|
+
log.debug(`Writing audiences to: ${audiencesFilePath}`, this.exportConfig.context);
|
|
60
|
+
fsUtil.writeFile(audiencesFilePath, this.audiences);
|
|
61
|
+
|
|
62
|
+
log.debug('Audiences export completed successfully', this.exportConfig.context);
|
|
63
|
+
log.success(
|
|
64
|
+
`Audiences exported successfully! Total audiences: ${this.audiences.length}`,
|
|
65
|
+
this.exportConfig.context,
|
|
66
|
+
);
|
|
44
67
|
return;
|
|
45
68
|
}
|
|
46
69
|
} catch (error) {
|
|
47
|
-
log(
|
|
48
|
-
|
|
70
|
+
log.debug(`Error occurred during audiences export: ${error}`, this.exportConfig.context);
|
|
71
|
+
handleAndLogError(error, { ...this.exportConfig.context });
|
|
49
72
|
}
|
|
50
73
|
}
|
|
51
74
|
|
|
@@ -53,6 +76,11 @@ export default class ExportAudiences extends PersonalizationAdapter<ExportConfig
|
|
|
53
76
|
* function to remove invalid keys from audience object
|
|
54
77
|
*/
|
|
55
78
|
sanitizeAttribs() {
|
|
79
|
+
log.debug(`Sanitizing ${this.audiences?.length || 0} audiences`, this.exportConfig.context);
|
|
80
|
+
log.debug(`Invalid keys to remove: ${JSON.stringify(this.audiencesConfig.invalidKeys)}`, this.exportConfig.context);
|
|
81
|
+
|
|
56
82
|
this.audiences = this.audiences?.map((audience) => omit(audience, this.audiencesConfig.invalidKeys)) || [];
|
|
83
|
+
|
|
84
|
+
log.debug(`Sanitization complete. Total audiences after sanitization: ${this.audiences.length}`, this.exportConfig.context);
|
|
57
85
|
}
|
|
58
86
|
}
|
package/src/export/events.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import omit from 'lodash/omit';
|
|
2
2
|
import { resolve as pResolve } from 'node:path';
|
|
3
|
+
import { log, handleAndLogError } from '@contentstack/cli-utilities';
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
+
import { fsUtil, PersonalizationAdapter } from '../utils';
|
|
5
6
|
import { PersonalizeConfig, ExportConfig, EventStruct, EventsConfig } from '../types';
|
|
6
7
|
|
|
7
8
|
export default class ExportEvents extends PersonalizationAdapter<ExportConfig> {
|
|
@@ -25,27 +26,49 @@ export default class ExportEvents extends PersonalizationAdapter<ExportConfig> {
|
|
|
25
26
|
this.eventsConfig.dirName,
|
|
26
27
|
);
|
|
27
28
|
this.events = [];
|
|
29
|
+
this.exportConfig.context.module = 'events';
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
async start() {
|
|
31
33
|
try {
|
|
32
|
-
log(
|
|
34
|
+
log.debug('Starting events export process...', this.exportConfig.context);
|
|
35
|
+
log.info('Starting events export', this.exportConfig.context);
|
|
36
|
+
|
|
37
|
+
log.debug('Initializing personalization adapter...', this.exportConfig.context);
|
|
33
38
|
await this.init();
|
|
39
|
+
log.debug('Personalization adapter initialized successfully', this.exportConfig.context);
|
|
40
|
+
|
|
41
|
+
log.debug(`Creating events directory at: ${this.eventsFolderPath}`, this.exportConfig.context);
|
|
34
42
|
await fsUtil.makeDirectory(this.eventsFolderPath);
|
|
43
|
+
log.debug('Events directory created successfully', this.exportConfig.context);
|
|
44
|
+
|
|
45
|
+
log.debug('Fetching events from personalization API...', this.exportConfig.context);
|
|
35
46
|
this.events = (await this.getEvents()) as EventStruct[];
|
|
47
|
+
log.debug(`Fetched ${this.events?.length || 0} events`, this.exportConfig.context);
|
|
36
48
|
|
|
37
49
|
if (!this.events?.length) {
|
|
38
|
-
log(
|
|
50
|
+
log.debug('No events found, completing export', this.exportConfig.context);
|
|
51
|
+
log.info('No Events found with the given project!', this.exportConfig.context);
|
|
39
52
|
return;
|
|
40
53
|
} else {
|
|
54
|
+
log.debug(`Processing ${this.events.length} events`, this.exportConfig.context);
|
|
41
55
|
this.sanitizeAttribs();
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
log.debug('Events sanitization completed', this.exportConfig.context);
|
|
57
|
+
|
|
58
|
+
const eventsFilePath = pResolve(this.eventsFolderPath, this.eventsConfig.fileName);
|
|
59
|
+
log.debug(`Writing events to: ${eventsFilePath}`, this.exportConfig.context);
|
|
60
|
+
fsUtil.writeFile(eventsFilePath, this.events);
|
|
61
|
+
|
|
62
|
+
log.debug('Events export completed successfully', this.exportConfig.context);
|
|
63
|
+
log.success(
|
|
64
|
+
`Events exported successfully! Total events: ${this.events.length}`,
|
|
65
|
+
this.exportConfig.context,
|
|
66
|
+
);
|
|
44
67
|
return;
|
|
45
68
|
}
|
|
46
69
|
} catch (error) {
|
|
47
|
-
log(
|
|
48
|
-
|
|
70
|
+
log.debug(`Error occurred during events export: ${error}`, this.exportConfig.context);
|
|
71
|
+
handleAndLogError(error, { ...this.exportConfig.context });
|
|
49
72
|
}
|
|
50
73
|
}
|
|
51
74
|
|
|
@@ -53,6 +76,11 @@ export default class ExportEvents extends PersonalizationAdapter<ExportConfig> {
|
|
|
53
76
|
* function to remove invalid keys from event object
|
|
54
77
|
*/
|
|
55
78
|
sanitizeAttribs() {
|
|
79
|
+
log.debug(`Sanitizing ${this.events?.length || 0} events`, this.exportConfig.context);
|
|
80
|
+
log.debug(`Invalid keys to remove: ${JSON.stringify(this.eventsConfig.invalidKeys)}`, this.exportConfig.context);
|
|
81
|
+
|
|
56
82
|
this.events = this.events?.map((event) => omit(event, this.eventsConfig.invalidKeys)) || [];
|
|
83
|
+
|
|
84
|
+
log.debug(`Sanitization complete. Total events after sanitization: ${this.events.length}`, this.exportConfig.context);
|
|
57
85
|
}
|
|
58
86
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
|
-
import { sanitizePath } from '@contentstack/cli-utilities';
|
|
2
|
+
import { sanitizePath, log, handleAndLogError } from '@contentstack/cli-utilities';
|
|
3
3
|
import { PersonalizeConfig, ExportConfig, ExperienceStruct } from '../types';
|
|
4
|
-
import {
|
|
4
|
+
import { fsUtil, PersonalizationAdapter } from '../utils';
|
|
5
5
|
|
|
6
6
|
export default class ExportExperiences extends PersonalizationAdapter<ExportConfig> {
|
|
7
7
|
private experiencesFolderPath: string;
|
|
@@ -25,6 +25,7 @@ export default class ExportExperiences extends PersonalizationAdapter<ExportConf
|
|
|
25
25
|
sanitizePath(this.personalizeConfig.dirName),
|
|
26
26
|
'experiences',
|
|
27
27
|
);
|
|
28
|
+
this.exportConfig.context.module = 'experiences';
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
async start() {
|
|
@@ -32,66 +33,115 @@ export default class ExportExperiences extends PersonalizationAdapter<ExportConf
|
|
|
32
33
|
// get all experiences
|
|
33
34
|
// loop through experiences and get content types attached to it
|
|
34
35
|
// write experiences in to a file
|
|
35
|
-
log(
|
|
36
|
+
log.debug('Starting experiences export process...', this.exportConfig.context);
|
|
37
|
+
log.info('Starting experiences export', this.exportConfig.context);
|
|
38
|
+
|
|
39
|
+
log.debug('Initializing personalization adapter...', this.exportConfig.context);
|
|
36
40
|
await this.init();
|
|
41
|
+
log.debug('Personalization adapter initialized successfully', this.exportConfig.context);
|
|
42
|
+
|
|
43
|
+
log.debug(`Creating experiences directory at: ${this.experiencesFolderPath}`, this.exportConfig.context);
|
|
37
44
|
await fsUtil.makeDirectory(this.experiencesFolderPath);
|
|
38
|
-
|
|
45
|
+
log.debug('Experiences directory created successfully', this.exportConfig.context);
|
|
46
|
+
|
|
47
|
+
const versionsDirPath = path.resolve(sanitizePath(this.experiencesFolderPath), 'versions');
|
|
48
|
+
log.debug(`Creating versions directory at: ${versionsDirPath}`, this.exportConfig.context);
|
|
49
|
+
await fsUtil.makeDirectory(versionsDirPath);
|
|
50
|
+
log.debug('Versions directory created successfully', this.exportConfig.context);
|
|
51
|
+
|
|
52
|
+
log.debug('Fetching experiences from personalization API...', this.exportConfig.context);
|
|
39
53
|
const experiences: Array<ExperienceStruct> = (await this.getExperiences()) || [];
|
|
54
|
+
log.debug(`Fetched ${experiences?.length || 0} experiences`, this.exportConfig.context);
|
|
55
|
+
|
|
40
56
|
if (!experiences || experiences?.length < 1) {
|
|
41
|
-
log(
|
|
57
|
+
log.debug('No experiences found, completing export', this.exportConfig.context);
|
|
58
|
+
log.info('No Experiences found with the given project!', this.exportConfig.context);
|
|
42
59
|
return;
|
|
43
60
|
}
|
|
44
|
-
|
|
61
|
+
|
|
62
|
+
const experiencesFilePath = path.resolve(sanitizePath(this.experiencesFolderPath), 'experiences.json');
|
|
63
|
+
log.debug(`Writing experiences to: ${experiencesFilePath}`, this.exportConfig.context);
|
|
64
|
+
fsUtil.writeFile(experiencesFilePath, experiences);
|
|
45
65
|
|
|
46
66
|
const experienceToVariantsStrList: Array<string> = [];
|
|
47
67
|
const experienceToContentTypesMap: Record<string, string[]> = {};
|
|
68
|
+
|
|
69
|
+
log.debug(`Processing ${experiences.length} experiences for variants and content types`, this.exportConfig.context);
|
|
70
|
+
|
|
48
71
|
for (let experience of experiences) {
|
|
72
|
+
log.debug(`Processing experience: ${experience.name} (${experience.uid})`, this.exportConfig.context);
|
|
73
|
+
|
|
49
74
|
// create id mapper for experience to variants
|
|
50
75
|
let variants = experience?._cms?.variants ?? {};
|
|
76
|
+
log.debug(`Found ${Object.keys(variants).length} variants for experience: ${experience.name}`, this.exportConfig.context);
|
|
77
|
+
|
|
51
78
|
Object.keys(variants).forEach((variantShortId: string) => {
|
|
52
79
|
const experienceToVariantsStr = `${experience.uid}-${variantShortId}-${variants[variantShortId]}`;
|
|
53
80
|
experienceToVariantsStrList.push(experienceToVariantsStr);
|
|
81
|
+
log.debug(`Added variant mapping: ${experienceToVariantsStr}`, this.exportConfig.context);
|
|
54
82
|
});
|
|
55
83
|
|
|
56
84
|
try {
|
|
57
85
|
// fetch versions of experience
|
|
86
|
+
log.debug(`Fetching versions for experience: ${experience.name}`, this.exportConfig.context);
|
|
58
87
|
const experienceVersions = (await this.getExperienceVersions(experience.uid)) || [];
|
|
88
|
+
log.debug(`Fetched ${experienceVersions.length} versions for experience: ${experience.name}`, this.exportConfig.context);
|
|
89
|
+
|
|
59
90
|
if (experienceVersions.length > 0) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
);
|
|
91
|
+
const versionsFilePath = path.resolve(sanitizePath(this.experiencesFolderPath), 'versions', `${experience.uid}.json`);
|
|
92
|
+
log.debug(`Writing experience versions to: ${versionsFilePath}`, this.exportConfig.context);
|
|
93
|
+
fsUtil.writeFile(versionsFilePath, experienceVersions);
|
|
64
94
|
} else {
|
|
65
|
-
log(
|
|
95
|
+
log.debug(`No versions found for experience: ${experience.name}`, this.exportConfig.context);
|
|
96
|
+
log.info(
|
|
97
|
+
`No versions found for experience '${experience.name}'`,
|
|
98
|
+
this.exportConfig.context,
|
|
99
|
+
);
|
|
66
100
|
}
|
|
67
101
|
} catch (error) {
|
|
68
|
-
log(
|
|
102
|
+
log.debug(`Error occurred while fetching versions for experience: ${experience.name}`, this.exportConfig.context);
|
|
103
|
+
handleAndLogError(
|
|
104
|
+
error,
|
|
105
|
+
{...this.exportConfig.context},
|
|
106
|
+
`Failed to fetch versions of experience ${experience.name}`
|
|
107
|
+
);
|
|
69
108
|
}
|
|
70
109
|
|
|
71
110
|
try {
|
|
72
111
|
// fetch content of experience
|
|
112
|
+
log.debug(`Fetching variant group for experience: ${experience.name}`, this.exportConfig.context);
|
|
73
113
|
const { variant_groups: [variantGroup] = [] } =
|
|
74
114
|
(await this.getVariantGroup({ experienceUid: experience.uid })) || {};
|
|
115
|
+
|
|
75
116
|
if (variantGroup?.content_types?.length) {
|
|
117
|
+
log.debug(`Found ${variantGroup.content_types.length} content types for experience: ${experience.name}`, this.exportConfig.context);
|
|
76
118
|
experienceToContentTypesMap[experience.uid] = variantGroup.content_types;
|
|
119
|
+
} else {
|
|
120
|
+
log.debug(`No content types found for experience: ${experience.name}`, this.exportConfig.context);
|
|
77
121
|
}
|
|
78
122
|
} catch (error) {
|
|
79
|
-
log(
|
|
123
|
+
log.debug(`Error occurred while fetching content types for experience: ${experience.name}`, this.exportConfig.context);
|
|
124
|
+
handleAndLogError(
|
|
125
|
+
error,
|
|
126
|
+
{...this.exportConfig.context},
|
|
127
|
+
`Failed to fetch content types of experience ${experience.name}`
|
|
128
|
+
);
|
|
80
129
|
}
|
|
81
130
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
);
|
|
131
|
+
|
|
132
|
+
const variantsIdsFilePath = path.resolve(sanitizePath(this.experiencesFolderPath), 'experiences-variants-ids.json');
|
|
133
|
+
log.debug(`Writing experience variants mapping to: ${variantsIdsFilePath}`, this.exportConfig.context);
|
|
134
|
+
fsUtil.writeFile(variantsIdsFilePath, experienceToVariantsStrList);
|
|
86
135
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
log(
|
|
136
|
+
const contentTypesFilePath = path.resolve(sanitizePath(this.experiencesFolderPath), 'experiences-content-types.json');
|
|
137
|
+
log.debug(`Writing experience content types mapping to: ${contentTypesFilePath}`, this.exportConfig.context);
|
|
138
|
+
fsUtil.writeFile(contentTypesFilePath, experienceToContentTypesMap);
|
|
139
|
+
|
|
140
|
+
log.debug('Experiences export completed successfully', this.exportConfig.context);
|
|
141
|
+
log.success('Experiences exported successfully!', this.exportConfig.context);
|
|
92
142
|
} catch (error) {
|
|
93
|
-
log(
|
|
94
|
-
|
|
143
|
+
log.debug(`Error occurred during experiences export: ${error}`, this.exportConfig.context);
|
|
144
|
+
handleAndLogError(error, {...this.exportConfig.context});
|
|
95
145
|
}
|
|
96
146
|
}
|
|
97
147
|
}
|
package/src/export/projects.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
|
-
import { sanitizePath } from '@contentstack/cli-utilities';
|
|
2
|
+
import { sanitizePath, log } from '@contentstack/cli-utilities';
|
|
3
3
|
import { ExportConfig, PersonalizeConfig } from '../types';
|
|
4
|
-
import { PersonalizationAdapter,
|
|
4
|
+
import { PersonalizationAdapter, fsUtil, } from '../utils';
|
|
5
5
|
|
|
6
6
|
export default class ExportProjects extends PersonalizationAdapter<ExportConfig> {
|
|
7
7
|
private projectFolderPath: string;
|
|
@@ -21,26 +21,50 @@ export default class ExportProjects extends PersonalizationAdapter<ExportConfig>
|
|
|
21
21
|
sanitizePath(this.personalizeConfig.dirName),
|
|
22
22
|
'projects',
|
|
23
23
|
);
|
|
24
|
+
this.exportConfig.context.module = 'projects';
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
async start() {
|
|
27
28
|
try {
|
|
28
|
-
log(
|
|
29
|
+
log.debug('Starting projects export process...', this.exportConfig.context);
|
|
30
|
+
log.info(`Starting projects export`, this.exportConfig.context);
|
|
31
|
+
|
|
32
|
+
log.debug('Initializing personalization adapter...', this.exportConfig.context);
|
|
29
33
|
await this.init();
|
|
34
|
+
log.debug('Personalization adapter initialized successfully', this.exportConfig.context);
|
|
35
|
+
|
|
36
|
+
log.debug(`Creating projects directory at: ${this.projectFolderPath}`, this.exportConfig.context);
|
|
30
37
|
await fsUtil.makeDirectory(this.projectFolderPath);
|
|
38
|
+
log.debug('Projects directory created successfully', this.exportConfig.context);
|
|
39
|
+
|
|
40
|
+
log.debug(`Fetching projects for stack API key: ${this.exportConfig.apiKey}`, this.exportConfig.context);
|
|
31
41
|
const project = await this.projects({ connectedStackApiKey: this.exportConfig.apiKey });
|
|
42
|
+
log.debug(`Fetched ${project?.length || 0} projects`, this.exportConfig.context);
|
|
43
|
+
|
|
32
44
|
if (!project || project?.length < 1) {
|
|
33
|
-
log(
|
|
45
|
+
log.debug('No projects found, disabling personalization', this.exportConfig.context);
|
|
46
|
+
log.info(`No Personalize Project connected with the given stack`, this.exportConfig.context);
|
|
34
47
|
this.exportConfig.personalizationEnabled = false;
|
|
35
48
|
return;
|
|
36
49
|
}
|
|
50
|
+
|
|
51
|
+
log.debug(`Found ${project.length} projects, enabling personalization`, this.exportConfig.context);
|
|
37
52
|
this.exportConfig.personalizationEnabled = true;
|
|
38
53
|
this.exportConfig.project_id = project[0]?.uid;
|
|
39
|
-
|
|
40
|
-
|
|
54
|
+
log.debug(`Set project ID: ${project[0]?.uid}`, this.exportConfig.context);
|
|
55
|
+
|
|
56
|
+
const projectsFilePath = path.resolve(sanitizePath(this.projectFolderPath), 'projects.json');
|
|
57
|
+
log.debug(`Writing projects data to: ${projectsFilePath}`, this.exportConfig.context);
|
|
58
|
+
fsUtil.writeFile(projectsFilePath, project);
|
|
59
|
+
|
|
60
|
+
log.debug('Projects export completed successfully', this.exportConfig.context);
|
|
61
|
+
log.success(`Projects exported successfully!`, this.exportConfig.context);
|
|
41
62
|
} catch (error) {
|
|
42
63
|
if (error !== 'Forbidden') {
|
|
43
|
-
log(
|
|
64
|
+
log.debug(`Error occurred during projects export: ${error}`, this.exportConfig.context);
|
|
65
|
+
log.error('Failed to export projects!', this.exportConfig.context);
|
|
66
|
+
} else {
|
|
67
|
+
log.debug('Projects export forbidden, likely due to permissions', this.exportConfig.context);
|
|
44
68
|
}
|
|
45
69
|
throw error;
|
|
46
70
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { existsSync, mkdirSync } from 'fs';
|
|
2
2
|
import { join, resolve } from 'path';
|
|
3
|
-
import { FsUtility, sanitizePath } from '@contentstack/cli-utilities';
|
|
3
|
+
import { FsUtility, sanitizePath, log, handleAndLogError } from '@contentstack/cli-utilities';
|
|
4
4
|
|
|
5
|
-
import { APIConfig, AdapterType, ExportConfig
|
|
5
|
+
import { APIConfig, AdapterType, ExportConfig } from '../types';
|
|
6
6
|
import VariantAdapter, { VariantHttpClient } from '../utils/variant-api-adapter';
|
|
7
|
-
import { fsUtil, log } from '../utils';
|
|
8
7
|
|
|
9
8
|
export default class VariantEntries extends VariantAdapter<VariantHttpClient<ExportConfig>> {
|
|
10
9
|
public entriesDirPath: string;
|
|
@@ -24,7 +23,14 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Exp
|
|
|
24
23
|
},
|
|
25
24
|
};
|
|
26
25
|
super(Object.assign(config, conf));
|
|
27
|
-
this.entriesDirPath = resolve(
|
|
26
|
+
this.entriesDirPath = resolve(
|
|
27
|
+
sanitizePath(config.data),
|
|
28
|
+
sanitizePath(config.branchName || ''),
|
|
29
|
+
sanitizePath(config.modules.entries.dirName),
|
|
30
|
+
);
|
|
31
|
+
if (this.config && this.config.context) {
|
|
32
|
+
this.config.context.module = 'variant-entries';
|
|
33
|
+
}
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
/**
|
|
@@ -35,10 +41,27 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Exp
|
|
|
35
41
|
async exportVariantEntry(options: { locale: string; contentTypeUid: string; entries: Record<string, any>[] }) {
|
|
36
42
|
const variantEntry = this.config.modules.variantEntry;
|
|
37
43
|
const { entries, locale, contentTypeUid: content_type_uid } = options;
|
|
44
|
+
|
|
45
|
+
log.debug(`Starting variant entries export for content type: ${content_type_uid}, locale: ${locale}`, this.config.context);
|
|
46
|
+
log.debug(`Processing ${entries.length} entries for variant export`, this.config.context);
|
|
47
|
+
|
|
48
|
+
log.debug('Initializing variant instance...', this.config.context);
|
|
38
49
|
await this.variantInstance.init();
|
|
50
|
+
log.debug('Variant instance initialized successfully', this.config.context);
|
|
51
|
+
|
|
39
52
|
for (let index = 0; index < entries.length; index++) {
|
|
40
53
|
const entry = entries[index];
|
|
41
|
-
|
|
54
|
+
log.debug(`Processing variant entries for entry: ${entry.title} (${entry.uid}) - ${index + 1}/${entries.length}`, this.config.context);
|
|
55
|
+
|
|
56
|
+
const variantEntryBasePath = join(
|
|
57
|
+
sanitizePath(this.entriesDirPath),
|
|
58
|
+
sanitizePath(content_type_uid),
|
|
59
|
+
sanitizePath(locale),
|
|
60
|
+
sanitizePath(variantEntry.dirName),
|
|
61
|
+
sanitizePath(entry.uid),
|
|
62
|
+
);
|
|
63
|
+
log.debug(`Variant entry base path: ${variantEntryBasePath}`, this.config.context);
|
|
64
|
+
|
|
42
65
|
const variantEntriesFs = new FsUtility({
|
|
43
66
|
isArray: true,
|
|
44
67
|
keepMetadata: false,
|
|
@@ -48,17 +71,24 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Exp
|
|
|
48
71
|
chunkFileSize: variantEntry.chunkFileSize || 1,
|
|
49
72
|
createDirIfNotExist: false,
|
|
50
73
|
});
|
|
74
|
+
log.debug('Initialized FsUtility for variant entries', this.config.context);
|
|
51
75
|
|
|
52
76
|
const callback = (variantEntries: Record<string, any>[]) => {
|
|
77
|
+
log.debug(`Callback received ${variantEntries?.length || 0} variant entries for entry: ${entry.uid}`, this.config.context);
|
|
53
78
|
if (variantEntries?.length) {
|
|
54
79
|
if (!existsSync(variantEntryBasePath)) {
|
|
80
|
+
log.debug(`Creating directory: ${variantEntryBasePath}`, this.config.context);
|
|
55
81
|
mkdirSync(variantEntryBasePath, { recursive: true });
|
|
56
82
|
}
|
|
83
|
+
log.debug(`Writing ${variantEntries.length} variant entries to file`, this.config.context);
|
|
57
84
|
variantEntriesFs.writeIntoFile(variantEntries);
|
|
85
|
+
} else {
|
|
86
|
+
log.debug(`No variant entries found for entry: ${entry.uid}`, this.config.context);
|
|
58
87
|
}
|
|
59
88
|
};
|
|
60
89
|
|
|
61
90
|
try {
|
|
91
|
+
log.debug(`Fetching variant entries for entry: ${entry.uid}`, this.config.context);
|
|
62
92
|
await this.variantInstance.variantEntries({
|
|
63
93
|
callback,
|
|
64
94
|
getAllData: true,
|
|
@@ -66,22 +96,27 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Exp
|
|
|
66
96
|
entry_uid: entry.uid,
|
|
67
97
|
locale,
|
|
68
98
|
});
|
|
99
|
+
|
|
69
100
|
if (existsSync(variantEntryBasePath)) {
|
|
101
|
+
log.debug(`Completing file for entry: ${entry.uid}`, this.config.context);
|
|
70
102
|
variantEntriesFs.completeFile(true);
|
|
71
|
-
log(
|
|
72
|
-
this.config,
|
|
103
|
+
log.info(
|
|
73
104
|
`Exported variant entries of type '${entry.title} (${entry.uid})' locale '${locale}'`,
|
|
74
|
-
|
|
105
|
+
this.config.context,
|
|
75
106
|
);
|
|
107
|
+
} else {
|
|
108
|
+
log.debug(`No variant entries directory created for entry: ${entry.uid}`, this.config.context);
|
|
76
109
|
}
|
|
77
110
|
} catch (error) {
|
|
78
|
-
log(
|
|
79
|
-
|
|
111
|
+
log.debug(`Error occurred while exporting variant entries for entry: ${entry.uid}`, this.config.context);
|
|
112
|
+
handleAndLogError(
|
|
113
|
+
error,
|
|
114
|
+
{ ...this.config.context },
|
|
80
115
|
`Error exporting variant entries of type '${entry.title} (${entry.uid})' locale '${locale}'`,
|
|
81
|
-
'error',
|
|
82
116
|
);
|
|
83
|
-
log(this.config, error, 'error');
|
|
84
117
|
}
|
|
85
118
|
}
|
|
119
|
+
|
|
120
|
+
log.debug(`Completed variant entries export for content type: ${content_type_uid}, locale: ${locale}`, this.config.context);
|
|
86
121
|
}
|
|
87
122
|
}
|