mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-20 01:36:32 +00:00
refactor(errors): createError and createUserError accept an object (#1322)
Currently, both of these functions accept two arguments: the error title, and the error description. This function signature makes is hard to keep adding options to these error creation functions, like an error code, so this commit refactors them to take a single argument: an options object containing `title` and `description` properties. Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This commit is contained in:
parent
b93fd86092
commit
fe91be11e8
@ -152,7 +152,9 @@ return permissions.isElevated().then((elevated) => {
|
|||||||
name: packageJSON.displayName
|
name: packageJSON.displayName
|
||||||
}).then((stdout, stderr) => {
|
}).then((stdout, stderr) => {
|
||||||
if (!_.isEmpty(stderr)) {
|
if (!_.isEmpty(stderr)) {
|
||||||
throw errors.createError(stderr);
|
throw errors.createError({
|
||||||
|
title: stderr
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're hardcoding internal error messages declared by `sudo-prompt`.
|
// We're hardcoding internal error messages declared by `sudo-prompt`.
|
||||||
@ -167,10 +169,10 @@ return permissions.isElevated().then((elevated) => {
|
|||||||
}).catch({
|
}).catch({
|
||||||
message: 'No polkit authentication agent found.'
|
message: 'No polkit authentication agent found.'
|
||||||
}, () => {
|
}, () => {
|
||||||
throw errors.createUserError(
|
throw errors.createUserError({
|
||||||
'No polkit authentication agent found',
|
title: 'No polkit authentication agent found',
|
||||||
'Please install a polkit authentication agent for your desktop environment of choice to continue'
|
description: 'Please install a polkit authentication agent for your desktop environment of choice to continue'
|
||||||
);
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,10 +35,10 @@ const imagePath = options._[ARGV_IMAGE_PATH_INDEX];
|
|||||||
|
|
||||||
permissions.isElevated().then((elevated) => {
|
permissions.isElevated().then((elevated) => {
|
||||||
if (!elevated) {
|
if (!elevated) {
|
||||||
throw errors.createUserError(
|
throw errors.createUserError({
|
||||||
messages.error.elevationRequired(),
|
title: messages.error.elevationRequired(),
|
||||||
'This tool requires special permissions to write to external drives'
|
description: 'This tool requires special permissions to write to external drives'
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return form.run([
|
return form.run([
|
||||||
@ -66,7 +66,10 @@ permissions.isElevated().then((elevated) => {
|
|||||||
});
|
});
|
||||||
}).then((answers) => {
|
}).then((answers) => {
|
||||||
if (!answers.yes) {
|
if (!answers.yes) {
|
||||||
throw errors.createUserError('Aborted', 'We can\'t proceed without confirmation');
|
throw errors.createUserError({
|
||||||
|
title: 'Aborted',
|
||||||
|
description: 'We can\'t proceed without confirmation'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const progressBars = {
|
const progressBars = {
|
||||||
@ -80,10 +83,10 @@ permissions.isElevated().then((elevated) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!selectedDrive) {
|
if (!selectedDrive) {
|
||||||
throw errors.createUserError(
|
throw errors.createUserError({
|
||||||
'The selected drive was not found',
|
title: 'The selected drive was not found',
|
||||||
`We can't find ${answers.drive} in your system. Did you unplug the drive?`
|
description: `We can't find ${answers.drive} in your system. Did you unplug the drive?`
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return writer.writeImage(imagePath, selectedDrive, {
|
return writer.writeImage(imagePath, selectedDrive, {
|
||||||
|
@ -93,7 +93,9 @@ module.exports = yargs
|
|||||||
|
|
||||||
// Error reporting
|
// Error reporting
|
||||||
.fail((message, error) => {
|
.fail((message, error) => {
|
||||||
const errorObject = error || errors.createUserError(message);
|
const errorObject = error || errors.createUserError({
|
||||||
|
title: message
|
||||||
|
});
|
||||||
|
|
||||||
if (robot.isEnabled(process.env)) {
|
if (robot.isEnabled(process.env)) {
|
||||||
robot.printError(errorObject);
|
robot.printError(errorObject);
|
||||||
@ -112,7 +114,10 @@ module.exports = yargs
|
|||||||
try {
|
try {
|
||||||
fs.accessSync(imagePath);
|
fs.accessSync(imagePath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw errors.createUserError('Unable to access file', `The image ${imagePath} is not accessible`);
|
throw errors.createUserError({
|
||||||
|
title: 'Unable to access file',
|
||||||
|
description: `The image ${imagePath} is not accessible`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -120,10 +125,10 @@ module.exports = yargs
|
|||||||
|
|
||||||
.check((argv) => {
|
.check((argv) => {
|
||||||
if (robot.isEnabled(process.env) && !argv.drive) {
|
if (robot.isEnabled(process.env) && !argv.drive) {
|
||||||
throw errors.createUserError(
|
throw errors.createUserError({
|
||||||
'Missing drive',
|
title: 'Missing drive',
|
||||||
'You need to explicitly pass a drive when enabling robot mode'
|
description: 'You need to explicitly pass a drive when enabling robot mode'
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -70,10 +70,10 @@ exports.writeImage = (imagePath, drive, options, onProgress) => {
|
|||||||
}).then((driveFileDescriptor) => {
|
}).then((driveFileDescriptor) => {
|
||||||
return imageStream.getFromFilePath(imagePath).then((image) => {
|
return imageStream.getFromFilePath(imagePath).then((image) => {
|
||||||
if (!constraints.isDriveLargeEnough(drive, image)) {
|
if (!constraints.isDriveLargeEnough(drive, image)) {
|
||||||
throw errors.createUserError(
|
throw errors.createUserError({
|
||||||
'The image you selected is too big for this drive',
|
title: 'The image you selected is too big for this drive',
|
||||||
'Please connect a bigger drive and try again'
|
description: 'Please connect a bigger drive and try again'
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return imageWrite.write({
|
return imageWrite.write({
|
||||||
|
@ -119,11 +119,15 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
|||||||
|
|
||||||
case ACTIONS.SET_AVAILABLE_DRIVES: {
|
case ACTIONS.SET_AVAILABLE_DRIVES: {
|
||||||
if (!action.data) {
|
if (!action.data) {
|
||||||
throw errors.createError('Missing drives');
|
throw errors.createError({
|
||||||
|
title: 'Missing drives'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isArray(action.data) || !_.every(action.data, _.isPlainObject)) {
|
if (!_.isArray(action.data) || !_.every(action.data, _.isPlainObject)) {
|
||||||
throw errors.createError(`Invalid drives: ${action.data}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid drives: ${action.data}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const newState = state.set('availableDrives', Immutable.fromJS(action.data));
|
const newState = state.set('availableDrives', Immutable.fromJS(action.data));
|
||||||
@ -170,35 +174,51 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
|||||||
|
|
||||||
case ACTIONS.SET_FLASH_STATE: {
|
case ACTIONS.SET_FLASH_STATE: {
|
||||||
if (!state.get('isFlashing')) {
|
if (!state.get('isFlashing')) {
|
||||||
throw errors.createError('Can\'t set the flashing state when not flashing');
|
throw errors.createError({
|
||||||
|
title: 'Can\'t set the flashing state when not flashing'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!action.data.type) {
|
if (!action.data.type) {
|
||||||
throw errors.createError('Missing state type');
|
throw errors.createError({
|
||||||
|
title: 'Missing state type'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isString(action.data.type)) {
|
if (!_.isString(action.data.type)) {
|
||||||
throw errors.createError(`Invalid state type: ${action.data.type}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid state type: ${action.data.type}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.isNil(action.data.percentage)) {
|
if (_.isNil(action.data.percentage)) {
|
||||||
throw errors.createError('Missing state percentage');
|
throw errors.createError({
|
||||||
|
title: 'Missing state percentage'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isNumber(action.data.percentage)) {
|
if (!_.isNumber(action.data.percentage)) {
|
||||||
throw errors.createError(`Invalid state percentage: ${action.data.percentage}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid state percentage: ${action.data.percentage}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.isNil(action.data.eta)) {
|
if (_.isNil(action.data.eta)) {
|
||||||
throw errors.createError('Missing state eta');
|
throw errors.createError({
|
||||||
|
title: 'Missing state eta'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isNumber(action.data.eta)) {
|
if (!_.isNumber(action.data.eta)) {
|
||||||
throw errors.createError(`Invalid state eta: ${action.data.eta}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid state eta: ${action.data.eta}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.isNil(action.data.speed)) {
|
if (_.isNil(action.data.speed)) {
|
||||||
throw errors.createError('Missing state speed');
|
throw errors.createError({
|
||||||
|
title: 'Missing state speed'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.set('flashState', Immutable.fromJS(action.data));
|
return state.set('flashState', Immutable.fromJS(action.data));
|
||||||
@ -218,7 +238,9 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
|||||||
|
|
||||||
case ACTIONS.UNSET_FLASHING_FLAG: {
|
case ACTIONS.UNSET_FLASHING_FLAG: {
|
||||||
if (!action.data) {
|
if (!action.data) {
|
||||||
throw errors.createError('Missing results');
|
throw errors.createError({
|
||||||
|
title: 'Missing results'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_.defaults(action.data, {
|
_.defaults(action.data, {
|
||||||
@ -226,19 +248,27 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!_.isBoolean(action.data.cancelled)) {
|
if (!_.isBoolean(action.data.cancelled)) {
|
||||||
throw errors.createError(`Invalid results cancelled: ${action.data.cancelled}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid results cancelled: ${action.data.cancelled}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.data.cancelled && action.data.sourceChecksum) {
|
if (action.data.cancelled && action.data.sourceChecksum) {
|
||||||
throw errors.createError('The sourceChecksum value can\'t exist if the flashing was cancelled');
|
throw errors.createError({
|
||||||
|
title: 'The sourceChecksum value can\'t exist if the flashing was cancelled'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.data.sourceChecksum && !_.isString(action.data.sourceChecksum)) {
|
if (action.data.sourceChecksum && !_.isString(action.data.sourceChecksum)) {
|
||||||
throw errors.createError(`Invalid results sourceChecksum: ${action.data.sourceChecksum}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid results sourceChecksum: ${action.data.sourceChecksum}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.data.errorCode && !_.isString(action.data.errorCode) && !_.isNumber(action.data.errorCode)) {
|
if (action.data.errorCode && !_.isString(action.data.errorCode) && !_.isNumber(action.data.errorCode)) {
|
||||||
throw errors.createError(`Invalid results errorCode: ${action.data.errorCode}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid results errorCode: ${action.data.errorCode}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return state
|
return state
|
||||||
@ -249,26 +279,36 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
|||||||
|
|
||||||
case ACTIONS.SELECT_DRIVE: {
|
case ACTIONS.SELECT_DRIVE: {
|
||||||
if (!action.data) {
|
if (!action.data) {
|
||||||
throw errors.createError('Missing drive');
|
throw errors.createError({
|
||||||
|
title: 'Missing drive'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isString(action.data)) {
|
if (!_.isString(action.data)) {
|
||||||
throw errors.createError(`Invalid drive: ${action.data}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid drive: ${action.data}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedDrive = findDrive(state, action.data);
|
const selectedDrive = findDrive(state, action.data);
|
||||||
|
|
||||||
if (!selectedDrive) {
|
if (!selectedDrive) {
|
||||||
throw errors.createError(`The drive is not available: ${action.data}`);
|
throw errors.createError({
|
||||||
|
title: `The drive is not available: ${action.data}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedDrive.get('protected')) {
|
if (selectedDrive.get('protected')) {
|
||||||
throw errors.createError('The drive is write-protected');
|
throw errors.createError({
|
||||||
|
title: 'The drive is write-protected'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const image = state.getIn([ 'selection', 'image' ]);
|
const image = state.getIn([ 'selection', 'image' ]);
|
||||||
if (image && !constraints.isDriveLargeEnough(selectedDrive.toJS(), image.toJS())) {
|
if (image && !constraints.isDriveLargeEnough(selectedDrive.toJS(), image.toJS())) {
|
||||||
throw errors.createError('The drive is not large enough');
|
throw errors.createError({
|
||||||
|
title: 'The drive is not large enough'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.setIn([ 'selection', 'drive' ], Immutable.fromJS(action.data));
|
return state.setIn([ 'selection', 'drive' ], Immutable.fromJS(action.data));
|
||||||
@ -276,45 +316,65 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
|||||||
|
|
||||||
case ACTIONS.SELECT_IMAGE: {
|
case ACTIONS.SELECT_IMAGE: {
|
||||||
if (!action.data.path) {
|
if (!action.data.path) {
|
||||||
throw errors.createError('Missing image path');
|
throw errors.createError({
|
||||||
|
title: 'Missing image path'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isString(action.data.path)) {
|
if (!_.isString(action.data.path)) {
|
||||||
throw errors.createError(`Invalid image path: ${action.data.path}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid image path: ${action.data.path}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!action.data.size) {
|
if (!action.data.size) {
|
||||||
throw errors.createError('Missing image size');
|
throw errors.createError({
|
||||||
|
title: 'Missing image size'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isPlainObject(action.data.size)) {
|
if (!_.isPlainObject(action.data.size)) {
|
||||||
throw errors.createError(`Invalid image size: ${action.data.size}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid image size: ${action.data.size}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const MINIMUM_IMAGE_SIZE = 0;
|
const MINIMUM_IMAGE_SIZE = 0;
|
||||||
|
|
||||||
if (!_.isInteger(action.data.size.original) || action.data.size.original < MINIMUM_IMAGE_SIZE) {
|
if (!_.isInteger(action.data.size.original) || action.data.size.original < MINIMUM_IMAGE_SIZE) {
|
||||||
throw errors.createError(`Invalid original image size: ${action.data.size.original}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid original image size: ${action.data.size.original}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isInteger(action.data.size.final.value) || action.data.size.final.value < MINIMUM_IMAGE_SIZE) {
|
if (!_.isInteger(action.data.size.final.value) || action.data.size.final.value < MINIMUM_IMAGE_SIZE) {
|
||||||
throw errors.createError(`Invalid final image size: ${action.data.size.final.value}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid final image size: ${action.data.size.final.value}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isBoolean(action.data.size.final.estimation)) {
|
if (!_.isBoolean(action.data.size.final.estimation)) {
|
||||||
throw errors.createError(`Invalid final image size estimation flag: ${action.data.size.final.estimation}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid final image size estimation flag: ${action.data.size.final.estimation}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.data.url && !_.isString(action.data.url)) {
|
if (action.data.url && !_.isString(action.data.url)) {
|
||||||
throw errors.createError(`Invalid image url: ${action.data.url}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid image url: ${action.data.url}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.data.name && !_.isString(action.data.name)) {
|
if (action.data.name && !_.isString(action.data.name)) {
|
||||||
throw errors.createError(`Invalid image name: ${action.data.name}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid image name: ${action.data.name}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.data.logo && !_.isString(action.data.logo)) {
|
if (action.data.logo && !_.isString(action.data.logo)) {
|
||||||
throw errors.createError(`Invalid image logo: ${action.data.logo}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid image logo: ${action.data.logo}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedDrive = findDrive(state, state.getIn([ 'selection', 'drive' ]));
|
const selectedDrive = findDrive(state, state.getIn([ 'selection', 'drive' ]));
|
||||||
@ -346,19 +406,27 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
|||||||
const value = action.data.value;
|
const value = action.data.value;
|
||||||
|
|
||||||
if (!key) {
|
if (!key) {
|
||||||
throw errors.createError('Missing setting key');
|
throw errors.createError({
|
||||||
|
title: 'Missing setting key'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isString(key)) {
|
if (!_.isString(key)) {
|
||||||
throw errors.createError(`Invalid setting key: ${key}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid setting key: ${key}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DEFAULT_STATE.get('settings').has(key)) {
|
if (!DEFAULT_STATE.get('settings').has(key)) {
|
||||||
throw errors.createError(`Unsupported setting: ${key}`);
|
throw errors.createError({
|
||||||
|
title: `Unsupported setting: ${key}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.isObject(value)) {
|
if (_.isObject(value)) {
|
||||||
throw errors.createError(`Invalid setting value: ${value}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid setting value: ${value}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.setIn([ 'settings', key ], value);
|
return state.setIn([ 'settings', key ], value);
|
||||||
|
@ -68,9 +68,12 @@ module.exports = function(
|
|||||||
*/
|
*/
|
||||||
this.selectImage = (image) => {
|
this.selectImage = (image) => {
|
||||||
if (!supportedFormats.isSupportedImage(image.path)) {
|
if (!supportedFormats.isSupportedImage(image.path)) {
|
||||||
const invalidImageError = errors.createUserError('Invalid image', messages.error.invalidImage({
|
const invalidImageError = errors.createUserError({
|
||||||
|
title: 'Invalid image',
|
||||||
|
description: messages.error.invalidImage({
|
||||||
image
|
image
|
||||||
}));
|
})
|
||||||
|
});
|
||||||
|
|
||||||
OSDialogService.showError(invalidImageError);
|
OSDialogService.showError(invalidImageError);
|
||||||
AnalyticsService.logEvent('Invalid image', image);
|
AnalyticsService.logEvent('Invalid image', image);
|
||||||
|
@ -41,7 +41,9 @@ module.exports = (ManifestBindService) => {
|
|||||||
const value = ManifestBindService.get(attributes.manifestBind);
|
const value = ManifestBindService.get(attributes.manifestBind);
|
||||||
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
throw errors.createError(`ManifestBind: Unknown property \`${attributes.manifestBind}\``);
|
throw errors.createError({
|
||||||
|
title: `ManifestBind: Unknown property \`${attributes.manifestBind}\``
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
element.html(value);
|
element.html(value);
|
||||||
|
@ -89,7 +89,9 @@ exports.extractFile = (archive, entries, file) => {
|
|||||||
if (!_.find(entries, {
|
if (!_.find(entries, {
|
||||||
name: file
|
name: file
|
||||||
})) {
|
})) {
|
||||||
throw errors.createError(`Invalid entry: ${file}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid entry: ${file}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
yauzl.openAsync(archive, {
|
yauzl.openAsync(archive, {
|
||||||
|
@ -119,10 +119,10 @@ const extractArchiveMetadata = (archive, basePath, options) => {
|
|||||||
try {
|
try {
|
||||||
return JSON.parse(manifest);
|
return JSON.parse(manifest);
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
throw errors.createUserError(
|
throw errors.createUserError({
|
||||||
'Invalid archive manifest.json',
|
title: 'Invalid archive manifest.json',
|
||||||
'The archive manifest.json file is not valid JSON'
|
description: 'The archive manifest.json file is not valid JSON'
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -178,10 +178,10 @@ exports.extractImage = (archive, hooks) => {
|
|||||||
|
|
||||||
const VALID_NUMBER_OF_IMAGE_ENTRIES = 1;
|
const VALID_NUMBER_OF_IMAGE_ENTRIES = 1;
|
||||||
if (imageEntries.length !== VALID_NUMBER_OF_IMAGE_ENTRIES) {
|
if (imageEntries.length !== VALID_NUMBER_OF_IMAGE_ENTRIES) {
|
||||||
throw errors.createUserError(
|
throw errors.createUserError({
|
||||||
'Invalid archive image',
|
title: 'Invalid archive image',
|
||||||
'The archive image should contain one and only one top image file'
|
description: 'The archive image should contain one and only one top image file'
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const imageEntry = _.first(imageEntries);
|
const imageEntry = _.first(imageEntries);
|
||||||
|
@ -69,12 +69,18 @@ const errors = require('../shared/errors');
|
|||||||
exports.getFromFilePath = (file) => {
|
exports.getFromFilePath = (file) => {
|
||||||
return fs.statAsync(file).then((fileStats) => {
|
return fs.statAsync(file).then((fileStats) => {
|
||||||
if (!fileStats.isFile()) {
|
if (!fileStats.isFile()) {
|
||||||
throw errors.createUserError('Invalid image', 'The image must be a file');
|
throw errors.createUserError({
|
||||||
|
title: 'Invalid image',
|
||||||
|
description: 'The image must be a file'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils.getArchiveMimeType(file).then((type) => {
|
return utils.getArchiveMimeType(file).then((type) => {
|
||||||
if (!_.has(handlers, type)) {
|
if (!_.has(handlers, type)) {
|
||||||
throw errors.createUserError('Invalid image', `The ${type} format is not supported`);
|
throw errors.createUserError({
|
||||||
|
title: 'Invalid image',
|
||||||
|
description: `The ${type} format is not supported`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.invoke(handlers, type, file, {
|
return _.invoke(handlers, type, file, {
|
||||||
|
@ -231,23 +231,27 @@ exports.getDescription = (error, options = {}) => {
|
|||||||
* @function
|
* @function
|
||||||
* @public
|
* @public
|
||||||
*
|
*
|
||||||
* @param {String} title - error title
|
* @param {Object} options - options
|
||||||
* @param {String} [description] - error description
|
* @param {String} options.title - error title
|
||||||
* @param {Object} [options] - options
|
* @param {String} [options.description] - error description
|
||||||
* @param {Boolean} [options.report] - report error
|
* @param {Boolean} [options.report] - report error
|
||||||
* @returns {Error} error
|
* @returns {Error} error
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const error = errors.createError('Foo', 'Bar');
|
* const error = errors.createError({
|
||||||
|
* title: 'Foo'
|
||||||
|
* description: 'Bar'
|
||||||
|
* });
|
||||||
|
*
|
||||||
* throw error;
|
* throw error;
|
||||||
*/
|
*/
|
||||||
exports.createError = (title, description, options = {}) => {
|
exports.createError = (options) => {
|
||||||
if (isBlank(title)) {
|
if (isBlank(options.title)) {
|
||||||
throw new Error(`Invalid error title: ${title}`);
|
throw new Error(`Invalid error title: ${options.title}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const error = new Error(title);
|
const error = new Error(options.title);
|
||||||
error.description = description;
|
error.description = options.description;
|
||||||
|
|
||||||
if (!_.isNil(options.report) && !options.report) {
|
if (!_.isNil(options.report) && !options.report) {
|
||||||
error.report = false;
|
error.report = false;
|
||||||
@ -267,16 +271,23 @@ exports.createError = (title, description, options = {}) => {
|
|||||||
* Therefore, user errors don't get reported to analytics
|
* Therefore, user errors don't get reported to analytics
|
||||||
* and error reporting services.
|
* and error reporting services.
|
||||||
*
|
*
|
||||||
* @param {String} title - error title
|
* @param {Object} options - options
|
||||||
* @param {String} [description] - error description
|
* @param {String} options.title - error title
|
||||||
|
* @param {String} [options.description] - error description
|
||||||
* @returns {Error} user error
|
* @returns {Error} user error
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const error = errors.createUserError('Foo', 'Bar');
|
* const error = errors.createUserError({
|
||||||
|
* title: 'Foo',
|
||||||
|
* description: 'Bar'
|
||||||
|
* });
|
||||||
|
*
|
||||||
* throw error;
|
* throw error;
|
||||||
*/
|
*/
|
||||||
exports.createUserError = (title, description) => {
|
exports.createUserError = (options) => {
|
||||||
return exports.createError(title, description, {
|
return exports.createError({
|
||||||
|
title: options.title,
|
||||||
|
description: options.description,
|
||||||
report: false
|
report: false
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -120,7 +120,11 @@ functions: `.printError()` and `.recomposeErrorMessage()`.
|
|||||||
Here's an example of these functions in action:
|
Here's an example of these functions in action:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const error = errors.createError('This is an error', 'My description');
|
const error = errors.createError({
|
||||||
|
title: 'This is an error',
|
||||||
|
description: 'My description'
|
||||||
|
});
|
||||||
|
|
||||||
robot.printError(error);
|
robot.printError(error);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -56,7 +56,9 @@ exports.isEnabled = (environment) => {
|
|||||||
*/
|
*/
|
||||||
exports.buildMessage = (title, data = {}) => {
|
exports.buildMessage = (title, data = {}) => {
|
||||||
if (!_.isPlainObject(data)) {
|
if (!_.isPlainObject(data)) {
|
||||||
throw errors.createError(`Invalid data: ${data}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid data: ${data}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
@ -117,11 +119,17 @@ exports.parseMessage = (string) => {
|
|||||||
try {
|
try {
|
||||||
output = JSON.parse(string);
|
output = JSON.parse(string);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw errors.createError('Invalid message', `${string}, ${error.message}`);
|
throw errors.createError({
|
||||||
|
title: 'Invalid message',
|
||||||
|
description: `${string}, ${error.message}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!output.command || !output.data) {
|
if (!output.command || !output.data) {
|
||||||
throw errors.createError('Invalid message', `No command or data: ${string}`);
|
throw errors.createError({
|
||||||
|
title: 'Invalid message',
|
||||||
|
description: `No command or data: ${string}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
@ -71,7 +71,9 @@ exports.isValidPercentage = (percentage) => {
|
|||||||
*/
|
*/
|
||||||
exports.percentageToFloat = (percentage) => {
|
exports.percentageToFloat = (percentage) => {
|
||||||
if (!exports.isValidPercentage(percentage)) {
|
if (!exports.isValidPercentage(percentage)) {
|
||||||
throw errors.createError(`Invalid percentage: ${percentage}`);
|
throw errors.createError({
|
||||||
|
title: `Invalid percentage: ${percentage}`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return percentage / PERCENTAGE_MAXIMUM;
|
return percentage / PERCENTAGE_MAXIMUM;
|
||||||
|
@ -390,12 +390,18 @@ describe('Shared: Errors', function() {
|
|||||||
describe('.createError()', function() {
|
describe('.createError()', function() {
|
||||||
|
|
||||||
it('should not set `error.report` by default', function() {
|
it('should not set `error.report` by default', function() {
|
||||||
const error = errors.createError('Foo', 'Something happened');
|
const error = errors.createError({
|
||||||
|
title: 'Foo',
|
||||||
|
description: 'Something happened'
|
||||||
|
});
|
||||||
|
|
||||||
m.chai.expect(error.report).to.be.undefined;
|
m.chai.expect(error.report).to.be.undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set `error.report` to false if `options.report` is false', function() {
|
it('should set `error.report` to false if `options.report` is false', function() {
|
||||||
const error = errors.createError('Foo', 'Something happened', {
|
const error = errors.createError({
|
||||||
|
title: 'Foo',
|
||||||
|
description: 'Something happened',
|
||||||
report: false
|
report: false
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -403,7 +409,9 @@ describe('Shared: Errors', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should set `error.report` to false if `options.report` evaluates to false', function() {
|
it('should set `error.report` to false if `options.report` evaluates to false', function() {
|
||||||
const error = errors.createError('Foo', 'Something happened', {
|
const error = errors.createError({
|
||||||
|
title: 'Foo',
|
||||||
|
description: 'Something happened',
|
||||||
report: 0
|
report: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -411,47 +419,78 @@ describe('Shared: Errors', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be an instance of Error', function() {
|
it('should be an instance of Error', function() {
|
||||||
const error = errors.createError('Foo', 'Something happened');
|
const error = errors.createError({
|
||||||
|
title: 'Foo',
|
||||||
|
description: 'Something happened'
|
||||||
|
});
|
||||||
|
|
||||||
m.chai.expect(error).to.be.an.instanceof(Error);
|
m.chai.expect(error).to.be.an.instanceof(Error);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly add both a message and a description', function() {
|
it('should correctly add both a title and a description', function() {
|
||||||
const error = errors.createError('Foo', 'Something happened');
|
const error = errors.createError({
|
||||||
|
title: 'Foo',
|
||||||
|
description: 'Something happened'
|
||||||
|
});
|
||||||
|
|
||||||
m.chai.expect(errors.getTitle(error)).to.equal('Foo');
|
m.chai.expect(errors.getTitle(error)).to.equal('Foo');
|
||||||
m.chai.expect(errors.getDescription(error)).to.equal('Something happened');
|
m.chai.expect(errors.getDescription(error)).to.equal('Something happened');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly add only a message', function() {
|
it('should correctly add only a title', function() {
|
||||||
const error = errors.createError('Foo');
|
const error = errors.createError({
|
||||||
|
title: 'Foo'
|
||||||
|
});
|
||||||
|
|
||||||
m.chai.expect(errors.getTitle(error)).to.equal('Foo');
|
m.chai.expect(errors.getTitle(error)).to.equal('Foo');
|
||||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should ignore an empty description', function() {
|
it('should ignore an empty description', function() {
|
||||||
const error = errors.createError('Foo', '');
|
const error = errors.createError({
|
||||||
|
title: 'Foo',
|
||||||
|
description: ''
|
||||||
|
});
|
||||||
|
|
||||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should ignore a blank description', function() {
|
it('should ignore a blank description', function() {
|
||||||
const error = errors.createError('Foo', ' ');
|
const error = errors.createError({
|
||||||
|
title: 'Foo',
|
||||||
|
description: ' '
|
||||||
|
});
|
||||||
|
|
||||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if no message', function() {
|
it('should throw if no title', function() {
|
||||||
m.chai.expect(() => {
|
m.chai.expect(() => {
|
||||||
errors.createError();
|
errors.createError({});
|
||||||
}).to.throw('Invalid error title: undefined');
|
}).to.throw('Invalid error title: undefined');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if message is empty', function() {
|
it('should throw if there is a description but no title', function() {
|
||||||
m.chai.expect(() => {
|
m.chai.expect(() => {
|
||||||
errors.createError('');
|
errors.createError({
|
||||||
|
description: 'foo'
|
||||||
|
});
|
||||||
|
}).to.throw('Invalid error title: undefined');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw if title is empty', function() {
|
||||||
|
m.chai.expect(() => {
|
||||||
|
errors.createError({
|
||||||
|
title: ''
|
||||||
|
});
|
||||||
}).to.throw('Invalid error title: ');
|
}).to.throw('Invalid error title: ');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if message is blank', function() {
|
it('should throw if title is blank', function() {
|
||||||
m.chai.expect(() => {
|
m.chai.expect(() => {
|
||||||
errors.createError(' ');
|
errors.createError({
|
||||||
|
title: ' '
|
||||||
|
});
|
||||||
}).to.throw('Invalid error title: ');
|
}).to.throw('Invalid error title: ');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -460,52 +499,87 @@ describe('Shared: Errors', function() {
|
|||||||
describe('.createUserError()', function() {
|
describe('.createUserError()', function() {
|
||||||
|
|
||||||
it('should set the `report` flag to `false`', function() {
|
it('should set the `report` flag to `false`', function() {
|
||||||
const error = errors.createUserError('Foo', 'Something happened');
|
const error = errors.createUserError({
|
||||||
|
title: 'Foo',
|
||||||
|
description: 'Something happened'
|
||||||
|
});
|
||||||
|
|
||||||
m.chai.expect(error.report).to.be.false;
|
m.chai.expect(error.report).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be an instance of Error', function() {
|
it('should be an instance of Error', function() {
|
||||||
const error = errors.createUserError('Foo', 'Something happened');
|
const error = errors.createUserError({
|
||||||
|
title: 'Foo',
|
||||||
|
description: 'Something happened'
|
||||||
|
});
|
||||||
|
|
||||||
m.chai.expect(error).to.be.an.instanceof(Error);
|
m.chai.expect(error).to.be.an.instanceof(Error);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly add both a message and a description', function() {
|
it('should correctly add both a title and a description', function() {
|
||||||
const error = errors.createUserError('Foo', 'Something happened');
|
const error = errors.createUserError({
|
||||||
|
title: 'Foo',
|
||||||
|
description: 'Something happened'
|
||||||
|
});
|
||||||
|
|
||||||
m.chai.expect(errors.getTitle(error)).to.equal('Foo');
|
m.chai.expect(errors.getTitle(error)).to.equal('Foo');
|
||||||
m.chai.expect(errors.getDescription(error)).to.equal('Something happened');
|
m.chai.expect(errors.getDescription(error)).to.equal('Something happened');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly add only a message', function() {
|
it('should correctly add only a title', function() {
|
||||||
const error = errors.createUserError('Foo');
|
const error = errors.createUserError({
|
||||||
|
title: 'Foo'
|
||||||
|
});
|
||||||
|
|
||||||
m.chai.expect(errors.getTitle(error)).to.equal('Foo');
|
m.chai.expect(errors.getTitle(error)).to.equal('Foo');
|
||||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should ignore an empty description', function() {
|
it('should ignore an empty description', function() {
|
||||||
const error = errors.createUserError('Foo', '');
|
const error = errors.createUserError({
|
||||||
|
title: 'Foo',
|
||||||
|
description: ''
|
||||||
|
});
|
||||||
|
|
||||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should ignore a blank description', function() {
|
it('should ignore a blank description', function() {
|
||||||
const error = errors.createUserError('Foo', ' ');
|
const error = errors.createUserError({
|
||||||
|
title: 'Foo',
|
||||||
|
description: ' '
|
||||||
|
});
|
||||||
|
|
||||||
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
m.chai.expect(errors.getDescription(error)).to.equal(error.stack);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if no message', function() {
|
it('should throw if no title', function() {
|
||||||
m.chai.expect(() => {
|
m.chai.expect(() => {
|
||||||
errors.createUserError();
|
errors.createUserError({});
|
||||||
}).to.throw('Invalid error title: undefined');
|
}).to.throw('Invalid error title: undefined');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if message is empty', function() {
|
it('should throw if title is empty', function() {
|
||||||
m.chai.expect(() => {
|
m.chai.expect(() => {
|
||||||
errors.createUserError('');
|
errors.createUserError({
|
||||||
|
title: ''
|
||||||
|
});
|
||||||
}).to.throw('Invalid error title: ');
|
}).to.throw('Invalid error title: ');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if message is blank', function() {
|
it('should throw if there is a description but no title', function() {
|
||||||
m.chai.expect(() => {
|
m.chai.expect(() => {
|
||||||
errors.createUserError(' ');
|
errors.createUserError({
|
||||||
|
description: 'foo'
|
||||||
|
});
|
||||||
|
}).to.throw('Invalid error title: undefined');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw if title is blank', function() {
|
||||||
|
m.chai.expect(() => {
|
||||||
|
errors.createUserError({
|
||||||
|
title: ' '
|
||||||
|
});
|
||||||
}).to.throw('Invalid error title: ');
|
}).to.throw('Invalid error title: ');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user