Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,30 @@ Your application just need to configurer `Update.exe` or `Squirrel.Windows` to u

You'll just need to upload as release assets: `RELEASES`, `*-delta.nupkg` and `-full.nupkg` (files generated by `Squirrel.Windows` releaser).

##### Channel Updates

Nuts lets you manage updates for non-stable release channels.

By default Nuts will only look for newer versions related to the same primary version as the current version which on the same or higher precedence channel. (Nuts uses the [node-semver module](https://github.com/npm/node-semver) to compare version tags.)

```
// Given versions 1.2.3-alpha.1, 1.2.3-beta.1
GET http://download.myapp.com/update/osx/1.2.3-alpha.1
// Returns download info for 1.2.3-beta.1

// Given versions 1.2.3-alpha.1, 1.2.3-beta.1, 1.2.3, 1.2.4-alpha.1
GET http://download.mayapp.com/update/osx/1.2.3-alpha.1
// Returns download info for 1.2.3
```

You can override this behavior and tell Nuts to check updates only on a given channel regardless of which primary version they are related to by appending a channel query parameter after the update URL.

```
// Given versions 1.2.3-alpha.1, 1.2.3-beta.1, 1.2.3, 1.2.4-alpha.1
GET http://download.mayapp.com/update/osx/1.2.3-alpha.1?channel=alpha
// Returns download info for 1.2.4-alpha.1
```

#### ChangeLog

Nuts provides a `/notes` endpoint that output release notes as text or json.
Expand Down
25 changes: 13 additions & 12 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ module.exports = function nuts(opts) {
router.get('/update/:platform/:version', function(req, res, next) {
var platform = req.params.platform;
var tag = req.params.version;
var channel = req.query.channel;

Q()
.then(function() {
Expand All @@ -169,10 +170,10 @@ module.exports = function nuts(opts) {

platform = platforms.detect(platform);

return versions.filter({
tag: '>='+tag,
return versions.newer({
tag: tag,
platform: platform,
channel: '*'
channel: channel
});
})
.then(function(versions) {
Expand All @@ -182,7 +183,7 @@ module.exports = function nuts(opts) {
var releaseNotes = notes.merge(versions.slice(0, -1), { includeTag: false });

res.status(200).send({
"url": getBaseDownloadUrl(req) + '/version/' + latest.tag + '/' + platform + '?filetype=zip',
"url": getBaseDownloadUrl(req) + '/version/' + latest.tag + '/' + platform + '?filetype=zip',
"name": latest.tag,
"notes": releaseNotes,
"pub_date": latest.published_at.toISOString()
Expand All @@ -196,15 +197,16 @@ module.exports = function nuts(opts) {
router.get('/update/:platform/:version/RELEASES', function(req, res, next) {
var platform = 'win_32';
var tag = req.params.version;
var channel = req.query.channel;

Q()
.then(function() {
platform = platforms.detect(platform);

return versions.filter({
tag: '>='+tag,
return versions.newer({
tag: tag,
platform: platform,
channel: '*'
channel: channel
});
})
.then(function(versions) {
Expand Down Expand Up @@ -249,9 +251,8 @@ module.exports = function nuts(opts) {

Q()
.then(function() {
return versions.filter({
tag: tag? '>='+tag : '*',
channel: '*'
return versions.select({
tag: tag
});
})
.then(function(versions) {
Expand Down Expand Up @@ -301,9 +302,9 @@ module.exports = function nuts(opts) {

// List versions
router.get('/api/versions', function (req, res, next) {
versions.filter({
versions.select({
platform: req.query.platform,
channel: req.query.channel || '*'
channel: req.query.channel
})
.then(function(results) {
res.send(results);
Expand Down
75 changes: 57 additions & 18 deletions lib/versions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,43 @@ var semver = require('semver');

var platforms = require('./platforms');

// Creates filter function that checks for updates
function newVersionFilter(opts) {
return function(version) {
// Not available for requested paltform
if (!supportsPlatform(opts.platform, version.platforms)) return false;

// If the caller specifies a channel then stay on that channel. Otherwise
// look for anything closer to the main release.
if (opts.channel) {
return (opts.channel === version.channel &&
semver.rcompare(version.tag, opts.tag) < 0);
} else {
return semver.satisfies(version.tag, '>' + opts.tag);
}
}
}

// Creates generic filter function for all versions
function allVersionFilter(opts) {
return function(version) {
return ((!opts.tag || opts.tag === version.tag) &&
matchingChannel(opts.channel, version.channel) &&
supportsPlatform(opts.platform, version.platforms));
}
}

function matchingChannel(requestedChannel, versionChannel) {
return (!requestedChannel ||
requestedChannel === '*' ||
versionChannel === requestedChannel);
}

function supportsPlatform(requestedPlatform, versionPlatforms) {
return (!requestedPlatform ||
platforms.satisfies(requestedPlatform, _.pluck(versionPlatforms, 'type')));
}

module.exports = function(github, opts) {
// Normalize tag name
function normalizeTag(tag) {
Expand Down Expand Up @@ -83,35 +120,36 @@ module.exports = function(github, opts) {
});
}

// Get new versions for updates
function getNewVersions(opts) {
return filterVersions(opts, newVersionFilter)
}

// Get all versions, subject to any options passed in
function getMatchingVersions(opts) {
return filterVersions(opts, allVersionFilter)
}

// Filter versions
function filterVersions(opts) {
opts = _.defaults(opts || {}, {
tag: 'latest',
platform: null,
channel: 'stable'
});
function filterVersions(opts, filterBuilder) {
opts = opts || {};
if (opts.platform) opts.platform = platforms.detect(opts.platform);

return listVersions()
.then(function(versions) {
return _.chain(versions)
.filter(function(version) {
// Check channel
if (opts.channel != '*' && version.channel != opts.channel) return false;

// Not available for requested paltform
if (opts.platform && !platforms.satisfies(opts.platform, _.pluck(version.platforms, 'type'))) return false;

// Check tag satisfies request version
return opts.tag == 'latest' || semver.satisfies(version.tag, opts.tag);
})
.filter(filterBuilder(opts))
.value();
});
}

// Resolve a platform
function resolveVersion(opts) {
return filterVersions(opts)
opts = opts || {}
opts.channel = opts.channel || 'stable';
if (opts.tag === 'latest') opts.tag = null;

return filterVersions(opts, allVersionFilter)
.then(function(versions) {
var version = _.first(versions);
if (!version) throw new Error('Version not found: '+opts.tag);
Expand Down Expand Up @@ -155,7 +193,8 @@ module.exports = function(github, opts) {
return {
list: listVersions,
get: getVersion,
filter: filterVersions,
newer: getNewVersions,
select: getMatchingVersions,
resolve: resolveVersion,
channels: listChannels
};
Expand Down
89 changes: 45 additions & 44 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,47 +1,48 @@
{
"name": "nuts-serve",
"version": "2.6.2",
"description": "Server to make GitHub releases (private) available to download with Squirrel support",
"main": "./lib/index.js",
"homepage": "https://github.com/GitbookIO/nuts",
"license": "Apache-2.0",
"main": "./lib/index.js",
"dependencies": {
"express": "^4.13.3",
"lodash": "3.7.0",
"q": "1.2.0",
"body-parser": "1.12.3",
"octonode": "0.7.1",
"semver": "5.0.1",
"request": "2.60.0",
"basic-auth": "1.0.3",
"express-useragent": "0.1.9",
"stores": "0.0.2",
"analytics-node": "1.2.2",
"uuid": "2.0.1",
"github-webhook-handler": "0.5.0",
"strip-bom": "2.0.0",
"destroy": "1.0.3"
},
"devDependencies": {
"mocha": "1.18.2",
"should": "7.0.4"
},
"bugs": {
"url": "https://github.com/GitbookIO/nuts/issues"
},
"authors": [
{
"name": "Samy Pesse",
"email": "samypesse@gmail.com"
}
],
"repository": {
"type" : "git",
"url" : "https://github.com/GitbookIO/nuts.git"
},
"scripts": {
"start": "node bin/web.js",
"test": "mocha --reporter list"
"name": "nuts-serve",
"version": "2.6.2",
"description": "Server to make GitHub releases (private) available to download with Squirrel support",
"main": "./lib/index.js",
"homepage": "https://github.com/GitbookIO/nuts",
"license": "Apache-2.0",
"dependencies": {
"analytics-node": "1.2.2",
"basic-auth": "1.0.3",
"body-parser": "1.12.3",
"destroy": "1.0.3",
"express": "^4.13.3",
"express-useragent": "0.1.9",
"github-webhook-handler": "0.5.0",
"lodash": "3.7.0",
"octonode": "0.7.1",
"q": "1.2.0",
"request": "2.60.0",
"semver": "5.0.1",
"stores": "0.0.2",
"strip-bom": "2.0.0",
"uuid": "2.0.1"
},
"devDependencies": {
"mocha": "1.18.2",
"mockery": "^1.4.0",
"rewire": "^2.5.1",
"should": "7.0.4"
},
"bugs": {
"url": "https://github.com/GitbookIO/nuts/issues"
},
"authors": [
{
"name": "Samy Pesse",
"email": "samypesse@gmail.com"
}
],
"repository": {
"type": "git",
"url": "https://github.com/GitbookIO/nuts.git"
},
"scripts": {
"start": "node bin/web.js",
"test": "mocha --reporter list"
}
}
Loading