Skip to content

Commit 6125f29

Browse files
Merge branch 'release260' into metadataEnablementEnhancements
2 parents 958e61e + d98239d commit 6125f29

File tree

22 files changed

+1169
-122
lines changed

22 files changed

+1169
-122
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
# OmniStudio Migration Assistant
1+
# Omnistudio Migration Assistant
22

33
The Omnistudio Migration Assistant is a Salesforce CLI plugin that automates the migration of Omnistudio components. When run on a custom data model with managed package runtime, it migrates components to the standard data model and switches them to the Omnistudio standard runtime. When run on a standard data model with managed package, it cleans record names, enables the metadata API, and switches to the Omnistudio standard runtime.
44

5-
### Before You Begin
5+
## 🚀 Before You Begin
6+
7+
⚠️ IMPORTANT: Before installing and using the Omnistudio Migration Assistant, contact Salesforce support.
68

79
- Review the migration phases in [Migration Process from Omnistudio for Managed Packages to Omnistudio](https://help.salesforce.com/s/articleView?id=xcloud.os_migrate_omnistudio_custom_objects_to_standard_objects.htm&language=en_US&type=5)
810

@@ -32,7 +34,7 @@ You can also authenticate using a consumer key (client ID) and secret key throug
3234
3. In a new terminal session, Install the Omnistudio Migration Assistant by running the `sf plugins install` command. For example
3335

3436
```
35-
sf plugins install @salesforce/[email protected]rc.43
37+
sf plugins install @salesforce/[email protected]dev.1
3638
```
3739

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

messages/assess.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@
4646
"allVersionsInfo": "All versions: %s",
4747
"assessmentInitialization": "Assessment process started. Using namespace: %s",
4848
"apiVersionInfo": "API version: %s",
49-
"unknownNamespace": "Org doesn't have Omnistudio namespace(s) configured",
50-
"noOmniStudioLicenses": "OmniStudio licenses are not found in the org. OmniStudio licenses are required for migration assessment",
49+
"unknownNamespace": "Omnistudio namespace is not configured in this org. Configure the namespace and try again",
50+
"noOmniStudioLicenses": "We couldn’t find Omnistudio licenses in this org. Omnistudio licenses are required for migration assessment",
5151
"assessmentTargets": "Assessment targets: %s",
5252
"relatedObjectsInfo": "Related objects: %s",
5353
"allVersionsFlagInfo": "All versions: %s",
@@ -199,4 +199,5 @@
199199
"assessmentSuccessfulMessage": "Migration assessment for org %s is complete and reports are ready for review in the folder %s",
200200
"errorCheckingOmniStudioMetadata": "Error while checking the Omnistudio settings metadata status: %s.",
201201
"omniStudioSettingsMetadataAlreadyEnabled": "The Omnistudio Metadata setting is already enabled with standard data model. No need for migration."
202+
"missingMandatoryField": "Missing mandatory field: %s for %s"
202203
}

messages/info.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
"greetingOrgInfo": "Hello %s! This is org: %s",
1313
"greetingOrgInfoWithDate": "Hello %s! This is org: %s and I will be around until %s!",
1414
"hubOrgId": "My hub org id is: %s",
15-
"allVersionsAppended": " and all versions will be migrated"
15+
"allVersionsAppended": " and all versions will be migrated",
16+
"errorRunningInfo": "Error occurred while running info command"
1617
}

