Skip to content

Commit bae7e52

Browse files
authored
Merge pull request #416 from snehaljha-sf/apexFix
Apex Migration fixes
2 parents 7e9379e + 4c6e0ff commit bae7e52

File tree

7 files changed

+145
-99
lines changed

7 files changed

+145
-99
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ You can also authenticate using a consumer key (client ID) and secret key throug
3434
3. In a new terminal session, Install the Omnistudio Migration Assistant by running the `sf plugins install` command. For example
3535

3636
```
37-
sf plugins install @salesforce/[email protected].51
37+
sf plugins install @salesforce/[email protected].52
3838
```
3939

4040
4. Run the Omnistudio Migration Assistant from the Salesforce CLI:

messages/assess.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,10 @@
192192
"generatedCustomLabelAssessmentReportPage": "Generated custom label assessment report page %s of %s with %s labels",
193193
"manualDeploymentSteps": "<a href='%s' target='_blank'>Please refer to this documentation for manual deployment process</a>",
194194
"varDeclarationUpdated": "Variable initialization will be updated for target name",
195-
"ipNameUpdateFailed": "IP reference %s can’t be updated",
196-
"dmNameUpdateFailed": "DM reference %s can’t be updated",
195+
"ipNameUpdateFailed": "Integration Procedure reference can’t be updated at line %s",
196+
"dmNameUpdateFailed": "Data Mapper reference can’t be updated at line %s",
197+
"ipNameReferenceNotFound": "Integration Procedure reference can’t be updated",
198+
"dmNameReferenceNotFound": "Data Mapper reference can’t be updated",
197199
"invalidTypeAssessErrorMessage": "We couldn't assess your Omnistudio components in the %s namespace. Select the correct namespace and try again",
198200
"assessmentSuccessfulMessage": "Migration assessment for org %s is complete and reports are ready for review in the folder %s",
199201
"missingMandatoryField": "Missing mandatory field: %s for %s"

src/migration/related/ApexMigration.ts

