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:
bulldozer-balena[bot] 2020-10-13 07:59:51 +00:00 committed by GitHub
commit 9b6ffecaba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 344 additions and 332 deletions

View File

@ -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);
}
}

View File

@ -1,6 +1,6 @@
/** /**
* @license * @license
* Copyright 2019 Balena Ltd. * Copyright 2019-2020 Balena Ltd.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,20 +15,118 @@
* limitations under the License. * 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 * Sentry.io setup
* call this function. * @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( export async function run(
cliArgs = process.argv, cliArgs = process.argv,
options: import('./preparser').AppOptions = {}, options: import('./preparser').AppOptions = {},
) { ) {
// DEBUG set to falsy for negative values else is truthy try {
process.env.DEBUG = ['0', 'no', 'false', '', undefined].includes( const { normalizeEnvVars, pkgExec } = await import('./utils/bootstrap');
process.env.DEBUG?.toLowerCase(), normalizeEnvVars();
)
? ''
: '1';
// The 'pkgExec' special/internal command provides a Node.js interpreter // The 'pkgExec' special/internal command provides a Node.js interpreter
// for use of the standalone zip package. See pkgExec function. // for use of the standalone zip package. See pkgExec function.
@ -36,57 +134,19 @@ export async function run(
return pkgExec(cliArgs[3], cliArgs.slice(4)); return pkgExec(cliArgs[3], cliArgs.slice(4));
} }
const { globalInit } = await import('./app-common'); await init();
const { preparseArgs, checkDeletedCommand } = await import('./preparser');
// globalInit() must be called very early on (before other imports) because const { preparseArgs, checkDeletedCommand } = await import('./preparser');
// 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 // Look for commands that have been removed and if so, exit with a notice
checkDeletedCommand(cliArgs.slice(2)); checkDeletedCommand(cliArgs.slice(2));
const args = await preparseArgs(cliArgs); const args = await preparseArgs(cliArgs);
await (await import('./app-oclif')).run(args, options); await oclifRun(args, options);
} catch (err) {
await (await import('./errors')).handleError(err);
} finally {
// Windows fix: reading from stdin prevents the process from exiting // Windows fix: reading from stdin prevents the process from exiting
process.stdin.pause(); 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);
}
} catch (err) {
console.error(`Error executing pkgExec "${modFunc}" [${args.join()}]`);
console.error(err);
} }
} }

View File

@ -162,6 +162,18 @@ export const getSentry = async function () {
return await import('@sentry/node'); 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) { export async function handleError(error: Error) {
// Set appropriate exitCode // Set appropriate exitCode
process.exitCode = process.exitCode =
@ -189,15 +201,10 @@ export async function handleError(error: Error) {
printErrorMessage(message.join('\n')); printErrorMessage(message.join('\n'));
// Report "unexpected" errors via Sentry.io // Report "unexpected" errors via Sentry.io
const Sentry = await getSentry(); if (!process.env.BALENARC_NO_SENTRY) {
Sentry.captureException(error); await sentryCaptureException(error);
try {
await Sentry.close(1000);
} catch (e) {
if (process.env.DEBUG) {
console.error('Timeout reporting error to sentry.io');
}
} }
// Unhandled/unexpected error: ensure that the process terminates. // Unhandled/unexpected error: ensure that the process terminates.
// The exit error code was set above through `process.exitCode`. // The exit error code was set above through `process.exitCode`.
process.exit(); process.exit();

View File

@ -49,10 +49,13 @@ interface CachedUsername {
*/ */
export async function trackCommand(commandSignature: string) { export async function trackCommand(commandSignature: string) {
try { try {
const Sentry = await import('@sentry/node'); let Sentry: typeof import('@sentry/node');
if (!process.env.BALENARC_NO_SENTRY) {
Sentry = await import('@sentry/node');
Sentry.configureScope((scope) => { Sentry.configureScope((scope) => {
scope.setExtra('command', commandSignature); scope.setExtra('command', commandSignature);
}); });
}
const settings = await import('balena-settings-client'); const settings = await import('balena-settings-client');
const balenaUrl = settings.get('balenaUrl') as string; const balenaUrl = settings.get('balenaUrl') as string;
@ -90,12 +93,14 @@ export async function trackCommand(commandSignature: string) {
const mixpanel = getMixpanel(balenaUrl); const mixpanel = getMixpanel(balenaUrl);
Sentry.configureScope((scope) => { if (!process.env.BALENARC_NO_SENTRY) {
Sentry!.configureScope((scope) => {
scope.setUser({ scope.setUser({
id: username, id: username,
username, username,
}); });
}); });
}
// Don't actually call mixpanel.track() while running test cases // Don't actually call mixpanel.track() while running test cases
if (!process.env.BALENA_CLI_TEST_TYPE) { if (!process.env.BALENA_CLI_TEST_TYPE) {
await mixpanel.track(`[CLI] ${commandSignature}`, { await mixpanel.track(`[CLI] ${commandSignature}`, {

103
lib/utils/bootstrap.ts Normal file
View 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);
}
}

View File

@ -15,6 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Main } from '@oclif/command';
import type * as Config from '@oclif/config'; 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]' */ /** Convert e.g. 'env add NAME [VALUE]' to 'env add <name> [value]' */
export function capitanoizeOclifUsage( export function capitanoizeOclifUsage(
oclifUsage: string | string[] | undefined, oclifUsage: string | string[] | undefined,

View File

@ -15,71 +15,11 @@
* limitations under the License. * 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'; import type { Options as GlobalTunnelNgConfig } from 'global-tunnel-ng';
export type { GlobalTunnelNgConfig }; export type { GlobalTunnelNgConfig };
import { CliSettings } from './bootstrap';
type ProxyConfig = string | GlobalTunnelNgConfig; 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, * '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. * 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 // `global-tunnel-ng` accepts lowercase variables with higher precedence
// than uppercase variables, but `global-agent` does not accept lowercase. // than uppercase variables, but `global-agent` does not accept lowercase.
// Set uppercase versions for backwards compatibility. // Set uppercase versions for backwards compatibility.
@ -207,37 +147,3 @@ export function makeUrlFromTunnelNgConfig(cfg: GlobalTunnelNgConfig): string {
} }
return url; 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
View File

@ -1250,107 +1250,69 @@
"resolved": "https://registry.npmjs.org/@resin.io/valid-email/-/valid-email-0.1.0.tgz", "resolved": "https://registry.npmjs.org/@resin.io/valid-email/-/valid-email-0.1.0.tgz",
"integrity": "sha1-DnUwmoQ8AUqAqhSC+WmQYvL6UV0=" "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": { "@sentry/core": {
"version": "5.21.1", "version": "5.25.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.21.1.tgz", "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.25.0.tgz",
"integrity": "sha512-Luulwx3GLUiY0gmHOhU+4eSga28Ce8DwoBcRq9GkGuhPu9r80057d5urxrDLp/leIZBXVvpY7tvmSN/rMtvF9w==", "integrity": "sha512-hY6Zmo7t/RV+oZuvXHP6nyAj/QnZr2jW0e7EbL5YKMV8q0vlnjcE0LgqFXme726OJemoLk67z+sQOJic/Ztehg==",
"requires": { "requires": {
"@sentry/hub": "5.21.1", "@sentry/hub": "5.25.0",
"@sentry/minimal": "5.21.1", "@sentry/minimal": "5.25.0",
"@sentry/types": "5.21.1", "@sentry/types": "5.25.0",
"@sentry/utils": "5.21.1", "@sentry/utils": "5.25.0",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"dependencies": { "dependencies": {
"tslib": { "tslib": {
"version": "1.13.0", "version": "1.14.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" "integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw=="
} }
} }
}, },
"@sentry/hub": { "@sentry/hub": {
"version": "5.21.1", "version": "5.25.0",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.21.1.tgz", "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.25.0.tgz",
"integrity": "sha512-x5i9Ggi5ZYMhBYL5kyTu2fUJ6owjKH2tgJL3UExoZdRyZkbLAFZb+DtfSnteWgQ6wriGfgPD3r/hAIEdaomk2A==", "integrity": "sha512-kOlOiJV8wMX50lYpzMlOXBoH7MNG0Ho4RTusdZnXZBaASq5/ljngDJkLr6uylNjceZQP21wzipCQajsJMYB7EQ==",
"requires": { "requires": {
"@sentry/types": "5.21.1", "@sentry/types": "5.25.0",
"@sentry/utils": "5.21.1", "@sentry/utils": "5.25.0",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"dependencies": { "dependencies": {
"tslib": { "tslib": {
"version": "1.13.0", "version": "1.14.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" "integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw=="
} }
} }
}, },
"@sentry/minimal": { "@sentry/minimal": {
"version": "5.21.1", "version": "5.25.0",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.21.1.tgz", "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.25.0.tgz",
"integrity": "sha512-OBVPASZ+mcXMKajvJon9RjEZ+ny3+VGhOI66acoP1hmYxKvji1OC2bYEuP1r4qtHxWVLAdV7qFj3EQ9ckErZmQ==", "integrity": "sha512-9JFKuW7U+1vPO86k3+XRtJyooiVZsVOsFFO4GulBzepi3a0ckNyPgyjUY1saLH+cEHx18hu8fGgajvI8ANUF2g==",
"requires": { "requires": {
"@sentry/hub": "5.21.1", "@sentry/hub": "5.25.0",
"@sentry/types": "5.21.1", "@sentry/types": "5.25.0",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"dependencies": { "dependencies": {
"tslib": { "tslib": {
"version": "1.13.0", "version": "1.14.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" "integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw=="
} }
} }
}, },
"@sentry/node": { "@sentry/node": {
"version": "5.21.1", "version": "5.25.0",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.21.1.tgz", "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.25.0.tgz",
"integrity": "sha512-+QLqGz6+/gtShv0F16nI2+AuVEDZG2k9L25BVCNoysYzH1J1/QIKHsl7YF2trDMlWM4T7cbu5Fh8AhK6an+5/g==", "integrity": "sha512-zxoUVdAFTeK9kdEGY95TMs6g8Zx/P55HxG4gHD80BG/XIEvWiGPcGCLOspO4IdGqYXkGS74KfBOIXmmCawWwLg==",
"requires": { "requires": {
"@sentry/apm": "5.21.1", "@sentry/core": "5.25.0",
"@sentry/core": "5.21.1", "@sentry/hub": "5.25.0",
"@sentry/hub": "5.21.1", "@sentry/tracing": "5.25.0",
"@sentry/types": "5.21.1", "@sentry/types": "5.25.0",
"@sentry/utils": "5.21.1", "@sentry/utils": "5.25.0",
"cookie": "^0.4.1", "cookie": "^0.4.1",
"https-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0",
"lru_map": "^0.3.3", "lru_map": "^0.3.3",
@ -1358,30 +1320,49 @@
}, },
"dependencies": { "dependencies": {
"tslib": { "tslib": {
"version": "1.13.0", "version": "1.14.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" "integrity": "sha512-+Zw5lu0D9tvBMjGP8LpvMb0u2WW2QV3y+D8mO6J+cNzCYIN4sVy43Bf9vl92nqFahutN0I8zHa7cc4vihIshnw=="
} }
} }
}, },
"@sentry/types": { "@sentry/tracing": {
"version": "5.21.1", "version": "5.25.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.21.1.tgz", "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.25.0.tgz",
"integrity": "sha512-hFN4aDduMpjj6vZSIIp+9kSr8MglcKO/UmbuUXN6hKLewhxt+Zj2wjXN7ulSs5OK5mjXP9QLA5YJvVQsl2//qw==" "integrity": "sha512-KcyHEGFpqSDubHrdWT/vF2hKkjw/ts6NpJ6tPDjBXUNz98BHdAyMKtLOFTCeJFply7/s5fyiAYu44M+M6IG3Bw==",
},
"@sentry/utils": {
"version": "5.21.1",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.21.1.tgz",
"integrity": "sha512-p5vPuc7+GfOmW8CXxWd0samS77Q00YrN8q5TC/ztF8nBhEF18GiMeWAdQnlSwt3iWal3q3gSSrbF4c9guIugng==",
"requires": { "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" "tslib": "^1.9.3"
}, },
"dependencies": { "dependencies": {
"tslib": { "tslib": {
"version": "1.13.0", "version": "1.14.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" "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=="
} }
} }
}, },

View File

@ -197,7 +197,7 @@
"@balena/es-version": "^1.0.0", "@balena/es-version": "^1.0.0",
"@oclif/command": "^1.8.0", "@oclif/command": "^1.8.0",
"@resin.io/valid-email": "^0.1.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/fast-levenshtein": "0.0.1",
"@types/update-notifier": "^4.1.1", "@types/update-notifier": "^4.1.1",
"@zeit/dockerignore": "0.0.3", "@zeit/dockerignore": "0.0.3",

View File

@ -23,7 +23,6 @@ import * as nock from 'nock';
import * as path from 'path'; import * as path from 'path';
import * as balenaCLI from '../build/app'; import * as balenaCLI from '../build/app';
import { setupSentry } from '../build/app-common';
const balenaExe = process.platform === 'win32' ? 'balena.exe' : 'balena'; const balenaExe = process.platform === 'win32' ? 'balena.exe' : 'balena';
const standalonePath = path.resolve(__dirname, '..', 'build-bin', balenaExe); const standalonePath = path.resolve(__dirname, '..', 'build-bin', balenaExe);
@ -287,7 +286,7 @@ export function fillTemplateArray(
export async function switchSentry( export async function switchSentry(
enabled: boolean | undefined, enabled: boolean | undefined,
): Promise<boolean | undefined> { ): Promise<boolean | undefined> {
const sentryOpts = (await setupSentry()).getClient()?.getOptions(); const sentryOpts = (await balenaCLI.setupSentry()).getClient()?.getOptions();
if (sentryOpts) { if (sentryOpts) {
const sentryStatus = sentryOpts.enabled; const sentryStatus = sentryOpts.enabled;
sentryOpts.enabled = enabled; sentryOpts.enabled = enabled;

View File

@ -20,7 +20,7 @@ import { expect } from 'chai';
import { import {
GlobalTunnelNgConfig, GlobalTunnelNgConfig,
makeUrlFromTunnelNgConfig, makeUrlFromTunnelNgConfig,
} from '../build/app-common'; } from '../build/utils/proxy';
describe('makeUrlFromTunnelNgConfig() function', function () { describe('makeUrlFromTunnelNgConfig() function', function () {
it('should return a URL given a GlobalTunnelNgConfig object', () => { it('should return a URL given a GlobalTunnelNgConfig object', () => {