Skip to content

Commit

Permalink
Allow channel updates across releases.
Browse files Browse the repository at this point in the history
  • Loading branch information
skewart committed Dec 31, 2015
1 parent 5ea6604 commit d4decce
Show file tree
Hide file tree
Showing 5 changed files with 336 additions and 74 deletions.
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": "[email protected]"
}
],
"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": "[email protected]"
}
],
"repository": {
"type": "git",
"url": "https://github.com/GitbookIO/nuts.git"
},
"scripts": {
"start": "node bin/web.js",
"test": "mocha --reporter list"
}
}
Loading

0 comments on commit d4decce

Please sign in to comment.