From c642fb56fdceabe3d8f08088869ccf716e14bf4d Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Tue, 28 Apr 2020 11:44:12 -0700 Subject: [PATCH 1/2] feat(logger): expose errors better --- package.json | 2 +- src/commands/activate.ts | 8 +++++++- src/commands/deploy.ts | 22 ++++++---------------- src/commands/list.ts | 13 +++++++++++-- src/commands/logs.ts | 19 ++++++++++++++----- src/utils/logger.ts | 16 ++++++++++++++++ 6 files changed, 55 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index cb4a0ce6..8c87d87b 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "author": "Dominik Kundel ", "license": "MIT", "dependencies": { - "@twilio-labs/serverless-api": "^1.1.0", + "@twilio-labs/serverless-api": "^2.0.1", "@twilio-labs/serverless-runtime-types": "^1.1.7", "@types/express": "^4.17.0", "@types/inquirer": "^6.0.3", diff --git a/src/commands/activate.ts b/src/commands/activate.ts index 92e162ab..3e998385 100644 --- a/src/commands/activate.ts +++ b/src/commands/activate.ts @@ -10,6 +10,7 @@ import { printActivateConfig, printActivateResult } from '../printers/activate'; import { getDebugFunction, getOraSpinner, + logApiError, logger, setLogLevelByName, } from '../utils/logger'; @@ -25,7 +26,12 @@ function logError(msg: string) { function handleError(err: Error, spinner: Ora) { debug('%O', err); if (spinner) { - spinner.fail(err.message); + if (err.name === 'TwilioApiError') { + spinner.fail('Failed promoting build.'); + logApiError(logger, err); + } else { + spinner.fail(err.message); + } } process.exit(1); } diff --git a/src/commands/deploy.ts b/src/commands/deploy.ts index 5dbb4c52..5a5ae453 100644 --- a/src/commands/deploy.ts +++ b/src/commands/deploy.ts @@ -2,6 +2,7 @@ import { DeployLocalProjectConfig, TwilioServerlessApiClient, } from '@twilio-labs/serverless-api'; +import { ClientApiError } from '@twilio-labs/serverless-api/dist/utils/error'; import { stripIndent } from 'common-tags'; import { Ora } from 'ora'; import path from 'path'; @@ -10,14 +11,11 @@ import { checkConfigForCredentials } from '../checks/check-credentials'; import checkProjectStructure from '../checks/project-structure'; import { DeployCliFlags, getConfigFromFlags } from '../config/deploy'; import { printConfigInfo, printDeployedResources } from '../printers/deploy'; -import { - ApiErrorResponse, - HttpError, - saveLatestDeploymentData, -} from '../serverless-api/utils'; +import { HttpError, saveLatestDeploymentData } from '../serverless-api/utils'; import { getDebugFunction, getOraSpinner, + logApiError, logger, setLogLevelByName, } from '../utils/logger'; @@ -60,17 +58,9 @@ function handleError( > ${constructCommandName(fullCommand, 'deploy', ['--force'])} `; logger.error(messageBody, err.message); - } else if (err.name === 'HTTPError') { - const responseBody = JSON.parse( - (err as HttpError).body - ) as ApiErrorResponse; - const messageBody = stripIndent` - ${responseBody.message} - - More info: ${responseBody.more_info} - `; - - logger.error(messageBody); + } else if (err.name === 'TwilioApiError') { + const apiError = err as ClientApiError; + logApiError(logger, apiError); } else { logger.error(err.message); } diff --git a/src/commands/list.ts b/src/commands/list.ts index 23d172da..3425ca07 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -4,7 +4,12 @@ import { checkConfigForCredentials } from '../checks/check-credentials'; import checkForValidServiceSid from '../checks/check-service-sid'; import { getConfigFromFlags, ListCliFlags, ListConfig } from '../config/list'; import { printListResult } from '../printers/list'; -import { getDebugFunction, logger, setLogLevelByName } from '../utils/logger'; +import { + getDebugFunction, + logApiError, + logger, + setLogLevelByName, +} from '../utils/logger'; import { ExternalCliOptions, sharedCliOptions } from './shared'; import { CliInfo } from './types'; import { getFullCommand } from './utils'; @@ -17,7 +22,11 @@ function logError(msg: string) { function handleError(err: Error) { debug('%O', err); - logError(err.message); + if (err.name === 'TwilioApiError') { + logApiError(logger, err); + } else { + logError(err.message); + } process.exit(1); } diff --git a/src/commands/logs.ts b/src/commands/logs.ts index 4512250f..f62127a1 100644 --- a/src/commands/logs.ts +++ b/src/commands/logs.ts @@ -1,13 +1,18 @@ import { - TwilioServerlessApiClient, LogApiResource, + TwilioServerlessApiClient, } from '@twilio-labs/serverless-api'; -import { LogsCliFlags, LogsConfig, getConfigFromFlags } from '../config/logs'; import { Argv } from 'yargs'; import { checkConfigForCredentials } from '../checks/check-credentials'; import checkForValidServiceSid from '../checks/check-service-sid'; -import { printLogs, printLog } from '../printers/logs'; -import { getDebugFunction, logger, setLogLevelByName } from '../utils/logger'; +import { getConfigFromFlags, LogsCliFlags, LogsConfig } from '../config/logs'; +import { printLog, printLogs } from '../printers/logs'; +import { + getDebugFunction, + logApiError, + logger, + setLogLevelByName, +} from '../utils/logger'; import { ExternalCliOptions, sharedCliOptions } from './shared'; import { CliInfo } from './types'; import { getFullCommand } from './utils'; @@ -20,7 +25,11 @@ function logError(msg: string) { function handleError(err: Error) { debug('%O', err); - logError(err.message); + if (err.name === 'TwilioApiError') { + logApiError(logger, err); + } else { + logError(err.message); + } process.exit(1); } diff --git a/src/utils/logger.ts b/src/utils/logger.ts index a8615a0b..19f666c8 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -1,6 +1,8 @@ +import { ClientApiError } from '@twilio-labs/serverless-api/dist/utils/error'; import debug from 'debug'; import ora from 'ora'; import { Writable } from 'stream'; +import terminalLink from 'terminal-link'; import { errorMessage, warningMessage } from '../printers/utils'; // an empty stream that immediately drops everything. Like /dev/null @@ -100,6 +102,20 @@ export function setLogLevelByName(name: LoggingLevelNames) { logger.config = { level: LoggingLevel[name] }; } +export function logApiError(logger: ILogger, err: ClientApiError) { + let messageBody = err.message; + const moreInfoLink = err.details?.more_info; + if (typeof moreInfoLink === 'string') { + const linkText = terminalLink(moreInfoLink, moreInfoLink, { + fallback: () => moreInfoLink, + }); + messageBody += `\n\nMore info: ${linkText}`; + } + const title = `Failed API Request ${err.code}`; + + logger.error(messageBody, title); +} + export function getOraSpinner(options?: string | ora.Options): ora.Ora { let oraOptions: ora.Options; if (typeof options === 'string') { From 1f432e5aafc2da15547f78fa235d0928a2169b52 Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Thu, 7 May 2020 10:11:07 -0700 Subject: [PATCH 2/2] fix: adjust for comment from review --- src/commands/deploy.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/commands/deploy.ts b/src/commands/deploy.ts index 5a5ae453..684b554b 100644 --- a/src/commands/deploy.ts +++ b/src/commands/deploy.ts @@ -2,7 +2,6 @@ import { DeployLocalProjectConfig, TwilioServerlessApiClient, } from '@twilio-labs/serverless-api'; -import { ClientApiError } from '@twilio-labs/serverless-api/dist/utils/error'; import { stripIndent } from 'common-tags'; import { Ora } from 'ora'; import path from 'path'; @@ -59,8 +58,7 @@ function handleError( `; logger.error(messageBody, err.message); } else if (err.name === 'TwilioApiError') { - const apiError = err as ClientApiError; - logApiError(logger, apiError); + logApiError(logger, err); } else { logger.error(err.message); }