messages/migrate.json

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
"processingLwcsForMigration": "Processing LWCs for migration",
7474
"successfullyProcessedLwcsForMigration": "Successfully processed %s LWCs for migration",
7575
"lwcMigrationResults": "LWC migration results: %s",
76-
"retrievingMetadata": "Retrieving metadata for %s in project path: %s",
76+
"retrievingMetadata": "Retrieving metadata for %s for : %s",
7777
"creatingProject": "Creating project %s",
7878
"projectCreated": "Project %s created",
7979
"metadataRetrieved": "Metadata %s retrieved from %s",
@@ -200,7 +200,7 @@
200200
"skippingAsAngularDependencies": "(%s skipped due to Angular dependencies)",
201201
"noMetadataToDeploy": "No metadata to deploy",
202202
"missingMandatoryField": "Missing mandatory field: %s for %s",
203-
"dataMapperMigrationFailed": "DataMapper migration failed for: %s",
203+
"dataMapperMigrationFailed": "DataMapper migration failed for: %s ",
204204
"dataMapperNameStartsWithNumber": "DataMapper name '%s' starts with a number which causes migration issues. Proposed new name: %s",
205205
"integrationProcedureTypeEmptyAfterCleaning": "Integration Procedure Type '%s' becomes empty after name cleaning. Please provide a valid Type value.",
206206
"integrationProcedureSubtypeEmptyAfterCleaning": "Integration Procedure SubType '%s' becomes empty after name cleaning. Please provide a valid SubType value.",
@@ -247,6 +247,45 @@
247247
"generatedCustomLabelAssessmentReportPage": "Generated custom label assessment report page %s of %s with %s labels",
248248
"varDeclarationUpdated": "Variable initialization has been updated for target name",
249249
"migrationSuccessfulMessage": "Migration process for org %s is complete and reports are ready for review in the folder %s",
250+
"elementValueMapUnexpectedType": "ElementValueMap has unexpected data type '%s' for element '%s'. Expected object format.",
251+
"errorProcessingFormulaInElement": "Error processing formula for key '%s' in element '%s': %s",
252+
"errorProcessingElementValueMap": "Error processing elementValueMap in Integration Procedure element '%s': %s",
253+
"startingOmniscriptPackageDeployment": "Starting deployment of omniscript customization package...",
254+
"omniscriptPackageDeploymentStarted": "Omniscript package deployment started with ID: %s",
255+
"omniscriptPackageIntegrated": "Omniscript customization package deployed successfully",
256+
"pollingDeploymentStatus": "Polling deployment status for ID: %s (attempt %s/%s)",
257+
"deploymentStatusUpdate": "Deployment %s status: %s - %s%% complete",
258+
"deploymentInProgress": "Deployment in progress... Elapsed: %s, Estimated remaining: %s",
259+
"deploymentCompleted": "Omniscript package deployment completed successfully in %s",
260+
"deploymentFailed": "Omniscript package deployment failed: %s",
261+
"deploymentCancelled": "Omniscript package deployment was cancelled",
262+
"deploymentTimedOut": "Omniscript package deployment timed out after %s minutes",
263+
"retryingDeployment": "Retrying deployment due to %s (attempt %s/%s)",
264+
"deploymentRetryExhausted": "Maximum retry attempts (%s) exceeded for omniscript package deployment",
265+
"extractingDeploymentId": "Extracting deployment ID from command output...",
266+
"deploymentIdNotFound": "Could not extract deployment ID from deployment response",
267+
"checkingDeploymentStatus": "Checking deployment status for ID: %s",
268+
"deploymentStatusCheckFailed": "Failed to check deployment status: %s",
269+
"deploymentStatusCheckExhausted": "Failed to check deployment status after %s attempts: %s",
270+
"errorIntegratingOmniscriptPackage": "Error occurred while integrating omniscript customization package",
271+
"omniscriptPackageDeploymentError": "Omniscript package deployment error details: %s",
272+
"omniscriptPackagePathNotFound": "Omniscript customization package not found at: %s",
273+
"asyncDeploymentStart": "Starting async deployment for source directory: %s",
274+
"asyncDeploymentStatusCheck": "Checking async deployment status for ID: %s",
275+
"deploymentProgressDetails": "Components deployed: %s/%s, Errors: %s, Warnings: %s",
276+
"waitingForDeploymentCompletion": "Waiting for omniscript package deployment completion before proceeding...",
277+
"deploymentSkipped": "Deployment skipped - autoDeploy is disabled or package.xml not found",
278+
"deployOmniscriptPackageManually": "Omniscript customization package deployment failed. Please deploy the omniscript unmanaged package components manually before deploying your migrated metadata components. Please check the documentation <a href='%s' target='_blank'>link</a> for manual steps",
279+
"deployComponentsManually": "Metadata Components deployment failed. Please deploy using generated package.xml manually using Salesforce CLI or Workbench. Check the logs for detailed error information.",
280+
"omniscriptDeploymentFailedContinuing": "Omniscript package deployment failed, continuing with report generation. Manual deployment required.",
281+
"deploymentFailedContinuing": "Deployment failed, continuing with report generation. Manual deployment required.",
282+
"ensurePackageInstalled": "Please ensure omniscript customization package is properly installed: %s",
283+
"packageDeploymentFailedWithError": "Omniscript package deployment failed after %s attempts. Error: %s. Please check deployment logs and org settings.",
284+
"maxRetryAttemptsExceeded": "Maximum retry attempts (%s) exceeded for omniscript package deployment",
285+
"deploymentNonRetryableError": "Deployment failed with non-retryable error: %s. Please review and fix the issue manually",
286+
"deploymentTriggeredSuccessfully": "Please monitor your Deployment: %s using deployment status page in Org",
287+
"omniscriptPackageDeploymentFailedReturnedFalse": "Omniscript package deployment failed - deployment returned false. This may be due to missing package, permissions, or deployment timeout.",
288+
"omniscriptPackageDeploymentFailedWithMessage": "Omniscript package deployment failed: %s",
250289
"metadataTablesAlreadyClean": "OmniStudio metadata tables are empty",
251290
"startingMetadataCleanup": "Initiated cleanup process for Omnistudio metadata tables.",
252291
"failedToCleanTables": "Table cleanup failed: %s, Please contact Salesforce Support.",

