Skip to content

Commit baaf8ad

Browse files
Merge pull request #326 from mdmehran-qureshi/prerelease/alpha
Project directory enhancement in Migrate mode
2 parents 24b18d7 + 3a34317 commit baaf8ad

File tree

6 files changed

+216
-121
lines changed

6 files changed

+216
-121
lines changed

messages/assess.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@
104104
"operationCancelled": "Operation cancelled.",
105105
"invalidYesNoResponse": "Invalid response. Please answer y or n.",
106106
"notSfdxProjectFolderPath": "Provided folder is not a valid Salesforce DX project. Please select a folder containing sfdx-project.json",
107+
"failedToGetValidProjectPath": "Failed to get valid project path",
108+
"errorRunningAssess": "Error running assess",
107109
"enableVerboseOutput": "Enable verbose output",
108110
"apexFileChangesIdentifiedNotApplied": "Changes identified for Apex class {0} but not applied (assessment mode)",
109111
"apexFileHasMultipleInterfaces": "File {0} has multiple interfaces including Callable, standardizing to System.Callable only",

messages/migrate.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,24 @@
3636
"alreadyStandardModel": "The org is already on standard data model.",
3737
"invalidRelatedObjectsOptionGA": "Invalid option provided for -r: %s. Valid options are apex, lwc.",
3838
"invalidRelatedObjectsOption": "Invalid option provided for -r: %s. Valid option is apex.",
39-
"userConsentMessage": "By proceeding further, you hereby consent to the use, accept changes to your custom code, and the accompanying terms and conditions associated with the use of the OmniStudio Migration Tool. Do you want to proceed? [y/n]",
39+
"userConsentMessage": "By proceeding further, you hereby consent to the use, accept changes to your custom code and the accompanying terms and conditions associated with the use of the OmniStudio Migration Tool. Do you want to proceed? [y/n]",
4040
"userDeclinedConsent": "User declined consent, will not process %s .",
4141
"userConsentedToProceed": "User consented to proceed",
42+
"existingApexPrompt": "Do you have a sfdc project that already contains the APEX classes retrieved from your org? [y/n]",
43+
"enterExistingProjectPath": "Enter the path to the project folder that contains the retrieved APEX classes:",
44+
"invalidProjectFolderPath": "Provided project folder does not exist. Please provide a valid project folder path",
45+
"requestTimedOut": "Request timed out",
46+
"retrieveApexPrompt": "Omnistudio Migration Tool can connect to your org and retrieve the APEX classes. Provide an empty project folder to store the retrieved APEX classes. Would you like to proceed with the retrieval? [y/n]",
47+
"enterEmptyProjectPath": "Enter the path to an empty project folder to retrieve to and process the APEX classes:",
48+
"notEmptyProjectFolderPath": "Provided project folder is not empty. Please provide a valid empty project folder name and path",
49+
"invalidYesNoResponse": "Invalid response. Please answer y or n.",
50+
"notSfdxProjectFolderPath": "Provided folder is not a valid Salesforce DX project. Please select a folder containing sfdx-project.json",
51+
"operationCancelled": "Operation cancelled.",
52+
"failedToGetValidProjectPath": "Failed to get valid project path",
53+
"errorRunningMigrate": "Error running migrate %s",
54+
"couldNotEnableOmniPreferences": "Could not enable Omni preferences: %s",
55+
"errorSettingDesignersToStandardDataModel": "Error occurred while setting designers to use the standard data model %s",
56+
"exceptionSettingDesignersToStandardDataModel": "Exception occurred while setting designers to use the standard data model %s",
4257
"projectPathConfirmation": "Do you have a sfdc project where %s files are already retrieved from org - y\nor you want tool to create a project omnistudio_migration in current directory for processing - n ? [y/n]",
4358
"enterProjectPath": "Enter the project path for processing %s :",
4459
"projectJsonNotFound": "Could not find any %s in %s.",

src/commands/omnistudio/migration/assess.ts

Lines changed: 3 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import * as os from 'os';
2-
import * as path from 'path';
3-
import * as fs from 'fs';
42
import { flags } from '@salesforce/command';
53
import { Messages, Connection } from '@salesforce/core';
64
import OmniStudioBaseCommand from '../../basecommand';
@@ -15,31 +13,11 @@ import OmnistudioRelatedObjectMigrationFacade from '../../../migration/related/O
1513
import { OmnistudioOrgDetails, OrgUtils } from '../../../utils/orgUtils';
1614
import { OrgPreferences } from '../../../utils/orgPreferences';
1715
import { Constants } from '../../../utils/constants/stringContants';
18-
import { sfProject } from '../../../utils/sfcli/project/sfProject';
19-
import { PromptUtil } from '../../../utils/promptUtil';
16+
import { ProjectPathUtil } from '../../../utils/projectPathUtil';
2017

