diff --git a/CHANGELOG b/CHANGELOG index d0884b2b82..721f47a4c1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,14 @@ devel ----- +* improved error messages when managing Foxx services + + Install/replace/upgrade will now provide additional information when an error + is encountered during setup. Errors encountered during a `require` call will + also include information about the underlying cause in the error message. + +* fixed some Foxx script names being displayed incorrectly in web UI and Foxx CLI + * major revision of the maintenance feature * added `uuidv4` and `genRandomBytes` methods to crypto module diff --git a/js/apps/system/_api/foxx/APP/index.js b/js/apps/system/_api/foxx/APP/index.js index 9f40aabab1..f1c4734580 100644 --- a/js/apps/system/_api/foxx/APP/index.js +++ b/js/apps/system/_api/foxx/APP/index.js @@ -89,7 +89,11 @@ router.use((req, res, next) => { if (e.isArangoError) { const status = actions.arangoErrorToHttpCode(e.errorNum); console.errorStack(e); - res.throw(status, e.errorMessage, { + res.throw(status, ( + e.codeFrame + ? `${e.codeFrame}\n${e}` + : String(e) + ), { errorNum: e.errorNum, cause: e }); diff --git a/js/common/bootstrap/modules.js b/js/common/bootstrap/modules.js index e4003c4e23..7fa21255d2 100644 --- a/js/common/bootstrap/modules.js +++ b/js/common/bootstrap/modules.js @@ -542,7 +542,7 @@ Module._extensions[extension](this, filename); } catch (e) { if (e.errorNum !== internal.errors.ERROR_MODULE_FAILURE.code) { - let msg = `${internal.errors.ERROR_MODULE_FAILURE.message}`; + let msg = `${internal.errors.ERROR_MODULE_FAILURE.message}\nReason: ${e}`; if (e.fileName !== undefined) { msg += `\nFile: ${e.fileName}`; diff --git a/js/common/bootstrap/modules/console.js b/js/common/bootstrap/modules/console.js index 1e0c0f7760..1d9a70df2b 100644 --- a/js/common/bootstrap/modules/console.js +++ b/js/common/bootstrap/modules/console.js @@ -438,12 +438,6 @@ global.DEFINE_MODULE('console', (function () { exports.levelStack = function (lvl, e, msg) { let logStrings = []; - if (msg) { - logStrings.push(msg); - } - if (e.codeFrame) { - logStrings.push(e.codeFrame); - } let err = e; while (err) { if (!msg && err === e) { @@ -458,6 +452,13 @@ global.DEFINE_MODULE('console', (function () { } err = err.cause; } + if (e.codeFrame) { + logStrings[0] = `\n${logStrings[0]}`; + logStrings.unshift(e.codeFrame); + } + if (msg) { + logStrings.unshift(msg); + } exports.logLvlLines(lvl, logStrings); }; diff --git a/js/common/modules/@arangodb/foxx/manager-utils.js b/js/common/modules/@arangodb/foxx/manager-utils.js index 928fd810d5..3385d820fb 100644 --- a/js/common/modules/@arangodb/foxx/manager-utils.js +++ b/js/common/modules/@arangodb/foxx/manager-utils.js @@ -45,11 +45,12 @@ var pathRegex = /^((\.{0,2}(\/|\\))|(~\/)|[a-zA-Z]:\\)/; const DEFAULT_REPLICATION_FACTOR_SYSTEM = internal.DEFAULT_REPLICATION_FACTOR_SYSTEM; function getReadableName (name) { - return name.charAt(0).toUpperCase() + name.substr(1) + const readable = name .replace(/([-_]|\s)+/g, ' ') .replace(/([a-z])([A-Z])/g, (m) => `${m[0]} ${m[1]}`) .replace(/([A-Z])([A-Z][a-z])/g, (m) => `${m[0]} ${m[1]}`) - .replace(/\s([a-z])/g, (m) => ` ${m[0].toUpperCase()}`); + .replace(/\s([a-z])/g, (m) => ` ${m[1].toUpperCase()}`); + return readable.charAt(0).toUpperCase() + readable.substr(1) } function getStorage () { diff --git a/js/common/modules/@arangodb/util.js b/js/common/modules/@arangodb/util.js index 97f4a3a760..689d9519d7 100644 --- a/js/common/modules/@arangodb/util.js +++ b/js/common/modules/@arangodb/util.js @@ -108,7 +108,9 @@ exports.codeFrame = function (e, basePath, withColor = internal.COLOR_OUTPUT) { highlightCode: withColor, forceColor: withColor }); - const location = `@ ${ctx.fileName}:${ctx.lineNumber}:${ctx.columnNumber}\n`; + const location = `@ ${ + basePath ? ctx.fileName.slice(basePath.length + 1) : ctx.fileName + }:${ctx.lineNumber}:${ctx.columnNumber}\n`; return (withColor ? chalk.grey(location) : location) + frame; } } catch (e) {} diff --git a/js/common/tests/shell/shell-foxx-manager-utils-spec.js b/js/common/tests/shell/shell-foxx-manager-utils-spec.js new file mode 100644 index 0000000000..adca6b4f9f --- /dev/null +++ b/js/common/tests/shell/shell-foxx-manager-utils-spec.js @@ -0,0 +1,10 @@ +"use strict"; +const { expect } = require("chai"); +const { getReadableName } = require("@arangodb/foxx/manager-utils"); + +test("getReadableName", () => { + expect(getReadableName("catch-fire")).to.equal("Catch Fire"); + expect(getReadableName("catchFire")).to.equal("Catch Fire"); + expect(getReadableName("CatchFire")).to.equal("Catch Fire"); + expect(getReadableName("cAtChFiRe")).to.equal("C At Ch Fi Re"); +}); diff --git a/js/server/modules/@arangodb/foxx/manager.js b/js/server/modules/@arangodb/foxx/manager.js index 531ac52414..4000af07dc 100644 --- a/js/server/modules/@arangodb/foxx/manager.js +++ b/js/server/modules/@arangodb/foxx/manager.js @@ -44,6 +44,7 @@ const ArangoClusterControl = require('@arangodb/cluster'); const request = require('@arangodb/request'); const actions = require('@arangodb/actions'); const isZipBuffer = require('@arangodb/util').isZipBuffer; +const codeFrame = require('@arangodb/util').codeFrame; const SYSTEM_SERVICE_MOUNTS = [ '/_admin/aardvark', // Admin interface. @@ -676,6 +677,7 @@ function _install (mount, tempPaths, options = {}) { } } catch (e) { if (!options.force) { + e.codeFrame = codeFrame(e, servicePath); throw e; } else { console.warnStack(e); @@ -940,8 +942,13 @@ function runScript (scriptName, mount, options) { service = reloadInstalledService(mount, runSetup); } ensureServiceLoaded(mount); - const result = service.executeScript(scriptName, options); - return result === undefined ? null : result; + try { + const result = service.executeScript(scriptName, options); + return result === undefined ? null : result; + } catch (e) { + e.codeFrame = codeFrame(e, service.basePath); + throw e; + } } function runTests (mount, options = {}) {