diff --git a/src/controllers/DisplayResourceDependencyGraphController.ts b/src/controllers/DisplayResourceDependencyGraphController.ts index 904b3a9..8d4e2c6 100644 --- a/src/controllers/DisplayResourceDependencyGraphController.ts +++ b/src/controllers/DisplayResourceDependencyGraphController.ts @@ -1,7 +1,6 @@ import * as vscode from 'vscode'; import { IResourceDependencyGraphService } from '../services/ResourcesGraphService'; -import { isHumanitecExtensionError } from '../errors/IHumanitecExtensionError'; -import { ILoggerService } from '../services/LoggerService'; +import { IErrorHandlerService } from '../services/ErrorHandlerService'; export class DisplayResourcesGraphController { private constructor() {} @@ -9,7 +8,7 @@ export class DisplayResourcesGraphController { static register( context: vscode.ExtensionContext, resourcesGraphService: IResourceDependencyGraphService, - logger: ILoggerService + errorHandler: IErrorHandlerService ) { const disposable = vscode.commands.registerCommand( 'humanitec.display_resources_graph', @@ -27,15 +26,7 @@ export class DisplayResourcesGraphController { ); panel.webview.html = this.getWebviewContent(graph); } catch (error) { - if (isHumanitecExtensionError(error)) { - vscode.window.showErrorMessage(error.message()); - logger.error(error.details()); - } else { - logger.error(JSON.stringify({ error })); - vscode.window.showErrorMessage( - 'Unexpected error occurred. Please contact the extension developer' - ); - } + errorHandler.handle(error); } } ); diff --git a/src/controllers/HumanitecSidebarController.ts b/src/controllers/HumanitecSidebarController.ts index 8dd60e9..4ae481b 100644 --- a/src/controllers/HumanitecSidebarController.ts +++ b/src/controllers/HumanitecSidebarController.ts @@ -4,8 +4,6 @@ import { ResourceTypeTreeItem, } from '../providers/AvailableResourceTypesProvider'; import { IResourceTypeRepository } from '../repos/ResourceTypeRepository'; -import { ILoggerService } from '../services/LoggerService'; -import { isHumanitecExtensionError } from '../errors/IHumanitecExtensionError'; import { OrganizationStructureItem, OrganizationStructureProvider, @@ -18,6 +16,7 @@ import { Organization } from '../domain/Organization'; import { ConfigKey } from '../domain/ConfigKey'; import { Application } from '../domain/Application'; import { ControllerIsAlreadyRegisteredError } from '../errors/ControllerIsAlreadyRegisteredError'; +import { IErrorHandlerService } from '../services/ErrorHandlerService'; export class HumanitecSidebarController { private static instance: HumanitecSidebarController; @@ -34,7 +33,7 @@ export class HumanitecSidebarController { applicationRepository: IApplicationRepository, environmentRepository: IEnvironmentRepository, configurationRepository: IConfigurationRepository, - logger: ILoggerService + errorHandler: IErrorHandlerService ) { if (this.instance !== undefined) { throw new ControllerIsAlreadyRegisteredError( @@ -43,13 +42,15 @@ export class HumanitecSidebarController { } const availableResourceTypesProvider = new AvailableResourceTypesProvider( - resourceTypeRepository + resourceTypeRepository, + errorHandler ); const organizationStructureProvider = new OrganizationStructureProvider( organizationRepository, applicationRepository, environmentRepository, - configurationRepository + configurationRepository, + errorHandler ); this.instance = new HumanitecSidebarController( availableResourceTypesProvider, @@ -72,15 +73,7 @@ export class HumanitecSidebarController { try { availableResourceTypesProvider.refresh(); } catch (error) { - if (isHumanitecExtensionError(error)) { - logger.error(error.details()); - vscode.window.showErrorMessage(error.message()); - } else { - logger.error(JSON.stringify({ error })); - vscode.window.showErrorMessage( - 'Unexpected error occurred. Please contact the extension developer' - ); - } + errorHandler.handle(error); } } ); @@ -92,15 +85,7 @@ export class HumanitecSidebarController { try { organizationStructureProvider.refresh(); } catch (error) { - if (isHumanitecExtensionError(error)) { - logger.error(error.details()); - vscode.window.showErrorMessage(error.message()); - } else { - logger.error(JSON.stringify({ error })); - vscode.window.showErrorMessage( - 'Unexpected error occurred. Please contact the extension developer' - ); - } + errorHandler.handle(error); } } ); @@ -121,10 +106,7 @@ export class HumanitecSidebarController { } vscode.env.openExternal(url); } catch (error) { - logger.error(JSON.stringify({ error })); - vscode.window.showErrorMessage( - 'Unexpected error occurred. Please contact the extension developer' - ); + errorHandler.handle(error); } } ); @@ -179,10 +161,7 @@ export class HumanitecSidebarController { await availableResourceTypesProvider.refresh(); await organizationStructureProvider.refresh(); } catch (error) { - logger.error(JSON.stringify({ error })); - vscode.window.showErrorMessage( - 'Unexpected error occurred. Please contact the extension developer' - ); + errorHandler.handle(error); } } ); diff --git a/src/controllers/InitializeScoreFileController.ts b/src/controllers/InitializeScoreFileController.ts index 4ac9342..9fc0a70 100644 --- a/src/controllers/InitializeScoreFileController.ts +++ b/src/controllers/InitializeScoreFileController.ts @@ -1,7 +1,6 @@ import * as vscode from 'vscode'; import { IScoreInitializationService } from '../services/ScoreInitializationService'; -import { ILoggerService } from '../services/LoggerService'; -import { isHumanitecExtensionError } from '../errors/IHumanitecExtensionError'; +import { IErrorHandlerService } from '../services/ErrorHandlerService'; export class InitializeScoreFileController { private constructor() {} @@ -10,7 +9,7 @@ export class InitializeScoreFileController { context: vscode.ExtensionContext, initializationService: IScoreInitializationService, enable: boolean, - logger: ILoggerService + errorHandler: IErrorHandlerService ) { const disposable = vscode.commands.registerCommand( 'humanitec.score.init', @@ -43,15 +42,7 @@ export class InitializeScoreFileController { vscode.window.showInformationMessage('No workspace is opened'); } } catch (error) { - if (isHumanitecExtensionError(error)) { - logger.error(error.details()); - vscode.window.showErrorMessage(error.message()); - } else { - logger.error(JSON.stringify({ error })); - vscode.window.showErrorMessage( - 'Unexpected error occurred. Please contact the extension developer' - ); - } + errorHandler.handle(error); } } ); diff --git a/src/controllers/LoginController.ts b/src/controllers/LoginController.ts index 3122552..5ccc766 100644 --- a/src/controllers/LoginController.ts +++ b/src/controllers/LoginController.ts @@ -1,9 +1,8 @@ import * as vscode from 'vscode'; import { ISecretRepository } from '../repos/SecretRepository'; import { SecretKey } from '../domain/SecretKey'; -import { ILoggerService } from '../services/LoggerService'; import { ILoginService } from '../services/LoginService'; -import { isHumanitecExtensionError } from '../errors/IHumanitecExtensionError'; +import { IErrorHandlerService } from '../services/ErrorHandlerService'; export class LoginController { private constructor() {} @@ -12,7 +11,7 @@ export class LoginController { context: vscode.ExtensionContext, loginService: ILoginService, secrets: ISecretRepository, - logger: ILoggerService + errorHandler: IErrorHandlerService ) { const disposable = vscode.commands.registerCommand( 'humanitec.login', @@ -51,15 +50,7 @@ export class LoginController { 'Humanitec extension successfully configured!' ); } catch (error) { - if (isHumanitecExtensionError(error)) { - vscode.window.showErrorMessage(error.message()); - logger.error(error.details()); - } else { - vscode.window.showErrorMessage( - 'Unexpected error occurred. Please contact the extension developer' - ); - logger.error(JSON.stringify({ error })); - } + errorHandler.handle(error); } } ); diff --git a/src/controllers/OpenConfiguredTerminalController.ts b/src/controllers/OpenConfiguredTerminalController.ts index 34c2897..ae9f0ea 100644 --- a/src/controllers/OpenConfiguredTerminalController.ts +++ b/src/controllers/OpenConfiguredTerminalController.ts @@ -3,8 +3,7 @@ import { IConfigurationRepository } from '../repos/ConfigurationRepository'; import { ISecretRepository } from '../repos/SecretRepository'; import { SecretKey } from '../domain/SecretKey'; import { ConfigKey } from '../domain/ConfigKey'; -import { isHumanitecExtensionError } from '../errors/IHumanitecExtensionError'; -import { ILoggerService } from '../services/LoggerService'; +import { IErrorHandlerService } from '../services/ErrorHandlerService'; export class OpenConfiguredTerminalController { private constructor() {} @@ -13,7 +12,7 @@ export class OpenConfiguredTerminalController { context: vscode.ExtensionContext, configs: IConfigurationRepository, secrets: ISecretRepository, - logger: ILoggerService + errorHandler: IErrorHandlerService ) { const disposable = vscode.commands.registerCommand( 'humanitec.open_configured_terminal', @@ -38,15 +37,7 @@ export class OpenConfiguredTerminalController { terminal.show(); } catch (error) { - if (isHumanitecExtensionError(error)) { - logger.error(error.details()); - vscode.window.showErrorMessage(error.message()); - } else { - logger.error(JSON.stringify({ error })); - vscode.window.showErrorMessage( - 'Unexpected error occurred. Please contact the extension developer' - ); - } + errorHandler.handle(error); } } ); diff --git a/src/controllers/SetTokenController.ts b/src/controllers/SetTokenController.ts index 988bad0..0cb2bc5 100644 --- a/src/controllers/SetTokenController.ts +++ b/src/controllers/SetTokenController.ts @@ -1,7 +1,7 @@ import * as vscode from 'vscode'; import { ISecretRepository } from '../repos/SecretRepository'; import { SecretKey } from '../domain/SecretKey'; -import { ILoggerService } from '../services/LoggerService'; +import { IErrorHandlerService } from '../services/ErrorHandlerService'; export class SetTokenController { private constructor() {} @@ -9,7 +9,7 @@ export class SetTokenController { static register( context: vscode.ExtensionContext, secrets: ISecretRepository, - logger: ILoggerService + errorHandler: IErrorHandlerService ) { const disposable = vscode.commands.registerCommand( 'humanitec.set_token', @@ -35,10 +35,7 @@ export class SetTokenController { ); } } catch (error) { - logger.error(JSON.stringify({ error })); - vscode.window.showErrorMessage( - 'Unexpected error occurred. Please contact the extension developer' - ); + errorHandler.handle(error); } } ); diff --git a/src/controllers/ValidateScoreFileController.ts b/src/controllers/ValidateScoreFileController.ts index 077f5e5..8b1cfe4 100644 --- a/src/controllers/ValidateScoreFileController.ts +++ b/src/controllers/ValidateScoreFileController.ts @@ -8,10 +8,9 @@ import { Range, TextDocument, } from 'vscode'; -import { isHumanitecExtensionError } from '../errors/IHumanitecExtensionError'; -import { ILoggerService } from '../services/LoggerService'; import { IConfigurationRepository } from '../repos/ConfigurationRepository'; import { ConfigKey } from '../domain/ConfigKey'; +import { IErrorHandlerService } from '../services/ErrorHandlerService'; export class ValidateScoreFileController { private static instance: ValidateScoreFileController; @@ -29,7 +28,7 @@ export class ValidateScoreFileController { context: vscode.ExtensionContext, validationService: IScoreValidationService, config: IConfigurationRepository, - logger: ILoggerService + errorHandler: IErrorHandlerService ) { if (this.instance === undefined) { this.instance = new ValidateScoreFileController( @@ -61,15 +60,7 @@ export class ValidateScoreFileController { ); } } catch (error) { - if (isHumanitecExtensionError(error)) { - vscode.window.showErrorMessage(error.message()); - logger.error(error.details()); - } else { - vscode.window.showErrorMessage( - 'Unexpected error occurred. Please contact the extension developer' - ); - logger.error(JSON.stringify({ error })); - } + errorHandler.handle(error); } }); } @@ -95,7 +86,7 @@ export class ValidateScoreFileController { ); } } catch (error) { - logger.error(JSON.stringify({ error })); + errorHandler.handle(error); } }); }); @@ -125,7 +116,7 @@ export class ValidateScoreFileController { ); } } catch (error) { - logger.error(JSON.stringify({ error })); + errorHandler.handle(error); } }); context.subscriptions.push(disposable); diff --git a/src/errors/HumctlError.ts b/src/errors/HumctlError.ts new file mode 100644 index 0000000..c2f85a3 --- /dev/null +++ b/src/errors/HumctlError.ts @@ -0,0 +1,21 @@ +import { IHumanitecExtensionError } from './IHumanitecExtensionError'; + +export class HumctlError implements IHumanitecExtensionError { + constructor( + private readonly command: string, + private readonly output: string, + private readonly exitCode: number + ) {} + + message(): string { + return 'Command: ' + this.command + ' returned an unexpected error'; + } + + details(): string { + return JSON.stringify({ + command: this.command, + output: this.output, + exitCode: this.exitCode, + }); + } +} diff --git a/src/errors/IHumanitecExtensionError.ts b/src/errors/IHumanitecExtensionError.ts index 70120cf..2726f6f 100644 --- a/src/errors/IHumanitecExtensionError.ts +++ b/src/errors/IHumanitecExtensionError.ts @@ -2,15 +2,3 @@ export interface IHumanitecExtensionError { message(): string; details(): string; } - -export function isHumanitecExtensionError( - error: unknown -): error is IHumanitecExtensionError { - const isObject = error !== null && typeof error === 'object'; - if (isObject) { - const hasMessage = 'message' in error; - const hasDetails = 'details' in error; - return hasMessage && hasDetails; - } - return false; -} diff --git a/src/extension.ts b/src/extension.ts index 6337880..cd0e11d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -18,11 +18,13 @@ import { EnvironmentRepository } from './repos/EnvironmentRepository'; import { HumctlAdapter } from './adapters/humctl/HumctlAdapter'; import { LoginController } from './controllers/LoginController'; import { LoginService } from './services/LoginService'; +import { ErrorHandlerService } from './services/ErrorHandlerService'; export const loggerChannel = vscode.window.createOutputChannel('Humanitec'); export async function activate(context: vscode.ExtensionContext) { const logger = new LoggerService(loggerChannel); + const errorHandler = new ErrorHandlerService(logger, loggerChannel); const configurationRepository = new ConfigurationRepository(); const secretRepository = new SecretRepository(); const humctl = new HumctlAdapter( @@ -43,34 +45,37 @@ export async function activate(context: vscode.ExtensionContext) { applicationRepository, environmentRepository, configurationRepository, - logger + errorHandler ); - - LoginController.register(context, loginService, secretRepository, logger); - SetTokenController.register(context, secretRepository, logger); - + LoginController.register( + context, + loginService, + secretRepository, + errorHandler + ); + SetTokenController.register(context, secretRepository, errorHandler); ValidateScoreFileController.register( context, new ScoreValidationService(humctl), configurationRepository, - logger + errorHandler ); InitializeScoreFileController.register( context, new ScoreInitializationService(humctl), false, - logger + errorHandler ); DisplayResourcesGraphController.register( context, new ResourcesGraphService(humctl), - logger + errorHandler ); OpenConfiguredTerminalController.register( context, configurationRepository, secretRepository, - logger + errorHandler ); vscode.commands.executeCommand('humanitec.score.validate'); diff --git a/src/providers/AvailableResourceTypesProvider.ts b/src/providers/AvailableResourceTypesProvider.ts index e47eaff..dc27881 100644 --- a/src/providers/AvailableResourceTypesProvider.ts +++ b/src/providers/AvailableResourceTypesProvider.ts @@ -1,11 +1,15 @@ import * as vscode from 'vscode'; import { ResourceTypeVariable } from '../domain/ResourceType'; import { IResourceTypeRepository } from '../repos/ResourceTypeRepository'; +import { IErrorHandlerService } from '../services/ErrorHandlerService'; export class AvailableResourceTypesProvider implements vscode.TreeDataProvider { - constructor(private resourceTypeRepository: IResourceTypeRepository) {} + constructor( + private resourceTypeRepository: IResourceTypeRepository, + private errorHandler: IErrorHandlerService + ) {} getTreeItem(element: AvailableResourceTypesTreeItem): vscode.TreeItem { return element; @@ -15,16 +19,22 @@ export class AvailableResourceTypesProvider element: AvailableResourceTypesTreeItem ): Thenable { if (element === undefined) { - return this.resourceTypeRepository.getAvailable().then(resourceTypes => - Promise.resolve( - resourceTypes.map(resourceType => { - return new ResourceTypeTreeItem( - resourceType.type, - resourceType.name - ); - }) + return this.resourceTypeRepository + .getAvailable() + .then(resourceTypes => + Promise.resolve( + resourceTypes.map(resourceType => { + return new ResourceTypeTreeItem( + resourceType.type, + resourceType.name + ); + }) + ) ) - ); + .catch(error => { + this.errorHandler.handle(error); + return []; + }); } else if (element instanceof ResourceTypeTreeItem) { return Promise.resolve([ new ResourceTypePropertyTreeItem('inputs', element.resourceType), @@ -63,6 +73,10 @@ export class AvailableResourceTypesProvider }); } return Promise.resolve(vars); + }) + .catch(error => { + this.errorHandler.handle(error); + return []; }); } return Promise.resolve([]); diff --git a/src/providers/OrganizationStructureProvider.ts b/src/providers/OrganizationStructureProvider.ts index d379310..cf667a6 100644 --- a/src/providers/OrganizationStructureProvider.ts +++ b/src/providers/OrganizationStructureProvider.ts @@ -8,6 +8,7 @@ import { IEnvironmentRepository } from '../repos/EnvironmentRepository'; import { IConfigurationRepository } from '../repos/ConfigurationRepository'; import { ConfigKey } from '../domain/ConfigKey'; import path from 'path'; +import { IErrorHandlerService } from '../services/ErrorHandlerService'; export class OrganizationStructureProvider implements vscode.TreeDataProvider @@ -16,7 +17,8 @@ export class OrganizationStructureProvider private organizationRepository: IOrganizationRepository, private applicationRepository: IApplicationRepository, private environmentRepository: IEnvironmentRepository, - private configurationRepository: IConfigurationRepository + private configurationRepository: IConfigurationRepository, + private errorHandler: IErrorHandlerService ) {} getTreeItem( @@ -70,15 +72,25 @@ export class OrganizationStructureProvider element?: OrganizationStructureItem | undefined ): vscode.ProviderResult { if (element === undefined) { - return this.organizationRepository.getAll().then(organizations => { - return Promise.resolve(organizations); - }); + return this.organizationRepository + .getAll() + .then(organizations => { + return Promise.resolve(organizations); + }) + .catch(error => { + this.errorHandler.handle(error); + return []; + }); } if (element instanceof Organization) { return this.applicationRepository .getFrom(element.id) .then(applications => { return Promise.resolve(applications); + }) + .catch(error => { + this.errorHandler.handle(error); + return []; }); } if (element instanceof Application) { @@ -86,6 +98,10 @@ export class OrganizationStructureProvider .getFrom(element.organizationId, element.id) .then(environments => { return Promise.resolve(environments); + }) + .catch(error => { + this.errorHandler.handle(error); + return []; }); } return Promise.resolve([]); diff --git a/src/repos/ApplicationRepository.ts b/src/repos/ApplicationRepository.ts index 417bf1b..2f535e4 100644 --- a/src/repos/ApplicationRepository.ts +++ b/src/repos/ApplicationRepository.ts @@ -1,5 +1,6 @@ import { IHumctlAdapter } from '../adapters/humctl/IHumctlAdapter'; import { Application } from '../domain/Application'; +import { HumctlError } from '../errors/HumctlError'; export interface IApplicationRepository { getFrom(organizationId: string): Promise; @@ -24,6 +25,14 @@ export class ApplicationRepository implements IApplicationRepository { 'get', 'apps', ]); + if (result.stderr !== '') { + throw new HumctlError( + 'humctl --org ' + organizationId + ' get apps', + result.stderr, + result.exitcode + ); + } + const applications: Application[] = []; const rawApplications = JSON.parse(result.stdout); diff --git a/src/repos/EnvironmentRepository.ts b/src/repos/EnvironmentRepository.ts index eb74ec6..a12818b 100644 --- a/src/repos/EnvironmentRepository.ts +++ b/src/repos/EnvironmentRepository.ts @@ -1,5 +1,6 @@ import { IHumctlAdapter } from '../adapters/humctl/IHumctlAdapter'; import { Environment } from '../domain/Environment'; +import { HumctlError } from '../errors/HumctlError'; export interface IEnvironmentRepository { getFrom( @@ -32,6 +33,18 @@ export class EnvironmentRepository implements IEnvironmentRepository { 'get', 'envs', ]); + if (result.stderr !== '') { + throw new HumctlError( + 'humctl --org ' + + organizationId + + ' --app ' + + applicationId + + ' get envs', + result.stderr, + result.exitcode + ); + } + const environments: Environment[] = []; const rawEnvironments = JSON.parse(result.stdout); diff --git a/src/repos/OrganizationRepository.ts b/src/repos/OrganizationRepository.ts index 637ffe1..fad575e 100644 --- a/src/repos/OrganizationRepository.ts +++ b/src/repos/OrganizationRepository.ts @@ -1,5 +1,6 @@ import { IHumctlAdapter } from '../adapters/humctl/IHumctlAdapter'; import { Organization } from '../domain/Organization'; +import { HumctlError } from '../errors/HumctlError'; export interface IOrganizationRepository { getAll(): Promise; @@ -19,6 +20,10 @@ export class OrganizationRepository implements IOrganizationRepository { async getAll(): Promise { const result = await this.humctl.execute(['get', 'orgs']); + if (result.stderr !== '') { + throw new HumctlError('humctl get orgs', result.stderr, result.exitcode); + } + const organizations: Organization[] = []; const rawOrganizations = JSON.parse(result.stdout); diff --git a/src/repos/ResourceTypeRepository.ts b/src/repos/ResourceTypeRepository.ts index 9aec568..4d7fc5e 100644 --- a/src/repos/ResourceTypeRepository.ts +++ b/src/repos/ResourceTypeRepository.ts @@ -5,6 +5,7 @@ import { } from '../domain/ResourceType'; import { IHumctlAdapter } from '../adapters/humctl/IHumctlAdapter'; import { NotFoundError } from '../errors/NotFoundError'; +import { HumctlError } from '../errors/HumctlError'; export interface IResourceTypeRepository { getAvailable(): Promise; @@ -46,6 +47,13 @@ export class ResourceTypeRepository implements IResourceTypeRepository { 'score', 'available-resource-types', ]); + if (result.stderr !== '') { + throw new HumctlError( + 'score available-resource-types', + result.stderr, + result.exitcode + ); + } const resourceTypes = JSON.parse( result.stdout @@ -79,6 +87,14 @@ export class ResourceTypeRepository implements IResourceTypeRepository { 'score', 'available-resource-types', ]); + if (result.stderr !== '') { + throw new HumctlError( + 'score available-resource-types', + result.stderr, + result.exitcode + ); + } + const resourceTypes: ResourceType[] = []; const availableResourceTypes = JSON.parse( diff --git a/src/services/ErrorHandlerService.ts b/src/services/ErrorHandlerService.ts new file mode 100644 index 0000000..a5d89ef --- /dev/null +++ b/src/services/ErrorHandlerService.ts @@ -0,0 +1,60 @@ +import * as vscode from 'vscode'; +import { ILoggerService } from './LoggerService'; +import { IHumanitecExtensionError } from '../errors/IHumanitecExtensionError'; + +export interface IErrorHandlerService { + handle(error: unknown): void; +} + +export class ErrorHandlerService implements IErrorHandlerService { + constructor( + private readonly logger: ILoggerService, + private readonly outputChannel: vscode.OutputChannel + ) {} + + handle(error: unknown) { + if (this.isHumanitecExtensionError(error)) { + this.logger.error(error.details()); + this.showErrorMessage(error.message()); + } else if (error instanceof Error) { + this.logger.error( + JSON.stringify({ + message: error.message, + stack: error.stack, + name: error.name, + }) + ); + this.showErrorMessage( + 'Unexpected error occurred. More details in the output' + ); + } else { + this.logger.error(JSON.stringify({ error })); + this.showErrorMessage( + 'Unexpected error occurred. Please contact the extension developer' + ); + } + } + + private async showErrorMessage(message: string): Promise { + const showOutputButton = 'Show output log'; + const action = await vscode.window.showErrorMessage( + message, + showOutputButton + ); + if (action === showOutputButton) { + this.outputChannel.show(); + } + } + + private isHumanitecExtensionError( + error: unknown + ): error is IHumanitecExtensionError { + const isObject = error !== null && typeof error === 'object'; + if (isObject) { + const hasMessage = 'message' in error; + const hasDetails = 'details' in error; + return hasMessage && hasDetails; + } + return false; + } +} diff --git a/src/services/ResourcesGraphService.ts b/src/services/ResourcesGraphService.ts index 1b1ee91..79a70b1 100644 --- a/src/services/ResourcesGraphService.ts +++ b/src/services/ResourcesGraphService.ts @@ -1,4 +1,5 @@ import { IHumctlAdapter } from '../adapters/humctl/IHumctlAdapter'; +import { HumctlError } from '../errors/HumctlError'; export interface IResourceDependencyGraphService { generate(): Promise; @@ -9,8 +10,12 @@ export class ResourcesGraphService implements IResourceDependencyGraphService { async generate(): Promise { const result = await this.humctl.execute(['resources', 'graph']); - if (result.stdout === '') { - throw result.stderr; + if (result.stderr !== '') { + throw new HumctlError( + 'humctl resources graph', + result.stderr, + result.exitcode + ); } return result.stdout; } diff --git a/src/services/ScoreInitializationService.ts b/src/services/ScoreInitializationService.ts index 599cbab..2a4092e 100644 --- a/src/services/ScoreInitializationService.ts +++ b/src/services/ScoreInitializationService.ts @@ -1,4 +1,5 @@ import { IHumctlAdapter } from '../adapters/humctl/IHumctlAdapter'; +import { HumctlError } from '../errors/HumctlError'; export interface IScoreInitializationService { generateInitFile(): Promise; @@ -9,6 +10,13 @@ export class ScoreInitializationService implements IScoreInitializationService { async generateInitFile(): Promise { const result = await this.humctl.execute(['score', 'init']); + if (result.stderr !== '') { + throw new HumctlError( + 'humctl score init', + result.stderr, + result.exitcode + ); + } return result.stdout; } } diff --git a/src/services/ScoreValidationService.ts b/src/services/ScoreValidationService.ts index ab665fe..68bcbfa 100644 --- a/src/services/ScoreValidationService.ts +++ b/src/services/ScoreValidationService.ts @@ -1,4 +1,5 @@ import { IHumctlAdapter } from '../adapters/humctl/IHumctlAdapter'; +import { HumctlError } from '../errors/HumctlError'; export interface IScoreValidationService { validate(filepath: string, onlyLocal: boolean): Promise; @@ -33,9 +34,25 @@ export class ScoreValidationService implements IScoreValidationService { if (onlyLocal) { command.push('--local'); } + + const os = process.platform.toString(); + if (os === 'win32') { + console.log('Windows'); + console.log(filepath); + // eslint-disable-next-line + filepath = filepath.replace('/^(\/)/', ''); + console.log(filepath); + } command.push(filepath); const result = await this.humctl.execute(command); + if (result.stdout === '') { + throw new HumctlError( + 'humctl ' + command.join(' '), + result.stderr, + result.exitcode + ); + } const validationErrors: ValidationError[] = []; // TODO: Make the handling better diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 7c239c3..608c645 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -130,7 +130,8 @@ suite('Extension Test Suite', () => { ); expect(showErrorMessage).to.have.been.calledWith( - 'Unexpected error occurred. Please contact the extension developer' + 'Command: humctl resources graph returned an unexpected error', + 'Show output log' ); });