mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-23 15:32:22 +00:00
Merge pull request #1791 from balena-io/errors-refactor
Errors refactor
This commit is contained in:
commit
3b53b75626
@ -87,6 +87,7 @@ Examples:
|
||||
const balena = getBalenaSdk();
|
||||
const patterns = await import('../utils/patterns');
|
||||
const messages = await import('../utils/messages');
|
||||
const { exitWithExpectedError } = await import('../errors');
|
||||
|
||||
const doLogin = async (loginOptions: Options): Promise<void> => {
|
||||
if (loginOptions.token != null) {
|
||||
@ -103,7 +104,7 @@ Examples:
|
||||
}
|
||||
await balena.auth.loginWithToken(token);
|
||||
if (!(await balena.auth.whoami())) {
|
||||
patterns.exitWithExpectedError('Token authentication failed');
|
||||
exitWithExpectedError('Token authentication failed');
|
||||
}
|
||||
return;
|
||||
} else if (loginOptions.credentials) {
|
||||
@ -120,7 +121,7 @@ Examples:
|
||||
const signupUrl = 'https://dashboard.balena-cloud.com/signup';
|
||||
const open = await import('open');
|
||||
open(signupUrl, { wait: false });
|
||||
return patterns.exitWithExpectedError(`Please sign up at ${signupUrl}`);
|
||||
return exitWithExpectedError(`Please sign up at ${signupUrl}`);
|
||||
}
|
||||
|
||||
loginOptions[loginType] = true;
|
||||
|
@ -322,7 +322,7 @@ Examples:
|
||||
generateApplicationConfig,
|
||||
} = require('../utils/config');
|
||||
const helpers = require('../utils/helpers');
|
||||
const { exitWithExpectedError } = require('../utils/patterns');
|
||||
const { exitWithExpectedError } = require('../errors');
|
||||
|
||||
if (options.device == null && options.application == null) {
|
||||
exitWithExpectedError(`\
|
||||
|
@ -20,7 +20,7 @@ import * as capitano from 'capitano';
|
||||
import * as columnify from 'columnify';
|
||||
import * as messages from '../utils/messages';
|
||||
import { getManualSortCompareFunction } from '../utils/helpers';
|
||||
import { exitWithExpectedError } from '../utils/patterns';
|
||||
import { exitWithExpectedError } from '../errors';
|
||||
import { getOclifHelpLinePairs } from './help_ts';
|
||||
|
||||
const parse = object =>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as Promise from 'bluebird';
|
||||
import * as _ from 'lodash';
|
||||
import * as dockerUtils from '../../utils/docker';
|
||||
import { exitWithExpectedError } from '../../utils/patterns';
|
||||
import { exitWithExpectedError } from '../../errors';
|
||||
import { getChalk } from '../../utils/lazy';
|
||||
|
||||
export const dockerPort = 2375;
|
||||
|
@ -91,9 +91,8 @@ export const logs: CommandDefinition<
|
||||
'../utils/device/logs'
|
||||
);
|
||||
const { validateIPAddress } = await import('../utils/validation');
|
||||
const { exitIfNotLoggedIn, exitWithExpectedError } = await import(
|
||||
'../utils/patterns'
|
||||
);
|
||||
const { checkLoggedIn } = await import('../utils/patterns');
|
||||
const { exitWithExpectedError } = await import('../errors');
|
||||
const Logger = await import('../utils/logger');
|
||||
|
||||
const logger = Logger.getLogger();
|
||||
@ -152,7 +151,7 @@ export const logs: CommandDefinition<
|
||||
servicesToDisplay,
|
||||
);
|
||||
} else {
|
||||
await exitIfNotLoggedIn();
|
||||
await checkLoggedIn();
|
||||
if (options.tail) {
|
||||
return balena.logs
|
||||
.subscribe(params.uuidOrDevice, { count: 100 })
|
||||
|
@ -87,7 +87,7 @@ const getApplicationsWithSuccessfulBuilds = function(deviceType) {
|
||||
const selectApplication = function(deviceType) {
|
||||
const visuals = getVisuals();
|
||||
const form = require('resin-cli-form');
|
||||
const { exitWithExpectedError } = require('../utils/patterns');
|
||||
const { exitWithExpectedError } = require('../errors');
|
||||
|
||||
const applicationInfoSpinner = new visuals.Spinner(
|
||||
'Downloading list of applications and releases.',
|
||||
@ -116,7 +116,7 @@ const selectApplication = function(deviceType) {
|
||||
|
||||
const selectApplicationCommit = function(releases) {
|
||||
const form = require('resin-cli-form');
|
||||
const { exitWithExpectedError } = require('../utils/patterns');
|
||||
const { exitWithExpectedError } = require('../errors');
|
||||
|
||||
if (releases.length === 0) {
|
||||
exitWithExpectedError('This application has no successful releases.');
|
||||
@ -263,7 +263,7 @@ Examples:
|
||||
const balenaPreload = require('balena-preload');
|
||||
const visuals = getVisuals();
|
||||
const nodeCleanup = require('node-cleanup');
|
||||
const { exitWithExpectedError } = require('../utils/patterns');
|
||||
const { exitWithExpectedError } = require('../errors');
|
||||
|
||||
const progressBars = {};
|
||||
|
||||
|
@ -60,7 +60,7 @@ export const list: CommandDefinition<
|
||||
const _ = await import('lodash');
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
const { exitWithExpectedError } = await import('../utils/patterns');
|
||||
const { exitWithExpectedError } = await import('../errors');
|
||||
|
||||
return Bluebird.try<ApplicationTag[] | DeviceTag[] | ReleaseTag[]>(
|
||||
async () => {
|
||||
@ -161,7 +161,7 @@ export const set: CommandDefinition<
|
||||
const _ = await import('lodash');
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
const { exitWithExpectedError } = await import('../utils/patterns');
|
||||
const { exitWithExpectedError } = await import('../errors');
|
||||
|
||||
if (_.isEmpty(params.tagKey)) {
|
||||
return exitWithExpectedError('No tag key was provided');
|
||||
@ -250,7 +250,7 @@ export const remove: CommandDefinition<
|
||||
async action(params, options) {
|
||||
const _ = await import('lodash');
|
||||
const balena = getBalenaSdk();
|
||||
const { exitWithExpectedError } = await import('../utils/patterns');
|
||||
const { exitWithExpectedError } = await import('../errors');
|
||||
|
||||
if (_.isEmpty(params.tagKey)) {
|
||||
return exitWithExpectedError('No tag key was provided');
|
||||
|
@ -22,7 +22,7 @@ import * as events from './events';
|
||||
|
||||
capitano.permission('user', done =>
|
||||
require('./utils/patterns')
|
||||
.exitIfNotLoggedIn()
|
||||
.checkLoggedIn()
|
||||
.then(done, done),
|
||||
);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2016-2020 Balena
|
||||
Copyright 2016-2020 Balena Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -18,6 +18,8 @@ import { stripIndent } from 'common-tags';
|
||||
import * as _ from 'lodash';
|
||||
import * as os from 'os';
|
||||
import { TypedError } from 'typed-error';
|
||||
import { getChalk } from './utils/lazy';
|
||||
import { getHelp } from './utils/messages';
|
||||
|
||||
export class ExpectedError extends TypedError {}
|
||||
|
||||
@ -130,8 +132,6 @@ const messages: {
|
||||
};
|
||||
|
||||
export async function handleError(error: any) {
|
||||
const { printErrorMessage } = await import('./utils/patterns');
|
||||
|
||||
process.exitCode =
|
||||
error.exitCode === 0
|
||||
? 0
|
||||
@ -145,7 +145,7 @@ export async function handleError(error: any) {
|
||||
const message = [interpret(error)];
|
||||
|
||||
if (process.env.DEBUG && error.stack) {
|
||||
message.push(error.stack);
|
||||
message.push('\n' + error.stack);
|
||||
}
|
||||
printErrorMessage(message.join('\n'));
|
||||
|
||||
@ -171,3 +171,29 @@ export async function handleError(error: any) {
|
||||
// The exit error code was set above through `process.exitCode`.
|
||||
process.exit();
|
||||
}
|
||||
|
||||
export function printErrorMessage(message: string) {
|
||||
const chalk = getChalk();
|
||||
console.error(chalk.red(message));
|
||||
console.error(chalk.red(`\n${getHelp}\n`));
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a friendly error message and exit the CLI with an error code, BYPASSING
|
||||
* error reporting through Sentry.io's platform (raven.Raven.captureException).
|
||||
* Note that lib/errors.ts provides top-level error handling code to catch any
|
||||
* otherwise uncaught errors, AND to report them through Sentry.io. But many
|
||||
* "expected" errors (say, a JSON parsing error in a file provided by the user)
|
||||
* don't warrant reporting through Sentry.io. For such mundane errors, catch
|
||||
* them and call this function.
|
||||
*
|
||||
* DEPRECATED: Use `throw new ExpectedError(<message>)` instead.
|
||||
*/
|
||||
export function exitWithExpectedError(message: string | Error): never {
|
||||
if (message instanceof Error) {
|
||||
({ message } = message);
|
||||
}
|
||||
|
||||
printErrorMessage(message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
import { stripIndent } from 'common-tags';
|
||||
|
||||
import { exitWithExpectedError } from './utils/patterns';
|
||||
import { exitWithExpectedError } from './errors';
|
||||
|
||||
export interface AppOptions {
|
||||
// Prevent the default behavior of flushing stdout after running a command
|
||||
|
@ -74,7 +74,7 @@ async function environmentFromInput(
|
||||
serviceNames: string[],
|
||||
logger: Logger,
|
||||
): Promise<ParsedEnvironment> {
|
||||
const { exitWithExpectedError } = await import('../patterns');
|
||||
const { exitWithExpectedError } = await import('../../errors');
|
||||
// A normal environment variable regex, with an added part
|
||||
// to find a colon followed servicename at the start
|
||||
const varRegex = /^(?:([^\s:]+):)?([^\s]+?)=(.*)$/;
|
||||
@ -121,7 +121,7 @@ async function environmentFromInput(
|
||||
|
||||
export async function deployToDevice(opts: DeviceDeployOptions): Promise<void> {
|
||||
const { tarDirectory } = await import('../compose');
|
||||
const { exitWithExpectedError } = await import('../patterns');
|
||||
const { exitWithExpectedError } = await import('../../errors');
|
||||
const { displayDeviceLogs } = await import('./logs');
|
||||
|
||||
const api = new DeviceAPI(globalLogger, opts.deviceHost);
|
||||
@ -574,7 +574,7 @@ export function generateTargetState(
|
||||
}
|
||||
|
||||
async function inspectBuildResults(images: LocalImage[]): Promise<void> {
|
||||
const { exitWithExpectedError } = await import('../patterns');
|
||||
const { exitWithExpectedError } = await import('../../errors');
|
||||
|
||||
const failures: LocalPushErrors.BuildFailure[] = [];
|
||||
|
||||
|
@ -270,7 +270,7 @@ export const createClient = function(opts) {
|
||||
};
|
||||
|
||||
var ensureDockerSeemsAccessible = function(docker) {
|
||||
const { exitWithExpectedError } = require('./patterns');
|
||||
const { exitWithExpectedError } = require('../errors');
|
||||
return docker
|
||||
.ping()
|
||||
.catch(() =>
|
||||
|
@ -20,9 +20,8 @@ import { stripIndent } from 'common-tags';
|
||||
import _ = require('lodash');
|
||||
import _form = require('resin-cli-form');
|
||||
|
||||
import { instanceOf, NotLoggedInError } from '../errors';
|
||||
import { getBalenaSdk, getChalk, getVisuals } from './lazy';
|
||||
import messages = require('./messages');
|
||||
import { exitWithExpectedError, instanceOf, NotLoggedInError } from '../errors';
|
||||
import { getBalenaSdk, getVisuals } from './lazy';
|
||||
import validation = require('./validation');
|
||||
|
||||
const getForm = _.once((): typeof _form => require('resin-cli-form'));
|
||||
@ -88,22 +87,6 @@ export async function checkLoggedIn(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if logged in, and call `exitWithExpectedError()` if not.
|
||||
* DEPRECATED: Use checkLoggedIn() instead.
|
||||
*/
|
||||
export async function exitIfNotLoggedIn(): Promise<void> {
|
||||
try {
|
||||
await checkLoggedIn();
|
||||
} catch (error) {
|
||||
if (error instanceof NotLoggedInError) {
|
||||
exitWithExpectedError(error);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function askLoginType() {
|
||||
return getForm().ask<'web' | 'credentials' | 'token' | 'register'>({
|
||||
message: 'How would you like to login?',
|
||||
@ -435,29 +418,3 @@ export function selectFromList<T>(
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
export function printErrorMessage(message: string) {
|
||||
const chalk = getChalk();
|
||||
console.error(chalk.red(message));
|
||||
console.error(chalk.red(`\n${messages.getHelp}\n`));
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a friendly error message and exit the CLI with an error code, BYPASSING
|
||||
* error reporting through Sentry.io's platform (raven.Raven.captureException).
|
||||
* Note that lib/errors.ts provides top-level error handling code to catch any
|
||||
* otherwise uncaught errors, AND to report them through Sentry.io. But many
|
||||
* "expected" errors (say, a JSON parsing error in a file provided by the user)
|
||||
* don't warrant reporting through Sentry.io. For such mundane errors, catch
|
||||
* them and call this function.
|
||||
*
|
||||
* DEPRECATED: Use `throw new ExpectedError(<message>)` instead.
|
||||
*/
|
||||
export function exitWithExpectedError(message: string | Error): never {
|
||||
if (message instanceof Error) {
|
||||
({ message } = message);
|
||||
}
|
||||
|
||||
printErrorMessage(message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
import * as BalenaSdk from 'balena-sdk';
|
||||
import { stripIndent } from 'common-tags';
|
||||
|
||||
import { ExpectedError } from '../errors';
|
||||
import { ExpectedError, printErrorMessage } from '../errors';
|
||||
import { getVisuals } from './lazy';
|
||||
import Logger = require('./logger');
|
||||
import { exec, execBuffered, getDeviceOsRelease } from './ssh';
|
||||
@ -325,7 +325,6 @@ async function createApplication(
|
||||
): Promise<BalenaSdk.Application> {
|
||||
const form = await import('resin-cli-form');
|
||||
const validation = await import('./validation');
|
||||
const patterns = await import('./patterns');
|
||||
|
||||
let username = await sdk.auth.whoami();
|
||||
if (!username) {
|
||||
@ -352,7 +351,9 @@ async function createApplication(
|
||||
],
|
||||
},
|
||||
});
|
||||
patterns.printErrorMessage(
|
||||
// TODO: This is the only example in the codebase where `printErrorMessage()`
|
||||
// is called directly. Consider refactoring.
|
||||
printErrorMessage(
|
||||
'You already have an application with that name; please choose another.',
|
||||
);
|
||||
continue;
|
||||
|
@ -24,7 +24,7 @@ import streamToPromise = require('stream-to-promise');
|
||||
import { Pack } from 'tar-stream';
|
||||
|
||||
import { ExpectedError } from '../errors';
|
||||
import { exitWithExpectedError } from '../utils/patterns';
|
||||
import { exitWithExpectedError } from '../errors';
|
||||
import { tarDirectory } from './compose';
|
||||
import { getVisuals } from './lazy';
|
||||
import Logger = require('./logger');
|
||||
|
Loading…
Reference in New Issue
Block a user