Skip to content

Commit 6c1ba46

Browse files
committed
feat: add ErrorHandler class
1 parent 789e2a7 commit 6c1ba46

File tree

12 files changed

+82
-16
lines changed

12 files changed

+82
-16
lines changed

solo.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44
*/
55
import * as fnm from './src/index.js';
66
import {type SoloLogger} from './src/core/logging.js';
7+
import {InjectTokens} from './src/core/dependency_injection/inject_tokens.js';
8+
import {container} from 'tsyringe-neo';
9+
import {type ErrorHandler} from './src/core/error_handler.js';
710

811
const context: {logger: SoloLogger} = {logger: undefined};
912
await fnm
1013
.main(process.argv, context)
1114
.then(() => {
1215
context.logger.info('Solo CLI completed, via entrypoint');
1316
})
14-
.catch(err => {
15-
context.logger.showUserError(err);
17+
.catch(e => {
18+
const errorHandler: ErrorHandler = container.resolve(InjectTokens.ErrorHandler);
19+
errorHandler.handle(e);
1620
});

src/commands/cluster/configs.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {Flags as flags} from '../flags.js';
66
import * as constants from '../../core/constants.js';
77
import {ListrInquirerPromptAdapter} from '@listr2/prompt-adapter-inquirer';
88
import {confirm as confirmPrompt} from '@inquirer/prompts';
9-
import {SoloError} from '../../core/errors.js';
9+
import {SoloError, UserBreak} from '../../core/errors.js';
1010
import {type NamespaceName} from '../../core/kube/resources/namespace/namespace_name.js';
1111
import {type DeploymentName} from '../../core/config/remote/types.js';
1212
import {inject, injectable} from 'tsyringe-neo';
@@ -44,7 +44,7 @@ export class ClusterCommandConfigs {
4444

4545
public async connectConfigBuilder(argv, ctx, task) {
4646
if (!this.localConfig.configFileExists()) {
47-
this.logger.logAndExitError(new SoloError(ErrorMessages.LOCAL_CONFIG_DOES_NOT_EXIST));
47+
throw new SoloError(ErrorMessages.LOCAL_CONFIG_DOES_NOT_EXIST);
4848
}
4949

5050
this.configManager.update(argv);
@@ -110,7 +110,7 @@ export class ClusterCommandConfigs {
110110
});
111111

112112
if (!confirmResult) {
113-
this.logger.logAndExitSuccess('Aborted application by user prompt');
113+
throw new UserBreak('Aborted application by user prompt');
114114
}
115115
}
116116

src/commands/cluster/tasks.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import path from 'path';
1212
import chalk from 'chalk';
1313
import {ListrLease} from '../../core/lease/listr_lease.js';
1414
import {ErrorMessages} from '../../core/error_messages.js';
15-
import {SoloError} from '../../core/errors.js';
15+
import {SoloError, UserBreak} from '../../core/errors.js';
1616
import {RemoteConfigManager} from '../../core/config/remote/remote_config_manager.js';
1717
import {type RemoteConfigDataWrapper} from '../../core/config/remote/remote_config_data_wrapper.js';
1818
import {type K8Factory} from '../../core/kube/k8_factory.js';
@@ -528,7 +528,7 @@ export class ClusterCommandTasks {
528528
});
529529

530530
if (!confirm) {
531-
self.logger.logAndExitSuccess('Aborted application by user prompt');
531+
throw new UserBreak('Aborted application by user prompt');
532532
}
533533
}
534534
await self.chartManager.uninstall(

src/commands/explorer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import {ListrInquirerPromptAdapter} from '@listr2/prompt-adapter-inquirer';
55
import {confirm as confirmPrompt} from '@inquirer/prompts';
66
import {Listr} from 'listr2';
7-
import {SoloError, MissingArgumentError} from '../core/errors.js';
7+
import {SoloError, MissingArgumentError, UserBreak} from '../core/errors.js';
88
import * as constants from '../core/constants.js';
99
import {type ProfileManager} from '../core/profile_manager.js';
1010
import {BaseCommand, type Opts} from './base.js';
@@ -404,7 +404,7 @@ export class ExplorerCommand extends BaseCommand {
404404
});
405405

406406
if (!confirmResult) {
407-
this.logger.info('Aborted application by user prompt');
407+
throw new UserBreak('Aborted application by user prompt');
408408
}
409409
}
410410

src/commands/init.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import path from 'path';
66
import {BaseCommand} from './base.js';
77
import fs from 'fs';
88
import * as constants from '../core/constants.js';
9-
import {SoloError} from '../core/errors.js';
9+
import {SoloError, UserBreak} from '../core/errors.js';
1010
import {Flags as flags} from './flags.js';
1111
import chalk from 'chalk';
1212

src/commands/mirror_node.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import {ListrInquirerPromptAdapter} from '@listr2/prompt-adapter-inquirer';
55
import {confirm as confirmPrompt} from '@inquirer/prompts';
66
import {Listr} from 'listr2';
7-
import {IllegalArgumentError, MissingArgumentError, SoloError} from '../core/errors.js';
7+
import {IllegalArgumentError, MissingArgumentError, SoloError, UserBreak} from '../core/errors.js';
88
import * as constants from '../core/constants.js';
99
import {type AccountManager} from '../core/account_manager.js';
1010
import {type ProfileManager} from '../core/profile_manager.js';
@@ -703,7 +703,7 @@ export class MirrorNodeCommand extends BaseCommand {
703703
});
704704

