mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-18 21:27:51 +00:00
Merge pull request #2061 from balena-io/2060-balenarc-no-sentry
Update Sentry, add BALENARC_NO_SENTRY var, refactor CLI initialization
This commit is contained in:
commit
9b6ffecaba
@ -1,61 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2019 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Main } from '@oclif/command';
|
||||
|
||||
import { trackPromise } from './hooks/prerun/track';
|
||||
|
||||
class CustomMain extends Main {
|
||||
protected _helpOverride(): boolean {
|
||||
// Disable oclif's default handler for the 'version' command
|
||||
if (['-v', '--version', 'version'].includes(this.argv[0])) {
|
||||
return false;
|
||||
} else {
|
||||
return super._helpOverride();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import type { AppOptions } from './preparser';
|
||||
|
||||
/**
|
||||
* oclif CLI entrypoint
|
||||
*/
|
||||
export async function run(command: string[], options: AppOptions) {
|
||||
const runPromise = CustomMain.run(command).then(
|
||||
() => {
|
||||
if (!options.noFlush) {
|
||||
return require('@oclif/command/flush');
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
// oclif sometimes exits with ExitError code 0 (not an error)
|
||||
// (Avoid `error instanceof ExitError` here for the reasons explained
|
||||
// in the CONTRIBUTING.md file regarding the `instanceof` operator.)
|
||||
if (error.oclif?.exit === 0) {
|
||||
return;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
);
|
||||
try {
|
||||
await Promise.all([trackPromise, runPromise]);
|
||||
} catch (err) {
|
||||
await (await import('./errors')).handleError(err);
|
||||
}
|
||||
}
|
190
lib/app.ts
190
lib/app.ts
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2019 Balena Ltd.
|
||||
* Copyright 2019-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.
|
||||
@ -15,78 +15,138 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as packageJSON from '../package.json';
|
||||
import { CliSettings } from './utils/bootstrap';
|
||||
import { onceAsync, stripIndent } from './utils/lazy';
|
||||
|
||||
/**
|
||||
* CLI entrypoint, but see also `bin/balena` and `bin/balena-dev` which
|
||||
* call this function.
|
||||
* Sentry.io setup
|
||||
* @see https://docs.sentry.io/error-reporting/quickstart/?platform=node
|
||||
*/
|
||||
export const setupSentry = onceAsync(async () => {
|
||||
const config = await import('./config');
|
||||
const Sentry = await import('@sentry/node');
|
||||
Sentry.init({
|
||||
dsn: config.sentryDsn,
|
||||
release: packageJSON.version,
|
||||
});
|
||||
Sentry.configureScope((scope) => {
|
||||
scope.setExtras({
|
||||
is_pkg: !!(process as any).pkg,
|
||||
node_version: process.version,
|
||||
platform: process.platform,
|
||||
});
|
||||
});
|
||||
return Sentry.getCurrentHub();
|
||||
});
|
||||
|
||||
async function checkNodeVersion() {
|
||||
const validNodeVersions = packageJSON.engines.node;
|
||||
if (!(await import('semver')).satisfies(process.version, validNodeVersions)) {
|
||||
console.warn(stripIndent`
|
||||
------------------------------------------------------------------------------
|
||||
Warning: Node version "${process.version}" does not match required versions "${validNodeVersions}".
|
||||
This may cause unexpected behavior. To upgrade Node, visit:
|
||||
https://nodejs.org/en/download/
|
||||
------------------------------------------------------------------------------
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Setup balena-sdk options that are shared with imported packages */
|
||||
function setupBalenaSdkSharedOptions(settings: CliSettings) {
|
||||
const BalenaSdk = require('balena-sdk') as typeof import('balena-sdk');
|
||||
BalenaSdk.setSharedOptions({
|
||||
apiUrl: settings.get<string>('apiUrl'),
|
||||
dataDirectory: settings.get<string>('dataDirectory'),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Addresses the console warning:
|
||||
* (node:49500) MaxListenersExceededWarning: Possible EventEmitter memory
|
||||
* leak detected. 11 error listeners added. Use emitter.setMaxListeners() to
|
||||
* increase limit
|
||||
*/
|
||||
export function setMaxListeners(maxListeners: number) {
|
||||
require('events').EventEmitter.defaultMaxListeners = maxListeners;
|
||||
}
|
||||
|
||||
/** Selected CLI initialization steps */
|
||||
async function init() {
|
||||
if (process.env.BALENARC_NO_SENTRY) {
|
||||
console.error(`WARN: disabling Sentry.io error reporting`);
|
||||
} else {
|
||||
await setupSentry();
|
||||
}
|
||||
checkNodeVersion();
|
||||
|
||||
const settings = new CliSettings();
|
||||
|
||||
// Proxy setup should be done early on, before loading balena-sdk
|
||||
await (await import('./utils/proxy')).setupGlobalHttpProxy(settings);
|
||||
|
||||
setupBalenaSdkSharedOptions(settings);
|
||||
|
||||
// check for CLI updates once a day
|
||||
(await import('./utils/update')).notify();
|
||||
}
|
||||
|
||||
/** Execute the oclif parser and the CLI command. */
|
||||
async function oclifRun(
|
||||
command: string[],
|
||||
options: import('./preparser').AppOptions,
|
||||
) {
|
||||
const { CustomMain } = await import('./utils/oclif-utils');
|
||||
const runPromise = CustomMain.run(command).then(
|
||||
() => {
|
||||
if (!options.noFlush) {
|
||||
return require('@oclif/command/flush');
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
// oclif sometimes exits with ExitError code 0 (not an error)
|
||||
// (Avoid `error instanceof ExitError` here for the reasons explained
|
||||
// in the CONTRIBUTING.md file regarding the `instanceof` operator.)
|
||||
if (error.oclif?.exit === 0) {
|
||||
return;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
);
|
||||
const { trackPromise } = await import('./hooks/prerun/track');
|
||||
await Promise.all([trackPromise, runPromise]);
|
||||
}
|
||||
|
||||
/** CLI entrypoint. Called by the `bin/balena` and `bin/balena-dev` scripts. */
|
||||
export async function run(
|
||||
cliArgs = process.argv,
|
||||
options: import('./preparser').AppOptions = {},
|
||||
) {
|
||||
// DEBUG set to falsy for negative values else is truthy
|
||||
process.env.DEBUG = ['0', 'no', 'false', '', undefined].includes(
|
||||
process.env.DEBUG?.toLowerCase(),
|
||||
)
|
||||
? ''
|
||||
: '1';
|
||||
|
||||
// The 'pkgExec' special/internal command provides a Node.js interpreter
|
||||
// for use of the standalone zip package. See pkgExec function.
|
||||
if (cliArgs.length > 3 && cliArgs[2] === 'pkgExec') {
|
||||
return pkgExec(cliArgs[3], cliArgs.slice(4));
|
||||
}
|
||||
|
||||
const { globalInit } = await import('./app-common');
|
||||
const { preparseArgs, checkDeletedCommand } = await import('./preparser');
|
||||
|
||||
// globalInit() must be called very early on (before other imports) because
|
||||
// it sets up Sentry error reporting, global HTTP proxy settings, balena-sdk
|
||||
// shared options, and performs node version requirement checks.
|
||||
await globalInit();
|
||||
|
||||
// Look for commands that have been removed and if so, exit with a notice
|
||||
checkDeletedCommand(cliArgs.slice(2));
|
||||
|
||||
const args = await preparseArgs(cliArgs);
|
||||
await (await import('./app-oclif')).run(args, options);
|
||||
|
||||
// Windows fix: reading from stdin prevents the process from exiting
|
||||
process.stdin.pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the 'pkgExec' command, used as a way to provide a Node.js
|
||||
* interpreter for child_process.spawn()-like operations when the CLI is
|
||||
* executing as a standalone zip package (built-in Node interpreter) and
|
||||
* the system may not have a separate Node.js installation. A present use
|
||||
* case is a patched version of the 'windosu' package that requires a
|
||||
* Node.js interpreter to spawn a privileged child process.
|
||||
*
|
||||
* @param modFunc Path to a JS module that will be executed via require().
|
||||
* The modFunc argument may optionally contain a function name separated
|
||||
* by '::', for example '::main' in:
|
||||
* 'C:\\snapshot\\balena-cli\\node_modules\\windosu\\lib\\pipe.js::main'
|
||||
* in which case that function is executed in the require'd module.
|
||||
* @param args Optional arguments to passed through process.argv and as
|
||||
* arguments to the function specified via modFunc.
|
||||
*/
|
||||
async function pkgExec(modFunc: string, args: string[]) {
|
||||
const [modPath, funcName] = modFunc.split('::');
|
||||
let replacedModPath = modPath;
|
||||
const match = modPath
|
||||
.replace(/\\/g, '/')
|
||||
.match(/\/snapshot\/balena-cli\/(.+)/);
|
||||
if (match) {
|
||||
replacedModPath = `../${match[1]}`;
|
||||
}
|
||||
process.argv = [process.argv[0], process.argv[1], ...args];
|
||||
try {
|
||||
const mod: any = await import(replacedModPath);
|
||||
if (funcName) {
|
||||
await mod[funcName](...args);
|
||||
const { normalizeEnvVars, pkgExec } = await import('./utils/bootstrap');
|
||||
normalizeEnvVars();
|
||||
|
||||
// The 'pkgExec' special/internal command provides a Node.js interpreter
|
||||
// for use of the standalone zip package. See pkgExec function.
|
||||
if (cliArgs.length > 3 && cliArgs[2] === 'pkgExec') {
|
||||
return pkgExec(cliArgs[3], cliArgs.slice(4));
|
||||
}
|
||||
|
||||
await init();
|
||||
|
||||
const { preparseArgs, checkDeletedCommand } = await import('./preparser');
|
||||
|
||||
// Look for commands that have been removed and if so, exit with a notice
|
||||
checkDeletedCommand(cliArgs.slice(2));
|
||||
|
||||
const args = await preparseArgs(cliArgs);
|
||||
await oclifRun(args, options);
|
||||
} catch (err) {
|
||||
console.error(`Error executing pkgExec "${modFunc}" [${args.join()}]`);
|
||||
console.error(err);
|
||||
await (await import('./errors')).handleError(err);
|
||||
} finally {
|
||||
// Windows fix: reading from stdin prevents the process from exiting
|
||||
process.stdin.pause();
|
||||
}
|
||||
}
|
||||
|
@ -162,6 +162,18 @@ export const getSentry = async function () {
|
||||
return await import('@sentry/node');
|
||||
};
|
||||
|
||||
async function sentryCaptureException(error: Error) {
|
||||
const Sentry = await getSentry();
|
||||
Sentry.captureException(error);
|
||||
try {
|
||||
await Sentry.close(1000);
|
||||
} catch (e) {
|
||||
if (process.env.DEBUG) {
|
||||
console.error('Timeout reporting error to sentry.io');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function handleError(error: Error) {
|
||||
// Set appropriate exitCode
|
||||
process.exitCode =
|
||||
@ -189,15 +201,10 @@ export async function handleError(error: Error) {
|
||||
printErrorMessage(message.join('\n'));
|
||||
|
||||
// Report "unexpected" errors via Sentry.io
|
||||
const Sentry = await getSentry();
|
||||
Sentry.captureException(error);
|
||||
try {
|
||||
await Sentry.close(1000);
|
||||
} catch (e) {
|
||||
if (process.env.DEBUG) {
|
||||
console.error('Timeout reporting error to sentry.io');
|
||||
}
|
||||
if (!process.env.BALENARC_NO_SENTRY) {
|
||||
await sentryCaptureException(error);
|
||||
}
|
||||
|
||||
// Unhandled/unexpected error: ensure that the process terminates.
|
||||
// The exit error code was set above through `process.exitCode`.
|
||||
process.exit();
|
||||
|
@ -49,10 +49,13 @@ interface CachedUsername {
|
||||
*/
|
||||
export async function trackCommand(commandSignature: string) {
|
||||
try {
|
||||
const Sentry = await import('@sentry/node');
|
||||
Sentry.configureScope((scope) => {
|
||||
scope.setExtra('command', commandSignature);
|
||||
});
|
||||
let Sentry: typeof import('@sentry/node');
|
||||
if (!process.env.BALENARC_NO_SENTRY) {
|
||||
Sentry = await import('@sentry/node');
|
||||
Sentry.configureScope((scope) => {
|
||||
scope.setExtra('command', commandSignature);
|
||||
});
|
||||
}
|
||||
const settings = await import('balena-settings-client');
|
||||
const balenaUrl = settings.get('balenaUrl') as string;
|
||||
|
||||
@ -90,12 +93,14 @@ export async function trackCommand(commandSignature: string) {
|
||||
|
||||
const mixpanel = getMixpanel(balenaUrl);
|
||||
|
||||
Sentry.configureScope((scope) => {
|
||||
scope.setUser({
|
||||
id: username,
|
||||
username,
|
||||
if (!process.env.BALENARC_NO_SENTRY) {
|
||||
Sentry!.configureScope((scope) => {
|
||||
scope.setUser({
|
||||
id: username,
|
||||
username,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
// Don't actually call mixpanel.track() while running test cases
|
||||
if (!process.env.BALENA_CLI_TEST_TYPE) {
|
||||
await mixpanel.track(`[CLI] ${commandSignature}`, {
|
||||
|
103
lib/utils/bootstrap.ts
Normal file
103
lib/utils/bootstrap.ts
Normal file
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2019-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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* THIS MODULE SHOULD NOT IMPORT / REQUIRE ANYTHING AT THE GLOBAL LEVEL.
|
||||
* It is meant to contain elementary helper functions or classes that
|
||||
* can be used very early on during CLI startup, before anything else
|
||||
* like Sentry error reporting, preparser, oclif parser and the like.
|
||||
*/
|
||||
|
||||
export class CliSettings {
|
||||
public readonly settings: any;
|
||||
constructor() {
|
||||
this.settings = require('balena-settings-client') as typeof import('balena-settings-client');
|
||||
}
|
||||
|
||||
public get<T>(name: string): T {
|
||||
return this.settings.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like settings.get(), but return `undefined` instead of throwing an
|
||||
* error if the setting is not found / not defined.
|
||||
*/
|
||||
public getCatch<T>(name: string): T | undefined {
|
||||
try {
|
||||
return this.settings.get(name);
|
||||
} catch (err) {
|
||||
if (!/Setting not found/i.test(err.message)) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function parseBoolEnvVar(varName: string): boolean {
|
||||
return !['0', 'no', 'false', '', undefined].includes(
|
||||
process.env[varName]?.toLowerCase(),
|
||||
);
|
||||
}
|
||||
|
||||
export function normalizeEnvVar(varName: string) {
|
||||
process.env[varName] = parseBoolEnvVar(varName) ? '1' : '';
|
||||
}
|
||||
|
||||
const bootstrapVars = ['DEBUG', 'BALENARC_NO_SENTRY'];
|
||||
|
||||
export function normalizeEnvVars(varNames: string[] = bootstrapVars) {
|
||||
for (const varName of varNames) {
|
||||
normalizeEnvVar(varName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the 'pkgExec' command, used as a way to provide a Node.js
|
||||
* interpreter for child_process.spawn()-like operations when the CLI is
|
||||
* executing as a standalone zip package (built-in Node interpreter) and
|
||||
* the system may not have a separate Node.js installation. A present use
|
||||
* case is a patched version of the 'windosu' package that requires a
|
||||
* Node.js interpreter to spawn a privileged child process.
|
||||
*
|
||||
* @param modFunc Path to a JS module that will be executed via require().
|
||||
* The modFunc argument may optionally contain a function name separated
|
||||
* by '::', for example '::main' in:
|
||||
* 'C:\\snapshot\\balena-cli\\node_modules\\windosu\\lib\\pipe.js::main'
|
||||
* in which case that function is executed in the require'd module.
|
||||
* @param args Optional arguments to passed through process.argv and as
|
||||
* arguments to the function specified via modFunc.
|
||||
*/
|
||||
export async function pkgExec(modFunc: string, args: string[]) {
|
||||
const [modPath, funcName] = modFunc.split('::');
|
||||
let replacedModPath = modPath;
|
||||
const match = modPath
|
||||
.replace(/\\/g, '/')
|
||||
.match(/\/snapshot\/balena-cli\/(.+)/);
|
||||
if (match) {
|
||||
replacedModPath = `../${match[1]}`;
|
||||
}
|
||||
process.argv = [process.argv[0], process.argv[1], ...args];
|
||||
try {
|
||||
const mod: any = await import(replacedModPath);
|
||||
if (funcName) {
|
||||
await mod[funcName](...args);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Error executing pkgExec "${modFunc}" [${args.join()}]`);
|
||||
console.error(err);
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Main } from '@oclif/command';
|
||||
import type * as Config from '@oclif/config';
|
||||
|
||||
/**
|
||||
@ -48,6 +49,17 @@ export class CommandHelp {
|
||||
}
|
||||
}
|
||||
|
||||
export class CustomMain extends Main {
|
||||
protected _helpOverride(): boolean {
|
||||
// Disable oclif's default handler for the 'version' command
|
||||
if (['-v', '--version', 'version'].includes(this.argv[0])) {
|
||||
return false;
|
||||
} else {
|
||||
return super._helpOverride();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Convert e.g. 'env add NAME [VALUE]' to 'env add <name> [value]' */
|
||||
export function capitanoizeOclifUsage(
|
||||
oclifUsage: string | string[] | undefined,
|
||||
|
@ -15,71 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as packageJSON from '../package.json';
|
||||
import { onceAsync, stripIndent } from './utils/lazy';
|
||||
|
||||
class CliSettings {
|
||||
public readonly settings: any;
|
||||
constructor() {
|
||||
this.settings = require('balena-settings-client') as typeof import('balena-settings-client');
|
||||
}
|
||||
|
||||
public get<T>(name: string): T {
|
||||
return this.settings.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like settings.get(), but return `undefined` instead of throwing an
|
||||
* error if the setting is not found / not defined.
|
||||
*/
|
||||
public getCatch<T>(name: string): T | undefined {
|
||||
try {
|
||||
return this.settings.get(name);
|
||||
} catch (err) {
|
||||
if (!/Setting not found/i.test(err.message)) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sentry.io setup
|
||||
* @see https://docs.sentry.io/error-reporting/quickstart/?platform=node
|
||||
*/
|
||||
export const setupSentry = onceAsync(async () => {
|
||||
const config = await import('./config');
|
||||
const Sentry = await import('@sentry/node');
|
||||
Sentry.init({
|
||||
dsn: config.sentryDsn,
|
||||
release: packageJSON.version,
|
||||
});
|
||||
Sentry.configureScope((scope) => {
|
||||
scope.setExtras({
|
||||
is_pkg: !!(process as any).pkg,
|
||||
node_version: process.version,
|
||||
platform: process.platform,
|
||||
});
|
||||
});
|
||||
return Sentry.getCurrentHub();
|
||||
});
|
||||
|
||||
async function checkNodeVersion() {
|
||||
const validNodeVersions = packageJSON.engines.node;
|
||||
if (!(await import('semver')).satisfies(process.version, validNodeVersions)) {
|
||||
console.warn(stripIndent`
|
||||
------------------------------------------------------------------------------
|
||||
Warning: Node version "${process.version}" does not match required versions "${validNodeVersions}".
|
||||
This may cause unexpected behavior. To upgrade Node, visit:
|
||||
https://nodejs.org/en/download/
|
||||
------------------------------------------------------------------------------
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
import type { Options as GlobalTunnelNgConfig } from 'global-tunnel-ng';
|
||||
export type { GlobalTunnelNgConfig };
|
||||
|
||||
import { CliSettings } from './bootstrap';
|
||||
|
||||
type ProxyConfig = string | GlobalTunnelNgConfig;
|
||||
|
||||
/**
|
||||
@ -104,7 +44,7 @@ type ProxyConfig = string | GlobalTunnelNgConfig;
|
||||
* 'localhost' and '127.0.0.1' are always excluded. If NO_PROXY is not defined,
|
||||
* default exclusion patterns are added for all private IPv4 address ranges.
|
||||
*/
|
||||
async function setupGlobalHttpProxy(settings: CliSettings) {
|
||||
export async function setupGlobalHttpProxy(settings: CliSettings) {
|
||||
// `global-tunnel-ng` accepts lowercase variables with higher precedence
|
||||
// than uppercase variables, but `global-agent` does not accept lowercase.
|
||||
// Set uppercase versions for backwards compatibility.
|
||||
@ -207,37 +147,3 @@ export function makeUrlFromTunnelNgConfig(cfg: GlobalTunnelNgConfig): string {
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
function setupBalenaSdkSharedOptions(settings: CliSettings) {
|
||||
// We don't yet use balena-sdk directly everywhere, but we set up shared
|
||||
// options correctly so we can do safely in submodules
|
||||
const BalenaSdk = require('balena-sdk') as typeof import('balena-sdk');
|
||||
BalenaSdk.setSharedOptions({
|
||||
apiUrl: settings.get<string>('apiUrl'),
|
||||
dataDirectory: settings.get<string>('dataDirectory'),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Addresses the console warning:
|
||||
* (node:49500) MaxListenersExceededWarning: Possible EventEmitter memory
|
||||
* leak detected. 11 error listeners added. Use emitter.setMaxListeners() to
|
||||
* increase limit
|
||||
*/
|
||||
export function setMaxListeners(maxListeners: number) {
|
||||
require('events').EventEmitter.defaultMaxListeners = maxListeners;
|
||||
}
|
||||
|
||||
export async function globalInit() {
|
||||
await setupSentry();
|
||||
checkNodeVersion();
|
||||
|
||||
const settings = new CliSettings();
|
||||
|
||||
// Proxy setup should be done early on, before loading balena-sdk
|
||||
await setupGlobalHttpProxy(settings);
|
||||
setupBalenaSdkSharedOptions(settings);
|
||||
|
||||
// check for CLI updates once a day
|
||||
(await import('./utils/update')).notify();
|
||||
}
|
157
npm-shrinkwrap.json
generated
157
npm-shrinkwrap.json
generated
@ -1250,107 +1250,69 @@
|
||||
"resolved": "https://registry.npmjs.org/@resin.io/valid-email/-/valid-email-0.1.0.tgz",
|
||||
"integrity": "sha1-DnUwmoQ8AUqAqhSC+WmQYvL6UV0="
|
||||
},
|
||||
"@sentry/apm": {
|
||||
"version": "5.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/apm/-/apm-5.21.1.tgz",
|
||||
"integrity": "sha512-mxMOCpeXULbQCC/f9SwPqW+g12mk3nWRNjeAUm5dyiKHY13agtQBSSYs4ROEH190YxmwTZr3vxhlR2jNSdSZcg==",
|
||||
"requires": {
|
||||
"@sentry/browser": "5.21.1",
|
||||
"@sentry/hub": "5.21.1",
|
||||
"@sentry/minimal": "5.21.1",
|
||||
"@sentry/types": "5.21.1",
|
||||
"@sentry/utils": "5.21.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
||||
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/browser": {
|
||||
"version": "5.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.21.1.tgz",
|
||||
"integrity": "sha512-sUxsW545klZxJE4iBAYQ8SuVS85HTOGNmIIIZWFUogB5oW3O0L+nJluXEqf/pHU82LnjDIzqsWCYQ0cRUaeYow==",
|
||||
"requires": {
|
||||
"@sentry/core": "5.21.1",
|
||||
"@sentry/types": "5.21.1",
|
||||
"@sentry/utils": "5.21.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
||||
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/core": {
|
||||
"version": "5.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.21.1.tgz",
|
||||
"integrity": "sha512-Luulwx3GLUiY0gmHOhU+4eSga28Ce8DwoBcRq9GkGuhPu9r80057d5urxrDLp/leIZBXVvpY7tvmSN/rMtvF9w==",
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.25.0.tgz",
|
||||
"integrity": "sha512-hY6Zmo7t/RV+oZuvXHP6nyAj/QnZr2jW0e7EbL5YKMV8q0vlnjcE0LgqFXme726OJemoLk67z+sQOJic/Ztehg==",
|
||||
"requires": {
|
||||
"@sentry/hub": "5.21.1",
|
||||
"@sentry/minimal": "5.21.1",
|
||||
"@sentry/types": "5.21.1",
|
||||
"@sentry/utils": "5.21.1",
|
||||
"@sentry/hub": "5.25.0",
|
||||
"@sentry/minimal": "5.25.0",
|
||||
"@sentry/types": "5.25.0",
|
||||
"@sentry/utils": "5.25.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
||||
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz",
|
||||
"integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/hub": {
|
||||
"version": "5.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.21.1.tgz",
|
||||
"integrity": "sha512-x5i9Ggi5ZYMhBYL5kyTu2fUJ6owjKH2tgJL3UExoZdRyZkbLAFZb+DtfSnteWgQ6wriGfgPD3r/hAIEdaomk2A==",
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.25.0.tgz",
|
||||
"integrity": "sha512-kOlOiJV8wMX50lYpzMlOXBoH7MNG0Ho4RTusdZnXZBaASq5/ljngDJkLr6uylNjceZQP21wzipCQajsJMYB7EQ==",
|
||||
"requires": {
|
||||
"@sentry/types": "5.21.1",
|
||||
"@sentry/utils": "5.21.1",
|
||||
"@sentry/types": "5.25.0",
|
||||
"@sentry/utils": "5.25.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
||||
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz",
|
||||
"integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/minimal": {
|
||||
"version": "5.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.21.1.tgz",
|
||||
"integrity": "sha512-OBVPASZ+mcXMKajvJon9RjEZ+ny3+VGhOI66acoP1hmYxKvji1OC2bYEuP1r4qtHxWVLAdV7qFj3EQ9ckErZmQ==",
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.25.0.tgz",
|
||||
"integrity": "sha512-9JFKuW7U+1vPO86k3+XRtJyooiVZsVOsFFO4GulBzepi3a0ckNyPgyjUY1saLH+cEHx18hu8fGgajvI8ANUF2g==",
|
||||
"requires": {
|
||||
"@sentry/hub": "5.21.1",
|
||||
"@sentry/types": "5.21.1",
|
||||
"@sentry/hub": "5.25.0",
|
||||
"@sentry/types": "5.25.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
||||
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz",
|
||||
"integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/node": {
|
||||
"version": "5.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.21.1.tgz",
|
||||
"integrity": "sha512-+QLqGz6+/gtShv0F16nI2+AuVEDZG2k9L25BVCNoysYzH1J1/QIKHsl7YF2trDMlWM4T7cbu5Fh8AhK6an+5/g==",
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.25.0.tgz",
|
||||
"integrity": "sha512-zxoUVdAFTeK9kdEGY95TMs6g8Zx/P55HxG4gHD80BG/XIEvWiGPcGCLOspO4IdGqYXkGS74KfBOIXmmCawWwLg==",
|
||||
"requires": {
|
||||
"@sentry/apm": "5.21.1",
|
||||
"@sentry/core": "5.21.1",
|
||||
"@sentry/hub": "5.21.1",
|
||||
"@sentry/types": "5.21.1",
|
||||
"@sentry/utils": "5.21.1",
|
||||
"@sentry/core": "5.25.0",
|
||||
"@sentry/hub": "5.25.0",
|
||||
"@sentry/tracing": "5.25.0",
|
||||
"@sentry/types": "5.25.0",
|
||||
"@sentry/utils": "5.25.0",
|
||||
"cookie": "^0.4.1",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"lru_map": "^0.3.3",
|
||||
@ -1358,30 +1320,49 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
||||
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz",
|
||||
"integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "5.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.21.1.tgz",
|
||||
"integrity": "sha512-hFN4aDduMpjj6vZSIIp+9kSr8MglcKO/UmbuUXN6hKLewhxt+Zj2wjXN7ulSs5OK5mjXP9QLA5YJvVQsl2//qw=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "5.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.21.1.tgz",
|
||||
"integrity": "sha512-p5vPuc7+GfOmW8CXxWd0samS77Q00YrN8q5TC/ztF8nBhEF18GiMeWAdQnlSwt3iWal3q3gSSrbF4c9guIugng==",
|
||||
"@sentry/tracing": {
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.25.0.tgz",
|
||||
"integrity": "sha512-KcyHEGFpqSDubHrdWT/vF2hKkjw/ts6NpJ6tPDjBXUNz98BHdAyMKtLOFTCeJFply7/s5fyiAYu44M+M6IG3Bw==",
|
||||
"requires": {
|
||||
"@sentry/types": "5.21.1",
|
||||
"@sentry/hub": "5.25.0",
|
||||
"@sentry/minimal": "5.25.0",
|
||||
"@sentry/types": "5.25.0",
|
||||
"@sentry/utils": "5.25.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
||||
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz",
|
||||
"integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.25.0.tgz",
|
||||
"integrity": "sha512-8M4PREbcar+15wrtEqcwfcU33SS+2wBSIOd/NrJPXJPTYxi49VypCN1mZBDyWkaK+I+AuQwI3XlRPCfsId3D1A=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "5.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.25.0.tgz",
|
||||
"integrity": "sha512-Hz5spdIkMSRH5NR1YFOp5qbsY5Ud2lKhEQWlqxcVThMG5YNUc10aYv5ijL19v0YkrC2rqPjCRm7GrVtzOc7bXQ==",
|
||||
"requires": {
|
||||
"@sentry/types": "5.25.0",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz",
|
||||
"integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -197,7 +197,7 @@
|
||||
"@balena/es-version": "^1.0.0",
|
||||
"@oclif/command": "^1.8.0",
|
||||
"@resin.io/valid-email": "^0.1.0",
|
||||
"@sentry/node": "^5.21.1",
|
||||
"@sentry/node": "^5.25.0",
|
||||
"@types/fast-levenshtein": "0.0.1",
|
||||
"@types/update-notifier": "^4.1.1",
|
||||
"@zeit/dockerignore": "0.0.3",
|
||||
|
@ -23,7 +23,6 @@ import * as nock from 'nock';
|
||||
import * as path from 'path';
|
||||
|
||||
import * as balenaCLI from '../build/app';
|
||||
import { setupSentry } from '../build/app-common';
|
||||
|
||||
const balenaExe = process.platform === 'win32' ? 'balena.exe' : 'balena';
|
||||
const standalonePath = path.resolve(__dirname, '..', 'build-bin', balenaExe);
|
||||
@ -287,7 +286,7 @@ export function fillTemplateArray(
|
||||
export async function switchSentry(
|
||||
enabled: boolean | undefined,
|
||||
): Promise<boolean | undefined> {
|
||||
const sentryOpts = (await setupSentry()).getClient()?.getOptions();
|
||||
const sentryOpts = (await balenaCLI.setupSentry()).getClient()?.getOptions();
|
||||
if (sentryOpts) {
|
||||
const sentryStatus = sentryOpts.enabled;
|
||||
sentryOpts.enabled = enabled;
|
||||
|
@ -20,7 +20,7 @@ import { expect } from 'chai';
|
||||
import {
|
||||
GlobalTunnelNgConfig,
|
||||
makeUrlFromTunnelNgConfig,
|
||||
} from '../build/app-common';
|
||||
} from '../build/utils/proxy';
|
||||
|
||||
describe('makeUrlFromTunnelNgConfig() function', function () {
|
||||
it('should return a URL given a GlobalTunnelNgConfig object', () => {
|
Loading…
Reference in New Issue
Block a user