Skip to content

Commit

Permalink
feat(doctor): add binary dependency check (#1040)
Browse files Browse the repository at this point in the history
no issue
- checks if the node version has changed on start, to prevent issues with binary deps
  • Loading branch information
acburdine authored Nov 4, 2019
1 parent 514ad02 commit 1716b38
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 3 deletions.
26 changes: 26 additions & 0 deletions lib/commands/doctor/checks/binary-deps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const chalk = require('chalk');
const {SystemError} = require('../../../errors');

const taskTitle = 'Checking binary dependencies';

function binaryDeps(ctx, task) {
if (!ctx.instance) {
return task.skip('Instance not set');
}

if (process.versions.node !== ctx.instance.nodeVersion) {
const currentVersion = ctx.instance.version;

throw new SystemError({
message: 'The installed node version has changed since Ghost was installed.',
help: `Run ${chalk.green(`ghost update ${currentVersion} --force`)} to re-install binary dependencies.`,
task: taskTitle
});
}
}

module.exports = {
title: taskTitle,
task: binaryDeps,
category: ['start']
};
4 changes: 3 additions & 1 deletion lib/commands/doctor/checks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const folderPermissions = require('./folder-permissions');
const filePermissions = require('./file-permissions');
const contentFolder = require('./content-folder');
const checkMemory = require('./check-memory');
const binaryDeps = require('./binary-deps');

module.exports = [
nodeVersion,
Expand All @@ -24,5 +25,6 @@ module.exports = [
folderPermissions,
filePermissions,
contentFolder,
checkMemory
checkMemory,
binaryDeps
];
1 change: 1 addition & 0 deletions lib/commands/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ class UpdateCommand extends Command {

instance.previousVersion = rollback ? null : instance.version;
instance.version = version;
instance.nodeVersion = process.versions.node;
}
}

Expand Down
15 changes: 15 additions & 0 deletions lib/instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,21 @@ class Instance {
return true;
}

/**
* Node Version used when installing this version
*
* @property nodeVersion
* @type string
* @public
*/
get nodeVersion() {
return this._cliConfig.get('node-version', process.versions.node);
}
set nodeVersion(value) {
this._cliConfig.set('node-version', value).save();
return true;
}

/**
* Returns whether or not the instance has been setup
*
Expand Down
49 changes: 49 additions & 0 deletions test/unit/commands/doctor/checks/binary-deps-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const {expect} = require('chai');
const sinon = require('sinon');
const semver = require('semver');

const {SystemError} = require('../../../../../lib/errors');
const check = require('../../../../../lib/commands/doctor/checks/binary-deps');

describe('Unit: Doctor Checks > Binary Deps', function () {
afterEach(() => {
sinon.restore();
});

it('exports proper task', function () {
expect(check.title).to.equal('Checking binary dependencies');
expect(check.task).to.be.a('function');
expect(check.category).to.deep.equal(['start']);
});

it('skips if instance not set', function () {
const skip = sinon.stub();

check.task({}, {skip});
expect(skip.calledOnce).to.be.true;
});

it('does nothing if node versions are the same', function () {
const skip = sinon.stub();
const instance = {nodeVersion: process.versions.node};

check.task({instance}, {skip});
expect(skip.called).to.be.false;
});

it('throws error if node versions are different', function () {
const skip = sinon.stub();
const instance = {nodeVersion: semver.inc(process.versions.node, 'major')};

try {
check.task({instance}, {skip});
} catch (error) {
expect(error).to.be.an.instanceof(SystemError);
expect(error.message).to.include('node version has changed');
expect(skip.called).to.be.false;
return;
}

expect.fail('should have thrown an error');
});
});
2 changes: 2 additions & 0 deletions test/unit/commands/update-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,7 @@ describe('Unit: Commands > Update', function () {
expect(fs.readlinkSync(path.join(env.dir, 'current'))).to.equal(path.join(env.dir, 'versions/1.0.1'));
expect(instance.version).to.equal('1.0.1');
expect(instance.previousVersion).to.equal('1.0.0');
expect(instance.nodeVersion).to.equal(process.versions.node);
});

it('does things correctly with rollback', function () {
Expand All @@ -1120,6 +1121,7 @@ describe('Unit: Commands > Update', function () {
expect(fs.readlinkSync(path.join(env.dir, 'current'))).to.equal(path.join(env.dir, 'versions/1.0.0'));
expect(instance.version).to.equal('1.0.0');
expect(instance.previousVersion).to.be.null;
expect(instance.nodeVersion).to.equal(process.versions.node);
});
});
});
5 changes: 3 additions & 2 deletions test/unit/instance-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ const Instance = require('../../lib/instance');
const Config = require('../../lib/utils/config');
const ProcessManager = require('../../lib/process-manager');

function testConfigAccessors(instanceProp, configProp) {
function testConfigAccessors(instanceProp, configProp, defaultValue = null) {
return () => {
const config = createConfigStub();
config.get.withArgs(configProp, null).returns('1.0.0');
config.get.withArgs(configProp, defaultValue).returns('1.0.0');

const instance = new Instance({}, {}, '');
instance._cliConfig = config;
Expand Down Expand Up @@ -157,6 +157,7 @@ describe('Unit: Instance', function () {
it('version getter/setter works', testConfigAccessors('version', 'active-version'));
it('cliVersion getter/setter works', testConfigAccessors('cliVersion', 'cli-version'));
it('previousVersion getter/setter works', testConfigAccessors('previousVersion', 'previous-version'));
it('nodeVersion getter/setter works', testConfigAccessors('nodeVersion', 'node-version', process.versions.node));

it('isSetup accessor works', function () {
const hasInstance = sinon.stub();
Expand Down

0 comments on commit 1716b38

Please sign in to comment.