src/commands/omnistudio/migration/migrate.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,12 @@ export default class Migrate extends OmniStudioBaseCommand {
241241
);
242242

243243
try {
244-
postMigrate.deploy();
244+
await postMigrate.deploy(actionItems);
245245
} catch (error) {
246246
Logger.error(messages.getMessage('errorDeployingComponents'), error);
247247
Logger.logVerbose(error);
248+
// Even if deployment fails completely, continue with report generation
249+
// Action items are already added to the array by the deploy method
248250
}
249251

250252
await ResultsBuilder.generateReport(

src/error/deploymentErrors.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Custom error classes for deployment failures
3+
*/
4+
5+
/**
6+
* Error thrown when omniscript package deployment fails
7+
*/
8+
export class OmniscriptPackageDeploymentError extends Error {
9+
public constructor(message: string) {
10+
super(message);
11+
this.name = 'OmniscriptPackageDeploymentError';
12+
13+
// Maintains proper stack trace for where our error was thrown (only available on V8)
14+
if (Error.captureStackTrace) {
15+
Error.captureStackTrace(this, OmniscriptPackageDeploymentError);
16+
}
17+
}
18+
}
19+
20+
/**
21+
* Error thrown when general deployment fails
22+
*/
23+
export class DeploymentError extends Error {
24+
public constructor(message: string) {
25+
super(message);
26+
this.name = 'DeploymentError';
27+
28+
// Maintains proper stack trace for where our error was thrown (only available on V8)
29+
if (Error.captureStackTrace) {
30+
Error.captureStackTrace(this, DeploymentError);
31+
}
32+
}
33+
}

src/migration/dataraptor.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,6 @@ export class DataRaptorMigrationTool extends BaseMigrationTool implements Migrat
179179
continue;
180180
}
181181

182-
duplicatedNames.add(transformedDataRaptor['Name']);
183-
184182
// Create a map of the original records
185183
originalDrRecords.set(recordId, dr);
186184

@@ -210,9 +208,12 @@ export class DataRaptorMigrationTool extends BaseMigrationTool implements Migrat
210208

