Skip to content

Commit c96a768

Browse files
committed
fix(yarn-install): remove folder on ghost download error
refs #726 - if an error occurs when installing the Ghost code during install or update, we remove the versions folder so that Ghost doesn't treat it as successfully installed
1 parent 105bde4 commit c96a768

File tree

2 files changed

+79
-5
lines changed

2 files changed

+79
-5
lines changed

lib/tasks/yarn-install.js

+15-5
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ const subTasks = {
5454
file.path = file.path.replace('package/', '');
5555
return file;
5656
}
57+
}).catch((error) => {
58+
// Clean up the install folder since the decompress failed
59+
fs.removeSync(ctx.installPath);
60+
return Promise.reject(error);
5761
});
5862
});
5963
}
@@ -73,11 +77,17 @@ module.exports = function yarnInstall(ui, zipFile) {
7377

7478
tasks.push({
7579
title: 'Installing dependencies',
76-
task: (ctx) => yarn(['install', '--no-emoji', '--no-progress'], {
77-
cwd: ctx.installPath,
78-
env: {NODE_ENV: 'production'},
79-
observe: true
80-
})
80+
task: (ctx) => {
81+
return yarn(['install', '--no-emoji', '--no-progress'], {
82+
cwd: ctx.installPath,
83+
env: {NODE_ENV: 'production'},
84+
observe: true
85+
}).catch((error) => {
86+
// Add error catcher so we can cleanup the install path if an error occurs
87+
fs.removeSync(ctx.installPath);
88+
return Promise.reject(error);
89+
});
90+
}
8191
});
8292

8393
return ui.listr(tasks, false);

test/unit/tasks/yarn-install-spec.js

+64
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,41 @@ describe('Unit: Tasks > yarn-install', function () {
6666
});
6767
});
6868

69+
it('catches errors from yarn and cleans up install folder', function () {
70+
const yarnStub = sinon.stub().rejects(new Error('an error occurred'));
71+
const yarnInstall = proxyquire(modulePath, {
72+
'../utils/yarn': yarnStub
73+
});
74+
const subTasks = yarnInstall.subTasks;
75+
const env = setupTestFolder();
76+
const ctx = {installPath: env.dir};
77+
const listrStub = sinon.stub().callsFake((tasks) => {
78+
expect(tasks).to.have.length(3);
79+
80+
return Promise.each(tasks, (task) => task.task(ctx));
81+
});
82+
83+
const distTaskStub = sinon.stub(subTasks, 'dist').resolves();
84+
const downloadTaskStub = sinon.stub(subTasks, 'download');
85+
86+
return yarnInstall({listr: listrStub}).then(() => {
87+
expect(false, 'error should have been thrown').to.be.true;
88+
}).catch((error) => {
89+
expect(error.message).to.equal('an error occurred');
90+
expect(listrStub.calledOnce).to.be.true;
91+
expect(distTaskStub.calledOnce).to.be.true;
92+
expect(downloadTaskStub.calledOnce).to.be.true;
93+
expect(yarnStub.calledOnce).to.be.true;
94+
expect(yarnStub.args[0][0]).to.deep.equal(['install', '--no-emoji', '--no-progress']);
95+
expect(yarnStub.args[0][1]).to.deep.equal({
96+
cwd: env.dir,
97+
env: {NODE_ENV: 'production'},
98+
observe: true
99+
});
100+
expect(fs.existsSync(env.dir)).to.be.false;
101+
});
102+
});
103+
69104
describe('dist subtask', function () {
70105
it('rejects if yarn util returns invalid json', function () {
71106
const yarnStub = sinon.stub().resolves({stdout: 'not json'});
@@ -253,5 +288,34 @@ describe('Unit: Tasks > yarn-install', function () {
253288
expect(mapResult).to.deep.equal([{path: 'index.js'}, {path: 'package.json'}, {path: 'yarn.lock'}]);
254289
});
255290
});
291+
292+
it('catches errors from decompress and cleans up the install folder', function () {
293+
const env = setupTestFolder();
294+
const downloadStub = sinon.stub().resolves({downloadedData: true});
295+
const shasumStub = sinon.stub().returns('asdf1234');
296+
const decompressStub = sinon.stub().rejects(new Error('an error occurred'));
297+
const downloadTask = proxyquire(modulePath, {
298+
download: downloadStub,
299+
shasum: shasumStub,
300+
decompress: decompressStub
301+
}).subTasks.download;
302+
const ctx = {
303+
tarball: 'something.tgz',
304+
shasum: 'asdf1234',
305+
installPath: path.join(env.dir, 'versions/1.0.0')
306+
};
307+
308+
return downloadTask(ctx).then(() => {
309+
expect(false, 'Error should have been thrown').to.be.true;
310+
}).catch((error) => {
311+
expect(error.message).to.equal('an error occurred');
312+
expect(downloadStub.calledOnce).to.be.true;
313+
expect(downloadStub.calledWithExactly('something.tgz'));
314+
expect(shasumStub.calledOnce).to.be.true;
315+
expect(shasumStub.calledWithExactly({downloadedData: true})).to.be.true;
316+
expect(decompressStub.calledOnce).to.be.true;
317+
expect(fs.existsSync(ctx.installPath)).to.be.false;
318+
});
319+
});
256320
});
257321
});

0 commit comments

Comments
 (0)