Skip to content

Commit

Permalink
Enable remote releases
Browse files Browse the repository at this point in the history
  • Loading branch information
unindented committed Feb 8, 2016
1 parent 318c37f commit 86b100c
Show file tree
Hide file tree
Showing 11 changed files with 408 additions and 71 deletions.
10 changes: 10 additions & 0 deletions README.md
Expand Up @@ -304,6 +304,16 @@ Default: `undefined`

Parameters to pass to `signtool`. Overrides `certificateFile` and `certificatePassword`.

#### options.remoteReleases
Type: `String`
Default: `undefined`

URL to your existing updates. If given, these will be downloaded to create delta updates.

If you are using Amazon S3 to store your releases, read the documentation for [Squirrel.Windows on Amazon S3](https://github.com/Squirrel/Squirrel.Windows/blob/master/docs/using/amazon-s3.md).

If you are using GitHub, read the documentation for [Squirrel.Windows on GitHub](https://github.com/Squirrel/Squirrel.Windows/blob/master/docs/using/github.md).


## Signing

Expand Down
4 changes: 3 additions & 1 deletion package.json
Expand Up @@ -41,7 +41,9 @@
"eslint": "^1.10.3",
"eslint-config-standard": "^4.4.0",
"eslint-plugin-standard": "^1.3.1",
"finalhandler": "^0.4.1",
"mocha": "^2.4.2",
"rimraf": "^2.5.1"
"rimraf": "^2.5.1",
"serve-static": "^1.10.2"
}
}
30 changes: 30 additions & 0 deletions src/installer.js
Expand Up @@ -133,6 +133,8 @@ var getDefaults = function (data, callback) {
certificatePassword: undefined,
signWithParams: undefined,

remoteReleases: undefined,

noMsi: false
}

Expand Down Expand Up @@ -284,6 +286,33 @@ var findPackage = function (options, dir, callback) {
})
}

/**
* Sync remote releases.
*/
var syncRemoteReleases = function (options, dir, pkg, callback) {
if (!options.remoteReleases) {
callback(null, dir, pkg)
return
}

options.logger('Syncing package at ' + dir)

var url = options.remoteReleases
var squirrelDir = path.join(dir, 'squirrel')

var cmd = path.resolve(__dirname, '../vendor/squirrel/SyncReleases.exe')
var args = [
'--url',
url,
'--releaseDir',
squirrelDir
]

exec(options, cmd, args, function (err) {
callback(err && new Error('Error syncing remote releases: ' + (err.message || err)), dir, pkg)
})
}