2118
Messages.importMessagesDirectory(__dirname);
2219
const messages = Messages.loadMessages('@salesforce/plugin-omnistudio-migration-tool', 'assess');
2320

24-
const EXISTING_MODE = 'existing';
25-
const EMPTY_MODE = 'empty';
26-
const YES_SHORT = 'y';
27-
const NO_SHORT = 'n';
28-
const YES_LONG = 'yes';
29-
const NO_LONG = 'no';
30-
31-
// Helper to create SFDX project if needed
32-
function createSfdxProject(folderPath: string): void {
33-
const projectName = path.basename(folderPath);
34-
const parentDir = path.dirname(folderPath);
35-
sfProject.create(projectName, parentDir);
36-
}
37-
38-
function isSfdxProject(folderPath: string): boolean {
39-
const sfdxProjectJson = path.join(folderPath, 'sfdx-project.json');
40-
return fs.existsSync(sfdxProjectJson);
41-
}
42-
4321
export default class Assess extends OmniStudioBaseCommand {
4422
public static description = messages.getMessage('commandDescription');
4523

@@ -78,7 +56,7 @@ export default class Assess extends OmniStudioBaseCommand {
7856
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
7957
return await this.runAssess();
8058
} catch (error) {
81-
Logger.error('Error running assess');
59+
Logger.error(messages.getMessage('errorRunningAssess'));
8260
Logger.error(error);
8361
process.exit(1);
8462
}
@@ -116,7 +94,7 @@ export default class Assess extends OmniStudioBaseCommand {
11694
const namespace = orgs.packageDetails.namespace;
11795
let projectPath = '';
11896
if (relatedObjects) {
119-
projectPath = await this.getProjectPath();
97+
projectPath = await ProjectPathUtil.getProjectPath(messages, true);
12098
}
12199

122100
const assesmentInfo: AssessmentInfo = {
@@ -252,74 +230,4 @@ export default class Assess extends OmniStudioBaseCommand {
252230
);
253231
Logger.log(messages.getMessage('omniScriptAssessmentCompleted'));
254232
}
255-
256-
private async getProjectPath(): Promise<string> {
257-
let projectPath = '';
258-
let mode: string = EXISTING_MODE;
259-
260-
// Prompt for project type
261-
const askWithTimeout = PromptUtil.askWithTimeOut(messages);
262-
// Prompt: Existing project?
263-
let response = '';
264-
let validResponse = false;
265-
266-
while (!validResponse) {
267-
try {
268-
const resp = await askWithTimeout(Logger.prompt.bind(Logger), messages.getMessage('existingApexPrompt'));
269-
response = typeof resp === 'string' ? resp.trim().toLowerCase() : '';
270-
} catch (err) {
271-
Logger.error(messages.getMessage('requestTimedOut'));
272-
process.exit(1);
273-
}
274-
275-
if (response === YES_SHORT || response === YES_LONG) {
276-
mode = EXISTING_MODE;
277-
validResponse = true;
278-
} else if (response === NO_SHORT || response === NO_LONG) {
279-
mode = EMPTY_MODE;
280-
validResponse = true;
281-
} else {
282-
Logger.error(messages.getMessage('invalidYesNoResponse'));
283-
}
284-
}
285-
286-
// Prompt for project path
287-
let gotValidPath = false;
288-
while (!gotValidPath) {
289-
let folderPath = '';
290-
try {
291-
const resp = await askWithTimeout(
292-
Logger.prompt.bind(Logger),
293-
mode === EXISTING_MODE
294-
? messages.getMessage('enterExistingProjectPath')
295-
: messages.getMessage('enterEmptyProjectPath')
296-
);
297-
folderPath = typeof resp === 'string' ? resp.trim() : '';
298-
} catch (err) {
299-
Logger.error(messages.getMessage('requestTimedOut'));
300-
process.exit(1);
301-
}
302-
folderPath = path.resolve(folderPath);
303-
304-
if (!fs.existsSync(folderPath) || !fs.lstatSync(folderPath).isDirectory()) {
305-
Logger.error(messages.getMessage('invalidProjectFolderPath'));
306-
continue;
307-
}
308-
if (mode === EMPTY_MODE && fs.readdirSync(folderPath).length > 0) {
309-
Logger.error(messages.getMessage('notEmptyProjectFolderPath'));
310-
continue;
311-
}
312-
// If empty, create SFDX project
313-
if (mode === EMPTY_MODE) {
314-
createSfdxProject(folderPath);
315-
} else if (!isSfdxProject(folderPath)) {
316-
Logger.error(messages.getMessage('notSfdxProjectFolderPath'));
317-
continue;
318-
}
319-
projectPath = folderPath;
320-
gotValidPath = true;
321-
}
322-
323-
return projectPath;
324-
}
325233
}

src/commands/omnistudio/migration/migrate.ts

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
99
*/
1010
import * as os from 'os';
11-
import * as fs from 'fs';
1211
import { flags } from '@salesforce/command';
1312
import { Messages } from '@salesforce/core';
1413
import { ExecuteAnonymousResult } from 'jsforce';
@@ -26,6 +25,7 @@ import { OmnistudioOrgDetails, OrgUtils } from '../../../utils/orgUtils';
2625
import { Constants } from '../../../utils/constants/stringContants';
2726
import { OrgPreferences } from '../../../utils/orgPreferences';
2827
import { AnonymousApexRunner } from '../../../utils/apex/executor/AnonymousApexRunner';
28+
import { ProjectPathUtil } from '../../../utils/projectPathUtil';
2929

3030
// Initialize Messages with the current plugin directory
3131
Messages.importMessagesDirectory(__dirname);
@@ -135,13 +135,11 @@ export default class Migrate extends OmniStudioBaseCommand {
135135
process.exit(1);
136136
}
137137
}
138-
// Ask for user consent
139-
const consent = await Logger.confirm(messages.getMessage('userConsentMessage'));
140-
if (!consent) {
141-
Logger.error(messages.getMessage('userDeclinedConsent', [relatedObjects]));
142-
} else {
143-
Logger.info(messages.getMessage('userConsentedToProceed'));
144-
projectPath = await this.getProjectPath(relatedObjects, projectPath);
138+
// Check for general consent to make modifications with OMT
139+
const generalConsent = await this.getGeneralConsent();
140+
if (generalConsent) {
141+
// Use ProjectPathUtil for APEX project folder selection (matches assess.ts logic)
142+
projectPath = await ProjectPathUtil.getProjectPath(messages, true);
145143
targetApexNamespace = await this.getTargetApexNamespace(objectsToProcess, targetApexNamespace);
146144
}
147145
}
@@ -333,22 +331,6 @@ export default class Migrate extends OmniStudioBaseCommand {
333331
return migrationObjects;
334332
}
335333

