Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Updater module #292

Merged
merged 8 commits into from

2 participants

@sindresorhus
Owner

Fixes #179

This should be done know, but it needs some thorough testing. @addyosmani @paulirish @mklabs and anyone else that could help out.

It was hard testing without actually having a yeoman module in NPM to test against, but I made it work by downgrading one of our dependencies, eg grunt-mocha and then try it against that one, which seems to work.

@mklabs Since you're our code master, would you mind taking a look and let me know if there's anything weird going on?

Testing tips

  • Try changing the version number in updater.getUpdate() to get different types of updates. Current Grunt version is 0.3.14. So you can set it to 0.3.13 to see patch type, 0.4.0 to see minor and 1.0.0 to major.

  • Other things I haven't thought of.

Short explanation

The API is simple. You call updater.getUpdate() each time your module is run and it will handle the rest for you. It will skip the update if the time since last update hasn't passed. updateCheckInterval and updatePromptTimeLimit can be easily overridden if the user want something else. optOut and the last time the update check was run is saved in ~/.config/npm-updater/[packageName].json. To opt out of auto-update you can just switch the false to true.

For testing I've set updateCheckInterval to 10sec and updatePromptTimeLimit to 20sec, so if you we try again before 10sec has passed it will be skipped, then just wait some seconds and try again.

The module comes with a prefilter (updater.shouldUpdate) that you can override to do your own logic on what to do on different update types. Currently we do this, but can easily be changed by the author:

// patch 0.0.x: Forced auto-update with opt-out
// ability. Since it should only contain backwards
// compatible bugfixes.
//
// minor 0.x.0: Update prompts (with auto-update
// after a set time) with ability to opt out of
// auto-update.
//
// major: x.0.0: Update prompts (no time-limit),
// since this can contain backwards incompatible changes.
@sindresorhus sindresorhus referenced this pull request
Closed

Updater #179

@addyosmani
Owner

Request for later: once we land this it would be great to document some of what it does / some of whats in this ticket in the wiki for future internal reference. Doesn't need to be at launch time, can be whenever we have time.

@sindresorhus
Owner

Sure thing

@addyosmani
Owner
  • Performed a code review. So far everything looks solid \o/ (please see comments below)
  • Testing

Notes on user experience/possibly bugs:

  • Once the updater has completed running, what's the expected behavior? If I'm a completely new user and I saw http://cl.ly/image/1047151V0g0o. I wouldn't know whether I should be running init again, restarting the terminal or doing something else. Is this the debug experience or are users expected to run their last command again? Should we automatically try running it for them once the update check is complete?

  • When I fired up init it was clear that yeoman was updating, but I wasn't sure what to expect or how soon I might be able to actually use it. Perhaps we should add a line at the start saying 'Good day, sir or madam. I'm going to run an update check real quick. Shouldn't take a minute!'. (or something)

  • I wonder if we need to be doing more stringent x.y.z testing on version numbers. Please correct me if I've interpreted this stupidly: http://cl.ly/image/0h2l360S3o05 thinks we need a patch update, I think incorrectly. I updated the version number to 0.5.13, which is higher than the current 0.3.14. It appears the updater checked against the last number only (z), not taking into account the others (x and y). In this case it would still update, which is totally fine, but the expected behavior of how often/how it prompts might not be what we want.

  • I might be reading this wrong, but to me (and again, I'm probably being silly) I felt a bit confused reading through:

You have version 0.5.13
Latest version is 0.3.14
Update checks complete
Update available: 0.5.13 (current: 0.3.14)
Updating grunt

It says that I have version 0.5.13 and that 0.3.14 is the latest version. Great. In the update available line however it says current 0.3.14. Does this mean the update available is 0.3.14? If so, why show the 0.5.13 in this context? Would that not confuse the user? I read this as 0.5.13 was available, but 0.3.14 was the update available (which feels weird to say). I'd just show the version available remotely personally.

Please feel free to let me know if I misinterpreted anything. Sure I have somewhere :)

Great work on this otherwise. The refactor looks awesome!

@sindresorhus
Owner

Once the updater has completed running, what's the expected behavior? If I'm a completely new user and I saw http://cl.ly/image/1047151V0g0o. I wouldn't know whether I should be running init again, restarting the terminal or doing something else. Is this the debug experience or are users expected to run their last command again? Should we automatically try running it for them once the update check is complete?

Right now it just exits, but I like the idea of capturing the command and just continuing.

