From 7187f10e49d78e015634feb369e7d94cfdd9d50b Mon Sep 17 00:00:00 2001 From: Alicia Lopez Date: Tue, 10 Mar 2020 04:10:33 +0800 Subject: [PATCH] feat: support NCU_VERBOSITY=debug environment variable Support NCU_VERBOSITY=debug which tells ncu to log CLI commands and HTTP requests to the command line for debugging. --- README.md | 10 ++++++++++ bin/get-metadata | 2 ++ bin/git-node | 2 ++ bin/ncu-ci | 2 ++ bin/ncu-config | 3 +++ bin/ncu-team | 3 +++ lib/request.js | 26 +++++++++++++++++++++++--- lib/run.js | 21 ++++++++++++++++----- lib/verbosity.js | 29 +++++++++++++++++++++++++++++ 9 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 lib/verbosity.js diff --git a/README.md b/README.md index 1d011e3..2426145 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ CLI tools for Node.js Core collaborators. - [Install](#install) - [Setting up credentials](#setting-up-credentials) - [Make sure your credentials won't be committed](#make-sure-your-credentials-wont-be-committed) + - [Troubleshooting](#troubleshooting) - [Contributing](#contributing) - [License](#license) @@ -99,6 +100,15 @@ serialized configurations. If you ever accidentally commit your access token on GitHub, you can simply revoke that token and use a new one. +### Troubleshooting + +If you encounter an error that you cannot fix by yourself, please + +1. Make sure you update NCU to the latest version +2. Try again with the `NCU_VERBOSITY=debug` environment variable set and + open an issue at https://github.com/nodejs/node-core-utils/issues with + detailed logs. + ## Contributing See [CONTRIBUTING.md](./CONTRIBUTING.md). diff --git a/bin/get-metadata b/bin/get-metadata index 622ff82..b13b731 100755 --- a/bin/get-metadata +++ b/bin/get-metadata @@ -3,6 +3,8 @@ const path = require('path'); const { runAsync } = require('../lib/run'); +const { setVerbosityFromEnv } = require('../lib/verbosity'); +setVerbosityFromEnv(); const script = path.join(__dirname, 'git-node'); runAsync(process.execPath, [script, 'metadata', ...process.argv.slice(2)]); diff --git a/bin/git-node b/bin/git-node index 6006a82..9815901 100755 --- a/bin/git-node +++ b/bin/git-node @@ -4,6 +4,8 @@ const yargs = require('yargs'); const path = require('path'); const epilogue = require('../components/git/epilogue'); +const { setVerbosityFromEnv } = require('../lib/verbosity'); +setVerbosityFromEnv(); const commandDir = path.join(__dirname, '..', 'components', 'git'); diff --git a/bin/ncu-ci b/bin/ncu-ci index 168e7ed..d54c29b 100755 --- a/bin/ncu-ci +++ b/bin/ncu-ci @@ -14,6 +14,8 @@ const { DAILY_MASTER } } = require('../lib/ci/ci_type_parser'); +const { setVerbosityFromEnv } = require('../lib/verbosity'); +setVerbosityFromEnv(); const { listBuilds } = require('../lib/ci/ci_utils'); diff --git a/bin/ncu-config b/bin/ncu-config index 047b515..e9fe64e 100755 --- a/bin/ncu-config +++ b/bin/ncu-config @@ -6,6 +6,9 @@ const { getConfig, updateConfig, GLOBAL_CONFIG, PROJECT_CONFIG, LOCAL_CONFIG } = require('../lib/config'); +const { setVerbosityFromEnv } = require('../lib/verbosity'); +setVerbosityFromEnv(); + const yargs = require('yargs'); const argv = yargs .command({ diff --git a/bin/ncu-team b/bin/ncu-team index 70d333d..2cdc62c 100755 --- a/bin/ncu-team +++ b/bin/ncu-team @@ -7,6 +7,9 @@ const { runPromise } = require('../lib/run'); const CLI = require('../lib/cli'); const TeamInfo = require('../lib/team_info'); +const { setVerbosityFromEnv } = require('../lib/verbosity'); +setVerbosityFromEnv(); + require('yargs') // eslint-disable-line .command({ command: 'list [org]', diff --git a/lib/request.js b/lib/request.js index 11e2c4b..e33b908 100644 --- a/lib/request.js +++ b/lib/request.js @@ -5,6 +5,17 @@ const fs = require('fs'); const path = require('path'); const { CI_DOMAIN } = require('./ci/ci_type_parser'); const proxy = require('./proxy'); +const { + isDebugVerbosity, + debuglog +} = require('./verbosity'); + +function wrappedFetch(url, options, ...args) { + if (isDebugVerbosity()) { + debuglog('[fetch]', url); + } + return fetch(url, options, ...args); +} class Request { constructor(credentials) { @@ -23,7 +34,7 @@ class Request { options.headers = options.headers || {}; Object.assign(options.headers, this.getJenkinsHeaders()); } - return fetch(url, options); + return wrappedFetch(url, options); } async text(url, options = {}) { @@ -32,7 +43,16 @@ class Request { async json(url, options = {}) { options.headers = options.headers || {}; - return this.fetch(url, options).then(res => res.json()); + const text = await this.text(url, options); + try { + return JSON.parse(text); + } catch (e) { + if (isDebugVerbosity()) { + debuglog('[Request] Cannot parse JSON response from', + url, ':\n', text); + } + throw e; + } } async gql(name, variables, path) { @@ -81,7 +101,7 @@ class Request { }) }; - const result = await fetch(url, options).then(res => res.json()); + const result = await this.json(url, options); if (result.errors) { const { type, message } = result.errors[0]; const err = new Error(`[${type}] GraphQL request Error: ${message}`); diff --git a/lib/run.js b/lib/run.js index 1247790..9be14f1 100644 --- a/lib/run.js +++ b/lib/run.js @@ -1,7 +1,10 @@ 'use strict'; const { spawn, spawnSync } = require('child_process'); - +const { + isDebugVerbosity, + debuglog +} = require('./verbosity'); const IGNORE = '__ignore__'; function runAsyncBase(cmd, args, { @@ -10,10 +13,14 @@ function runAsyncBase(cmd, args, { captureStdout = false } = {}) { return new Promise((resolve, reject) => { - const child = spawn(cmd, args, Object.assign({ + const opt = Object.assign({ cwd: process.cwd(), stdio: captureStdout ? ['inherit', 'pipe', 'inherit'] : 'inherit' - }, spawnArgs)); + }, spawnArgs); + if (isDebugVerbosity()) { + debuglog('[Spawn]', `${cmd} ${(args || []).join(' ')}`, opt); + } + const child = spawn(cmd, args, opt); let stdout; if (captureStdout) { stdout = ''; @@ -64,9 +71,13 @@ exports.runAsync = function(cmd, args, options) { }; exports.runSync = function(cmd, args, options) { - const child = spawnSync(cmd, args, Object.assign({ + const opt = Object.assign({ cwd: process.cwd() - }, options)); + }, options); + if (isDebugVerbosity()) { + debuglog('[SpawnSync]', `${cmd} ${(args || []).join(' ')}`, opt); + } + const child = spawnSync(cmd, args, opt); if (child.error) { throw child.error; } else if (child.status !== 0) { diff --git a/lib/verbosity.js b/lib/verbosity.js new file mode 100644 index 0000000..37b381d --- /dev/null +++ b/lib/verbosity.js @@ -0,0 +1,29 @@ +'use strict'; + +const chalk = require('chalk'); +const util = require('util'); + +const VERBOSITY = { + NONE: 0, + DEBUG: 2 +}; + +let verbosity = VERBOSITY.NONE; + +exports.isDebugVerbosity = function() { + return verbosity === VERBOSITY.DEBUG; +}; + +exports.setVerbosityFromEnv = function() { + const env = (process.env.NCU_VERBOSITY || '').toUpperCase(); + if (Object.keys(VERBOSITY).includes(env)) { + verbosity = VERBOSITY[env]; + } +}; + +exports.debuglog = function(...args) { + // Prepend a line break in case it's logged while the spinner is running + console.error(chalk.green(util.format('\n[DEBUG]', ...args))); +}; + +exports.VERBOSITY = VERBOSITY;