705705
if (!confirmResult) {
706-
this.logger.info('Aborted application by user prompt');
706+
throw new UserBreak('Aborted application by user prompt');
707707
}
708708
}
709709

src/commands/network.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {ListrInquirerPromptAdapter} from '@listr2/prompt-adapter-inquirer';
55
import {confirm as confirmPrompt} from '@inquirer/prompts';
66
import chalk from 'chalk';
77
import {Listr} from 'listr2';
8-
import {IllegalArgumentError, MissingArgumentError, SoloError} from '../core/errors.js';
8+
import {IllegalArgumentError, MissingArgumentError, SoloError, UserBreak} from '../core/errors.js';
99
import {BaseCommand, type Opts} from './base.js';
1010
import {Flags as flags} from './flags.js';
1111
import * as constants from '../core/constants.js';
@@ -1127,7 +1127,7 @@ export class NetworkCommand extends BaseCommand {
11271127
});
11281128

11291129
if (!confirmResult) {
1130-
this.logger.info('Aborted application by user prompt');
1130+
throw new UserBreak('Aborted application by user prompt');
11311131
}
11321132
}
11331133

src/core/dependency_injection/container_init.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {NodeCommandHandlers} from '../../commands/node/handlers.js';
3232
import {NodeCommandTasks} from '../../commands/node/tasks.js';
3333
import {ClusterCommandConfigs} from '../../commands/cluster/configs.js';
3434
import {NodeCommandConfigs} from '../../commands/node/configs.js';
35+
import {ErrorHandler} from '../error_handler.js';
3536

3637
/**
3738
* Container class to manage the dependency injection container
@@ -170,6 +171,8 @@ export class Container {
170171
{useClass: NodeCommandConfigs},
171172
{lifecycle: Lifecycle.Singleton},
172173
);
174+
175+
container.register(InjectTokens.ErrorHandler, {useClass: ErrorHandler}, {lifecycle: Lifecycle.Singleton});
173176
}
174177

175178
/**

src/core/dependency_injection/inject_tokens.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,5 @@ export const InjectTokens = {
4040
NodeCommandHandlers: Symbol.for('NodeCommandHandlers'),
4141
ClusterCommandConfigs: Symbol.for('ClusterCommandConfigs'),
4242
NodeCommandConfigs: Symbol.for('NodeCommandConfigs'),
43+
ErrorHandler: Symbol.for('ErrorHandler'),
4344
};

src/core/error_handler.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* SPDX-License-Identifier: Apache-2.0
3+
*/
4+
import {inject, injectable} from 'tsyringe-neo';
5+
import {InjectTokens} from './dependency_injection/inject_tokens.js';
6+
import {patchInject} from './dependency_injection/container_helper.js';
7+
import {type SoloLogger} from './logging.js';
8+
import {UserBreak} from './errors.js';
9+
10+
@injectable()
11+
export class ErrorHandler {
12+
constructor(@inject(InjectTokens.SoloLogger) private readonly logger: SoloLogger) {
13+
this.logger = patchInject(logger, InjectTokens.SoloLogger, this.constructor.name);
14+
}
15+
16+
public handle(error: Error | any): void {
17+
const userBreak = this.extractUserBreak(error);
18+
if (userBreak) {
19+
this.handleUserBreak(userBreak);
20+
} else {
21+
this.handleError(error);
22+
}
23+
}
24+
25+
private handleUserBreak(userBreak: UserBreak): void {
26+
this.logger.showUser(userBreak.message);
27+
}
28+
29+
private handleError(error: Error | any): void {
30+
this.logger.showUserError(error);
31+
}
32+
33+
/**
34+
* Recursively checks if an error is or is caused by a UserBreak
35+
* Returns the UserBreak if found, otherwise false
36+
* @param err
37+
*/
38+
private extractUserBreak(err: Error | any): UserBreak | false {
39+
if (err instanceof UserBreak) {
40+
return err;
41+
}
42+
if (err?.cause) {
43+
return this.extractUserBreak(err.cause);
44+
}
45+
return false;
46+
}
47+
}

src/core/errors.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,14 @@ export class DataValidationError extends SoloError {
8787
super(message, cause, {expected, found});
8888
}
8989
}
90+
91+
export class UserBreak extends SoloError {
92+
/**
93+
* Create a custom error for user break scenarios
94+
*
95+
* @param message - break message
96+
*/
97+
constructor(message: string) {
98+
super(message);
99+
}
100+
}

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {Container} from './core/dependency_injection/container_init.js';
3434
import {InjectTokens} from './core/dependency_injection/inject_tokens.js';
3535
import {type Opts} from './commands/base.js';
3636
import {Middlewares} from './core/middlewares.js';
37-
import {SoloError} from './core/errors.js';
37+
import {SoloError, UserBreak} from './core/errors.js';
3838

3939
export async function main(argv: string[], context?: {logger: SoloLogger}) {
4040
try {
@@ -65,7 +65,7 @@ export async function main(argv: string[], context?: {logger: SoloLogger}) {
6565
logger.showUser(chalk.cyan('\n******************************* Solo *********************************************'));
6666
logger.showUser(chalk.cyan('Version\t\t\t:'), chalk.yellow(helpers.getSoloVersion()));
6767
logger.showUser(chalk.cyan('**********************************************************************************'));
68-
logger.info('displayed version information, exiting');
68+
throw new UserBreak('displayed version information, exiting');
6969
}
7070

7171
// prepare dependency manger registry

0 commit comments

Comments
 (0)