Skip to content

Commit 0faa5f6

Browse files
committed
feat(doctor): ghost install/setup doctor check improvements
closes #312, #314 - move setup checks into install checks - add checks for mysql - improve doctor messaging
1 parent 43ceff1 commit 0faa5f6

File tree

6 files changed

+110
-104
lines changed

6 files changed

+110
-104
lines changed

lib/commands/config/advanced.js

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ module.exports = {
6969
db: {
7070
description: 'Type of database Ghost should use E.g. mysql or sqlite3',
7171
validate: value => includes(['sqlite3', 'mysql'], value),
72+
default: 'mysql',
7273
configPath: 'database.client',
7374
type: 'string',
7475
group: 'Database Options:'

lib/commands/doctor/checks/install.js

+74-2
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
'use strict';
22
const fs = require('fs');
3+
const os = require('os');
34
const eol = require('os').EOL;
45
const chalk = require('chalk');
6+
const execa = require('execa');
57
const semver = require('semver');
68
const constants = require('constants');
9+
10+
const errors = require('../../../errors');
711
const cliPackage = require('../../../../package');
812

913
module.exports = [{
1014
title: 'Checking system node version',
1115
task: () => {
1216
if (process.env.GHOST_NODE_VERSION_CHECK !== 'false' &&
1317
!semver.satisfies(process.versions.node, cliPackage.engines.node)) {
14-
return Promise.reject(new Error(
18+
return Promise.reject(new errors.SystemError(
1519
`${chalk.red('The version of node you are using is not supported.')}${eol}` +
1620
`${chalk.gray('Supported: ')}${cliPackage.engines.node}${eol}` +
1721
`${chalk.gray('Installed: ')}${process.versions.node}${eol}` +
@@ -26,10 +30,78 @@ module.exports = [{
2630
try {
2731
fs.accessSync(process.cwd(), constants.R_OK | constants.W_OK);
2832
} catch (e) {
29-
return Promise.reject(new Error(
33+
return Promise.reject(new errors.SystemError(
3034
`The current directory is not writable.${eol}` +
3135
'Please fix your directory permissions.'
3236
));
3337
}
3438
}
39+
}, {
40+
title: 'Checking official system stack',
41+
skip: (ctx) => ctx.local || (ctx.argv && !ctx.argv.stack),
42+
task: (ctx) => {
43+
let promise;
44+
45+
if (os.platform() !== 'linux') {
46+
promise = Promise.reject({message: 'Platform is not Linux'});
47+
} else {
48+
promise = execa.shell('lsb_release -a').catch(
49+
() => Promise.reject({message: 'Linux version is not Ubuntu 16'})
50+
).then((result) => {
51+
if (!result.stdout || !result.stdout.match(/Ubuntu 16/)) {
52+
return Promise.reject({message: 'Linux version is not Ubuntu 16'});
53+
}
54+
55+
return ctx.ui.listr([{
56+
title: 'Systemd',
57+
task: () => execa.shell('dpkg -l | grep systemd')
58+
.catch(() => Promise.reject({missing: 'systemd'}))
59+
}, {
60+
title: 'Nginx',
61+
task: () => execa.shell('dpkg -l | grep nginx')
62+
.catch(() => Promise.reject({missing: 'nginx'}))
63+
}], ctx, {
64+
concurrent: true,
65+
exitOnError: false,
66+
renderer: ctx.ui.verbose ? 'verbose' : 'silent'
67+
}).catch(error => Promise.reject({
68+
message: `Missing package(s): ${error.errors.map(e => e.missing).join(', ')}`
69+
}))
70+
});
71+
}
72+
73+
return promise.then(() => { return {yes: true}; }).catch((error) => {
74+
ctx.ui.log(
75+
`System Stack checks failed with message: '${error.message}'${eol}` +
76+
`Some features of Ghost-CLI may not work without additional configuration.${eol}` +
77+
'For local installs we recommend using `ghost install local` instead.',
78+
'yellow'
79+
);
80+
81+
return ctx.ui.confirm(chalk.blue('Continue anyways?'), false);
82+
}).then(answer => answer.yes || Promise.reject(
83+
new errors.SystemError('System Stack checks failed.')
84+
));
85+
}
86+
}, {
87+
title: 'Checking for MySQL availability',
88+
skip: (ctx) => ctx.local || (ctx.argv && ctx.argv.db === 'sqlite3'),
89+
task: (ctx) => {
90+
// Technically this doesn't work on windows, but there's
91+
// not an easy way to do that anyways so ¯\_(ツ)_/¯
92+
return execa.shell('which mysqld').catch(() => {
93+
ctx.ui.log(
94+
chalk.yellow(`Local MySQL install not found. You can ignore this if you are using a remote MySQL host.${eol}`) +
95+
chalk.yellow(`Alternatively you could:${eol}`) +
96+
`${chalk.blue('a)')} install MySQL locally${eol}` +
97+
`${chalk.blue('b)')} run ${chalk.cyan('`ghost install --db=sqlite3`')} to use sqlite ${eol}` +
98+
`${chalk.blue('c)')} run ${chalk.cyan('`ghost install local`')} to get a non-production install with sqlite3.`
99+
);
100+
101+
return ctx.ui.confirm(chalk.blue('Continue anyways?'), false)
102+
.then(answer => answer.yes || Promise.reject(
103+
new errors.SystemError('MySQL check failed.')
104+
));
105+
});
106+
}
35107
}];

lib/commands/doctor/checks/setup.js

-65
This file was deleted.

lib/commands/doctor/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class DoctorCommand extends Command {
1818
return Promise.reject(e);
1919
}
2020

21-
return this.ui.listr(checks, {ui: this.ui, system: this.system}, {concurrent: true}).then(() => {
21+
return this.ui.listr(checks, {ui: this.ui, system: this.system}).then(() => {
2222
this.ui.success(`All ${category} checks passed`);
2323
}).catch((error) => {
2424
if (error instanceof errors.SystemError) {

lib/commands/install.js

+34-26
Original file line numberDiff line numberDiff line change
@@ -47,33 +47,36 @@ class InstallCommand extends Command {
4747
this.system.setEnvironment(true, true);
4848
}
4949

50-
return this.ui.listr([{
51-
title: 'Checking for latest Ghost version',
52-
task: this.version
53-
}, {
54-
title: 'Running system checks',
55-
task: () => this.ui.listr(installChecks, false, {concurrent: true})
56-
}, {
57-
title: 'Setting up install directory',
58-
task: ensureStructure
59-
}, {
60-
title: 'Downloading and installing Ghost',
61-
task: (ctx, task) => {
62-
task.title = `Downloading and installing Ghost v${ctx.version}`;
63-
return yarnInstall(ctx.ui);
64-
}
65-
}, {
66-
title: 'Moving files',
67-
task: () => this.ui.listr([{
68-
title: 'Linking things',
69-
task: this.link.bind(this)
50+
return this.ui.listr(installChecks, {
51+
ui: this.ui,
52+
argv: argv,
53+
local: local
54+
}).then(() => {
55+
return this.ui.listr([{
56+
title: 'Checking for latest Ghost version',
57+
task: this.version
58+
}, {
59+
title: 'Setting up install directory',
60+
task: ensureStructure
61+
}, {
62+
title: 'Downloading and installing Ghost',
63+
task: (ctx, task) => {
64+
task.title = `Downloading and installing Ghost v${ctx.version}`;
65+
return yarnInstall(ctx.ui);
66+
}
7067
}, {
71-
title: 'Summoning Casper',
72-
task: this.casper
73-
}], false)
74-
}], {
75-
version: version,
76-
cliVersion: this.cliVersion
68+
title: 'Moving files',
69+
task: () => this.ui.listr([{
70+
title: 'Linking things',
71+
task: this.link.bind(this)
72+
}, {
73+
title: 'Summoning Casper',
74+
task: this.casper
75+
}], false)
76+
}], {
77+
version: version,
78+
cliVersion: this.cliVersion
79+
})
7780
}).then(() => {
7881
if (!argv.setup) {
7982
return;
@@ -121,6 +124,11 @@ InstallCommand.options = {
121124
description: 'Folder to install Ghost in',
122125
type: 'string'
123126
},
127+
stack: {
128+
description: '[--no-stack] Enable/Disable system stack checks on install',
129+
type: 'boolean',
130+
default: true
131+
},
124132
setup: {
125133
description: '[--no-setup] Enable/Disable auto-running the setup command',
126134
type: 'boolean',

lib/commands/setup.js

-10
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ const includes = require('lodash/includes');
77

88
const Command = require('../command');
99
const migrate = require('../tasks/migrate');
10-
const setupChecks = require('./doctor/checks/setup');
1110
const StartCommand = require('./start');
1211
const ConfigCommand = require('./config');
1312

@@ -88,10 +87,6 @@ class SetupCommand extends Command {
8887
}
8988

9089
let initialStages = [{
91-
title: 'Running setup checks',
92-
skip: () => !argv.stack,
93-
task: () => this.ui.listr(setupChecks, false)
94-
}, {
9590
title: 'Setting up instance',
9691
task: (ctx) => {
9792
ctx.instance = this.system.getInstance();
@@ -167,11 +162,6 @@ class SetupCommand extends Command {
167162
SetupCommand.description = 'Setup an installation of Ghost (after it is installed)';
168163
SetupCommand.params = '[stages..]';
169164
SetupCommand.options = {
170-
stack: {
171-
description: '[--no-stack] Enable/Disable system stack checks on setup',
172-
type: 'boolean',
173-
default: true
174-
},
175165
start: {
176166
description: 'Automatically start Ghost without prompting',
177167
type: 'boolean',

0 commit comments

Comments
 (0)