336-
private async getProjectPath(relatedObjects: string, projectPath: string): Promise<string> {
337-
const projectPathConfirmation = await Logger.confirm(
338-
messages.getMessage('projectPathConfirmation', [relatedObjects])
339-
);
340-
if (projectPathConfirmation) {
341-
Logger.info(messages.getMessage('userConsentedToProceed'));
342-
projectPath = await Logger.prompt(messages.getMessage('enterProjectPath', [relatedObjects]));
343-
const projectJsonFile = 'sfdx-project.json';
344-
if (!fs.existsSync(projectPath + '/' + projectJsonFile)) {
345-
throw new Error(messages.getMessage('projectJsonNotFound', [projectJsonFile, projectPath]));
346-
}
347-
Logger.log(messages.getMessage('usingProjectPath', [projectPath]));
348-
}
349-
return projectPath;
350-
}
351-
352334
private async getTargetApexNamespace(objectsToProcess: string[], targetApexNamespace: string): Promise<string> {
353335
if (objectsToProcess.includes(Constants.Apex)) {
354336
targetApexNamespace = await this.ux.prompt(messages.getMessage('enterTargetNamespace'));
@@ -357,6 +339,21 @@ export default class Migrate extends OmniStudioBaseCommand {
357339
return targetApexNamespace;
358340
}
359341

342+
private async getGeneralConsent(): Promise<boolean> {
343+
let consent: boolean | null = null;
344+
345+
while (consent === null) {
346+
try {
347+
consent = await Logger.confirm(messages.getMessage('userConsentMessage'));
348+
} catch (error) {
349+
Logger.log(messages.getMessage('invalidYesNoResponse'));
350+
consent = null;
351+
}
352+
}
353+
354+
return consent;
355+
}
356+
360357
private mergeRecordAndUploadResults(
361358
migrationResults: MigrationResult,
362359
migrationTool: MigrationTool

src/utils/orgUtils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ export class OrgUtils {
329329
// Handle multiple packages by prompting user to select one
330330
if (installedOmniPackages.length > 1) {
331331
Logger.log(messages.getMessage('multiplePackagesFound'));
332-
332+
installedOmniPackages.sort((a, b) => a.NamespacePrefix.localeCompare(b.NamespacePrefix));
333333
// Display available packages
334334
for (let i = 0; i < installedOmniPackages.length; i++) {
335335
const pkg = installedOmniPackages[i];

0 commit comments

Comments
 (0)