Lines changed: 87 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
} from '../../utils/apex/parser/apexparser';
1616
import { FileUtil, File } from '../../utils/file/fileUtil';
1717
import { Logger } from '../../utils/logger';
18-
import { ApexAssessmentInfo } from '../../utils';
18+
import { ApexAssessmentInfo, DiffPair } from '../../utils';
1919
import { FileDiffUtil } from '../../utils/lwcparser/fileutils/FileDiffUtil';
2020
import { Constants } from '../../utils/constants/stringContants';
2121
import { ComponentType, createProgressBar } from '../base';
@@ -118,6 +118,7 @@ export class ApexMigration extends BaseRelatedObjectMigration {
118118
infos: [],
119119
path: file.location,
120120
diff: '',
121+
status: 'Failed',
121122
});
122123
processingErrorsList.push(assessMessages.getMessage('errorProcessingApexFile', [file.name]));
123124
progressBar.update(++progressCounter);
@@ -134,21 +135,12 @@ export class ApexMigration extends BaseRelatedObjectMigration {
134135
const fileContent = fs.readFileSync(file.location, 'utf8');
135136
const interfaces: InterfaceImplements[] = [];
136137
interfaces.push(this.vlocityOpenInterface, this.vlocityOpenInterface2, this.callableInterface);
137-
const methodCalls = new Set<MethodCall>();
138-
const drNameParameter = new MethodParameter(2, ParameterType.DR_NAME);
139-
const ipNameParameter = new MethodParameter(1, ParameterType.IP_NAME);
140-
methodCalls.add(new MethodCall('DRGlobal', 'process', this.namespace, drNameParameter));
141-
methodCalls.add(new MethodCall('DRGlobal', 'processObjectsJSON', this.namespace, drNameParameter));
142-
methodCalls.add(new MethodCall('DRGlobal', 'processString', this.namespace, drNameParameter));
143-
methodCalls.add(new MethodCall('DRGlobal', 'processFromApex', this.namespace, drNameParameter));
144-
methodCalls.add(
145-
new MethodCall('IntegrationProcedureService', 'runIntegrationService', this.namespace, ipNameParameter)
146-
);
138+
const methodCalls = this.prepareMethodCall();
147139
const parser = new ApexASTParser(fileContent, interfaces, methodCalls, this.namespace);
148140
parser.parse();
149141
const tokenUpdates: TokenUpdater[] = [];
150142
const tokenUpdatesForRemoteCalls = this.processApexFileForRemotecalls(file, parser);
151-
const ipNameUpdateFailed = new Set<string>();
143+
const ipNameUpdateFailed = new Set<string | number>();
152144
const dmNameUpdateFailed = new Set<string>();
153145
const tokenUpdatesForMethodCalls = this.processApexFileForMethodCalls(file, parser, ipNameUpdateFailed);
154146
const tokenUpdatesForSimpleVarDeclarations = this.processApexFileForSimpleVarDeclarations(
@@ -157,7 +149,11 @@ export class ApexMigration extends BaseRelatedObjectMigration {
157149
dmNameUpdateFailed
158150
);
159151
const updateMessages: string[] = [];
152+
let status: 'Ready for migration' | 'Failed' | 'Complete' | 'Needs manual intervention' | 'Skipped' =
153+
type === 'migration' ? 'Complete' : 'Ready for migration';
160154

155+
let methodCallsUpdated = false;
156+
let simpleVarDeclarationsUpdated = false;
161157
if (tokenUpdatesForRemoteCalls && tokenUpdatesForRemoteCalls.length > 0) {
162158
tokenUpdates.push(...tokenUpdatesForRemoteCalls);
163159
if (type === 'migration') {
@@ -167,48 +163,57 @@ export class ApexMigration extends BaseRelatedObjectMigration {
167163
}
168164
}
169165
if (tokenUpdatesForMethodCalls && tokenUpdatesForMethodCalls.length > 0) {
170-
if (type === 'migration') {
171-
updateMessages.push(migrateMessages.getMessage('fileUpdatedToAllowCalls'));
172-
} else {
173-
updateMessages.push(assessMessages.getMessage('fileUpdatedToAllowCalls'));
174-
}
166+
methodCallsUpdated = true;
175167
tokenUpdates.push(...tokenUpdatesForMethodCalls);
176168
}
177169

178170
if (tokenUpdatesForSimpleVarDeclarations && tokenUpdatesForSimpleVarDeclarations.length > 0) {
179-
if (type === 'migration') {
180-
updateMessages.push(migrateMessages.getMessage('varDeclarationUpdated'));
181-
} else {
182-
updateMessages.push(assessMessages.getMessage('varDeclarationUpdated'));
183-
}
171+
simpleVarDeclarationsUpdated = true;
184172
tokenUpdates.push(...tokenUpdatesForSimpleVarDeclarations);
185173
}
186174

187175
const warnings: string[] = [];
188176

189177
if (ipNameUpdateFailed.size > 0) {
190-
ipNameUpdateFailed.forEach((name) => {
191-
warnings.push(assessMessages.getMessage('ipNameUpdateFailed', [name]));
178+
ipNameUpdateFailed.forEach((nameOrLine: string | number) => {
179+
if (typeof nameOrLine === 'number') {
180+
warnings.push(assessMessages.getMessage('ipNameUpdateFailed', [nameOrLine]));
181+
} else {
182+
warnings.push(assessMessages.getMessage('ipNameReferenceNotFound'));
183+
}
192184
});
185+
status = type === 'migration' ? 'Skipped' : 'Needs manual intervention';
193186
}
194187
if (dmNameUpdateFailed.size > 0) {
195-
dmNameUpdateFailed.forEach((name) => {
196-
warnings.push(assessMessages.getMessage('dmNameUpdateFailed', [name]));
188+
dmNameUpdateFailed.forEach((nameOrLine: string | number) => {
189+
if (typeof nameOrLine === 'number') {
190+
warnings.push(assessMessages.getMessage('dmNameUpdateFailed', [nameOrLine]));
191+
} else {
192+
warnings.push(assessMessages.getMessage('dmNameReferenceNotFound'));
193+
}
197194
});
195+
status = type === 'migration' ? 'Skipped' : 'Needs manual intervention';
198196
}
199197

200-
let difference = [];
201-
if (tokenUpdates && tokenUpdates.length > 0) {
202-
const updatedContent = parser.rewrite(tokenUpdates);
203-
// Only write file changes if we're in migration mode, not assessment mode
204-
if (type === 'migration') {
205-
fs.writeFileSync(file.location, updatedContent);
206-
Logger.logger.info(migrateMessages.getMessage('apexFileChangesApplied', [file.name]));
207-
} else {
208-
Logger.logger.info(assessMessages.getMessage('apexFileChangesIdentifiedNotApplied', [file.name]));
198+
if (!ipNameUpdateFailed?.size && !dmNameUpdateFailed?.size) {
199+
if (methodCallsUpdated) {
200+
updateMessages.push(
201+
type === 'migration'
202+
? migrateMessages.getMessage('fileUpdatedToAllowCalls')
203+
: assessMessages.getMessage('fileUpdatedToAllowCalls')
204+
);
205+
}
206+
207+
if (simpleVarDeclarationsUpdated) {
208+
updateMessages.push(
209+
type === 'migration'
210+
? migrateMessages.getMessage('varDeclarationUpdated')
211+
: assessMessages.getMessage('varDeclarationUpdated')
212+
);
209213
}
210-
difference = new FileDiffUtil().getFileDiff(file.name, fileContent, updatedContent);
211214
}
215+
216+
const difference = this.getDifferences(tokenUpdates, parser, file, type, fileContent);
212217
if (updateMessages.length === 0) {
213218
Logger.info(assessMessages.getMessage('fileNoOmnistudioCalls', [file.name]));
214219
}
@@ -220,11 +225,12 @@ export class ApexMigration extends BaseRelatedObjectMigration {
220225
infos: updateMessages,
221226
path: file.location,
222227
diff: JSON.stringify(difference),
228+
status,
223229
};
224230
}
225231
private processApexFileForSimpleVarDeclarations(
226232
parser: ApexASTParser,
227-
ipNameUpdateFailed: Set<string>,
233+
ipNameUpdateFailed: Set<string | number>,
228234
dmNameUpdateFailed: Set<string>
229235
): TokenUpdater[] {
230236
const simpleVarDeclarations = parser.simpleVarDeclarations;
@@ -235,6 +241,7 @@ export class ApexMigration extends BaseRelatedObjectMigration {
235241
for (const varName of dmVarInMethodCalls) {
236242
const varToken = simpleVarDeclarations.get(varName);
237243
if (!varToken) {
244+
Logger.logVerbose(`ERROR: dm variable reference not found: ${varName}`);
238245
dmNameUpdateFailed.add(varName);
239246
continue;
240247
}
@@ -251,13 +258,15 @@ export class ApexMigration extends BaseRelatedObjectMigration {
251258
for (const varName of ipVarInMethodCalls) {
252259
const varToken = simpleVarDeclarations.get(varName);
253260
if (!varToken) {
261+
Logger.logVerbose(`ERROR: ip variable reference not found: ${varName}`);
254262
ipNameUpdateFailed.add(varName);
255263
continue;
256264
}
257265
const oldName = varToken.text.substring(1, varToken.text.length - 1);
258266
const parts = oldName.split('_');
259267
if (parts.length !== 2) {
260-
ipNameUpdateFailed.add(varName);
268+
Logger.logVerbose(`ERROR: ip variable reference can't be updated: ${varName}`);
269+
ipNameUpdateFailed.add(varToken.line);
261270
continue;
262271
}
263272
const newName = `'${nameRegistry.getIntegrationProcedureCleanedName(oldName)}'`;
@@ -361,11 +370,11 @@ export class ApexMigration extends BaseRelatedObjectMigration {
361370
private processApexFileForMethodCalls(
362371
file: File,
363372
parser: ApexASTParser,
364-
ipNameUpdateFailed: Set<string>
373+
ipNameUpdateFailed: Set<string | number>
365374
): TokenUpdater[] {
366375
const namespaceChanges = parser.namespaceChanges;
367376
const tokenUpdates: TokenUpdater[] = [];
368-
if (namespaceChanges && namespaceChanges.has(this.namespace)) {
377+
if (namespaceChanges && namespaceChanges.has(this.namespace) && this.namespace !== this.updatedNamespace) {
369378
for (const tokenChange of namespaceChanges.get(this.namespace))
370379
tokenUpdates.push(new SingleTokenUpdate(this.updatedNamespace, tokenChange));
371380
}
@@ -389,7 +398,7 @@ export class ApexMigration extends BaseRelatedObjectMigration {
389398
const oldName = token.text;
390399
const parts = oldName.split('_');
391400
if (parts.length !== 2) {
392-
ipNameUpdateFailed.add(oldName);
401+
ipNameUpdateFailed.add(token.line);
393402
continue;
394403
}
395404
const newName = `'${nameRegistry.getIntegrationProcedureCleanedName(oldName)}'`;
@@ -430,6 +439,43 @@ export class ApexMigration extends BaseRelatedObjectMigration {
430439
}
431440
`;
432441
}
442+
443+
private prepareMethodCall(): Set<MethodCall> {
444+
const drNameParameter = new MethodParameter(2, ParameterType.DR_NAME);
445+
const ipNameParameter = new MethodParameter(1, ParameterType.IP_NAME);
446+
447+
const methodCalls = new Set<MethodCall>();
448+
methodCalls.add(new MethodCall('DRGlobal', 'process', this.namespace, drNameParameter));
449+
methodCalls.add(new MethodCall('DRGlobal', 'processObjectsJSON', this.namespace, drNameParameter));
450+
methodCalls.add(new MethodCall('DRGlobal', 'processString', this.namespace, drNameParameter));
451+
methodCalls.add(new MethodCall('DRGlobal', 'processFromApex', this.namespace, drNameParameter));
452+
methodCalls.add(
453+
new MethodCall('IntegrationProcedureService', 'runIntegrationService', this.namespace, ipNameParameter)
454+
);
455+
return methodCalls;
456+
}
457+
458+
private getDifferences(
459+
tokenUpdates: TokenUpdater[],
460+
parser: ApexASTParser,
461+
file: File,
462+
type: string,
463+
fileContent: string
464+
): DiffPair[] {
465+
let difference: DiffPair[] = [];
466+
if (tokenUpdates && tokenUpdates.length > 0) {
467+
const updatedContent = parser.rewrite(tokenUpdates);
468+
// Only write file changes if we're in migration mode, not assessment mode
469+
if (type === 'migration') {
470+
fs.writeFileSync(file.location, updatedContent);
471+
Logger.logger.info(migrateMessages.getMessage('apexFileChangesApplied', [file.name]));
472+
} else {
473+
Logger.logger.info(assessMessages.getMessage('apexFileChangesIdentifiedNotApplied', [file.name]));
474+
}
475+
difference = new FileDiffUtil().getFileDiff(file.name, fileContent, updatedContent);
476+
}
477+
return difference;
478+
}
433479
/*
434480
private mapTOName(apexAssessmentInfos: ApexAssessmentInfo[]): string[] {
435481
return apexAssessmentInfos.map((apexAssessmentInfo) => {

src/utils/interfaces.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export interface FileChangeInfo {
9292
export interface ApexAssessmentInfo extends FileChangeInfo {
9393
warnings: string[];
9494
infos: string[];
95+
status: 'Ready for migration' | 'Failed' | 'Skipped' | 'Complete' | 'Needs manual intervention' | 'Warnings';
9596
}
9697

9798
export interface FileParser {

src/utils/resultsbuilder/ApexAssessmentReporter.ts

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,23 @@ export class ApexAssessmentReporter {
3737
return [
3838
{
3939
name: 'Ready for migration',
40-
count: apexAssessmentInfos.filter(
41-
(apexAssessmentInfo) => this.getMigrationStatus(apexAssessmentInfo) === 'Ready for migration'
42-
).length,
40+
count: apexAssessmentInfos.filter((apexAssessmentInfo) => apexAssessmentInfo.status === 'Ready for migration')
41+
.length,
4342
cssClass: 'text-success',
4443
},
4544
{
4645
name: 'Warnings',
47-
count: apexAssessmentInfos.filter((info) => this.getMigrationStatus(info) === 'Warnings').length,
46+
count: apexAssessmentInfos.filter((info) => info.status === 'Warnings').length,
4847
cssClass: 'text-warning',
4948
},
5049
{
5150
name: 'Needs manual intervention',
52-
count: apexAssessmentInfos.filter((info) => this.getMigrationStatus(info) === 'Needs manual intervention')
53-
.length,
51+
count: apexAssessmentInfos.filter((info) => info.status === 'Needs manual intervention').length,
5452
cssClass: 'text-error',
5553
},
5654
{
5755
name: 'Failed',
58-
count: apexAssessmentInfos.filter((info) => this.getMigrationStatus(info) === 'Failed').length,
56+
count: apexAssessmentInfos.filter((info) => info.status === 'Failed').length,
5957
cssClass: 'text-error',
6058
},
6159
];
@@ -74,8 +72,7 @@ export class ApexAssessmentReporter {
7472
false,
7573
undefined,
7674
undefined,
77-
this.getMigrationStatus(apexAssessmentInfo) === 'Needs manual intervention' ||
78-
this.getMigrationStatus(apexAssessmentInfo) === 'Failed'
75+
apexAssessmentInfo.status === 'Needs manual intervention' || apexAssessmentInfo.status === 'Failed'
7976
? 'invalid-icon'
8077
: ''
8178
),
@@ -91,14 +88,14 @@ export class ApexAssessmentReporter {
9188
),
9289
createRowDataParam(
9390
'status',
94-
this.getMigrationStatus(apexAssessmentInfo),
91+
apexAssessmentInfo.status,
9592
false,
9693
1,
9794
1,
9895
false,
9996
undefined,
100-
this.getMigrationStatus(apexAssessmentInfo),
101-
this.getMigrationStatusCssClass(apexAssessmentInfo)
97+
apexAssessmentInfo.status,
98+
this.getMigrationStatusCssClass(apexAssessmentInfo.status)
10299
),
103100
createRowDataParam(
104101
'diff',
@@ -134,13 +131,16 @@ export class ApexAssessmentReporter {
134131
],
135132
}));
136133
}
137-
private static getMigrationStatusCssClass(apexAssessmentInfo: ApexAssessmentInfo, noClassForSuccess = false): string {
138-
if (apexAssessmentInfo.errors && apexAssessmentInfo.errors.length > 0) {
139-
return 'text-error';
140-
}
141-
if (apexAssessmentInfo.warnings && apexAssessmentInfo.warnings.length > 0) {
142-
return 'text-warning';
134+
private static getMigrationStatusCssClass(status: string, noClassForSuccess = false): string {
135+
switch (status) {
136+
case 'Warnings':
137+
return 'text-warning';
138+
case 'Needs manual intervention':
139+
return 'text-error';
140+
case 'Failed':
141+
return 'text-error';
143142
}
143+
144144
return noClassForSuccess ? '' : 'text-success';
145145
}
146146

@@ -149,7 +149,7 @@ export class ApexAssessmentReporter {
149149
return [];
150150
}
151151

152-
const distinctStatuses = [...new Set(apexAssessmentInfos.map((info) => this.getMigrationStatus(info)))];
152+
const distinctStatuses = Array.from(new Set(apexAssessmentInfos.map((info) => info.status)));
153153
const statusFilterGroupParam: FilterGroupParam[] =
154154
distinctStatuses.length > 0 && distinctStatuses.filter((status) => status).length > 0
155155
? [createFilterGroupParam('Filter By Assessment Status', 'status', distinctStatuses)]
@@ -196,14 +196,4 @@ export class ApexAssessmentReporter {
196196
},
197197
];
198198
}
199-
200-
private static getMigrationStatus(apexAssessmentInfo: ApexAssessmentInfo): string {
201-
if (apexAssessmentInfo.errors && apexAssessmentInfo.errors.length > 0) {
202-
return 'Failed';
203-
}
204-
if (apexAssessmentInfo.warnings && apexAssessmentInfo.warnings.length > 0) {
205-
return 'Warnings';
206-
}
207-
return 'Ready for migration';
208-
}
209199
}

0 commit comments

Comments
 (0)