Skip to content

Commit

Permalink
refactor(CLI): doctor command for modern handling of deprecations
Browse files Browse the repository at this point in the history
  • Loading branch information
medikoo committed Oct 20, 2021
1 parent 6991d66 commit 452e234
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 19 deletions.
19 changes: 19 additions & 0 deletions commands/doctor.js
@@ -0,0 +1,19 @@
'use strict';

const fsp = require('fs').promises;
const { writeText, log } = require('@serverless/utils/log');
const healthStatusFilename = require('../lib/utils/health-status-filename');

module.exports = async () => {
const healthStatus = await (async () => {
try {
return await fsp.readFile(healthStatusFilename);
} catch (error) {
if (error.code === 'ENOENT') return null;
throw error;
}
})();

if (healthStatus) writeText(healthStatus);
else log.notice('No deprecations were reported in the last command');
};
6 changes: 6 additions & 0 deletions lib/cli/commands-schema/no-service.js
Expand Up @@ -135,6 +135,12 @@ commands.set('dashboard', {
serviceDependencyMode: 'optional',
});

commands.set('doctor', {
usage: 'Print status on reported deprecations triggered in the last command run',
// TODO: Expose in v3
isHidden: true,
});

commands.set('generate-event', {
usage: 'Generate event',
lifecycleEvents: ['generate-event'],
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/handle-error.js
Expand Up @@ -210,7 +210,7 @@ module.exports = async (exception, options = {}) => {
legacy.consoleLog(chalk.yellow(` Components Version: ${componentsVersion}`));
legacy.consoleLog(' ');

logDeprecation.printSummary();
await logDeprecation.printSummary();

if (
!isTelemetryDisabled &&
Expand Down
6 changes: 6 additions & 0 deletions lib/utils/health-status-filename.js
@@ -0,0 +1,6 @@
'use strict';

const path = require('path');
const os = require('os');

module.exports = path.resolve(os.homedir(), '.serverless/last-command-health-status');
54 changes: 45 additions & 9 deletions lib/utils/logDeprecation.js
@@ -1,10 +1,15 @@
'use strict';

const path = require('path');
const fse = require('fs-extra');
const fsp = require('fs').promises;
const chalk = require('chalk');
const weakMemoizee = require('memoizee/weak');
const _ = require('lodash');
const resolveTmpdir = require('process-utils/tmpdir');
const ServerlessError = require('../serverless-error');
const { style, legacy, log } = require('@serverless/utils/log');
const healthStatusFilename = require('./health-status-filename');

const disabledDeprecationCodesByEnv = extractCodes(process.env.SLS_DEPRECATION_DISABLE);

Expand Down Expand Up @@ -112,27 +117,58 @@ module.exports.flushBuffered = () => {
}
};

module.exports.printSummary = () => {
if (!bufferedDeprecations.length) return;
module.exports.printSummary = async () => {
if (!bufferedDeprecations.length) {
try {
await fsp.unlink(healthStatusFilename);
} catch {
// ignore
}
return;
}

try {
const healthStatus = [];

deprecationLogger.warning();

if (bufferedDeprecations.length === 1) {
healthStatus.push('1 deprecation triggered in the last command:', '');
deprecationLogger.warning(
style.aside("1 deprecation found: run 'serverless doctor' for more details")
);
} else {
healthStatus.push(
`${bufferedDeprecations.length} deprecations triggered in the last command:`,
''
);
deprecationLogger.warning(
style.aside(
`${bufferedDeprecations.length} deprecations found: run 'serverless doctor' for more details`
)
);
}
for (const { code, message } of bufferedDeprecations) {
healthStatus.push(message);
if (!code.startsWith('EXT_')) {
healthStatus.push(
style.aside(`More info: https://serverless.com/framework/docs/deprecations/#${code}`)
);
}
}

const tmpHealthStatusFilename = path.resolve(await resolveTmpdir(), 'health-status');
await Promise.all([
fse.ensureDir(path.dirname(healthStatusFilename)),
fsp.writeFile(tmpHealthStatusFilename, healthStatus.join('\n')),
]);
await fsp.rename(tmpHealthStatusFilename, healthStatusFilename);

if (bufferedDeprecations.length === 1) {
const { code, message } = bufferedDeprecations[0];
writeDeprecation(code, message);
return;
}

deprecationLogger.warning(
style.aside(
`${bufferedDeprecations.length} deprecations found: run 'serverless doctor' for more details`
)
);

const prefix = 'Serverless: ';
legacy.write(`${prefix}${chalk.bold.keyword('orange')('Deprecation warnings:')}\n\n`);
for (const { code, message } of bufferedDeprecations) {
Expand Down
8 changes: 4 additions & 4 deletions scripts/serverless.js
Expand Up @@ -41,7 +41,7 @@ let hasTelemetryBeenReported = false;
// to properly handle e.g. `SIGINT` interrupt
const keepAliveTimer = setTimeout(() => {}, 60 * 60 * 1000);

const standaloneCommands = new Set(['plugin install', 'plugin uninstall']);
const standaloneCommands = new Set(['doctor', 'plugin install', 'plugin uninstall']);

process.once('uncaughtException', (error) => {
clearTimeout(keepAliveTimer);
Expand Down Expand Up @@ -123,7 +123,7 @@ const processSpanPromise = (async () => {
// If version number request, show it and abort
if (options.version) {
await require('../lib/cli/render-version')();
logDeprecation.printSummary();
await logDeprecation.printSummary();
return;
}

Expand Down Expand Up @@ -542,7 +542,7 @@ const processSpanPromise = (async () => {

progress.clear();

logDeprecation.printSummary();
await logDeprecation.printSummary();

if (!hasTelemetryBeenReported) {
hasTelemetryBeenReported = true;
Expand Down Expand Up @@ -831,7 +831,7 @@ const processSpanPromise = (async () => {
}
progress.clear();

logDeprecation.printSummary();
await logDeprecation.printSummary();

if (!hasTelemetryBeenReported) {
hasTelemetryBeenReported = true;
Expand Down
35 changes: 35 additions & 0 deletions test/unit/commands/doctor.test.js
@@ -0,0 +1,35 @@
'use strict';

const chai = require('chai');
const path = require('path');
const spawn = require('child-process-ext/spawn');
const { expect } = require('chai');

chai.use(require('chai-as-promised'));

const serverlessPath = path.resolve(__dirname, '../../../scripts/serverless.js');

describe('test/unit/commands/doctor.test.js', async () => {
before(() => {
process.env.SLS_DEPRECATION_NOTIFICATION_MODE = 'warn:summary';
process.env.SLS_DEV_LOG_MODE = '3';
});

it('should print health status after command which triggered deprecation', async () => {
// Trigger deprecation
await spawn('node', [serverlessPath, 'config', '--foo']);

// Gather Health status
expect(String((await spawn('node', [serverlessPath, 'doctor'])).stdoutBuffer)).to.include(
'deprecation triggered in the last command'
);
});

it('should inform of no issues when no health status found', async () => {
// Trigger command that reports no issues
await spawn('node', [serverlessPath, 'config', '--help']);

// Gather Health status
expect(String((await spawn('node', [serverlessPath, 'doctor'])).stdoutBuffer)).to.be.empty;
});
});
12 changes: 7 additions & 5 deletions test/unit/lib/utils/logDeprecation.test.js
Expand Up @@ -13,7 +13,9 @@ describe('test/unit/lib/utils/logDeprecation.test.js', () => {

beforeEach(() => {
delete require.cache[require.resolve('../../../../lib/utils/logDeprecation')];
({ originalEnv, restoreEnv } = overrideEnv());
({ originalEnv, restoreEnv } = overrideEnv({
whitelist: ['APPDATA', 'HOME', 'PATH', 'TEMP', 'TMP', 'TMPDIR', 'USERPROFILE'],
}));
});

afterEach(() => {
Expand Down Expand Up @@ -147,17 +149,17 @@ describe('test/unit/lib/utils/logDeprecation.test.js', () => {
expect(stdoutData).to.include('Second deprecation');
});

it('should expose working `printSummary` method', () => {
it('should expose working `printSummary` method', async () => {
let stdoutData = '';
overrideStdoutWrite(
await overrideStdoutWrite(
(data) => (stdoutData += data),
() => {
async () => {
const logDeprecation = require('../../../../lib/utils/logDeprecation');
logDeprecation('CODE1', 'First deprecation');
expect(stdoutData).to.not.include('First deprecation');
logDeprecation('CODE2', 'Second deprecation');
expect(stdoutData).to.not.include('Second deprecation');
logDeprecation.printSummary();
await logDeprecation.printSummary();
}
);
expect(stdoutData).to.include('First deprecation');
Expand Down

0 comments on commit 452e234

Please sign in to comment.