Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Dec 8, 2012
0 parents commit 7b7c83a
Show file tree
Hide file tree
Showing 11 changed files with 344 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# editorconfig.org
root = true

[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto
21 changes: 21 additions & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"node": true,
"es5": true,
"esnext": true,
"bitwise": true,
"camelcase": true,
"curly": true,
"eqeqeq": true,
"immed": true,
"indent": 4,
"latedef": true,
"newcap": true,
"noarg": true,
"quotmark": "single",
"regexp": true,
"undef": true,
"unused": true,
"strict": true,
"trailing": true,
"smarttabs": true
}
7 changes: 7 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.npmignore
.editorconfig
.jshintrc
.gitattributes
test
.travis.yml
screenshot.png
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
language: node_js
node_js:
- 0.8
1 change: 1 addition & 0 deletions contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
See the [contributing docs](https://github.com/yeoman/yeoman/blob/master/contributing.md)
108 changes: 108 additions & 0 deletions lib/update-notifier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
'use strict';
var util = require('util');
var path = require('path');
var Configstore = require('configstore');
var request = require('request');
var colors = require('colors');


function UpdateNotifier(options) {
options = options || {};

if (!options.packageName && !options.packageVersion) {
this.packageFile = require(path.resolve(path.dirname(module.parent.filename), options.packagePath || 'package'));
}

this.packageName = options.packageName || this.packageFile.name;
this.packageVersion = options.packageVersion || this.packageFile.version;
this.updateCheckInterval = options.updateCheckInterval || 1000 * 60 * 60 * 24; // 1 day
this.registryUrl = options.registryUrl || 'http://registry.npmjs.org/%s';
this.config = new Configstore('update-notifier-' + this.packageName, {
optOut: false
});
}

UpdateNotifier.prototype.check = function() {
if (this.config.get('optOut')) {
return;
}

// Only check for updates on a set interval
if (new Date() - this.config.get('lastUpdateCheck') < this.updateCheckInterval) {
return;
}

this.config.set('lastUpdateCheck', +new Date());
this.update = this.config.get('update');
this.config.del('update');

this.checkNpm(function(update) {
if (update.type && update.type !== 'latest') {
this.config.set('update', update);
}
}.bind(this));
};

UpdateNotifier.prototype.checkNpm = function(cb) {
var url = util.format(this.registryUrl, this.packageName);

request({url: url, json: true}, function(error, response, body) {
var currentVersion, latestVersion;

if (body.error) {
error = 'Package not found';
}

currentVersion = this.packageVersion;
latestVersion = Object.keys(body.time).reverse()[0];

cb({
latest: latestVersion,
current: currentVersion,
type: this.updateType(currentVersion, latestVersion),
date: body.time[latestVersion],
name: this.packageName,
error: error
});
}.bind(this));
};

UpdateNotifier.prototype.notify = function(customMessage) {
var message =
'-----------------------------------------'.blue.bold +
'\nUpdate available: ' + this.update.latest.green.bold +
(' (current: ' + this.update.current + ')').grey +
'\nRun ' + ('npm update -g ' + this.packageName).magenta +
' to update\n' +
'-----------------------------------------'.blue;
if (customMessage) {
process.on('exit', function() {
console.log(typeof customMessage === 'string' ? customMessage : message);
});
} else {
console.log(message);
}
};

UpdateNotifier.prototype.updateType = function(currentVersion, latestVersion) {
if (currentVersion === latestVersion) {
return 'latest';
}

currentVersion = currentVersion.split('.');
latestVersion = latestVersion.split('.');

if (latestVersion[0] > currentVersion[0]) {
return 'major';
} else if (latestVersion[1] > currentVersion[1]) {
return 'minor';
} else if (latestVersion[2] > currentVersion[2]) {
return 'patch';
}
};

module.exports = function(options) {
var updateNotifier = new UpdateNotifier(options);
updateNotifier.check();
return updateNotifier;
};
42 changes: 42 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "update-notifier",
"version": "0.1.0",
"description": "Update notifier for your package",
"keywords": [
"npm",
"update",
"notify",
"check"
],
"homepage": "https://github.com/yeoman/update-notifier",
"bugs": "https://github.com/yeoman/update-notifier/issues",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "http://sindresorhus.com"
},
"main": "lib/update-notifier.js",
"repository": {
"type": "git",
"url": "git://github.com/yeoman/update-notifier.git"
},
"scripts": {
"test": "node node_modules/mocha/bin/mocha --timeout 20000 test/test-*.js"
},
"dependencies": {
"colors": "~0.6.0-1",
"request": "~2.12.0",
"configstore": "~0.1.0"
},
"devDependencies": {
"mocha": "~1.7.3"
},
"engines": {
"node": ">=0.8.0"
},
"licenses": [
{
"type": "BSD"
}
]
}
127 changes: 127 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# update-notifier [![Build Status](https://secure.travis-ci.org/yeoman/update-notifier.png?branch=master)](http://travis-ci.org/yeoman/update-notifier)