When I fired up init it was clear that yeoman was updating, but I wasn't sure what to expect or how soon I might be able to actually use it. Perhaps we should add a line at the start saying 'Good day, sir or madam. I'm going to run an update check real quick. Shouldn't take a minute!'. (or something)

I'm not sure that's necessary. The update check is superquick and the update process itself is heavily console.log'd and process.pipe'd. Anyone else feel this is necessary? The reason I'm a bit against it is because I would like to keep the updater module fairly generic.

I wonder if we need to be doing more stringent x.y.z testing on version numbers. Please correct me if I've interpreted this stupidly: http://cl.ly/image/0h2l360S3o05 thinks we need a patch update, I think incorrectly. I updated the version number to 0.5.13, which is higher than the current 0.3.14. It appears the updater checked against the last number only (z), not taking into account the others (x and y). In this case it would still update, which is totally fine, but the expected behavior of how often/how it prompts might not be what we want.

That is because you've set the current version to higher than the latest version, which would never happen in a real scenario. Actually the original updater did check the last number first, but that was wrong, since it would return 'patch' on current 0.2.0 and latest 0.3.1, which obviously is 'minor'.

@addyosmani
Owner

Right now it just exits, but I like the idea of capturing the command and just continuing.

is this something you think you'll have time to implement today? :)

@sindresorhus
Owner

@addyosmani Done :)

I just put everything in bin/yeoman into a init() method and execute that after the update check. I had to change some of the semantics. Previously the getUpdate() callback was executed after the update check. It's now executed after the update is complete, which makes more sense, now that the updater handles all the update stuff and console.logging anyway. Thoughts?

We need to look into how to better handle the various error points at a later time.

@addyosmani
Owner

Excellent. Pending some minor further testing we can land this in the morning. Thanks!

@sindresorhus
Owner

@mklabs If you have a chance. Would love your comments on it.

Let me know if you need a look through or testing on the config stuff ;)

@addyosmani
Owner

Testing so far it seems to work fine. @sindresorhus Would you like us to hold off on a review from @mklabs before merging?

@sindresorhus
Owner

Yes

@addyosmani addyosmani merged commit c18d469 into master
@addyosmani
Owner

Just to confirm that @sindresorhus was happy with a merge so its been done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 307 additions and 223 deletions.
  1. +98 −95 cli/bin/yeoman
  2. +209 −128 cli/lib/plugins/updater.js
