Skip to content

Commit 74b2499

Browse files
fix: @W-19837693: Handling multiple versions migration and assessment for Omniscript and Flexcards
Changes: - Handle of multiple versions having same name pre/post clean up with allVersions - Added logic to check for unique and duplicate based on earlier versions - Added test cases
1 parent 96375ee commit 74b2499

File tree

7 files changed

+1338
-20
lines changed

7 files changed

+1338
-20
lines changed

messages/assess.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616
"couldNotTruncate": "We couldn't clear all %s records.",
1717
"couldNotTruncateOmnniProcess": "We couldn't clear all records of your %s because the %s is referenced in an Omniscript or a Flexcard.",
1818
"invalidOrRepeatingOmniscriptElementNames": "Omniscript with invalid or duplicate element names found. Rename your Omniscript elements and try again.",
19-
"duplicatedCardName": "Flexcard with duplicate name, type, subtype, or language found in this org. Modify your Flexcard and try again.",
19+
"duplicatedCardName": "Flexcard with duplicate name found in this org. Modify your Flexcard and try again.",
2020
"duplicatedDrName": "Data Mapper with duplicate name found in this org. Rename your Data Mapper and try again.",
2121
"duplicatedOSName": "Omniscript with duplicate name, type, subtype, or language found in this org. Modify your Omniscript and try again.",
22-
"duplicatedName": "Duplicated name",
22+
"duplicatedName": "Duplicated name %s",
23+
"lowerVersionDuplicateOmniscriptName": "A %s with name \"%s\" will not be migrated because lower version of same %s is marked as duplicate, which could lead to conflicts during migration.",
2324
"errorWhileActivatingOs": "We couldn't activate your %s:",
2425
"errorWhileActivatingCard": "We couldn't activate your Flexcard:",
2526
"errorWhileUploadingCard": "We couldn't deploy your Flexcard to your org. Review these errors:",
@@ -97,6 +98,7 @@
9798
"integrationProcedureNameChangeMessage": "The Integration Procedure %s will be renamed to %s during migration.",
9899
"integrationProcedureManualUpdateMessage": "All references to %s in this Integration Procedure must be manually updated after migration.",
99100
"duplicateCardNameMessage": "A Flexcard with the same name \"%s\" already exists after name cleaning, which could lead to conflicts during migration.",
101+
"lowerVersionDuplicateCardNameMessage": "A Flexcard with the name \"%s\" will not be migrated because lower version of same card is marked as duplicate, which could lead to conflicts during migration.",
100102
"startingCustomLabelAssessment": "Starting Custom Label assessment",
101103
"assessedCustomLabelsCount": "Found %s labels that need attention out of %s total",
102104
"customLabelAssessmentCompleted": "Custom Label assessment completed",

messages/migrate.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
"couldNotTruncate": "We couldn't clear all %s records.",
2020
"couldNotTruncateOmnniProcess": "We couldn't clear all records of your %s because the %s is referenced in an Omniscript or a Flexcard.",
2121
"invalidOrRepeatingOmniscriptElementNames": "Omniscript with invalid or duplicate element names found. Rename your Omniscript elements and try again.",
22-
"duplicatedCardName": "Flexcard with duplicate name, type, subtype, or language found in this org. Modify your Flexcard and try again.",
22+
"lowerVersionDuplicateCardName": "Flexcard with name %s can't be migrated because lower version of same card is marked as duplicate. Rename your Flexcard and try again.",
23+
"duplicatedCardName": "Flexcard with duplicate name %s found in this org. Rename your Flexcard and try again.",
2324
"duplicatedDrName": "Data Mapper with duplicate name found in this org. Rename your Data Mapper and try again.",
2425
"duplicatedOSName": "Omniscript with duplicate name, type, subtype, or language found in this org. Modify your Omniscript and try again.",
26+
"lowerVersionDuplicateOSName": "%s with name %s can't be migrated because lower version of same %s is marked as duplicate. Rename your %s and try again.",
2527
"errorWhileActivatingOs": "We couldn't activate your %s:",
2628
"errorWhileActivatingCard": "We couldn't activate your Flexcard:",
2729
"errorWhileUploadingCard": "We couldn't deploy your Flexcard to your org. Review these errors:",