211209
// Always add the response to track success/failure
212210
if (drUploadResponse && drUploadResponse.success === true) {
213-
const items = await this.getItemsForDataRaptor(dataRaptorItemsData, name, drUploadResponse.id);
211+
// Append the processed DM name into duplicateNames Map
212+
const dataMapperName = transformedDataRaptor[DRBundleMappings.Name];
213+
duplicatedNames.add(dataMapperName);
214214

215-
drUploadResponse.newName = transformedDataRaptor[DRBundleMappings.Name];
215+
const items = await this.getItemsForDataRaptor(dataRaptorItemsData, name, drUploadResponse.id);
216+
drUploadResponse.newName = dataMapperName;
216217

217218
// Move the items
218219
if (!this.IS_STANDARD_DATA_MODEL) {
@@ -234,13 +235,17 @@ export class DataRaptorMigrationTool extends BaseMigrationTool implements Migrat
234235
}
235236
} else {
236237
// Handle failed migration - add error information
237-
if (!drUploadResponse) {
238+
if (!drUploadResponse?.success) {
239+
Logger.logVerbose(
240+
`\n${this.messages.getMessage('dataMapperMigrationFailed', [name]) + drUploadResponse.errors}`
241+
);
242+
238243
drUploadResponse = {
239244
referenceId: recordId,
240245
id: '',
241246
success: false,
242247
hasErrors: true,
243-
errors: [this.messages.getMessage('dataMapperMigrationFailed', [name])],
248+
errors: [this.messages.getMessage('dataMapperMigrationFailed', [name]) + drUploadResponse.errors],
244249
warnings: [],
245250
newName: '',
246251
};

src/migration/deployer.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { Messages } from '@salesforce/core';
33
import * as shell from 'shelljs';
44
import { sfProject } from '../utils/sfcli/project/sfProject';
55
import { Logger } from '../utils/logger';
6+
import { OmniscriptPackageManager, OmniscriptPackageConfig } from '../utils/omniscriptPackageManager';
7+
import { OmniscriptPackageDeploymentError } from '../error/deploymentErrors';
68

79
export class Deployer {
810
private readonly projectPath: string;
@@ -11,30 +13,78 @@ export class Deployer {
1113
private readonly omniscriptCustomizationPackageVersion = '250.0.0';
1214
private readonly username: string;
1315
private readonly messages: Messages;
16+
private readonly omniscriptPackageConfig: OmniscriptPackageConfig;
17+
private omniscriptPackageManager?: OmniscriptPackageManager;
1418

1519
public constructor(projectPath: string, messages: Messages, username: string, authKey: string) {
1620
this.projectPath = projectPath;
1721
this.username = username;
1822
this.messages = messages;
1923
this.authKey = authKey;
24+
25+
// Configure omniscript package settings
26+
this.omniscriptPackageConfig = {
27+
packageName: this.omniscriptCustomizationPackage,
28+
version: this.omniscriptCustomizationPackageVersion,
29+
};
2030
}
2131

22-
public deploy(): void {
32+
public async deploy(): Promise<void> {
2333
const pwd = shell.pwd();
2434
shell.cd(this.projectPath);
35+
2536
try {
37+
// Install dependencies including omniscript customization package
2638
if (this.authKey) {
2739
sfProject.createNPMConfigFile(this.authKey);
2840
Logger.logVerbose(this.messages.getMessage('installingRequiredDependencies'));
2941
sfProject.installDependency();
3042
sfProject.installDependency(
3143
`${this.omniscriptCustomizationPackage}@${this.omniscriptCustomizationPackageVersion}`
3244
);
45+
46+
// Deploy omniscript customization package separately first
47+
await this.deployOmniscriptPackage();
3348
}
49+
50+
// Deploy the main project after omniscript package deployment succeeds
3451
Logger.log(path.join(pwd.toString(), 'package.xml'));
3552
sfProject.deployFromManifest(path.join(pwd.toString(), 'package.xml'), this.username);
3653
} finally {
3754
shell.cd(pwd);
3855
}
3956
}
57+
58+
private async deployOmniscriptPackage(): Promise<void> {
59+
try {
60+
this.omniscriptPackageManager = new OmniscriptPackageManager(
61+
this.projectPath,
62+
this.omniscriptPackageConfig,
63+
this.username
64+
);
65+
66+
const success = await this.omniscriptPackageManager.deployPackageAsync();
67+
if (success) {
68+
Logger.log(this.messages.getMessage('omniscriptPackageIntegrated'));
69+
} else {
70+
const errorMsg = this.messages.getMessage('omniscriptPackageDeploymentFailedReturnedFalse');
71+
Logger.error(errorMsg);
72+
throw new OmniscriptPackageDeploymentError(
73+
this.messages.getMessage('omniscriptPackageDeploymentFailedWithMessage', [errorMsg])
74+
);
75+
}
76+
} catch (error) {
77+
const errorMessage = error instanceof Error ? error.message : String(error);
78+
Logger.error(this.messages.getMessage('errorIntegratingOmniscriptPackage'), error);
79+
80+
// Re-throw as OmniscriptPackageDeploymentError for consistent error handling upstream
81+
if (error instanceof OmniscriptPackageDeploymentError) {
82+
throw error;
83+
} else {
84+
throw new OmniscriptPackageDeploymentError(
85+
this.messages.getMessage('omniscriptPackageDeploymentFailedWithMessage', [errorMessage])
86+
);
87+
}
88+
}
89+
}
4090
}

0 commit comments

Comments
 (0)