View
193 cli/bin/yeoman
@@ -1,5 +1,6 @@
#!/usr/bin/env node
var fs = require('fs'),
+ exec = require('child_process').exec,
join = require('path').join,
grunt = require('grunt'),
colors = require('colors'),
@@ -13,125 +14,127 @@ var fs = require('fs'),
async = grunt.util.async,
compiled = _.template( fs.readFileSync( join(__dirname, 'help.txt'), 'utf8' ));
+
// Returns the user's home directory in a platform agnostic way.
function getUserHome() {
return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
}
-// grunt with the plugin registered
-grunt.npmTasks(join(__dirname, '../'));
-
-// Get back a reference to the internal grunt cli object so that we can read
-// command line parsed options from grunt, to run our internal additional
-// logic.
+function init() {
+ // grunt with the plugin registered
+ grunt.npmTasks(join(__dirname, '../'));
-var cli = require('grunt/lib/grunt/cli');
+ // Get back a reference to the internal grunt cli object so that we can read
+ // command line parsed options from grunt, to run our internal additional
+ // logic.
-// avoid the deprecation notice: goo.gl/mk2De
-Object.defineProperty(grunt, 'utils', {
- get: function() {
- return grunt.util;
- }
-});
+ var cli = require('grunt/lib/grunt/cli');
-// command line options and remaining args
-var opts = cli.options,
- cmds = cli.tasks,
- route = cmds.join(' ').trim('');
+ // avoid the deprecation notice: goo.gl/mk2De
+ Object.defineProperty(grunt, 'utils', {
+ get: function() {
+ return grunt.util;
+ }
+ });
-// custom help, on `h5bp help`
-if(/^help/.test(route)) {
- if(/^help$/.test(route)) {
- return console.log( compiled() );
+ // command line options and remaining args
+ var opts = cli.options,
+ cmds = cli.tasks,
+ route = cmds.join(' ').trim('');
+
+ // custom help, on `h5bp help`
+ if(/^help/.test(route)) {
+ if(/^help$/.test(route)) {
+ return console.log( compiled() );
+ }
+ cli.tasks = cmds.join(':');
}
- cli.tasks = cmds.join(':');
-}
-// add the plugin version on `--version`
-if(opts.version) {
- return console.log('%s v%s', pkg.name, pkg.version);
-}
+ // add the plugin version on `--version`
+ if(opts.version) {
+ return console.log('%s v%s', pkg.name, pkg.version);
+ }
-// Matches everything after init to prevent
-// the user from seeing the default grunt init tasks
-if(/^init/.test(route)) {
- // required handling of options / arguments to workaround some internal check
- // of Grunt, and let the generators go through (init and invoked in our front
- // Grunt template)
- yeoman.generators.prepare(grunt);
-}
+ // Matches everything after init to prevent
+ // the user from seeing the default grunt init tasks
+ if(/^init/.test(route)) {
+ // required handling of options / arguments to workaround some internal check
+ // of Grunt, and let the generators go through (init and invoked in our front
+ // Grunt template)
+ yeoman.generators.prepare(grunt);
+ }
-// Inform users to run `server` instead of `watch`
-if ( /^watch/.test( route ) ) {
- return console.log('\nYeoman`s watch task is integrated within `yeoman server` to combine\n\
-the dev server, re-compilation and live reloading of changed assets.\n\n\
-Feel free to run ' + 'yeoman'.bold.red + ' ' + 'server'.bold.yellow + ' instead!');
-}
+ // Inform users to run `server` instead of `watch`
+ if ( /^watch/.test( route ) ) {
+ return console.log('\nYeoman`s watch task is integrated within `yeoman server` to combine\n\
+ the dev server, re-compilation and live reloading of changed assets.\n\n\
+ Feel free to run ' + 'yeoman'.bold.red + ' ' + 'server'.bold.yellow + ' instead!');
+ }
-// a bower command
-// Examples:
-// yeoman install jquery
-// yeoman install spine
-// yeoman install backbone (which does jquery etc too.)
-// yeoman update spine
-// yeoman lookup jquery
-// yeoman search jquery
-if(/^install|^uninstall|^search|^list|^ls|^lookup|^update/.test(route)) {
- cli.tasks = 'bower' + ':' + cmds.join(':');
-}
+ // a bower command
+ // Examples:
+ // yeoman install jquery
+ // yeoman install spine
+ // yeoman install backbone (which does jquery etc too.)
+ // yeoman update spine
+ // yeoman lookup jquery
+ // yeoman search jquery
+ if(/^install|^uninstall|^search|^list|^ls|^lookup|^update/.test(route)) {
+ cli.tasks = 'bower' + ':' + cmds.join(':');
+ }
+ /* Yeoman Insight =========================================================== */
+ async.series([function(cb) {
-/* Yeoman Upgrade =========================================================== */
-if ( /^upgrade/.test( route ) ) {
-
- // Query for the latest update (grunt is used as the pkg.name for debugging
- // purposes only)
- updater.getUpdate({ name: 'grunt', version: pkg.version }, function(update){
- console.log('Update type available is:', colors.yellow(update.severity));
- console.log('You have version', colors.blue(update.localVersion));
- console.log('Latest version is', colors.red(update.latestVersion));
- console.log('To get the latest version run:' + colors.green(' npm update yeoman -g'));
- });
-
- return console.log('Update checks complete.');
-}
+ // Are we dealing with yeoman in a test environment? If so, skip the
+ // insight prompt. This is specifically put into the environment by
+ // our test spawn helper.
+ if(process.env.yeoman_test) {
+ return cb();
+ }
-/* Yeoman Insight =========================================================== */
-async.series([function(cb) {
+ insight.init({
+ pkgname : pkg.name,
+ getUserHome: getUserHome,
+ cmds : cmds,
+ cb : cb
+ });
- // Are we dealing with yeoman in a test environment? If so, skip the
- // insight prompt. This is specifically put into the environment by
- // our test spawn helper.
- if(process.env.yeoman_test) {
- return cb();
- }
+ }, function(cb) {
- insight.init({
- pkgname : pkg.name,
- getUserHome: getUserHome,
- cmds : cmds,
- cb : cb
- });
+ // if the route is empty
+ if(/^$/.test(route)) {
+ // this is specific to an empty route code
+ console.log(pkg.name + ' v%s', pkg.version);
-}, function(cb) {
+ // we return early to prevent grunt from actually running
+ // and instead just output help.txt
+ cb();
+ return console.log( compiled() );
+ }
- // if the route is empty
- if(/^$/.test(route)) {
- // this is specific to an empty route code
- console.log(pkg.name + ' v%s', pkg.version);
+ // the grunt cli
+ grunt.cli();
- // we return early to prevent grunt from actually running
- // and instead just output help.txt
cb();
- return console.log( compiled() );
- }
- // the grunt cli
- grunt.cli();
-
- cb();
-
-}]);
+ }]);
+}
+/* Yeoman Upgrade =========================================================== */
+if ( !process.env.yeoman_test ) {
+ // TODO: Change to this before the release:
+ // updater.getUpdate({ localPackageUrl: '../../package.json' }, function() {
+ // init();
+ //});
+
+ // Query for the latest update (grunt is used as the pkg.name for debugging
+ // purposes only)
+ updater.getUpdate({ name: 'grunt', version: '0.1.13' }, function( update ) {
+ init();
+ });
+} else {
+ init();
+}
View
337 cli/lib/plugins/updater.js
@@ -1,30 +1,19 @@
-
// Updater.js: npm version checker and updater for packages
-// @author: Addy Osmani
+// @author: Addy Osmani and Sindre Sorhus
// @inspired by: npm, npm-latest
//
// Sample usage:
//
// Query for the latest update type
-// updater.getUpdate({ name: 'grunt', version: pkg.version }, function(update){
-//
-// console.log('Update type available is:', colors.yellow(update.severity));
-// console.log('You have version', colors.blue(update.localVersion));
-// console.log('Latest version is', colors.red(update.latestVersion));
-// console.log('To get the latest version run:' + colors.green(' npm update yeoman -g'));
-//
+// updater.getUpdate({ name: 'grunt', version: pkg.version }, function( error, update ) {
+// console.log('Update checking complete');
// });
//
// Alternatively, if you just want to pass in a package.json
// file directly, you can simply do:
//
-// updater.getUpdate({ localPackageUrl: '../package.json'}, function(update){
-//
-// console.log('Update type available is:', colors.yellow(update.severity));
-// console.log('You have version', colors.blue(update.localVersion));
-// console.log('Latest version is', colors.red(update.latestVersion));
-// console.log('To get the latest version run:' + colors.green(' npm update yeoman -g'));
-//
+// updater.getUpdate({ localPackageUrl: '../package.json' }, function( error, update ) {
+// console.log('Update checking complete');
// });
//
// Both will either return patch, minor, major or latest. These
@@ -44,36 +33,120 @@
// latest: you are already up to date
//
-var request = require('request'),
- colors = require('colors'),
- path = require('path'),
- fs = require('fs'),
- util = require('util'),
- EventEmitter = require('events').EventEmitter,
- childProcess = require('child_process');
+var fs = require('fs');
+var path = require('path');
+var util = require('util');
+var exec = require('child_process').exec;
+var EventEmitter = require('events').EventEmitter;
+var request = require('request');
+var colors = require('colors');
+var prompt = require('prompt');
+
+
+var updater = module.exports;
+
+
+var config = (function() {
+ var mkdirp = require('mkdirp');
+ var homeDir = process.env[ ( process.platform == 'win32' ) ? 'USERPROFILE' : 'HOME' ];
+ var folderPath = path.join( homeDir, '.config', 'npm-updater' );
+ // Function, since _packageName is not available when this is init'd
+ var filename = function() {
+ return updater._packageName + '.json';
+ };
+
+ var loadConfig = function() {
+ try {
+ return JSON.parse( fs.readFileSync( path.join( folderPath, filename() ), 'utf-8' ) || {} );
+ } catch ( err ) {
+ // Create dir if it doesn't exist
+ if ( err.errno === 34 ) {
+ mkdirp.sync( folderPath );
+ return {};
+ }
+ }
+ };
+
+ return {
+ get: function( key ) {
+ return loadConfig()[ key ];
+ },
+ set: function( key, val ) {
+ var config = loadConfig();
+ config[ key ] = val;
+ fs.writeFileSync( path.join( folderPath, filename() ), JSON.stringify( config, null, '\t' ) );
+ }
+ };
+})();
+
-updater = module.exports;
// Registry end-point
// Alternative registry mirrors
// http://85.10.209.91/%s
// http://165.225.128.50:8000/%s
-updater.registryUrl = "http://registry.npmjs.org/%s";
+updater.registryUrl = 'http://registry.npmjs.org/%s';
+
+// How often the updater should check for updates
+//updater.updateCheckInterval = 1000 * 60 * 60 * 24; // 1 day
+
+// How long it should wait until force auto-update
+//updater.updatePromptTimeLimit = 1000 * 60 * 60 * 24 * 7; // 1 week
+
+// TODO: Remove before release and uncomment aboves. Only for testing.
+updater.updateCheckInterval = 10000; // 10 sec
+updater.updatePromptTimeLimit = 20000; // 20 sec
-updater.npmParseLatest = function npmParseLatest(npmObj) {
- var versions = [];
- for (var version in npmObj.time) {
- versions.push(version);
+
+// Prompt for update
+updater.promptUpdate = function promptUpdate( cb ) {
+ prompt.start();
+ prompt.message = 'yeoman'.red;
+ prompt.get([{
+ name: 'shouldUpdate',
+ message: ( 'Do you want to upgrade ' + this._packageName + '?' ).yellow
+ }], function( err, result ) {
+ cb( !err && /^y/i.test( result.shouldUpdate ) );
+ });
+};
+
+
+// TODO(sindresorhus): Docs
+// Prefilter to be overriden if custom logic is needed
+updater.shouldUpdate = function shouldUpdate( update, cb ) {
+ var severity = update.severity;
+
+ console.log('Update available: ' + update.current.green +
+ (' (current: ' + update.latest + ')').grey );
+
+ if ( config.get('optOut') === true ) {
+ console.log('You have opted out of automatic updates');
+ console.log('Run `npm update -g yeoman` to update');
+ return cb( false );
+ }
+
+ if ( severity === 'patch' ) {
+ cb( true );
+ }
+
+ if ( severity === 'minor' ) {
+ // Force auto-update if it's past the set time limit
+ if ( new Date() - new Date( update.date ) > this.updatePromptTimeLimit ) {
+ console.log( 'Forcing update because it\'s been too long since last'.red );
+ return cb( true );
}
- var lastVersion = versions[versions.length - 1];
- var lastTime = npmObj.time[lastVersion];
+ this.promptUpdate(function( shouldUpdate ) {
+ cb( shouldUpdate );
+ });
+ }
- return {
- "version": lastVersion,
- "time": new Date(lastTime)
- };
+ if ( severity === 'major' ) {
+ this.promptUpdate(function( shouldUpdate ) {
+ cb( shouldUpdate );
+ });
+ }
};
@@ -90,87 +163,109 @@ updater.npmParseLatest = function npmParseLatest(npmObj) {
// @options.localPackageUrl: the url to a local package to be
// checked against if no package name or version are supplied
//
-// @options.fetchLatest: a boolean to indicate whether you
-// should also fetch the latest version at the same time
-//
-// cb: callback for successfully returning the
-// update type
+// cb: callback for when the update checks and update is complete
-updater.getUpdate = function getUpdate(options, cb){
+updater.getUpdate = function getUpdate( options, cb ) {
+ var localPackage, url;
+ var self = this;
+ var controller = new EventEmitter();
- var self = this, url, latest, updateType, update, controller;
- cb = cb || function(){};
-
- controller = new EventEmitter();
+ cb = cb || function() {};
// Step 1: We need a package name and version to work off.
// Ideally, supply us with the package name and version
- if(options.name === undefined || options.version === undefined){
+ if ( options.name === undefined || options.version === undefined ) {
+ // If not, we'll ascertain from a local package.json file
+ if ( options.localPackageUrl ) {
+ localPackage = require( options.localPackageUrl );
+ options.name = localPackage.name;
+ options.version = localPackage.version;
+ } else {
+ return console.error('No package name/version or local package supplied');
+ }
+ }
- // If not, we'll ascertain from a local package.json file
- if(options.localPackageUrl){
+ // Expose the packageName internally, but still
+ // make it accessible if somone would need it
+ this._packageName = options.name;
- var localPackage = JSON.parse(fs.readFileSync(options.localPackageUrl).toString());
- options.name = localPackage.name;
- options.version = localPackage.version;
+ // Create the `optOut` option, so it's easy to switch the flag
+ if ( config.get('optOut') === undefined ) {
+ config.set( 'optOut', false );
+ }
- }else{
- console.error('No package name/version or local package supplied');
- }
+ // Only check for updates on a set interval
+ if ( new Date() - config.get('lastUpdateCheck') < this.updateCheckInterval ) {
+ return;
}
- // Step 2: Query the NPM registry for the latest package
- url = util.format(this.registryUrl, options.name);
+ console.log('Starting update check...');
- request(url, function(err, response, body) {
+ // Update the last update check date
+ config.set( 'lastUpdateCheck', +new Date() );
- // Fetch issue incurred
- if (err) {
+ // Step 2: Query the NPM registry for the latest package
+ url = util.format( this.registryUrl, options.name );
- controller.emit("fetchError", {
- message: err.message,
- httpCode: response.statusCode
- });
+ request({ url: url, json: true }, function( error, response, body ) {
+ var latest, update;
- return;
+ // TODO(sindresorhus): Look into the best way to output errors, only cb or cb + emit?
- } else {
- var npmObj = JSON.parse(body);
+ // Fetch issue incurred
+ if ( error ) {
+ controller.emit('fetchError', {
+ message: error.message,
+ httpCode: response && response.statusCode
+ });
- // Whoops, package not found.
- if (npmObj.error) {
+ cb( error );
- controller.emit("npmError", {
- errType: npmObj.error, // not_found etc
- reason: npmObj.reason // additional reason
- });
+ return;
+ }
- return;
+ // Whoops, package not found
+ if ( body.error ) {
+ controller.emit('npmError', {
+ errorType: body.error, // not_found etc
+ reason: body.reason // additional reason
+ });
- } else {
+ cb( error );
- // Step 3: Package found, lets compare versions
- latest = self.npmParseLatest(npmObj);
- updateType = self.parseUpdateType(options.version, latest.version);
+ return;
+ }
- // Details to expose about the update
- update = {
- latestVersion: latest.version,
- localVersion: options.version,
- severity: updateType
- };
+ // Step 3: Package found, lets compare versions
+ latest = Object.keys( body.time ).reverse()[0];
- // Possibly deprecate: fetch latest
- if(updateType !== 'latest' && options.fetchLatest === true){
- self.npmRunUpdate(options.name);
- };
+ // Details to expose about the update
+ update = {
+ latest: latest,
+ date: body.time[ latest ],
+ current: options.version,
+ severity: self.parseUpdateType( options.version, latest )
+ };
- return cb(update);
+ if ( update.severity !== 'latest' ) {
+ self.shouldUpdate( update, function( shouldUpdate ) {
+ if ( shouldUpdate ) {
+ self.updatePackage( options.name, function( err, data ) {
+ if ( err ) {
+ console.error( '\nUpdate error', err );
+ } else {
+ console.log( '\nUpdated successfully!'.green );
}
- }
- });
+ cb( err, update );
+ });
+ } else {
+ cb( err, update );
+ }
+ });
+ }
+ });
};
@@ -178,46 +273,32 @@ updater.getUpdate = function getUpdate(options, cb){
// Compare a local package version and remote package version
// to discover what type of update (major, minor, patch) is
// available.
-updater.parseUpdateType = function parseUpdateType(currentVersion, remoteVersion){
-
- // already on latest?
- if( currentVersion === remoteVersion ){
- return 'latest';
- }else{
-
- // Regex against versions for comparison
- var current = currentVersion.split('.'),
- remote = remoteVersion.split('.');
-
- // major update?
- if( remote[2] > current[2] ){
- return 'major';
- // minor update?
- }else if( remote[1] > current[1] ){
- return 'minor';
- // patch?
- }else if( remote[0] > current[0] ){
- return 'patch';
- }else{
- return "Comparison error.";
- }
- }
-
-};
-
-
-// Run npm update against a specific package name
-updater.npmRunUpdate = function npmRunUpdate(packageName){
+updater.parseUpdateType = function parseUpdateType( current, remoteVersion ) {
+ var current, remote;
- var child = exec('npm update ' + packageName, function() {
- // complete
- });
-
- child.stdout.pipe(process.stdout);
- child.stderr.pipe(process.stderr);
+ if ( current === remoteVersion ) {
+ return 'latest';
+ }
+ current = current.split('.');
+ remote = remoteVersion.split('.');
+
+ if ( remote[0] > current[0] ) {
+ return 'major';
+ } else if ( remote[1] > current[1] ) {
+ return 'minor';
+ } else if ( remote[2] > current[2] ) {
+ return 'patch';
+ } else{
+ return 'Update comparison error';
+ }
};
-
-
+// Run `npm update` against a specific package name
+updater.updatePackage = function updatePackage( packageName, cb ) {
+ var child = exec( 'npm update ' + packageName, { cwd: __dirname }, cb );
+ console.log( 'Updating ' + packageName + '\n' );
+ child.stdout.pipe( process.stdout );
+ child.stderr.pipe( process.stderr );
+};
Something went wrong with that request. Please try again.