UNPKG

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