Skip to content

Commit 70c2ee8

Browse files
author
naman-contentstack
committed
add helper file for import path validation
1 parent 5a61356 commit 70c2ee8

3 files changed

Lines changed: 166 additions & 134 deletions

File tree

packages/contentstack-import/src/utils/common-helper.ts

Lines changed: 1 addition & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as _ from 'lodash';
99
import * as path from 'path';
1010
import { HttpClient, managementSDKClient, isAuthenticated, sanitizePath, log, handleAndLogError } from '@contentstack/cli-utilities';
1111
import { readFileSync, readdirSync, readFile, fileExistsSync } from './file-helper';
12-
import { askBranchSelection } from './interactive';
12+
1313
import chalk from 'chalk';
1414
import defaultConfig from '../config';
1515
import promiseLimit from 'promise-limit';
@@ -309,137 +309,4 @@ export const formatDate = (date: Date = new Date()) => {
309309
return formattedDate;
310310
};
311311

312-
export const selectBranchFromDirectory = async (contentDir: string): Promise<{ branchPath: string } | null> => {
313-
log.debug('Selecting branch directory from directory structure');
314-
315-
const branchesJsonPath = path.join(contentDir, 'branches.json');
316-
if (!fileExistsSync(branchesJsonPath)) {
317-
log.debug('No branches.json found - not a branch-enabled export');
318-
return null;
319-
}
320-
321-
log.debug('Found branches.json - handling branch selection');
322-
323-
try {
324-
const branchesData = readFileSync(branchesJsonPath);
325-
const branches = Array.isArray(branchesData) ? branchesData : [];
326-
327-
if (branches.length === 0) {
328-
log.debug('No branches found in branches.json - not a branch-enabled export');
329-
return null;
330-
}
331-
332-
if (branches.length === 1) {
333-
const singleBranch = branches[0];
334-
const branchPath = path.join(contentDir, singleBranch.uid);
335-
336-
if (!fileExistsSync(branchPath)) {
337-
log.warn(`Branch path does not exist: ${branchPath}, not a valid branch export`);
338-
return null;
339-
}
340-
341-
log.debug(`Single branch detected: ${singleBranch.uid} - using path: ${branchPath}`);
342-
return { branchPath };
343-
} else {
344-
log.debug(`Multiple branches detected: ${branches.map((b) => b.uid).join(', ')}`);
345-
346-
const branchNames = branches.map((b) => b.uid);
347-
const selectedBranch = await askBranchSelection(branchNames);
348-
349-
const selectedBranchPath = path.join(contentDir, selectedBranch);
350-
351-
if (!fileExistsSync(selectedBranchPath)) {
352-
log.warn(`Selected branch path does not exist: ${selectedBranchPath}, not a valid branch export`);
353-
return null;
354-
}
355-
356-
log.debug(`User selected branch directory: ${selectedBranch} - using path: ${selectedBranchPath}`);
357-
return { branchPath: selectedBranchPath };
358-
}
359-
} catch (error) {
360-
handleAndLogError(error, { module: 'branch-selection' }, 'Failed to read branches.json');
361-
throw new Error('Failed to read branches.json file. Please ensure the file exists and is valid JSON.');
362-
}
363-
};
364-
365-
export const resolveImportPath = async (importConfig: ImportConfig, stackAPIClient: any): Promise<string> => {
366-
log.debug('Resolving import path based on directory structure');
367-
368-
const contentDir = importConfig.contentDir || importConfig.data;
369-
log.debug(`Content directory: ${contentDir}`);
370-
371-
if (!fileExistsSync(contentDir)) {
372-
throw new Error(`Content directory does not exist: ${contentDir}`);
373-
}
374-
375-
if (importConfig.branchName) {
376-
log.debug(`User specified branch: ${importConfig.branchName}`);
377-
378-
const currentDirName = path.basename(contentDir);
379-
if (currentDirName === importConfig.branchName) {
380-
log.debug(`Already in correct branch directory: ${contentDir}`);
381-
return contentDir;
382-
}
383-
384-
const branchPath = path.join(contentDir, importConfig.branchName);
385-
if (fileExistsSync(branchPath)) {
386-
log.debug(`Navigating to specified branch directory: ${branchPath}`);
387-
return branchPath;
388-
}
389-
390-
log.debug(`Branch directory not found: ${branchPath}, using contentDir as-is`);
391-
return contentDir;
392-
}
393-
394-
const exportInfoPath = path.join(contentDir, 'export-info.json');
395-
if (fileExistsSync(exportInfoPath)) {
396-
log.debug('Found export-info.json - using contentDir as-is (v2 export)');
397-
return contentDir;
398-
}
399-
400-
const moduleTypes = defaultConfig.modules.types;
401-
const hasModuleFolders = moduleTypes.some((moduleType) => fileExistsSync(path.join(contentDir, moduleType)));
402-
403-
if (hasModuleFolders) {
404-
log.debug('Found module folders ');
405-
return contentDir;
406-
}
407-
408-
const branchSelection = await selectBranchFromDirectory(contentDir);
409-
if (branchSelection) {
410-
return branchSelection.branchPath;
411-
}
412-
413-
log.debug('No specific structure detected - using contentDir as-is');
414-
return contentDir;
415-
};
416-
417-
export const updateImportConfigWithResolvedPath = (importConfig: ImportConfig, resolvedPath: string): void => {
418-
log.debug(`Updating import config with resolved path: ${resolvedPath}`);
419-
420-
if (!fileExistsSync(resolvedPath)) {
421-
log.warn(`Resolved path does not exist: ${resolvedPath}, skipping config update`);
422-
return;
423-
}
424-
425-
importConfig.branchDir = resolvedPath;
426-
427-
importConfig.contentDir = resolvedPath;
428-
429-
importConfig.data = resolvedPath;
430-
431-
log.debug(
432-
`Import config updated - contentDir: ${importConfig.contentDir}, branchDir: ${importConfig.branchDir}, data: ${importConfig.data}`,
433-
);
434-
};
435-
436-
437-
export const executeImportPathLogic = async (importConfig: ImportConfig, stackAPIClient: any): Promise<string> => {
438-
log.debug('Executing import path resolution logic');
439312

440-
const resolvedPath = await resolveImportPath(importConfig, stackAPIClient);
441-
442-
updateImportConfigWithResolvedPath(importConfig, resolvedPath);
443-
444-
return resolvedPath;
445-
};
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import * as path from 'path';
2+
import { log } from '@contentstack/cli-utilities';
3+
import { fileExistsSync, readFile } from './file-helper';
4+
import { askBranchSelection } from './interactive';
5+
import { ImportConfig } from '../types';
6+
import defaultConfig from '../config';
7+
8+
/**
9+
* Selects a branch from directory structure when multiple branches are found
10+
* @param contentDir - The content directory path
11+
* @returns Promise<{ branchPath: string } | null>
12+
*/
13+
export const selectBranchFromDirectory = async (contentDir: string): Promise<{ branchPath: string } | null> => {
14+
log.debug('Selecting branch directory from directory structure');
15+
16+
const branchesJsonPath = path.join(contentDir, 'branches.json');
17+
if (!fileExistsSync(branchesJsonPath)) {
18+
log.debug('No branches.json found - not a branch-enabled export');
19+
return null;
20+
}
21+
22+
try {
23+
const branchesData = await readFile(branchesJsonPath);
24+
const branches = branchesData || [];
25+
26+
if (!branches || !Array.isArray(branches) || branches.length === 0) {
27+
log.debug('No branches found in branches.json - not a branch-enabled export');
28+
return null;
29+
}
30+
31+
if (branches.length === 1) {
32+
const singleBranch = branches[0];
33+
const branchPath = path.join(contentDir, singleBranch.uid);
34+
35+
if (!fileExistsSync(branchPath)) {
36+
log.warn(`Branch path does not exist: ${branchPath}, not a valid branch export`);
37+
return null;
38+
}
39+
40+
log.debug(`Single branch detected: ${singleBranch.uid} - auto-resolving to: ${branchPath}`);
41+
return { branchPath };
42+
} else {
43+
log.debug(`Multiple branches detected: ${branches.map((b) => b.uid).join(', ')}`);
44+
45+
const branchNames = branches.map((b) => b.uid);
46+
const selectedBranch = await askBranchSelection(branchNames);
47+
const selectedBranchPath = path.join(contentDir, selectedBranch);
48+
49+
if (!fileExistsSync(selectedBranchPath)) {
50+
log.warn(`Selected branch path does not exist: ${selectedBranchPath}, not a valid branch export`);
51+
return null;
52+
}
53+
54+
log.debug(`User selected branch directory: ${selectedBranch} - using path: ${selectedBranchPath}`);
55+
return { branchPath: selectedBranchPath };
56+
}
57+
} catch (error) {
58+
log.error(`Error reading branches.json: ${error}`);
59+
throw new Error('Failed to read branches.json file. Please ensure the file exists and is valid JSON.');
60+
}
61+
};
62+
63+
/**
64+
* Resolves the import path based on directory structure and user configuration
65+
* @param importConfig - The import configuration object
66+
* @param stackAPIClient - The Contentstack API client
67+
* @returns Promise<string> - The resolved path
68+
*/
69+
export const resolveImportPath = async (importConfig: ImportConfig, stackAPIClient: any): Promise<string> => {
70+
log.debug('Resolving import path based on directory structure');
71+
72+
const contentDir = importConfig.contentDir || importConfig.data;
73+
log.debug(`Content directory: ${contentDir}`);
74+
75+
if (!fileExistsSync(contentDir)) {
76+
throw new Error(`Content directory does not exist: ${contentDir}`);
77+
}
78+
79+
if (importConfig.branchName) {
80+
log.debug(`User specified branch: ${importConfig.branchName}`);
81+
82+
const currentDirName = path.basename(contentDir);
83+
if (currentDirName === importConfig.branchName) {
84+
log.debug(`Already in correct branch directory: ${contentDir}`);
85+
return contentDir;
86+
}
87+
88+
const branchPath = path.join(contentDir, importConfig.branchName);
89+
if (fileExistsSync(branchPath)) {
90+
log.debug(`Navigating to specified branch directory: ${branchPath}`);
91+
return branchPath;
92+
}
93+
94+
log.debug(`Branch directory not found: ${branchPath}, using contentDir as-is`);
95+
return contentDir;
96+
}
97+
98+
const exportInfoPath = path.join(contentDir, 'export-info.json');
99+
if (fileExistsSync(exportInfoPath)) {
100+
log.debug('Found export-info.json - using contentDir as-is (v2 export)');
101+
return contentDir;
102+
}
103+
104+
const moduleTypes = defaultConfig.modules.types;
105+
const hasModuleFolders = moduleTypes.some((moduleType) => fileExistsSync(path.join(contentDir, moduleType)));
106+
107+
if (hasModuleFolders) {
108+
log.debug('Found module folders ');
109+
return contentDir;
110+
}
111+
112+
const branchSelection = await selectBranchFromDirectory(contentDir);
113+
if (branchSelection) {
114+
return branchSelection.branchPath;
115+
}
116+
117+
log.debug('No specific structure detected - using contentDir as-is');
118+
return contentDir;
119+
};
120+
121+
/**
122+
* Updates the import configuration with the resolved path
123+
* @param importConfig - The import configuration object
124+
* @param resolvedPath - The resolved path
125+
*/
126+
export const updateImportConfigWithResolvedPath = (importConfig: ImportConfig, resolvedPath: string): void => {
127+
log.debug(`Updating import config with resolved path: ${resolvedPath}`);
128+
129+
if (!fileExistsSync(resolvedPath)) {
130+
log.warn(`Resolved path does not exist: ${resolvedPath}, skipping config update`);
131+
return;
132+
}
133+
134+
importConfig.branchDir = resolvedPath;
135+
136+
importConfig.contentDir = resolvedPath;
137+
138+
importConfig.data = resolvedPath;
139+
140+
log.debug(
141+
`Import config updated - contentDir: ${importConfig.contentDir}, branchDir: ${importConfig.branchDir}, data: ${importConfig.data}`,
142+
);
143+
};
144+
145+
/**
146+
* Executes the complete import path resolution logic
147+
* @param importConfig - The import configuration object
148+
* @param stackAPIClient - The Contentstack API client
149+
* @returns Promise<string> - The resolved path
150+
*/
151+
export const executeImportPathLogic = async (importConfig: ImportConfig, stackAPIClient: any): Promise<string> => {
152+
log.debug('Executing import path resolution logic');
153+
154+
const resolvedPath = await resolveImportPath(importConfig, stackAPIClient);
155+
156+
updateImportConfigWithResolvedPath(importConfig, resolvedPath);
157+
158+
return resolvedPath;
159+
};

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
export { setupBranchConfig } from './setup-branch';
2+
export {
3+
selectBranchFromDirectory,
4+
resolveImportPath,
5+
updateImportConfigWithResolvedPath,
6+
executeImportPathLogic
7+
} from './import-path-resolver';
28
export * as interactive from './interactive';
39
export { default as setupImportConfig } from './import-config-handler';
410
export * as fileHelper from './file-helper';

0 commit comments

Comments
 (0)