##### Update notifier for your Node.js NPM package

![screenshot](https://raw.github.com/yeoman/update-notifier/master/screenshot.png)

Inform users of your package about updates in a non-intrusive way. Mainly targets global CLI apps.

Whenever you initiate the update notifier and it's not inside the interval threshold it will asynchronously check with NPM if there's an available update and then persist the result. The next time the notifier is initiated the result will be loaded into the `.update` property. It shouldn't have any impact on your package startup performance.


## Example usage

```js
var updateNotifier = require('update-notifier');

// Checks for available update and returns an instance
var notifier = updateNotifier();

if (notifier.update) {
// Notify using the built-in convenience method
notifier.notify();
}

// `notifier.update` contains some useful info about the update
console.log(notifier.update);
/*
{
latest: '0.9.5',
current: '0.9.3',
type: 'patch', // possible values: latest, major, minor, patch
date: '2012-11-05T14:32:37.603Z',
name: 'yeoman',
error: null // contains any encountered error
}
*/
```

## Example with settings and custom message

```js
var notifier = updateNotifier({
updateCheckInterval: 1000 * 60 * 60 * 24 * 7 // 1 week
});

if (notifier.update) {
notifier.notify('Update available: ' + notifier.update.latest);
}
```


## Documentation


### updateNotifier([settings])

Checks if there are is an available update. Accepts some settings defined below. Returns an object with some update info if there is an available update, otherwise `undefined`.

### updateNotifier.notify([message || defer])

A convenience method that will inform the user about an available update, see screenshot. By default it will display the message right away. However if you supply a custom message or `true` it will be displayed right before the process exits.


### Settings


#### packagePath

Type: `string`
Default: `'package.json'`

Relative path to your module `package.json`.


#### packageName

Type: `string`
Default: Inferred from `packageFile`

Used instead of inferring it from `packageFile`.
Requires you to also specify `packageVersion`.


#### packageVersion

Type: `string`
Default: Inferred from `packageFile`

Used instead of inferring it from `packageFile`.
Requires you to also specify `packageName`.


#### updateCheckInterval

Type: `number`
Default: `1000 * 60 * 60 * 24` (1 day)

How often it should check for updates.


#### registryVersion

Type: `string`
Default: `'http://registry.npmjs.org/%s'`

Alternative registry mirrors:

- `http://85.10.209.91/%s`
- `http://165.225.128.50:8000/%s`


### User settings

Users of your module has the ability to opt-out of the update notifier by changing the `optOut` property to `true` in `~/.config/configstore/update-notifier-[your-module-name].yml`. The path is available in `notifier.config.path`.

You could also let the user opt-out on a per run basis:

```js
if (process.argv.indexOf('--no-update-notifier') === -1) {
// run updateNotifier()
}
```


## License

[BSD license](http://opensource.org/licenses/bsd-license.php) and copyright Google
Binary file added screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions test/test-update-notifier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*global describe, it, afterEach */
'use strict';
var assert = require('assert');
var fs = require('fs');
var updateNotifier = require('../lib/update-notifier');

describe('updateNotifier', function() {
var settings = {
packageName: 'yeoman',
packageVersion: '0.9.3'
};

var configstorePath = updateNotifier(settings).config.path;

afterEach(function() {
fs.unlinkSync(configstorePath);
});

it('should check for update', function(cb) {
updateNotifier(settings).checkNpm(function(update) {
assert.equal(update.current, '0.9.3');
cb();
});
});
});

0 comments on commit 7b7c83a

Please sign in to comment.