Skip to content

Commit b8ce61d

Browse files
committed
skip composition type and compositions if studio project failed to import
1 parent 81b4f26 commit b8ce61d

File tree

5 files changed

+103
-7
lines changed

5 files changed

+103
-7
lines changed

.talismanrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ fileignoreconfig:
6666
- filename: packages/contentstack-bulk-publish/src/producer/publish-unpublished-env.js
6767
checksum: 96fd15e027f38b156c69f10943ea1d5a70e580fa8a5efeb3286cd7132145c72d
6868
- filename: packages/contentstack-import/src/import/modules/entries.ts
69-
checksum: 2fd4e8ecf75e077632a6408d09997f0921d2a3508f9f2cb8f47fe79a28592300
69+
checksum: 290730774c61220645ec211b85b9e218cdbd8addc2d8fd8f061dfa5ede5b5c75
7070
- filename: packages/contentstack-utilities/src/logger/logger.ts
7171
checksum: 76429bc87e279624b386f00e7eb3f4ec25621ace7056289f812b9a076d6e184e
7272
- filename: packages/contentstack-bootstrap/src/bootstrap/utils.ts

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const config: DefaultConfig = {
3333
'stack',
3434
'assets',
3535
'taxonomies',
36+
'composable-studio',
3637
'extensions',
3738
'marketplace-apps',
3839
'global-fields',
@@ -44,7 +45,6 @@ const config: DefaultConfig = {
4445
'variant-entries',
4546
'labels',
4647
'webhooks',
47-
'composable-studio',
4848
],
4949
locales: {
5050
dirName: 'locales',

packages/contentstack-import/src/import/modules/composable-studio.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export default class ImportComposableStudio {
2020
private apiClient: HttpClient;
2121
private envUidMapperPath: string;
2222
private envUidMapper: Record<string, string>;
23+
private projectMapperPath: string;
2324

2425
constructor({ importConfig }: ModuleClassParams) {
2526
this.importConfig = importConfig;
@@ -28,6 +29,7 @@ export default class ImportComposableStudio {
2829

2930
// Setup paths
3031
this.composableStudioPath = join(this.importConfig.backupDir, this.composableStudioConfig.dirName);
32+
this.projectMapperPath = join(this.importConfig.backupDir, 'mapper', this.composableStudioConfig.dirName);
3133
this.composableStudioFilePath = join(this.composableStudioPath, this.composableStudioConfig.fileName);
3234
this.envUidMapperPath = join(this.importConfig.backupDir, 'mapper', 'environments', 'uid-mapping.json');
3335
this.envUidMapper = {};
@@ -244,6 +246,14 @@ export default class ImportComposableStudio {
244246
if (response.status >= 200 && response.status < 300) {
245247
projectCreated = true;
246248
log.debug(`Project created successfully with UID: ${response.data?.uid}`, this.importConfig.context);
249+
250+
// Create mapper directory if it doesn't exist
251+
await fsUtil.makeDirectory(this.projectMapperPath);
252+
253+
// write the project to file
254+
const projectFileSuccessPath = join(this.projectMapperPath, this.composableStudioConfig.fileName);
255+
fsUtil.writeFile(projectFileSuccessPath, response.data as unknown as Record<string, unknown>);
256+
log.debug(`Project written to: ${projectFileSuccessPath}`, this.importConfig.context);
247257
} else {
248258
throw new Error(`API call failed with status ${response.status}: ${JSON.stringify(response.data)}`);
249259
}

packages/contentstack-import/src/import/modules/content-types.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import * as path from 'path';
99
import { isEmpty, find, cloneDeep, map } from 'lodash';
1010
import { sanitizePath, log, handleAndLogError } from '@contentstack/cli-utilities';
11-
import { fsUtil, schemaTemplate, lookupExtension, lookUpTaxonomy } from '../../utils';
11+
import { fsUtil, schemaTemplate, lookupExtension, lookUpTaxonomy, fileHelper } from '../../utils';
1212
import { ImportConfig, ModuleClassParams } from '../../types';
1313
import BaseClass, { ApiOptions } from './base-class';
1414
import { updateFieldRules } from '../../utils/content-type-helper';
@@ -54,6 +54,8 @@ export default class ContentTypesImport extends BaseClass {
5454
public taxonomies: Record<string, unknown>;
5555
private extPendingPath: string;
5656
private isExtensionsUpdate = false;
57+
private composableStudioSuccessPath: string;
58+
private composableStudioExportPath: string;
5759

5860
constructor({ importConfig, stackAPIClient }: ModuleClassParams) {
5961
super({ importConfig, stackAPIClient });
@@ -84,6 +86,19 @@ export default class ContentTypesImport extends BaseClass {
8486
['schema.json', 'true'],
8587
['.DS_Store', 'true'],
8688
]);
89+
90+
this.composableStudioSuccessPath = path.join(
91+
sanitizePath(this.importConfig.data),
92+
'mapper',
93+
this.importConfig.modules['composable-studio'].dirName,
94+
this.importConfig.modules['composable-studio'].fileName,
95+
);
96+
97+
this.composableStudioExportPath = path.join(
98+
sanitizePath(this.importConfig.data),
99+
this.importConfig.modules['composable-studio'].dirName,
100+
this.importConfig.modules['composable-studio'].fileName,
101+
);
87102
this.cTs = [];
88103
this.createdCTs = [];
89104
this.titleToUIdMap = new Map();
@@ -110,6 +125,35 @@ export default class ContentTypesImport extends BaseClass {
110125
}
111126
log.debug(`Found ${this.cTs.length} content types to import`, this.importConfig.context);
112127

128+
// If success file doesn't exist but export file does, skip the composition content type
129+
if (
130+
!fileHelper.fileExistsSync(this.composableStudioSuccessPath) &&
131+
fileHelper.fileExistsSync(this.composableStudioExportPath)
132+
) {
133+
const exportedProject = fileHelper.readFileSync(this.composableStudioExportPath) as {
134+
contentTypeUid: string;
135+
};
136+
137+
if (exportedProject?.contentTypeUid) {
138+
const originalCount = this.cTs.length;
139+
this.cTs = this.cTs.filter((ct: Record<string, unknown>) => {
140+
const shouldSkip = ct.uid === exportedProject.contentTypeUid;
141+
if (shouldSkip) {
142+
log.info(
143+
`Skipping content type '${ct.uid}' as Composable Studio project was not created successfully`,
144+
this.importConfig.context,
145+
);
146+
}
147+
return !shouldSkip;
148+
});
149+
150+
const skippedCount = originalCount - this.cTs.length;
151+
if (skippedCount > 0) {
152+
log.debug(`Filtered out ${skippedCount} composition content type(s) from import`, this.importConfig.context);
153+
}
154+
}
155+
}
156+
113157
await fsUtil.makeDirectory(this.cTsMapperPath);
114158
log.debug('Created content types mapper directory.', this.importConfig.context);
115159

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

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ export default class EntriesImport extends BaseClass {
5757
public rteCTs: any;
5858
public rteCTsWithRef: any;
5959
public entriesForVariant: Array<{ content_type: string; locale: string; entry_uid: string }> = [];
60+
private composableStudioSuccessPath: string;
61+
private composableStudioExportPath: string;
6062

6163
constructor({ importConfig, stackAPIClient }: ModuleClassParams) {
6264
super({ importConfig, stackAPIClient });
@@ -92,6 +94,18 @@ export default class EntriesImport extends BaseClass {
9294
sanitizePath(importConfig.modules.locales.dirName),
9395
sanitizePath(importConfig.modules.locales.fileName),
9496
);
97+
this.composableStudioSuccessPath = path.join(
98+
sanitizePath(this.importConfig.data),
99+
'mapper',
100+
this.importConfig.modules['composable-studio'].dirName,
101+
this.importConfig.modules['composable-studio'].fileName,
102+
);
103+
104+
this.composableStudioExportPath = path.join(
105+
sanitizePath(this.importConfig.data),
106+
this.importConfig.modules['composable-studio'].dirName,
107+
this.importConfig.modules['composable-studio'].fileName,
108+
);
95109
this.importConcurrency = this.entriesConfig.importConcurrency || importConfig.importConcurrency;
96110
this.entriesUidMapper = {};
97111
this.modifiedCTs = [];
@@ -116,6 +130,37 @@ export default class EntriesImport extends BaseClass {
116130
return;
117131
}
118132
log.debug(`Found ${this.cTs.length} content types for entry import`, this.importConfig.context);
133+
// If success file doesn't exist but export file does, skip the composition entries
134+
if (
135+
!fileHelper.fileExistsSync(this.composableStudioSuccessPath) &&
136+
fileHelper.fileExistsSync(this.composableStudioExportPath)
137+
) {
138+
const exportedProject = fileHelper.readFileSync(this.composableStudioExportPath) as {
139+
contentTypeUid: string;
140+
};
141+
142+
if (exportedProject?.contentTypeUid) {
143+
const originalCount = this.cTs.length;
144+
this.cTs = this.cTs.filter((ct: Record<string, unknown>) => {
145+
const shouldSkip = ct.uid === exportedProject.contentTypeUid;
146+
if (shouldSkip) {
147+
log.info(
148+
`Skipping entries for content type '${ct.uid}' as Composable Studio project was not created successfully`,
149+
this.importConfig.context,
150+
);
151+
}
152+
return !shouldSkip;
153+
});
154+
155+
const skippedCount = originalCount - this.cTs.length;
156+
if (skippedCount > 0) {
157+
log.debug(
158+
`Filtered out ${skippedCount} composition content type(s) from entry import`,
159+
this.importConfig.context,
160+
);
161+
}
162+
}
163+
}
119164

120165
this.installedExtensions = (
121166
(fsUtil.readFile(this.marketplaceAppMapperPath) as any) || { extension_uid: {} }
@@ -124,10 +169,7 @@ export default class EntriesImport extends BaseClass {
124169

125170
this.assetUidMapper = (fsUtil.readFile(this.assetUidMapperPath) as Record<string, any>) || {};
126171
this.assetUrlMapper = (fsUtil.readFile(this.assetUrlMapperPath) as Record<string, any>) || {};
127-
log.debug(
128-
`Loaded asset mappings – UIDs: ${Object.keys(this.assetUidMapper).length}`,
129-
this.importConfig.context,
130-
);
172+
log.debug(`Loaded asset mappings – UIDs: ${Object.keys(this.assetUidMapper).length}`, this.importConfig.context);
131173

132174
this.taxonomies = (fsUtil.readFile(this.taxonomiesPath) || {}) as Record<string, any>;
133175
log.debug('Loaded taxonomy data for entry processing.', this.importConfig.context);

0 commit comments

Comments
 (0)