Skip to content

Commit 0f887ba

Browse files
author
Robert Jackson
authored
Add support for using yarn.lock file (#409)
Add support for using yarn.lock file
2 parents 57d9ea2 + f7dee65 commit 0f887ba

6 files changed

Lines changed: 328 additions & 26 deletions

File tree

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,15 @@ module.exports = function() {
126126
dependencies will be restored to their prior state.
127127
*/
128128
useYarn: true,
129+
130+
/*
131+
buildManagerOptions allows you to opt-out of the default options such as `--ignore-engines --no-lockfile`.
132+
The buildManagerOptions function is aware of each scenario so you can customize your options.
133+
*/
134+
buildManagerOptions(scenario) {
135+
return ['--ignore-engines'];
136+
}
137+
129138
scenarios: [
130139
{
131140
name: 'Ember 1.10 with ember-data',

lib/dependency-manager-adapters/npm.js

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@ module.exports = CoreObject.extend({
1616
},
1717
useYarnCommand: false,
1818
yarnLock: 'yarn.lock',
19+
yarnLockBackupFileName: 'yarn.lock.ember-try',
1920
configKey: 'npm',
2021
packageJSON: 'package.json',
2122
packageJSONBackupFileName: 'package.json.ember-try',
2223
nodeModules: 'node_modules',
2324
nodeModulesBackupLocation: '.node_modules.ember-try',
25+
npmShrinkWrap: 'npm-shrinkwrap.json',
26+
npmShrinkWrapBackupFileName: 'npm-shrinkwrap.json.ember-try',
27+
packageLock: 'package-lock.json',
28+
packageLockBackupFileName: 'package-lock.json.ember-try',
2429
setup(options) {
2530
if (!options) {
2631
options = {};
@@ -33,7 +38,7 @@ module.exports = CoreObject.extend({
3338

3439
adapter.applyDependencySet(depSet);
3540

36-
return adapter._install().then(() => {
41+
return adapter._install(depSet).then(() => {
3742
let deps = extend({}, depSet.dependencies || {}, depSet.devDependencies || {});
3843
let currentDeps = Object.keys(deps).map((dep) => {
3944
return {
@@ -58,6 +63,18 @@ module.exports = CoreObject.extend({
5863
let cleanupTasks = [rimraf(path.join(adapter.cwd, adapter.packageJSONBackupFileName)),
5964
rimraf(path.join(adapter.cwd, adapter.nodeModulesBackupLocation))];
6065

66+
if (fs.existsSync(path.join(this.cwd, this.yarnLockBackupFileName))) {
67+
cleanupTasks.push(rimraf(path.join(adapter.cwd, adapter.yarnLockBackupFileName)));
68+
}
69+
70+
if (fs.existsSync(path.join(this.cwd, this.npmShrinkWrapBackupFileName))) {
71+
cleanupTasks.push(rimraf(path.join(adapter.cwd, adapter.npmShrinkWrapBackupFileName)));
72+
}
73+
74+
if (fs.existsSync(path.join(this.cwd, this.packageLockBackupFileName))) {
75+
cleanupTasks.push(rimraf(path.join(adapter.cwd, adapter.packageLockBackupFileName)));
76+
}
77+
6178
return RSVP.all(cleanupTasks);
6279
}).catch((e) => {
6380
console.log('Error cleaning up npm scenario:', e); // eslint-disable-line no-console
@@ -82,26 +99,35 @@ module.exports = CoreObject.extend({
8299
return null;
83100
}
84101
},
85-
_install() {
102+
_install(depSet) {
86103
let adapter = this;
87104
let mgrOptions = this.managerOptions || [];
105+
let cmd = this.useYarnCommand ? 'yarn' : 'npm';
88106

89-
debug('Run npm install with options %s', mgrOptions);
107+
// buildManagerOptions overrides all default
108+
if (typeof this.buildManagerOptions === 'function') {
109+
mgrOptions = this.buildManagerOptions(depSet);
90110

91-
let cmd = this.useYarnCommand ? 'yarn' : 'npm';
92-
if (this.useYarnCommand) {
93-
if (mgrOptions.indexOf('--no-lockfile') === -1) {
94-
mgrOptions = mgrOptions.concat(['--no-lockfile']);
111+
if (!Array.isArray(mgrOptions)) {
112+
throw new Error('buildManagerOptions must return an array of options');
95113
}
96-
// npm warns on incompatible engines
97-
// yarn errors, not a good experience
98-
if (mgrOptions.indexOf('--ignore-engines') === -1) {
99-
mgrOptions = mgrOptions.concat(['--ignore-engines']);
114+
} else {
115+
if (this.useYarnCommand) {
116+
if (mgrOptions.indexOf('--no-lockfile') === -1) {
117+
mgrOptions = mgrOptions.concat(['--no-lockfile']);
118+
}
119+
// npm warns on incompatible engines
120+
// yarn errors, not a good experience
121+
if (mgrOptions.indexOf('--ignore-engines') === -1) {
122+
mgrOptions = mgrOptions.concat(['--ignore-engines']);
123+
}
124+
} else if (mgrOptions.indexOf('--no-shrinkwrap') === -1) {
125+
mgrOptions = mgrOptions.concat(['--no-shrinkwrap']);
100126
}
101-
} else if (mgrOptions.indexOf('--no-shrinkwrap') === -1) {
102-
mgrOptions = mgrOptions.concat(['--no-shrinkwrap']);
103127
}
104128

129+
debug('Run npm/yarn install with options %s', mgrOptions);
130+
105131
return this.run(cmd, [].concat(['install'], mgrOptions), { cwd: this.cwd }).then(() => {
106132
if (!adapter.useYarnCommand) {
107133
return adapter.run('npm', ['--version'], { cwd: this.cwd, stdio: 'pipe' }).then((res) => {
@@ -171,6 +197,21 @@ module.exports = CoreObject.extend({
171197
path.join(this.cwd, this.nodeModules), { clobber: true }),
172198
];
173199

200+
if (fs.existsSync(path.join(this.cwd, this.yarnLockBackupFileName))) {
201+
restoreTasks.push(copy(path.join(this.cwd, this.yarnLockBackupFileName),
202+
path.join(this.cwd, this.yarnLock)));
203+
}
204+
205+
if (fs.existsSync(path.join(this.cwd, this.npmShrinkWrapBackupFileName))) {
206+
restoreTasks.push(copy(path.join(this.cwd, this.npmShrinkWrapBackupFileName),
207+
path.join(this.cwd, this.npmShrinkWrap)));
208+
}
209+
210+
if (fs.existsSync(path.join(this.cwd, this.packageLockBackupFileName))) {
211+
restoreTasks.push(copy(path.join(this.cwd, this.packageLockBackupFileName),
212+
path.join(this.cwd, this.packageLock)));
213+
}
214+
174215
return RSVP.all(restoreTasks);
175216
},
176217
_backupOriginalDependencies() {
@@ -184,6 +225,21 @@ module.exports = CoreObject.extend({
184225
copy(path.join(this.cwd, this.nodeModules),
185226
path.join(this.cwd, this.nodeModulesBackupLocation), { clobber: true })];
186227

228+
if (fs.existsSync(path.join(this.cwd, this.yarnLock))) {
229+
backupTasks.push(copy(path.join(this.cwd, this.yarnLock),
230+
path.join(this.cwd, this.yarnLockBackupFileName)));
231+
}
232+
233+
if (fs.existsSync(path.join(this.cwd, this.npmShrinkWrap))) {
234+
backupTasks.push(copy(path.join(this.cwd, this.npmShrinkWrap),
235+
path.join(this.cwd, this.npmShrinkWrapBackupFileName)));
236+
}
237+
238+
if (fs.existsSync(path.join(this.cwd, this.packageLock))) {
239+
backupTasks.push(copy(path.join(this.cwd, this.packageLock),
240+
path.join(this.cwd, this.packageLockBackupFileName)));
241+
}
242+
187243
return RSVP.all(backupTasks);
188244
},
189245
});

lib/dependency-manager-adapters/workspace.js

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ module.exports = CoreObject.extend({
4747
run: this.run,
4848
managerOptions: this.managerOptions,
4949
useYarnCommand: true,
50+
buildManagerOptions: this.buildManagerOptions,
5051
});
5152
});
5253

@@ -59,7 +60,7 @@ module.exports = CoreObject.extend({
5960
adapter.applyDependencySet(depSet);
6061
});
6162

62-
return this._install().then(() => {
63+
return this._install(depSet).then(() => {
6364
let deps = extend({}, depSet.dependencies || {}, depSet.devDependencies || {});
6465
let currentDeps = Object.keys(deps).map((dep) => {
6566
return {
@@ -80,20 +81,29 @@ module.exports = CoreObject.extend({
8081
return RSVP.all(this._packageAdapters.map(adapter => adapter.cleanup()));
8182
},
8283

83-
_install() {
84+
_install(depSet) {
8485
let mgrOptions = this.managerOptions || [];
8586

86-
debug('Run yarn install with options %s', mgrOptions);
87-
88-
if (mgrOptions.indexOf('--no-lockfile') === -1) {
89-
mgrOptions = mgrOptions.concat(['--no-lockfile']);
90-
}
91-
// npm warns on incompatible engines
92-
// yarn errors, not a good experience
93-
if (mgrOptions.indexOf('--ignore-engines') === -1) {
94-
mgrOptions = mgrOptions.concat(['--ignore-engines']);
87+
// buildManagerOptions overrides all default
88+
if (typeof this.buildManagerOptions === 'function') {
89+
mgrOptions = this.buildManagerOptions(depSet);
90+
91+
if (!Array.isArray(mgrOptions)) {
92+
throw new Error('buildManagerOptions must return an array of options');
93+
}
94+
} else {
95+
if (mgrOptions.indexOf('--no-lockfile') === -1) {
96+
mgrOptions = mgrOptions.concat(['--no-lockfile']);
97+
}
98+
// npm warns on incompatible engines
99+
// yarn errors, not a good experience
100+
if (mgrOptions.indexOf('--ignore-engines') === -1) {
101+
mgrOptions = mgrOptions.concat(['--ignore-engines']);
102+
}
95103
}
96104

105+
debug('Run yarn install with options %s', mgrOptions);
106+
97107
return this.run('yarn', [].concat(['install'], mgrOptions), { cwd: this.cwd });
98108
},
99109

lib/utils/dependency-manager-adapter-factory.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,12 @@ module.exports = {
3131
new WorkspaceAdapter({
3232
cwd: root,
3333
managerOptions: config.npmOptions,
34-
useYarnCommand: config.useYarn
34+
useYarnCommand: config.useYarn,
35+
buildManagerOptions: config.buildManagerOptions
3536
})
3637
);
3738
} else if (hasNpm || hasBower) {
38-
adapters.push(new NpmAdapter({ cwd: root, managerOptions: config.npmOptions, useYarnCommand: config.useYarn }));
39+
adapters.push(new NpmAdapter({ cwd: root, managerOptions: config.npmOptions, useYarnCommand: config.useYarn, buildManagerOptions: config.buildManagerOptions }));
3940
adapters.push(new BowerAdapter({ cwd: root, managerOptions: config.bowerOptions }));
4041
}
4142

test/dependency-manager-adapters/npm-adapter-test.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,24 @@ describe('npmAdapter', () => {
3939
assertFileContainsJSON(path.join(tmpdir, '.node_modules.ember-try/prove-it.json'), { originalNodeModules: true });
4040
});
4141
});
42+
43+
it('backs up the yarn.lock file, npm-shrinkwrap.json and package-lock.json if they exist', () => {
44+
fs.mkdirSync('node_modules');
45+
writeJSONFile('node_modules/prove-it.json', { originalNodeModules: true });
46+
writeJSONFile('package.json', { originalPackageJSON: true });
47+
writeJSONFile('yarn.lock', { originalYarnLock: true });
48+
writeJSONFile('npm-shrinkwrap.json', { originalNpmShrinkWrap: true });
49+
writeJSONFile('package-lock.json', { originalPackageLock: true });
50+
return new NpmAdapter({
51+
cwd: tmpdir,
52+
}).setup().then(() => {
53+
assertFileContainsJSON(path.join(tmpdir, 'package.json.ember-try'), { originalPackageJSON: true });
54+
assertFileContainsJSON(path.join(tmpdir, '.node_modules.ember-try/prove-it.json'), { originalNodeModules: true });
55+
assertFileContainsJSON(path.join(tmpdir, 'yarn.lock.ember-try'), { originalYarnLock: true });
56+
assertFileContainsJSON(path.join(tmpdir, 'npm-shrinkwrap.json.ember-try'), { originalNpmShrinkWrap: true });
57+
assertFileContainsJSON(path.join(tmpdir, 'package-lock.json.ember-try'), { originalPackageLock: true });
58+
});
59+
});
4260
});
4361

4462
describe('#_install', () => {
@@ -127,6 +145,46 @@ describe('npmAdapter', () => {
127145
expect(runCount).to.equal(2);
128146
});
129147
});
148+
149+
it('uses buildManagerOptions for npm commands', () => {
150+
writeJSONFile('package.json', fixturePackage);
151+
let runCount = 0;
152+
let stubbedRun = generateMockRun([{
153+
command: 'npm install --flat',
154+
callback() {
155+
runCount++;
156+
return RSVP.resolve();
157+
},
158+
}, {
159+
command: 'npm --version',
160+
callback() {
161+
runCount++;
162+
return RSVP.resolve({stdout: '5.7.1'});
163+
},
164+
}], { allowPassthrough: false });
165+
166+
return new NpmAdapter({
167+
cwd: tmpdir,
168+
run: stubbedRun,
169+
buildManagerOptions: function() {
170+
return ['--flat'];
171+
},
172+
})._install().then(() => {
173+
expect(runCount).to.equal(2, 'npm install should run with buildManagerOptions');
174+
});
175+
});
176+
177+
it('throws an error if buildManagerOptions does not return an array', () => {
178+
expect(() => {
179+
new NpmAdapter({
180+
cwd: tmpdir,
181+
run: () => {},
182+
buildManagerOptions: function() {
183+
return 'string';
184+
},
185+
})._install()
186+
}).to.throw(/buildManagerOptions must return an array of options/);
187+
});
130188
});
131189

132190
describe('with yarn', () => {
@@ -171,6 +229,42 @@ describe('npmAdapter', () => {
171229
expect(runCount).to.equal(1, 'Only yarn install should run with manager options');
172230
});
173231
});
232+
233+
it('uses buildManagerOptions for yarn commands', () => {
234+
writeJSONFile('package.json', fixturePackage);
235+
let runCount = 0;
236+
let stubbedRun = generateMockRun([{
237+
command: 'yarn install --flat',
238+
callback() {
239+
runCount++;
240+
return RSVP.resolve();
241+
},
242+
}], { allowPassthrough: false });
243+
244+
return new NpmAdapter({
245+
cwd: tmpdir,
246+
run: stubbedRun,
247+
useYarnCommand: true,
248+
buildManagerOptions: function() {
249+
return ['--flat'];
250+
},
251+
})._install().then(() => {
252+
expect(runCount).to.equal(1, 'Only yarn install should run with buildManagerOptions');
253+
});
254+
});
255+
256+
it('throws an error if buildManagerOptions does not return an array', () => {
257+
expect(() => {
258+
new NpmAdapter({
259+
cwd: tmpdir,
260+
run: () => {},
261+
useYarnCommand: true,
262+
buildManagerOptions: function() {
263+
return 'string';
264+
},
265+
})._install()
266+
}).to.throw(/buildManagerOptions must return an array of options/);
267+
});
174268
});
175269
});
176270

@@ -185,6 +279,26 @@ describe('npmAdapter', () => {
185279
assertFileContainsJSON(path.join(tmpdir, 'node_modules/prove-it.json'), { originalNodeModules: true });
186280
});
187281
});
282+
283+
it('replaces the yarn.lock, npm-shrinkwrap.json and package-lock.json with the backed up version if they exist', () => {
284+
writeJSONFile('package.json.ember-try', { originalPackageJSON: true });
285+
writeJSONFile('package.json', { originalPackageJSON: false });
286+
fs.mkdirSync('.node_modules.ember-try');
287+
writeJSONFile('.node_modules.ember-try/prove-it.json', { originalNodeModules: true });
288+
writeJSONFile('yarn.lock.ember-try', { originalYarnLock: true });
289+
writeJSONFile('yarn.lock', { originalYarnLock: false });
290+
writeJSONFile('npm-shrinkwrap.json.ember-try', { originalNpmShrinkWrap: true });
291+
writeJSONFile('npm-shrinkwrap.json', { originalNpmShrinkWrap: false });
292+
writeJSONFile('package-lock.json.ember-try', { originalPackageLock: true });
293+
writeJSONFile('package-lock.json', { originalPackageLock: false });
294+
return new NpmAdapter({ cwd: tmpdir })._restoreOriginalDependencies().then(() => {
295+
assertFileContainsJSON(path.join(tmpdir, 'package.json'), { originalPackageJSON: true });
296+
assertFileContainsJSON(path.join(tmpdir, 'node_modules/prove-it.json'), { originalNodeModules: true });
297+
assertFileContainsJSON(path.join(tmpdir, 'yarn.lock'), { originalYarnLock: true });
298+
assertFileContainsJSON(path.join(tmpdir, 'npm-shrinkwrap.json'), { originalNpmShrinkWrap: true });
299+
assertFileContainsJSON(path.join(tmpdir, 'package-lock.json'), { originalPackageLock: true });
300+
});
301+
});
188302
});
189303

190304
describe('#_packageJSONForDependencySet', () => {

0 commit comments

Comments
 (0)