Skip to content

Commit

Permalink
fix(install): allow specifying custom version with import flag (#1058)
Browse files Browse the repository at this point in the history
  • Loading branch information
acburdine committed Nov 8, 2019
1 parent e9fcac1 commit f16f471
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 89 deletions.
41 changes: 22 additions & 19 deletions lib/commands/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,6 @@ class InstallCommand extends Command {
this.system.setEnvironment(true, true);
}

if (argv.fromExport) {
const semver = require('semver');
const {parseExport} = require('../tasks/import');
const parsed = parseExport(argv.fromExport);

if (version) {
this.ui.log('Warning: you specified both a specific version and an export file. The version specified in the export file will be used.', 'yellow');
}

if (semver.major(parsed.version) === 0) {
this.ui.log('Detected a v0.x export file. Installing latest v1.x version.', 'green');
version = null;
argv.v1 = true;
} else {
version = parsed.version;
}
}

return this.runCommand(DoctorCommand, Object.assign({
categories: ['install'],
skipInstanceCheck: true,
Expand Down Expand Up @@ -94,8 +76,25 @@ class InstallCommand extends Command {
}

async version(ctx) {
const semver = require('semver');
const {SystemError} = require('../errors');
const {resolveVersion, versionFromZip} = require('../utils/version');
const {version, zip, v1} = ctx.argv;
let {version, zip, v1, fromExport} = ctx.argv;
let exportVersion = null;

if (fromExport) {
const {parseExport} = require('../tasks/import');
const parsed = parseExport(fromExport);

exportVersion = parsed.version;

if (semver.major(exportVersion) === 0) {
ctx.ui.log('Detected a v0.x export file. Installing latest v1.x version.', 'green');
version = 'v1';
} else if (!version) {
version = exportVersion;
}
}

if (version && zip) {
ctx.ui.log('Warning: you specified both a specific version and a zip file. The version in the zip file will be used.', 'yellow');
Expand All @@ -108,6 +107,10 @@ class InstallCommand extends Command {
resolvedVersion = await resolveVersion(version, null, {v1});
}

if (exportVersion && semver.lt(resolvedVersion, exportVersion)) {
throw new SystemError(`Cannot import an export from v${exportVersion} into v${resolvedVersion} of Ghost.`);
}

ctx.version = resolvedVersion; // eslint-disable-line require-atomic-updates
ctx.installPath = path.join(process.cwd(), 'versions', resolvedVersion); // eslint-disable-line require-atomic-updates
}
Expand Down
136 changes: 66 additions & 70 deletions test/unit/commands/install-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,76 +160,6 @@ describe('Unit: Commands > Install', function () {
});
});

it('handles case with custom version and export file', function () {
const dirEmptyStub = sinon.stub().returns(true);
const yarnInstallStub = sinon.stub().resolves();
const ensureStructureStub = sinon.stub().resolves();
const parseExport = sinon.stub().returns({version: '1.4.0'});
const log = sinon.stub();
const listrStub = sinon.stub().callsFake((tasks, ctx) => Promise.each(tasks, task => task.task(ctx, {})));

const InstallCommand = proxyquire(modulePath, {
'../tasks/yarn-install': yarnInstallStub,
'../tasks/ensure-structure': ensureStructureStub,
'../utils/dir-is-empty': dirEmptyStub,
'../tasks/import': {parseExport}
});
const testInstance = new InstallCommand({listr: listrStub, log}, {cliVersion: '1.0.0'});
const runCommandStub = sinon.stub(testInstance, 'runCommand').resolves();
const versionStub = sinon.stub(testInstance, 'version').resolves();
const linkStub = sinon.stub(testInstance, 'link').resolves();
const casperStub = sinon.stub(testInstance, 'casper').resolves();

const argv = {version: '1.0.0', setup: false, fromExport: 'test-import.json'};
return testInstance.run(argv).then(() => {
expect(dirEmptyStub.calledOnce).to.be.true;
expect(log.calledOnce).to.be.true;
expect(listrStub.calledTwice).to.be.true;
expect(yarnInstallStub.calledOnce).to.be.true;
expect(ensureStructureStub.calledOnce).to.be.true;
expect(versionStub.calledOnce).to.be.true;
expect(versionStub.calledWithExactly({argv: {...argv, version: '1.4.0'}, cliVersion: '1.0.0'}));
expect(linkStub.calledOnce).to.be.true;
expect(casperStub.calledOnce).to.be.true;
expect(runCommandStub.calledOnce).to.be.true;
});
});

it('handles case with 0.x export file', function () {
const dirEmptyStub = sinon.stub().returns(true);
const yarnInstallStub = sinon.stub().resolves();
const ensureStructureStub = sinon.stub().resolves();
const parseExport = sinon.stub().returns({version: '0.11.14'});
const log = sinon.stub();
const listrStub = sinon.stub().callsFake((tasks, ctx) => Promise.each(tasks, task => task.task(ctx, {})));

const InstallCommand = proxyquire(modulePath, {
'../tasks/yarn-install': yarnInstallStub,
'../tasks/ensure-structure': ensureStructureStub,
'../utils/dir-is-empty': dirEmptyStub,
'../tasks/import': {parseExport}
});
const testInstance = new InstallCommand({listr: listrStub, log}, {cliVersion: '1.0.0'});
const runCommandStub = sinon.stub(testInstance, 'runCommand').resolves();
const versionStub = sinon.stub(testInstance, 'version').resolves();
const linkStub = sinon.stub(testInstance, 'link').resolves();
const casperStub = sinon.stub(testInstance, 'casper').resolves();

const argv = {setup: false, fromExport: 'test-import.json'};
return testInstance.run(argv).then(() => {
expect(dirEmptyStub.calledOnce).to.be.true;
expect(log.calledOnce).to.be.true;
expect(listrStub.calledTwice).to.be.true;
expect(yarnInstallStub.calledOnce).to.be.true;
expect(ensureStructureStub.calledOnce).to.be.true;
expect(versionStub.calledOnce).to.be.true;
expect(versionStub.calledWithExactly({argv: {...argv, version: null, v1: true}, cliVersion: '1.0.0'}));
expect(linkStub.calledOnce).to.be.true;
expect(casperStub.calledOnce).to.be.true;
expect(runCommandStub.calledOnce).to.be.true;
});
});

it('calls all tasks and returns after tasks run if --no-setup is passed', function () {
const dirEmptyStub = sinon.stub().returns(true);
const yarnInstallStub = sinon.stub().resolves();
Expand Down Expand Up @@ -341,6 +271,72 @@ describe('Unit: Commands > Install', function () {
expect(context.installPath).to.equal(path.join(process.cwd(), 'versions/1.5.2'));
expect(log.calledOnce).to.be.true;
});

it('handles v0.x export case', async function () {
const resolveVersion = sinon.stub().resolves('1.5.0');
const parseExport = sinon.stub().returns({version: '0.11.14'});
const InstallCommand = proxyquire(modulePath, {
'../utils/version': {resolveVersion},
'../tasks/import': {parseExport}
});
const log = sinon.stub();

const testInstance = new InstallCommand({}, {});
const context = {argv: {version: '2.0.0', fromExport: 'test-export.json'}, ui: {log}};

await testInstance.version(context);
expect(resolveVersion.calledOnceWithExactly('v1', null, {v1: undefined})).to.be.true;
expect(parseExport.calledOnceWithExactly('test-export.json')).to.be.true;
expect(context.version).to.equal('1.5.0');
expect(context.installPath).to.equal(path.join(process.cwd(), 'versions/1.5.0'));
expect(log.calledOnce).to.be.true;
});

it('uses export version if none defined', async function () {
const resolveVersion = sinon.stub().resolves('2.0.0');
const parseExport = sinon.stub().returns({version: '2.0.0'});
const InstallCommand = proxyquire(modulePath, {
'../utils/version': {resolveVersion},
'../tasks/import': {parseExport}
});
const log = sinon.stub();

const testInstance = new InstallCommand({}, {});
const context = {argv: {fromExport: 'test-export.json'}, ui: {log}};

await testInstance.version(context);
expect(resolveVersion.calledOnceWithExactly('2.0.0', null, {v1: undefined})).to.be.true;
expect(parseExport.calledOnceWithExactly('test-export.json')).to.be.true;
expect(context.version).to.equal('2.0.0');
expect(context.installPath).to.equal(path.join(process.cwd(), 'versions/2.0.0'));
expect(log.called).to.be.false;
});

it('errors if custom version is less than export version', async function () {
const resolveVersion = sinon.stub().resolves('2.0.0');
const parseExport = sinon.stub().returns({version: '3.0.0'});
const InstallCommand = proxyquire(modulePath, {
'../utils/version': {resolveVersion},
'../tasks/import': {parseExport}
});
const log = sinon.stub();

const testInstance = new InstallCommand({}, {});
const context = {argv: {version: 'v2', fromExport: 'test-export.json'}, ui: {log}};

try {
await testInstance.version(context);
} catch (error) {
expect(error).to.be.an.instanceof(errors.SystemError);
expect(error.message).to.include('v3.0.0 into v2.0.0');
expect(resolveVersion.calledOnceWithExactly('v2', null, {v1: undefined})).to.be.true;
expect(parseExport.calledOnceWithExactly('test-export.json')).to.be.true;
expect(log.called).to.be.false;
return;
}

expect.fail('version should have errored');
});
});

describe('tasks > casper', function () {
Expand Down

0 comments on commit f16f471

Please sign in to comment.