Skip to content

Commit

Permalink
fix(doctor): refactor doctor command
Browse files Browse the repository at this point in the history
refs TryGhost#47
- split doctor checks out into separate files
- refactor doctor command to work on a "filtering" basis
- refactor usage of doctor command in other commands
- fix tests
  • Loading branch information
acburdine committed Feb 4, 2018
1 parent b91fe09 commit 76829e9
Show file tree
Hide file tree
Showing 23 changed files with 1,321 additions and 1,175 deletions.
24 changes: 24 additions & 0 deletions lib/commands/doctor/checks/check-directory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';
const fs = require('fs-extra');
const Mode = require('stat-mode');
const path = require('path');
const isRoot = require('path-is-root');

const errors = require('../../../errors');

module.exports = function checkDirectoryAndAbove(dir, extra) {
if (isRoot(dir)) {
return Promise.resolve();
}

return fs.lstat(dir).then((stats) => {
const mode = new Mode(stats);

if (!mode.others.read) {
return Promise.reject(new errors.SystemError(`The path ${dir} is not readable by other users on the system.
This can cause issues with the CLI, please either make this directory readable by others or ${extra} in another location.`));
}

return checkDirectoryAndAbove(path.join(dir, '../'), extra);
});
}
25 changes: 25 additions & 0 deletions lib/commands/doctor/checks/folder-permissions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';
const fs = require('fs-extra');
const constants = require('constants');

const errors = require('../../../errors');
const checkDirectoryAndAbove = require('./check-directory');

function folderPermissions(ctx) {
return fs.access(process.cwd(), constants.R_OK | constants.W_OK).catch(() => {
return Promise.reject(new errors.SystemError(`The current directory is not writable.
Please fix your directory permissions.`));
}).then(() => {
if (ctx.local || !ctx.system.platform.linux || (ctx.argv && ctx.argv['setup-linux-user'] === false)) {
return Promise.resolve();
}

return checkDirectoryAndAbove(process.cwd(), 'run `ghost install`');
});
}

module.exports = {
title: 'Checking current folder permissions',
task: folderPermissions,
category: ['install']
};
14 changes: 14 additions & 0 deletions lib/commands/doctor/checks/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict';
const nodeVersion = require('./node-version');
const folderPermissions = require('./folder-permissions');
const systemStack = require('./system-stack');
const mysqlCheck = require('./mysql');
const validateConfig = require('./validate-config');

module.exports = [
nodeVersion,
folderPermissions,
systemStack,
mysqlCheck,
validateConfig
];
167 changes: 0 additions & 167 deletions lib/commands/doctor/checks/install.js

This file was deleted.

43 changes: 43 additions & 0 deletions lib/commands/doctor/checks/mysql.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use strict';
const execa = require('execa');
const chalk = require('chalk');
const includes = require('lodash/includes');

const errors = require('../../../errors');

function mysqlCheck(ctx) {
// On ubuntu, mysqld is in `/usr/sbin` but it's not automatically in the PATH of non-root users
// So, we modify the path env var to make things work
const options = ctx.system.platform.linux ? {env: {PATH: `/usr/sbin:${process.env.PATH}`}} : {};

// Technically this doesn't work on windows, but there's
// not an easy way to do that anyways so ¯\_(ツ)_/¯
return execa.shell('which mysqld', options).catch(() => {
ctx.ui.log(`${chalk.yellow(`Local MySQL install not found. You can ignore this if you are using a remote MySQL host.
Alternatively you could:`)}
${chalk.blue('a)')} install MySQL locally
${chalk.blue('b)')} run ${chalk.cyan('`ghost install --db=sqlite3`')} to use sqlite
${chalk.blue('c)')} run ${chalk.cyan('`ghost install local`')} to get a development install using sqlite3.`);

const confirmPromise = ctx.ui.allowPrompt ?
ctx.ui.confirm(chalk.blue('Continue anyway?'), false) :
Promise.resolve({yes: false});

return confirmPromise.then(answer => answer.yes || Promise.reject(
new errors.SystemError('MySQL check failed.')
));
});
}

module.exports = {
title: 'Checking for a MySQL installation',
task: mysqlCheck,
// Disable this check if:
// a) local install OR
// b) --db sqlite3 is passed OR
// c) --dbhost is passed and IS NOT 'localhost' or '127.0.0.1'
enabled: (ctx) => !ctx.local &&
ctx.argv.db !== 'sqlite3' &&
(!ctx.argv.dbhost || includes(['localhost', '127.0.0.1'], ctx.argv.dbhost)),
category: ['install']
};
28 changes: 28 additions & 0 deletions lib/commands/doctor/checks/node-version.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use strict';
const chalk = require('chalk');
const semver = require('semver');

const errors = require('../../../errors');
const cliPackage = require('../../../../package');
const checkDirectoryAndAbove = require('./check-directory');

function nodeVersion(ctx) {
if (process.env.GHOST_NODE_VERSION_CHECK !== 'false' && !semver.satisfies(process.versions.node, cliPackage.engines.node)) {
return Promise.reject(new errors.SystemError(`${chalk.red('The version of Node.js you are using is not supported.')}
${chalk.gray('Supported: ')}${cliPackage.engines.node}
${chalk.gray('Installed: ')}${process.versions.node}
See ${chalk.underline.blue('https://docs.ghost.org/v1/docs/supported-node-versions')} for more information`));
}

if (ctx.local || !ctx.system.platform.linux || (ctx.argv && ctx.argv['setup-linux-user'] === false)) {
return Promise.resolve();
}

return checkDirectoryAndAbove(process.argv[0], 'install node and Ghost-CLI');
}

module.exports = {
title: 'Checking system Node.js version',
task: nodeVersion,
category: ['install']
};
54 changes: 0 additions & 54 deletions lib/commands/doctor/checks/startup.js

This file was deleted.

0 comments on commit 76829e9

Please sign in to comment.