/**
* Releasify everything using `squirrel`.
*/
Expand Down Expand Up @@ -371,6 +400,7 @@ module.exports = function (data, callback) {
async.apply(createContents, options),
async.apply(createPackage, options),
async.apply(findPackage, options),
async.apply(syncRemoteReleases, options),
async.apply(releasifyPackage, options),
async.apply(movePackage, options)
], function (err) {
Expand Down
192 changes: 138 additions & 54 deletions test/cli.js
@@ -1,151 +1,235 @@
'use strict'

var fs = require('fs')
var child = require('child_process')

var spawn = function (cmd, args, callback) {
var cmds = cmd.split(' ')
var spawnedProcess = null
var error = null
var stderr = ''

try {
spawnedProcess = child.spawn(cmds[0], cmds.slice(1).concat(args))
} catch (err) {
process.nextTick(function () {
callback(err, stderr)
})
return
}

spawnedProcess.stderr.on('data', function (data) {
stderr += data
})

spawnedProcess.on('error', function (err) {
error = error || err
})

spawnedProcess.on('close', function (code, signal) {
if (code !== 0) {
error = error || signal || code
}

callback(error && new Error('Error executing command (' + (error.message || error) + '): ' +
'\n' + cmd + ' ' + args.join(' ') + '\n' + stderr))
})
}
var rimraf = require('rimraf')
var serve = require('./helpers/serve')
var spawn = require('./helpers/spawn')

describe('cli', function () {
this.timeout(20000)

describe('with an app with asar', function (test) {
var dest = 'test/fixtures/out/foo/'

before(function (done) {
spawn('node src/cli.js', [
'--src', 'test/fixtures/app-with-asar/',
'--dest', 'test/fixtures/out/foo/'
'--dest', dest
], done)
})

after(function (done) {
rimraf(dest, done)
})

it('generates a `RELEASES` manifest', function (done) {
fs.access('test/fixtures/out/foo/RELEASES', done)
fs.access(dest + 'RELEASES', done)
})

it('generates a `.nupkg` package', function (done) {
fs.access('test/fixtures/out/foo/footest-0.0.1-full.nupkg', done)
fs.access(dest + 'footest-0.0.1-full.nupkg', done)
})

it('generates a `.exe` package', function (done) {
fs.access('test/fixtures/out/foo/footest-0.0.1-setup.exe', done)
fs.access(dest + 'footest-0.0.1-setup.exe', done)
})

if (process.platform === 'win32') {
it('generates a `.msi` package', function (done) {
fs.access('test/fixtures/out/foo/footest-0.0.1-setup.msi', done)
fs.access(dest + 'footest-0.0.1-setup.msi', done)
})
}
})

describe('with an app without asar', function (test) {
var dest = 'test/fixtures/out/bar/'

before(function (done) {
spawn('node src/cli.js', [
'--src', 'test/fixtures/app-without-asar/',
'--dest', 'test/fixtures/out/bar/'
'--dest', dest
], done)
})

after(function (done) {
rimraf(dest, done)
})

it('generates a `RELEASES` manifest', function (done) {
fs.access('test/fixtures/out/bar/RELEASES', done)
fs.access(dest + 'RELEASES', done)
})

it('generates a `.nupkg` package', function (done) {
fs.access('test/fixtures/out/bar/bartest-0.0.1-full.nupkg', done)
fs.access(dest + 'bartest-0.0.1-full.nupkg', done)
})

it('generates a `.exe` package', function (done) {
fs.access('test/fixtures/out/bar/bartest-0.0.1-setup.exe', done)
fs.access(dest + 'bartest-0.0.1-setup.exe', done)
})

if (process.platform === 'win32') {
it('generates a `.msi` package', function (done) {
fs.access('test/fixtures/out/bar/bartest-0.0.1-setup.msi', done)
fs.access(dest + 'bartest-0.0.1-setup.msi', done)
})
}
})

// Signing only works on Win32.
if (process.platform === 'win32') {
describe('with a signed app with asar', function (test) {
var dest = 'test/fixtures/out/foo/'

before(function (done) {
spawn('node src/cli.js', [
'--src', 'test/fixtures/app-with-asar/',
'--dest', 'test/fixtures/out/foo/',
'--dest', dest,
'--certificateFile', 'test/fixtures/certificate.pfx',
'--certificatePassword', 'test'
], done)
})

after(function (done) {
rimraf(dest, done)
})

it('generates a `RELEASES` manifest', function (done) {
fs.access('test/fixtures/out/foo/RELEASES', done)
fs.access(dest + 'RELEASES', done)
})

it('generates a `.nupkg` package', function (done) {
fs.access('test/fixtures/out/foo/footest-0.0.1-full.nupkg', done)
fs.access(dest + 'footest-0.0.1-full.nupkg', done)
})

it('generates a `.exe` package', function (done) {
fs.access('test/fixtures/out/foo/footest-0.0.1-setup.exe', done)
fs.access(dest + 'footest-0.0.1-setup.exe', done)
})

it('generates a `.msi` package', function (done) {
fs.access('test/fixtures/out/foo/footest-0.0.1-setup.msi', done)
fs.access(dest + 'footest-0.0.1-setup.msi', done)
})
})

describe('with a signed app without asar', function (test) {
var dest = 'test/fixtures/out/bar/'

before(function (done) {
spawn('node src/cli.js', [
'--src', 'test/fixtures/app-without-asar/',
'--dest', 'test/fixtures/out/bar/',
'--dest', dest,
'--certificateFile', 'test/fixtures/certificate.pfx',
'--certificatePassword', 'test'
], done)
})

after(function (done) {
rimraf(dest, done)
})

it('generates a `RELEASES` manifest', function (done) {
fs.access('test/fixtures/out/bar/RELEASES', done)
fs.access(dest + 'RELEASES', done)
})

it('generates a `.nupkg` package', function (done) {
fs.access('test/fixtures/out/bar/bartest-0.0.1-full.nupkg', done)
fs.access(dest + 'bartest-0.0.1-full.nupkg', done)
})

it('generates a `.exe` package', function (done) {
fs.access('test/fixtures/out/bar/bartest-0.0.1-setup.exe', done)
fs.access(dest + 'bartest-0.0.1-setup.exe', done)
})

it('generates a `.msi` package', function (done) {
fs.access('test/fixtures/out/bar/bartest-0.0.1-setup.msi', done)
fs.access(dest + 'bartest-0.0.1-setup.msi', done)
})
})
}

describe('with a releases server', function (test) {
var server

before(function (done) {
server = serve('test/fixtures/releases/', 3000, done)
})

after(function (done) {
server.close(done)
})

describe('with an app with asar with the same remote release', function (test) {
var dest = 'test/fixtures/out/foo/'

before(function (done) {
spawn('node src/cli.js', [
'--src', 'test/fixtures/app-with-asar/',
'--dest', dest,
'--remoteReleases', 'http://localhost:3000/foo/'
], done)
})

after(function (done) {
rimraf(dest, done)
})

it('generates a `RELEASES` manifest', function (done) {
fs.access(dest + 'RELEASES', done)
})

it('does not generate a delta `.nupkg` package', function (done) {
fs.access(dest + 'footest-0.0.1-delta.nupkg', function (err) {
done(!err)
})
})

it('generates a full `.nupkg` package', function (done) {
fs.access(dest + 'footest-0.0.1-full.nupkg', done)
})

it('generates a `.exe` package', function (done) {
fs.access(dest + 'footest-0.0.1-setup.exe', done)
})

if (process.platform === 'win32') {
it('generates a `.msi` package', function (done) {
fs.access(dest + 'footest-0.0.1-setup.msi', done)
})
}
})

describe('with an app without asar with an old remote release', function (test) {
var dest = 'test/fixtures/out/bar/'

before(function (done) {
spawn('node src/cli.js', [
'--src', 'test/fixtures/app-without-asar/',
'--dest', dest,
'--remoteReleases', 'http://localhost:3000/bar/'
], done)
})

after(function (done) {
rimraf(dest, done)
})

it('generates a `RELEASES` manifest', function (done) {
fs.access(dest + 'RELEASES', done)
})

it('generates a delta `.nupkg` package', function (done) {
fs.access(dest + 'bartest-0.0.1-delta.nupkg', done)
})

it('generates a full `.nupkg` package', function (done) {
fs.access(dest + 'bartest-0.0.1-full.nupkg', done)
})

it('generates a `.exe` package', function (done) {
fs.access(dest + 'bartest-0.0.1-setup.exe', done)
})

if (process.platform === 'win32') {
it('generates a `.msi` package', function (done) {
fs.access(dest + 'bartest-0.0.1-setup.msi', done)
})
}
})
})
})
1 change: 1 addition & 0 deletions test/fixtures/releases/bar/RELEASES
@@ -0,0 +1 @@
4B957CE483024326E8075D8BF4E6EA46BEFA54B9 bartest-0.0.0-full.nupkg 612468
Binary file not shown.
1 change: 1 addition & 0 deletions test/fixtures/releases/foo/RELEASES
@@ -0,0 +1 @@
3DC922BEE4535A8831D0CA26B72025D3934404B4 footest-0.0.1-full.nupkg 611431
Binary file not shown.
18 changes: 18 additions & 0 deletions test/helpers/serve.js
@@ -0,0 +1,18 @@
'use strict'

var http = require('http')
var finalHandler = require('finalhandler')
var serveStatic = require('serve-static')

module.exports = function (path, port, callback) {
var serve = serveStatic(path)

var server = http.createServer(function (req, res) {
var handler = finalHandler(req, res)
serve(req, res, handler)
})

server.listen(port, callback)

return server
}

0 comments on commit 86b100c

Please sign in to comment.