src/migration/flexcard.ts

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,12 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
165165
const progressBar = createProgressBar('Assessing', 'Flexcards');
166166
progressBar.start(flexCards.length, progressCounter);
167167
const uniqueNames = new Set<string>();
168+
const dupFlexCardNames: Set<string> = new Set<string>();
168169

169170
// Now process each OmniScript and its elements
170171
for (const flexCard of flexCards) {
171172
try {
172-
const flexCardAssessmentInfo = await this.processFlexCard(flexCard, uniqueNames);
173+
const flexCardAssessmentInfo = await this.processFlexCard(flexCard, uniqueNames, dupFlexCardNames);
173174
flexCardAssessmentInfos.push(flexCardAssessmentInfo);
174175
} catch (e) {
175176
flexCardAssessmentInfos.push({
@@ -196,7 +197,11 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
196197
return flexCardAssessmentInfos;
197198
}
198199

199-
private async processFlexCard(flexCard: AnyJson, uniqueNames: Set<string>): Promise<FlexCardAssessmentInfo> {
200+
private async processFlexCard(
201+
flexCard: AnyJson,
202+
uniqueNames: Set<string>,
203+
dupFlexCardNames: Set<String>
204+
): Promise<FlexCardAssessmentInfo> {
200205
const flexCardName = flexCard['Name'];
201206
Logger.info(this.messages.getMessage('processingFlexCard', [flexCardName]));
202207
const version = flexCard[this.namespacePrefix + CardMigrationTool.VERSION_PROP];
@@ -230,11 +235,23 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
230235
}
231236

232237
// Check for duplicate names (include version when allVersions is true)
238+
// A Set that can only store original flexcard names to avoid conflicts with cleaned name
233239
const uniqueCleanedName = this.allVersions ? `${cleanedName}_${version}` : cleanedName;
234-
if (uniqueNames.has(uniqueCleanedName)) {
235-
flexCardAssessmentInfo.warnings.push(this.messages.getMessage('duplicateCardNameMessage', [uniqueCleanedName]));
240+
if (uniqueNames.has(uniqueCleanedName) || dupFlexCardNames.has(originalName)) {
241+
// Add the original flexcard name to the set
242+
if (this.allVersions && !dupFlexCardNames.has(originalName)) {
243+
dupFlexCardNames.add(originalName);
244+
}
245+
if (uniqueNames.has(uniqueCleanedName)) {
246+
flexCardAssessmentInfo.warnings.push(this.messages.getMessage('duplicateCardNameMessage', [uniqueCleanedName]));
247+
} else {
248+
flexCardAssessmentInfo.warnings.push(
249+
this.messages.getMessage('lowerVersionDuplicateCardNameMessage', [uniqueCleanedName])
250+
);
251+
}
236252
assessmentStatus = getUpdatedAssessmentStatus(assessmentStatus, 'Needs manual intervention');
237253
}
254+
238255
uniqueNames.add(uniqueCleanedName);
239256

240257
// Check for author name changes
@@ -721,11 +738,12 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
721738
const cardsUploadInfo = new Map<string, UploadRecordResult>();
722739
const originalRecords = new Map<string, any>();
723740
const uniqueNames = new Set<string>();
741+
const dupFlexCardNames: Set<string> = new Set<string>();
724742

725743
let progressCounter = 0;
726744
progressBar.start(cards.length, progressCounter);
727745
for (let card of cards) {
728-
await this.uploadCard(cards, card, cardsUploadInfo, originalRecords, uniqueNames);
746+
await this.uploadCard(cards, card, cardsUploadInfo, originalRecords, uniqueNames, dupFlexCardNames);
729747
progressBar.update(++progressCounter);
730748
}
731749

@@ -741,7 +759,8 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
741759
card: AnyJson,
742760
cardsUploadInfo: Map<string, UploadRecordResult>,
743761
originalRecords: Map<string, any>,
744-
uniqueNames: Set<string>
762+
uniqueNames: Set<string>,
763+
dupFlexCardNames: Set<String>
745764
) {
746765
const recordId = card['Id'];
747766

@@ -758,7 +777,7 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
758777
// Upload child cards
759778
const childCard = allCards.find((c) => c['Name'] === childCardName);
760779
if (childCard) {
761-
await this.uploadCard(allCards, childCard, cardsUploadInfo, originalRecords, uniqueNames);
780+
await this.uploadCard(allCards, childCard, cardsUploadInfo, originalRecords, uniqueNames, dupFlexCardNames);
762781
}
763782
}
764783

@@ -783,8 +802,16 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
783802
? `${transformedCard['Name']}_${transformedCard['VersionNumber']}`
784803
: transformedCard['Name'];
785804

786-
if (uniqueNames.has(uniqueCheckName)) {
787-
this.setRecordErrors(card, this.messages.getMessage('duplicatedCardName', [uniqueCheckName]));
805+
if (uniqueNames.has(uniqueCheckName) || dupFlexCardNames.has(transformedCard['Name'])) {
806+
if (this.allVersions && !dupFlexCardNames.has(transformedCard['Name'])) {
807+
dupFlexCardNames.add(transformedCard['Name']);
808+
}
809+
// change error message
810+
if (uniqueNames.has(uniqueCheckName)) {
811+
this.setRecordErrors(card, this.messages.getMessage('duplicatedCardName', [uniqueCheckName]));
812+
} else {
813+
this.setRecordErrors(card, this.messages.getMessage('lowerVersionDuplicateCardName', [uniqueCheckName]));
814+
}
788815
originalRecords.set(recordId, card);
789816
return;
790817
}

src/migration/omniscript.ts

Lines changed: 77 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
238238
const ipAssessmentInfos: IPAssessmentInfo[] = [];
239239

240240
// Create a set to store existing OmniScript names and also extract DataRaptor and FlexCard names
241+
const duplicateOmniscriptNames = new Set<string>();
241242
const existingOmniscriptNames = new Set<string>();
242243
const existingDataRaptorNames = new Set(dataRaptorAssessmentInfos.map((info) => info.name));
243244
const existingFlexCardNames = new Set(flexCardAssessmentInfos.map((info) => info.name));
@@ -256,7 +257,8 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
256257
omniscript,
257258
existingOmniscriptNames,
258259
existingDataRaptorNames,
259-
existingFlexCardNames
260+
existingFlexCardNames,
261+
duplicateOmniscriptNames
260262
);
261263
} catch (e) {
262264
const omniProcessType = omniscript[this.namespacePrefix + 'IsProcedure__c']
@@ -356,7 +358,8 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
356358
omniscript: AnyJson,
357359
existingOmniscriptNames: Set<string>,
358360
existingDataRaptorNames: Set<string>,
359-
existingFlexCardNames: Set<string>
361+
existingFlexCardNames: Set<string>,
362+
duplicateOmniscriptNames: Set<string>
360363
): Promise<OSAssessmentInfo> {
361364
const elements = await this.getAllElementsForOmniScript(omniscript['Id']);
362365

@@ -504,6 +507,11 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
504507
? `${omniscript[this.namespacePrefix + 'Language__c']}`
505508
: '';
506509

510+
const recordNameWithoutVersion =
511+
`${newType}_` +
512+
`${newSubType}` +
513+
(omniscript[this.namespacePrefix + 'Language__c'] ? `_${omniscript[this.namespacePrefix + 'Language__c']}` : '');
514+
507515
const recordName =
508516
`${newType}_` +
509517
`${newSubType}` +
@@ -562,11 +570,47 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
562570
);
563571
assessmentStatus = 'Warnings';
564572
}
565-
if (existingOmniscriptNames.has(recordName)) {
566-
warnings.push(this.messages.getMessage('duplicatedName') + ' ' + recordName);
573+
// Duplicate check logic:
574+
// - When allVersions=false: check without version (using recordNameWithoutVersion)
575+
// - When allVersions=true: check with version (using recordName)
576+
const nameToCheck = this.allVersions ? recordName : recordNameWithoutVersion;
577+
578+
if (existingOmniscriptNames.has(nameToCheck) || duplicateOmniscriptNames.has(recordNameWithoutVersion)) {
579+
// Mark the base name as duplicate for subsequent versions when allVersions=true
580+
if (this.allVersions && !duplicateOmniscriptNames.has(recordNameWithoutVersion)) {
581+
duplicateOmniscriptNames.add(recordNameWithoutVersion);
582+
}
583+
584+
// Message selection logic:
585+
// - When allVersions=false: always use "duplicatedName" (comparing without version)
586+
// - When allVersions=true:
587+
// - If exact match in existingOmniscriptNames (same name+version): use "duplicatedName"
588+
// - If base name in duplicateOmniscriptNames (different version): use "lowerVersionDuplicateOmniscriptName"
589+
let shouldUseDuplicatedNameMessage = false;
590+
591+
if (!this.allVersions) {
592+
// allVersions=false: always use duplicatedName message
593+
shouldUseDuplicatedNameMessage = true;
594+
} else {
595+
// allVersions=true: use duplicatedName only if exact match (same name+version)
596+
shouldUseDuplicatedNameMessage = existingOmniscriptNames.has(recordName);
597+
}
598+
599+
if (shouldUseDuplicatedNameMessage) {
600+
warnings.push(this.messages.getMessage('duplicatedName', [recordName]));
601+
} else {
602+
warnings.push(
603+
this.messages.getMessage('lowerVersionDuplicateOmniscriptName', [
604+
this.getName(true),
605+
recordName,
606+
this.getName(true),
607+
])
608+
);
609+
}
610+
567611
assessmentStatus = 'Needs manual intervention';
568612
} else {
569-
existingOmniscriptNames.add(recordName);
613+
existingOmniscriptNames.add(nameToCheck);
570614
}
571615

572616
// Add warning for duplicate element names within the same OmniScript
@@ -692,6 +736,7 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
692736
populateRegexForFunctionMetadata(functionDefinitionMetadata);
693737

694738
const duplicatedNames = new Set<string>();
739+
const duplicateOmniscriptNames = new Set<string>();
695740

696741
// Variables to be returned After Migration
697742
let originalOsRecords = new Map<string, any>();
@@ -971,9 +1016,18 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
9711016
}
9721017

9731018
// Check duplicated name
974-
let mappedOsName;
1019+
let mappedOsName: string;
1020+
const mappedOsNameWithoutVersion =
1021+
mappedOmniScript[OmniScriptMappings.Type__c] +
1022+
'_' +
1023+
mappedOmniScript[OmniScriptMappings.SubType__c] +
1024+
(mappedOmniScript[OmniScriptMappings.Language__c]
1025+
? '_' + mappedOmniScript[OmniScriptMappings.Language__c]
1026+
: '');
1027+
9751028
if (this.allVersions) {
9761029
mappedOmniScript[OmniScriptMappings.Version__c] = omniscript[`${this.namespacePrefix}Version__c`];
1030+
9771031
mappedOsName =
9781032
mappedOmniScript[OmniScriptMappings.Type__c] +
9791033
'_' +
@@ -994,9 +1048,24 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
9941048
'_1';
9951049
}
9961050

997-
if (duplicatedNames.has(mappedOsName)) {
1051+
if (duplicatedNames.has(mappedOsName) || duplicateOmniscriptNames.has(mappedOsNameWithoutVersion)) {
9981052
originalOsRecords.set(recordId, omniscript);
999-
const warningMessage = this.messages.getMessage('duplicatedOSName', [this.getName(true), mappedOsName]);
1053+
if (this.allVersions && !duplicateOmniscriptNames.has(mappedOsNameWithoutVersion)) {
1054+
duplicateOmniscriptNames.add(mappedOsNameWithoutVersion);
1055+
}
1056+
1057+
let warningMessage: string;
1058+
if (duplicatedNames.has(mappedOsName)) {
1059+
warningMessage = this.messages.getMessage('duplicatedOSName', [this.getName(true), mappedOsName]);
1060+
} else {
1061+
warningMessage = this.messages.getMessage('lowerVersionDuplicateOSName', [
1062+
this.getName(true),
1063+
mappedOsName,
1064+
this.getName(true),
1065+
this.getName(true),
1066+
]);
1067+
}
1068+
10001069
const skippedResponse: UploadRecordResult = {
10011070
referenceId: recordId,
10021071
id: '',

0 commit comments

Comments
 (0)