mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-20 22:23:07 +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);
|
|
||||||
}
|
|
||||||
}
|
|
166
lib/app.ts
166
lib/app.ts
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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
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.
|
* 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,
|
||||||
|
@ -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
157
npm-shrinkwrap.json
generated
@ -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=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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",
|
||||||
|
@ -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;
|
||||||
|
@ -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', () => {
|
Loading…
Reference in New Issue
Block a user