Skip to content

Commit 131a60b

Browse files
authored
Merge pull request #419 from sf-kishore-kurri/u/kkurri/W-19637353
fix: @W-19637353: Fix for the omnscript unmanaged package deployment issue
2 parents 29799ab + 5090384 commit 131a60b

File tree

14 files changed

+785
-93
lines changed

14 files changed

+785
-93
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 command-line interface (CLI) plugin that you install via Salesforce CLI. It creates records for your omnistudio components on the Salesforce standard objects.
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].43
37+
sf plugins install @salesforce/[email protected].50
3638
```
3739

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

messages/assess.json

Lines changed: 4 additions & 3 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",
@@ -195,5 +195,6 @@
195195
"ipNameUpdateFailed": "IP reference %s can’t be updated",
196196
"dmNameUpdateFailed": "DM reference %s can’t be updated",
197197
"invalidTypeAssessErrorMessage": "We couldn't assess your Omnistudio components in the %s namespace. Select the correct namespace and try again",
198-
"assessmentSuccessfulMessage": "Migration assessment for org %s is complete and reports are ready for review in the folder %s"
198+
"assessmentSuccessfulMessage": "Migration assessment for org %s is complete and reports are ready for review in the folder %s",
199+
"missingMandatoryField": "Missing mandatory field: %s for %s"
199200
}

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: 39 additions & 3 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",
@@ -247,5 +247,41 @@
247247
"migrationSuccessfulMessage": "Migration process for org %s is complete and reports are ready for review in the folder %s",
248248
"elementValueMapUnexpectedType": "ElementValueMap has unexpected data type '%s' for element '%s'. Expected object format.",
249249
"errorProcessingFormulaInElement": "Error processing formula for key '%s' in element '%s': %s",
250-
"errorProcessingElementValueMap": "Error processing elementValueMap in Integration Procedure element '%s': %s"
251-
}
250+
"errorProcessingElementValueMap": "Error processing elementValueMap in Integration Procedure element '%s': %s",
251+
"startingOmniscriptPackageDeployment": "Starting deployment of omniscript customization package...",
252+
"omniscriptPackageDeploymentStarted": "Omniscript package deployment started with ID: %s",
253+
"omniscriptPackageIntegrated": "Omniscript customization package deployed successfully",
254+
"pollingDeploymentStatus": "Polling deployment status for ID: %s (attempt %s/%s)",
255+
"deploymentStatusUpdate": "Deployment %s status: %s - %s%% complete",
256+
"deploymentInProgress": "Deployment in progress... Elapsed: %s, Estimated remaining: %s",
257+
"deploymentCompleted": "Omniscript package deployment completed successfully in %s",
258+
"deploymentFailed": "Omniscript package deployment failed: %s",
259+
"deploymentCancelled": "Omniscript package deployment was cancelled",
260+
"deploymentTimedOut": "Omniscript package deployment timed out after %s minutes",
261+
"retryingDeployment": "Retrying deployment due to %s (attempt %s/%s)",
262+
"deploymentRetryExhausted": "Maximum retry attempts (%s) exceeded for omniscript package deployment",
263+
"extractingDeploymentId": "Extracting deployment ID from command output...",
264+
"deploymentIdNotFound": "Could not extract deployment ID from deployment response",
265+
"checkingDeploymentStatus": "Checking deployment status for ID: %s",
266+
"deploymentStatusCheckFailed": "Failed to check deployment status: %s",
267+
"deploymentStatusCheckExhausted": "Failed to check deployment status after %s attempts: %s",
268+
"errorIntegratingOmniscriptPackage": "Error occurred while integrating omniscript customization package",
269+
"omniscriptPackageDeploymentError": "Omniscript package deployment error details: %s",
270+
"omniscriptPackagePathNotFound": "Omniscript customization package not found at: %s",
271+
"asyncDeploymentStart": "Starting async deployment for source directory: %s",
272+
"asyncDeploymentStatusCheck": "Checking async deployment status for ID: %s",
273+
"deploymentProgressDetails": "Components deployed: %s/%s, Errors: %s, Warnings: %s",
274+
"waitingForDeploymentCompletion": "Waiting for omniscript package deployment completion before proceeding...",
275+
"deploymentSkipped": "Deployment skipped - autoDeploy is disabled or package.xml not found",
276+
"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",
277+
"deployComponentsManually": "Metadata Components deployment failed. Please deploy using generated package.xml manually using Salesforce CLI or Workbench. Check the logs for detailed error information.",
278+
"omniscriptDeploymentFailedContinuing": "Omniscript package deployment failed, continuing with report generation. Manual deployment required.",
279+
"deploymentFailedContinuing": "Deployment failed, continuing with report generation. Manual deployment required.",
280+
"ensurePackageInstalled": "Please ensure omniscript customization package is properly installed: %s",
281+
"packageDeploymentFailedWithError": "Omniscript package deployment failed after %s attempts. Error: %s. Please check deployment logs and org settings.",
282+
"maxRetryAttemptsExceeded": "Maximum retry attempts (%s) exceeded for omniscript package deployment",
283+
"deploymentNonRetryableError": "Deployment failed with non-retryable error: %s. Please review and fix the issue manually",
284+
"deploymentTriggeredSuccessfully": "Please monitor your Deployment: %s using deployment status page in Org",
285+
"omniscriptPackageDeploymentFailedReturnedFalse": "Omniscript package deployment failed - deployment returned false. This may be due to missing package, permissions, or deployment timeout.",
286+
"omniscriptPackageDeploymentFailedWithMessage": "Omniscript package deployment failed: %s"
287+
}

src/commands/omnistudio/migration/migrate.ts

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

229229
try {
230-
postMigrate.deploy();
230+
await postMigrate.deploy(actionItems);
231231
} catch (error) {
232232
Logger.error(messages.getMessage('errorDeployingComponents'), error);
233233
Logger.logVerbose(error);
234+
// Even if deployment fails completely, continue with report generation
235+
// Action items are already added to the array by the deploy method
234236
}
235237

236238
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/NameMappingRegistry.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,9 @@ export class NameMappingRegistry {
151151
public getOmniScriptCleanedName(type: string, subType: string, language: string | 'English'): string {
152152
const originalName = `${type}_${subType}_${language}`;
153153
// Check if we have a mapping for this OmniScript first
154-
if (this.omniScriptMappings.has(originalName)) {
155-
return this.omniScriptMappings.get(originalName)!;
154+
const mappedName = this.omniScriptMappings.get(originalName);
155+
if (mappedName) {
156+
return mappedName;
156157
}
157158
// Fallback to cleaning individual parts
158159
const cleanedType = Stringutil.cleanName(type);

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
}

src/migration/postMigrate.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import { OmnistudioSettingsPrefManager } from '../utils/OmnistudioSettingsPrefMa
1010
import { OrgPreferences } from '../utils/orgPreferences';
1111
import { BaseMigrationTool } from './base';
1212
import { Deployer } from './deployer';
13+
import { OmniscriptPackageDeploymentError } from '../error/deploymentErrors';
1314
import * as fs from 'fs';
1415
import * as path from 'path';
16+
import { documentRegistry } from '../utils/constants/documentRegistry';
1517

1618
export class PostMigrate extends BaseMigrationTool {
1719
private readonly org: Org;
@@ -180,21 +182,39 @@ export class PostMigrate extends BaseMigrationTool {
180182
}
181183
}
182184

183-
public deploy(): void {
185+
public async deploy(userActionMessage: string[]): Promise<void> {
184186
if (!this.deploymentConfig.autoDeploy || !fs.existsSync(path.join(process.cwd(), 'package.xml'))) {
187+
Logger.logVerbose(this.messages.getMessage('deploymentSkipped'));
185188
return;
186189
}
190+
187191
try {
188192
const deployer = new Deployer(
189193
this.projectPath,
190194
this.messages,
191195
this.org.getUsername(),
192196
this.deploymentConfig.authKey
193197
);
194-
deployer.deploy();
195-
Logger.logVerbose('Deployment completed');
198+
199+
await deployer.deploy();
196200
} catch (error) {
201+
const errorMessage = error instanceof Error ? error.message : String(error);
197202
Logger.error(this.messages.getMessage('errorDeployingComponents'), error);
203+
204+
// Handle specific omniscript package deployment failures by error type (not message)
205+
if (error instanceof OmniscriptPackageDeploymentError) {
206+
userActionMessage.push(
207+
this.messages.getMessage('deployOmniscriptPackageManually', [documentRegistry.manualDeploymentSteps])
208+
);
209+
Logger.logVerbose(this.messages.getMessage('omniscriptDeploymentFailedContinuing'));
210+
} else {
211+
// Handle general deployment failures
212+
userActionMessage.push(this.messages.getMessage('deployComponentsManually'));
213+
Logger.logVerbose(this.messages.getMessage('deploymentFailedContinuing'));
214+
}
215+
216+
// Log the specific error details for troubleshooting
217+
Logger.logVerbose(`Deployment error details: ${errorMessage}`);
198218
}
199219
}
200220
}

src/migration/related/ExperienceSiteMigration.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export class ExperienceSiteMigration extends BaseRelatedObjectMigration {
9494
for (const file of fileArray) {
9595
progressBar.update(++progressCounter);
9696
if (file.ext !== '.json') {
97-
Logger.logVerbose(this.messages.getMessage('skipNonJsonFile ', [file.name]));
97+
Logger.logVerbose(this.messages.getMessage('skipNonJsonFile', [file.name]));
9898
continue;
9999
}
100100
try {

0 commit comments

Comments
 (0)