UNPKG

11.5 kBJavaScriptView Raw
1var la = require('lazy-ass');
2var check = require('check-more-types');
3var verify = check.verify;
4var q = require('q');
5var _ = require('lodash');
6var semver = require('semver');
7var quote = require('quote');
8var installModule = require('./module-install');
9var reportSuccess = require('./report').reportSuccess;
10var reportFailure = require('./report').reportFailure;
11var stats = require('./stats');
12
13var cleanVersions = require('./registry').cleanVersions;
14check.verify.fn(cleanVersions, 'cleanVersions should be a function');
15
16var revertModules = require('./revert');
17check.verify.fn(revertModules, 'revert is not a function, but ' +
18 JSON.stringify(revertModules));
19
20var npmTest = require('./npm-test').test;
21var execTest = require('./exec-test');
22var report = require('./report-available');
23var filterAllowed = require('./filter-allowed-updates');
24
25// expect array of objects, each {name, versions (Array) }
26// returns promise
27function testModulesVersions(options, available) {
28 verify.object(options, 'missing options');
29 verify.array(available, 'expected array of available modules');
30
31 var cleaned = cleanVersions(options.modules);
32 // console.log('cleaned', cleaned);
33 // var listed = _.zipObject(cleaned);
34 var names = _.pluck(cleaned, 'name');
35 var listed = _.zipObject(names, cleaned);
36
37 /*
38 console.log('testing module versions');
39 console.log('current versions', listed);
40 console.log('options', options);
41 console.log('available', available);
42 */
43
44 var allowed = filterAllowed(listed, available, options);
45 la(check.array(allowed), 'could not filter allowed updates', listed, available, options);
46
47 if (available.length && !allowed.length) {
48 console.log('No updates allowed using option', quote(options.allow || options.allowed));
49 console.log(available.length + ' available updates filtered');
50 return q(listed);
51 }
52
53 // console.log('allowed', allowed);
54 return q.when(report(allowed, listed, options))
55 .then(function testInstalls() {
56 // console.log('testing installs');
57 if (options.all) {
58 var install = installAll(allowed, options);
59 console.assert(install, 'could not get install all promise');
60 var test = testPromise(options, options.command);
61 console.assert(test, 'could not get test promise for command', options.command);
62 // console.dir(listed);
63 // console.dir(options.modules);
64
65 var installThenTest = install.then(test);
66 if (options.keep) {
67 return installThenTest;
68 }
69
70 var revert = revertModules.bind(null, listed);
71 console.assert(revert, 'could not get revert promise');
72 return installThenTest.then(revert);
73 }
74
75 return installEachTestRevert(listed, allowed,
76 options.command, options.color, options.keep, options.tldr);
77 });
78}
79
80// returns promise, does not revert
81function installAll(available, options) {
82 verify.array(available, 'expected array');
83
84 var installFunctions = available.map(function (nameVersions) {
85 var name = nameVersions.name;
86 var version = nameVersions.versions[0];
87 verify.string(name, 'missing module name from ' +
88 JSON.stringify(nameVersions));
89 verify.string(version, 'missing module version from ' +
90 JSON.stringify(nameVersions));
91
92 var installOptions = {
93 name: name,
94 version: version,
95 keep: keep,
96 tldr: tldr
97 };
98 var installFunction = installModule.bind(null, installOptions);
99 return installFunction;
100 });
101 var installAllPromise = installFunctions.reduce(q.when, q());
102 return installAllPromise;
103}
104
105function installEachTestRevert(listed, available, command, color, keep, tldr) {
106 verify.object(listed, 'expected listed object');
107 verify.array(available, 'expected array');
108
109 var checkModulesFunctions = available.map(function (nameVersion) {
110 var name = nameVersion.name;
111 var currentVersion = listed[name].version;
112 la(check.string(currentVersion), 'cannot find current version for', name,
113 'among current dependencies', listed);
114
115 var installOptions = {
116 name: name,
117 version: currentVersion,
118 keep: keep,
119 tldr: tldr
120 };
121 var revertFunction = installModule.bind(null, installOptions);
122
123 var checkModuleFunction = testModuleVersions.bind(null, {
124 moduleVersions: nameVersion,
125 revertFunction: revertFunction,
126 command: command,
127 color: color,
128 currentVersion: currentVersion,
129 keep: keep,
130 tldr: tldr
131 });
132 return checkModuleFunction;
133 });
134 var checkAllPromise = checkModulesFunctions.reduce(q.when, q());
135 return checkAllPromise;
136}
137
138// test particular dependency with multiple versions
139// returns promise
140function testModuleVersions(options, results) {
141 verify.object(options, 'missing options');
142 var nameVersions = options.moduleVersions;
143 var restoreVersionFunc = options.revertFunction;
144
145 var name = nameVersions.name;
146 var versions = nameVersions.versions;
147 verify.string(name, 'expected name string');
148 verify.array(versions, 'expected versions array');
149 results = results || [];
150 verify.array(results, 'expected results array');
151 if (!semver.valid(options.currentVersion)) {
152 throw new Error('do not have current version for ' + name);
153 }
154
155 var deferred = q.defer();
156 var checkPromises = versions.map(function (version) {
157 return testModuleVersion.bind(null, {
158 name: name,
159 version: version,
160 command: options.command,
161 color: options.color,
162 currentVersion: options.currentVersion,
163 tldr: options.tldr
164 });
165 });
166 var checkAllPromise = checkPromises.reduce(q.when, q());
167 if (options.keep) {
168 checkAllPromise = checkAllPromise.then(function (result) {
169 verify.array(result, 'expected array of results', result);
170 var lastSuccess = _.last(_.filter(result, { works: true }));
171 if (lastSuccess) {
172 console.log('keeping last working version', lastSuccess.name + '@' + lastSuccess.version);
173 return installModule({
174 name: lastSuccess.name,
175 version: lastSuccess.version,
176 keep: true,
177 tldr: options.tldr
178 }, result);
179 } else {
180 return restoreVersionFunc().then(function () {
181 // console.log('returning result after reverting', result);
182 return q(result);
183 });
184 }
185 });
186 } else {
187 checkAllPromise = checkAllPromise
188 .then(restoreVersionFunc);
189 }
190 checkAllPromise
191 .then(function (result) {
192 check.verify.array(result, 'could not get result array');
193 results.push(result);
194 deferred.resolve(results);
195 }, function (error) {
196 console.error('could not check', nameVersions, error);
197 deferred.reject(error);
198 });
199
200 return deferred.promise;
201}
202
203var logLine = (function formLine() {
204 var n = process.stdout.isTTY ? process.stdout.columns : 40;
205 verify.positiveNumber(n, 'expected to get terminal width, got ' + n);
206 var k;
207 var str = '';
208 for(k = 0; k < n; k += 1) {
209 str += '-'
210 }
211 return function () {
212 console.log(str);
213 };
214}());
215
216// checks specific module@version
217// returns promise
218function testModuleVersion(options, results) {
219 verify.object(options, 'missing test module options');
220 verify.string(options.name, 'missing module name');
221 verify.string(options.version, 'missing version string');
222 verify.unemptyString(options.currentVersion, 'missing current version');
223
224 if (options.command) {
225 verify.string(options.command, 'expected command string');
226 }
227 // console.log('options', options);
228
229 results = results || [];
230 verify.array(results, 'missing previous results array');
231
232 var nameVersion = options.name + '@' + options.version;
233
234 if (!options.tldr) {
235 console.log('\ntesting', nameVersion);
236 }
237
238 var result = {
239 name: options.name,
240 version: options.version,
241 from: options.currentVersion,
242 works: true
243 };
244
245 var test = testPromise(options, options.command);
246 console.assert(test, 'could not get test promise for command', options.command);
247
248 var deferred = q.defer();
249
250 var getSuccess = stats.getSuccessStats({
251 name: options.name,
252 from: options.currentVersion,
253 to: options.version
254 });
255
256 getSuccess
257 .then(stats.printStats.bind(null, options), function () {
258 console.log('could not get update stats', options.name);
259 return;
260 })
261 .then(function () {
262 return installModule({
263 name: options.name,
264 version: options.version,
265 keep: false,
266 tldr: options.tldr
267 });
268 })
269 .then(test)
270 .then(function () {
271 reportSuccess(nameVersion + ' works', options.color);
272
273 stats.sendUpdateResult({
274 name: options.name,
275 from: options.currentVersion,
276 to: options.version,
277 success: true
278 });
279 results.push(result);
280 deferred.resolve(results);
281 }, function (error) {
282 reportFailure(nameVersion + ' tests failed :(', options.color);
283
284 stats.sendUpdateResult({
285 name: options.name,
286 from: options.currentVersion,
287 to: options.version,
288 success: false
289 });
290
291 verify.number(error.code, 'expected code in error ' +
292 JSON.stringify(error, null, 2));
293
294 var horizontalLine = options.tldr ? _.noop : logLine;
295
296 horizontalLine();
297 if (!options.tldr) {
298 console.error('test finished with exit code', error.code);
299 verify.string(error.errors, 'expected errors string in error ' +
300 JSON.stringify(error, null, 2));
301 console.error(error.errors);
302 }
303
304 horizontalLine();
305
306 result.works = false;
307 results.push(result);
308 deferred.resolve(results);
309 });
310 return deferred.promise;
311}
312
313function testPromise(options, command) {
314 var testFunction = npmTest.bind(null, options);
315 if (command) {
316 verify.unemptyString(command, 'expected string command, not ' + command);
317 testFunction = execTest.bind(null, options, command);
318 }
319 return testFunction;
320}
321
322module.exports = {
323 testModulesVersions: testModulesVersions,
324 testModuleVersion: testModuleVersion,
325 testPromise: testPromise
326};