mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-24 07:17:18 +00:00
Merge pull request #2736 from balena-io/electron-updater-2
Add electron autoupdater
This commit is contained in:
commit
2fa5426cf5
4
dev-app-update.yml
Normal file
4
dev-app-update.yml
Normal file
@ -0,0 +1,4 @@
|
||||
owner: balena-io
|
||||
repo: etcher
|
||||
provider: github
|
||||
updaterCacheDirName: balena-etcher-updater
|
@ -27,24 +27,18 @@ var angular = require('angular')
|
||||
/* eslint-enable no-var */
|
||||
|
||||
const electron = require('electron')
|
||||
const Bluebird = require('bluebird')
|
||||
const sdk = require('etcher-sdk')
|
||||
const _ = require('lodash')
|
||||
const semver = require('semver')
|
||||
const uuidV4 = require('uuid/v4')
|
||||
|
||||
const EXIT_CODES = require('../../shared/exit-codes')
|
||||
const messages = require('../../shared/messages')
|
||||
const s3Packages = require('../../shared/s3-packages')
|
||||
const release = require('../../shared/release')
|
||||
const store = require('./models/store')
|
||||
const errors = require('../../shared/errors')
|
||||
const packageJSON = require('../../../package.json')
|
||||
const flashState = require('./models/flash-state')
|
||||
const settings = require('./models/settings')
|
||||
const windowProgress = require('./os/window-progress')
|
||||
const analytics = require('./modules/analytics')
|
||||
const updateNotifier = require('./components/update-notifier')
|
||||
const availableDrives = require('./models/available-drives')
|
||||
const selectionState = require('./models/selection-state')
|
||||
const driveScanner = require('./modules/drive-scanner')
|
||||
@ -134,84 +128,6 @@ app.run(() => {
|
||||
version: currentVersion,
|
||||
applicationSessionUuid
|
||||
})
|
||||
|
||||
const shouldCheckForUpdates = updateNotifier.shouldCheckForUpdates({
|
||||
currentVersion,
|
||||
lastSleptUpdateNotifier: settings.get('lastSleptUpdateNotifier'),
|
||||
lastSleptUpdateNotifierVersion: settings.get('lastSleptUpdateNotifierVersion')
|
||||
})
|
||||
|
||||
const isStableRelease = release.isStableRelease(currentVersion)
|
||||
const updatesEnabled = settings.get('updatesEnabled')
|
||||
|
||||
if (!shouldCheckForUpdates || !updatesEnabled) {
|
||||
analytics.logEvent('Not checking for updates', {
|
||||
shouldCheckForUpdates,
|
||||
updatesEnabled,
|
||||
stable: isStableRelease,
|
||||
applicationSessionUuid
|
||||
})
|
||||
|
||||
return Bluebird.resolve()
|
||||
}
|
||||
|
||||
const updateSemverRange = packageJSON.updates.semverRange
|
||||
const includeUnstableChannel = settings.get('includeUnstableUpdateChannel')
|
||||
|
||||
analytics.logEvent('Checking for updates', {
|
||||
currentVersion,
|
||||
stable: isStableRelease,
|
||||
updateSemverRange,
|
||||
includeUnstableChannel,
|
||||
applicationSessionUuid
|
||||
})
|
||||
|
||||
return s3Packages.getLatestVersion(release.getReleaseType(currentVersion), {
|
||||
range: updateSemverRange,
|
||||
includeUnstableChannel
|
||||
}).then((latestVersion) => {
|
||||
if (semver.gte(currentVersion, latestVersion || '0.0.0')) {
|
||||
analytics.logEvent('Update notification skipped', {
|
||||
reason: 'Latest version',
|
||||
applicationSessionUuid
|
||||
})
|
||||
return Bluebird.resolve()
|
||||
}
|
||||
|
||||
// In case the internet connection is not good and checking the
|
||||
// latest published version takes too long, only show notify
|
||||
// the user about the new version if he didn't start the flash
|
||||
// process (e.g: selected an image), otherwise such interruption
|
||||
// might be annoying.
|
||||
if (selectionState.hasImage()) {
|
||||
analytics.logEvent('Update notification skipped', {
|
||||
reason: 'Image selected',
|
||||
applicationSessionUuid
|
||||
})
|
||||
return Bluebird.resolve()
|
||||
}
|
||||
|
||||
analytics.logEvent('Notifying update', {
|
||||
latestVersion,
|
||||
applicationSessionUuid
|
||||
})
|
||||
|
||||
return updateNotifier.notify(latestVersion, {
|
||||
allowSleepUpdateCheck: isStableRelease
|
||||
})
|
||||
|
||||
// If the error is an update user error, then we don't want
|
||||
// to bother users each time they open the app.
|
||||
// See: https://github.com/resin-io/etcher/issues/1525
|
||||
}).catch((error) => {
|
||||
return errors.isUserError(error) && error.code === 'UPDATE_USER_ERROR'
|
||||
}, (error) => {
|
||||
analytics.logEvent('Update check user error', {
|
||||
title: errors.getTitle(error),
|
||||
description: errors.getDescription(error),
|
||||
applicationSessionUuid
|
||||
})
|
||||
}).catch(exceptionReporter.report)
|
||||
})
|
||||
|
||||
app.run(() => {
|
||||
|
@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const electron = require('electron')
|
||||
const Bluebird = require('bluebird')
|
||||
const _ = require('lodash')
|
||||
const store = require('../models/store')
|
||||
const settings = require('../models/settings')
|
||||
const analytics = require('../modules/analytics')
|
||||
const units = require('../../../shared/units')
|
||||
const release = require('../../../shared/release')
|
||||
const packageJSON = require('../../../../package.json')
|
||||
|
||||
/**
|
||||
* @summary The number of days the update notifier can be put to sleep
|
||||
* @constant
|
||||
* @private
|
||||
* @type {Number}
|
||||
*/
|
||||
exports.UPDATE_NOTIFIER_SLEEP_DAYS = packageJSON.updates.sleepDays
|
||||
|
||||
/**
|
||||
* @summary The current Electron browser window
|
||||
* @constant
|
||||
* @private
|
||||
* @type {Object}
|
||||
*/
|
||||
const currentWindow = electron.remote.getCurrentWindow()
|
||||
|
||||
/**
|
||||
* @summary Determine if it's time to check for updates
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {Object} options - options
|
||||
* @param {Number} [options.lastSleptUpdateNotifier] - last slept update notifier time
|
||||
* @param {String} [options.lastSleptUpdateNotifierVersion] - last slept update notifier version
|
||||
* @param {String} options.currentVersion - current version
|
||||
* @returns {Boolean} should check for updates
|
||||
*
|
||||
* @example
|
||||
* if (updateNotifier.shouldCheckForUpdates({
|
||||
* lastSleptUpdateNotifier: Date.now(),
|
||||
* lastSleptUpdateNotifierVersion: '1.0.0',
|
||||
* currentVersion: '1.0.0'
|
||||
* })) {
|
||||
* console.log('We should check for updates!');
|
||||
* }
|
||||
*/
|
||||
exports.shouldCheckForUpdates = (options) => {
|
||||
if (settings.get('resinUpdateLock')) {
|
||||
return false
|
||||
}
|
||||
|
||||
_.defaults(options, {
|
||||
lastSleptUpdateNotifierVersion: options.currentVersion
|
||||
})
|
||||
|
||||
if (_.some([
|
||||
!options.lastSleptUpdateNotifier,
|
||||
!release.isStableRelease(options.currentVersion),
|
||||
options.currentVersion !== options.lastSleptUpdateNotifierVersion
|
||||
])) {
|
||||
return true
|
||||
}
|
||||
|
||||
return Date.now() - options.lastSleptUpdateNotifier > units.daysToMilliseconds(exports.UPDATE_NOTIFIER_SLEEP_DAYS)
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Open the update notifier widget
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {String} version - version
|
||||
* @param {Object} [options] - options
|
||||
* @param {Boolean} [options.allowSleepUpdateCheck=true] - allow sleeping the update check
|
||||
* @returns {Promise}
|
||||
*
|
||||
* @example
|
||||
* updateNotifier.notify('1.0.0-beta.16', {
|
||||
* allowSleepUpdateCheck: true
|
||||
* });
|
||||
*/
|
||||
exports.notify = (version, options = {}) => {
|
||||
const BUTTONS = [
|
||||
'Download',
|
||||
'Skip'
|
||||
]
|
||||
|
||||
const BUTTON_CONFIRMATION_INDEX = _.indexOf(BUTTONS, _.first(BUTTONS))
|
||||
const BUTTON_REJECTION_INDEX = _.indexOf(BUTTONS, _.last(BUTTONS))
|
||||
|
||||
const dialogOptions = {
|
||||
type: 'info',
|
||||
buttons: BUTTONS,
|
||||
defaultId: BUTTON_CONFIRMATION_INDEX,
|
||||
cancelId: BUTTON_REJECTION_INDEX,
|
||||
title: 'New Update Available!',
|
||||
message: `Etcher ${version} is available for download`
|
||||
}
|
||||
|
||||
if (_.get(options, [ 'allowSleepUpdateCheck' ], true)) {
|
||||
_.merge(dialogOptions, {
|
||||
checkboxLabel: `Remind me again in ${exports.UPDATE_NOTIFIER_SLEEP_DAYS} days`,
|
||||
checkboxChecked: false
|
||||
})
|
||||
}
|
||||
|
||||
return new Bluebird((resolve) => {
|
||||
electron.remote.dialog.showMessageBox(currentWindow, dialogOptions, (response, checkboxChecked) => {
|
||||
return resolve({
|
||||
agreed: response === BUTTON_CONFIRMATION_INDEX,
|
||||
sleepUpdateCheck: checkboxChecked || false
|
||||
})
|
||||
})
|
||||
}).tap((results) => {
|
||||
// Only update the last slept update timestamp if the
|
||||
// user ticked the "Remind me again in ..." checkbox,
|
||||
// but didn't agree.
|
||||
if (results.sleepUpdateCheck && !results.agreed) {
|
||||
return Bluebird.all([
|
||||
settings.set('lastSleptUpdateNotifier', Date.now()),
|
||||
settings.set('lastSleptUpdateNotifierVersion', packageJSON.version)
|
||||
])
|
||||
}
|
||||
|
||||
return Bluebird.resolve()
|
||||
}).then((results) => {
|
||||
analytics.logEvent('Close update modal', {
|
||||
sleepUpdateCheck: results.sleepUpdateCheck,
|
||||
notifyVersion: version,
|
||||
currentVersion: packageJSON.version,
|
||||
agreed: results.agreed,
|
||||
applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
|
||||
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
|
||||
})
|
||||
|
||||
if (results.agreed) {
|
||||
electron.shell.openExternal('https://etcher.io?ref=etcher_update')
|
||||
}
|
||||
})
|
||||
}
|
@ -24,7 +24,6 @@ const _ = require('lodash')
|
||||
const Bluebird = require('bluebird')
|
||||
const localSettings = require('./local-settings')
|
||||
const errors = require('../../../shared/errors')
|
||||
const release = require('../../../shared/release')
|
||||
const packageJSON = require('../../../../package.json')
|
||||
const debug = require('debug')('etcher:models:settings')
|
||||
|
||||
@ -39,7 +38,6 @@ const DEFAULT_SETTINGS = {
|
||||
unmountOnSuccess: true,
|
||||
validateWriteOnSuccess: true,
|
||||
updatesEnabled: packageJSON.updates.enabled && !_.includes([ 'rpm', 'deb' ], packageJSON.packageType),
|
||||
includeUnstableUpdateChannel: !release.isStableRelease(packageJSON.version),
|
||||
lastSleptUpdateNotifier: null,
|
||||
lastSleptUpdateNotifierVersion: null,
|
||||
desktopNotifications: true
|
||||
|
@ -20,10 +20,8 @@ const _ = require('lodash')
|
||||
const resinCorvus = require('resin-corvus/browser')
|
||||
const packageJSON = require('../../../../package.json')
|
||||
const settings = require('../models/settings')
|
||||
const { hasProps } = require('../../../shared/utils')
|
||||
const { getConfig, hasProps } = require('../../../shared/utils')
|
||||
|
||||
const Bluebird = require('bluebird')
|
||||
const request = Bluebird.promisifyAll(require('request'))
|
||||
const sentryToken = settings.get('analyticsSentryToken') ||
|
||||
_.get(packageJSON, [ 'analytics', 'sentry', 'token' ])
|
||||
const mixpanelToken = settings.get('analyticsMixpanelToken') ||
|
||||
@ -73,23 +71,13 @@ const initConfig = async () => {
|
||||
|
||||
initConfig()
|
||||
|
||||
/**
|
||||
* @summary Get etcher configs stored online
|
||||
* @param {String} - url where config.json is stored
|
||||
*/
|
||||
// eslint-disable-next-line
|
||||
function getConfig(url) {
|
||||
return request.getAsync(url, { json: true })
|
||||
.get('body')
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Check that the client is eligible for analytics
|
||||
* @param {Object} - config
|
||||
*/
|
||||
// eslint-disable-next-line
|
||||
function isClientEligible(probability) {
|
||||
return Math.random() > probability
|
||||
return Math.random() < probability
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,14 +43,14 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox" ng-show="settings.model.get('updatesEnabled')">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
tabindex="9"
|
||||
ng-model="settings.currentData.includeUnstableUpdateChannel"
|
||||
ng-change="settings.toggle('includeUnstableUpdateChannel')">
|
||||
ng-model="settings.currentData.updatesEnabled"
|
||||
ng-change="settings.toggle('updatesEnabled')">
|
||||
|
||||
<span>Include unstable update channel</span>
|
||||
<span>Auto-updates enabled</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
@ -18,14 +18,41 @@
|
||||
|
||||
const electron = require('electron')
|
||||
const path = require('path')
|
||||
const _ = require('lodash')
|
||||
const { autoUpdater } = require('electron-updater')
|
||||
const Bluebird = require('bluebird')
|
||||
const EXIT_CODES = require('../shared/exit-codes')
|
||||
const buildWindowMenu = require('./menu')
|
||||
const settings = require('./app/models/settings')
|
||||
|
||||
const analytics = require('./app/modules/analytics')
|
||||
const { getConfig } = require('../shared/utils')
|
||||
/* eslint-disable lodash/prefer-lodash-method */
|
||||
|
||||
const config = settings.getDefaults()
|
||||
|
||||
const configUrl = settings.get('configUrl') || 'http://balena.io/etcher/static/config.json'
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Number} interval - interval to wait to check for updates
|
||||
* @example checkForUpdates()
|
||||
*/
|
||||
const checkForUpdates = async (interval) => {
|
||||
// We use a while loop instead of a setInterval to preserve
|
||||
// async execution time between each function call
|
||||
while (true) {
|
||||
try {
|
||||
const release = await autoUpdater.checkForUpdates()
|
||||
if (release.updateInfo.stagingPercentage) {
|
||||
await autoUpdater.downloadUpdate()
|
||||
}
|
||||
} catch (err) {
|
||||
analytics.logException(err)
|
||||
}
|
||||
await Bluebird.delay(interval)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Create Etcher's main window
|
||||
* @example
|
||||
@ -83,6 +110,28 @@ const createMainWindow = () => {
|
||||
} else {
|
||||
mainWindow.loadURL(`file://${path.join(__dirname, 'app', 'index.html')}`)
|
||||
}
|
||||
|
||||
const page = mainWindow.webContents
|
||||
|
||||
page.once('did-frame-finish-load', async () => {
|
||||
autoUpdater.on('error', (err) => {
|
||||
analytics.logException(err)
|
||||
})
|
||||
if (settings.get('updatesEnabled')) {
|
||||
try {
|
||||
const onlineConfig = await getConfig(configUrl)
|
||||
const autoUpdaterConfig = _.get(onlineConfig, [ 'autoUpdates', 'autoUpdaterConfig' ], {
|
||||
autoDownload: false
|
||||
})
|
||||
_.merge(autoUpdater, autoUpdaterConfig)
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
const checkForUpdatesTimer = _.get(onlineConfig, [ 'autoUpdates', 'checkForUpdatesTimer' ], 300000)
|
||||
checkForUpdates(checkForUpdatesTimer)
|
||||
} catch (err) {
|
||||
analytics.logException(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
electron.app.on('window-all-closed', electron.app.quit)
|
||||
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const _ = require('lodash')
|
||||
const semver = require('semver')
|
||||
|
||||
/**
|
||||
* @summary Application release types
|
||||
* @namespace RELEASE_TYPE
|
||||
* @public
|
||||
*/
|
||||
exports.RELEASE_TYPE = {
|
||||
|
||||
/**
|
||||
* @property {String} PRODUCTION
|
||||
* @memberof RELEASE_TYPE
|
||||
* @description
|
||||
* Production release type
|
||||
*/
|
||||
PRODUCTION: 'PRODUCTION',
|
||||
|
||||
/**
|
||||
* @property {String} SNAPSHOT
|
||||
* @memberof RELEASE_TYPE
|
||||
* @description
|
||||
* Snapshot release type
|
||||
*/
|
||||
SNAPSHOT: 'SNAPSHOT',
|
||||
|
||||
/**
|
||||
* @property {String} UNKNOWN
|
||||
* @memberof RELEASE_TYPE
|
||||
* @description
|
||||
* Unknown release type
|
||||
*/
|
||||
UNKNOWN: 'UNKNOWN'
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get the release type from a version string
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {String} version - application version
|
||||
* @returns {RELEASE_TYPE} release type
|
||||
*
|
||||
* @example
|
||||
* const version = require('../../package.json').version;
|
||||
* const releaseType = release.getReleaseType(version);
|
||||
*
|
||||
* if (releaseType === release.RELEASE_TYPE.PRODUCTION) {
|
||||
* console.log('This is a production release!');
|
||||
* }
|
||||
*/
|
||||
exports.getReleaseType = (version) => {
|
||||
const GIT_HASH_REGEX = /^[0-9a-f]{7,40}$/
|
||||
const buildNumber = _.get(semver.parse(version), [ 'build' ])
|
||||
|
||||
if (!_.isNil(buildNumber)) {
|
||||
if (_.isEmpty(buildNumber)) {
|
||||
return exports.RELEASE_TYPE.PRODUCTION
|
||||
}
|
||||
|
||||
if (GIT_HASH_REGEX.test(_.first(buildNumber))) {
|
||||
return exports.RELEASE_TYPE.SNAPSHOT
|
||||
}
|
||||
}
|
||||
|
||||
return exports.RELEASE_TYPE.UNKNOWN
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Check if a version is a stable release
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {String} version - version
|
||||
* @returns {Boolean} whether the version is a stable release
|
||||
*
|
||||
* @example
|
||||
* if (release.isStableRelease('1.0.0')) {
|
||||
* console.log('This is a stable release');
|
||||
* }
|
||||
*/
|
||||
exports.isStableRelease = (version) => {
|
||||
const parsedVersion = semver.parse(version)
|
||||
return _.every([
|
||||
_.isEmpty(_.get(parsedVersion, [ 'prerelease' ])),
|
||||
_.isEmpty(_.get(parsedVersion, [ 'build' ]))
|
||||
])
|
||||
}
|
@ -1,265 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const _ = require('lodash')
|
||||
const semver = require('semver')
|
||||
const Bluebird = require('bluebird')
|
||||
const request = Bluebird.promisifyAll(require('request'))
|
||||
const xml = Bluebird.promisifyAll(require('xml2js'))
|
||||
const release = require('./release')
|
||||
const errors = require('./errors')
|
||||
|
||||
/**
|
||||
* @summary Etcher S3 bucket URLs
|
||||
* @namespace BUCKET_URL
|
||||
* @public
|
||||
*/
|
||||
exports.BUCKET_URL = {
|
||||
|
||||
/**
|
||||
* @property {String} PRODUCTION
|
||||
* @memberof BUCKET_URL
|
||||
* @description
|
||||
* Etcher production S3 bucket URL
|
||||
*/
|
||||
PRODUCTION: 'https://resin-production-downloads.s3.amazonaws.com',
|
||||
|
||||
/**
|
||||
* @property {String} SNAPSHOT
|
||||
* @memberof BUCKET_URL
|
||||
* @description
|
||||
* Etcher snapshot S3 bucket URL
|
||||
*/
|
||||
SNAPSHOT: 'https://resin-nightly-downloads.s3.amazonaws.com'
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Etcher S3 package name
|
||||
* @constant
|
||||
* @private
|
||||
* @type {String}
|
||||
*/
|
||||
const S3_PACKAGE_NAME = 'etcher'
|
||||
|
||||
/**
|
||||
* @summary Number of packages per Etcher version
|
||||
* @constant
|
||||
* @private
|
||||
* @type {Number}
|
||||
*/
|
||||
const NUMBER_OF_PACKAGES = 8
|
||||
|
||||
/**
|
||||
* @summary Get the correct S3 bucket url from a release type
|
||||
* @function
|
||||
* @private
|
||||
*
|
||||
* @param {RELEASE_TYPE} releaseType - release type
|
||||
* @returns {?String} S3 bucket url
|
||||
*
|
||||
* @example
|
||||
* const bucketUrl = s3Packages.getBucketUrlFromReleaseType(release.RELEASE_TYPE.PRODUCTION);
|
||||
*
|
||||
* if (bucketUrl) {
|
||||
* console.log(bucketUrl);
|
||||
* }
|
||||
*/
|
||||
exports.getBucketUrlFromReleaseType = (releaseType) => {
|
||||
if (releaseType === release.RELEASE_TYPE.PRODUCTION) {
|
||||
return exports.BUCKET_URL.PRODUCTION
|
||||
}
|
||||
|
||||
if (releaseType === release.RELEASE_TYPE.SNAPSHOT) {
|
||||
return exports.BUCKET_URL.SNAPSHOT
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get all remote versions from an S3 bucket
|
||||
* @function
|
||||
* @private
|
||||
*
|
||||
* @description
|
||||
* We memoize based on the assumption that the received latest version
|
||||
* number will not increase while the application is running.
|
||||
*
|
||||
* @param {String} bucketUrl - s3 bucket url
|
||||
* @fulfil {String[]} - remote versions
|
||||
* @returns {Promise}
|
||||
*
|
||||
* @example
|
||||
* s3Packages.getRemoteVersions(s3Packages.BUCKET_URL.PRODUCTION).then((versions) => {
|
||||
* _.each(versions, (version) => {
|
||||
* console.log(version);
|
||||
* });
|
||||
* });
|
||||
*/
|
||||
exports.getRemoteVersions = _.memoize((bucketUrl) => {
|
||||
if (_.isNil(bucketUrl)) {
|
||||
return Bluebird.reject(new Error(`Invalid bucket url: ${bucketUrl}`))
|
||||
}
|
||||
|
||||
/* eslint-disable lodash/prefer-lodash-method */
|
||||
|
||||
return request.getAsync(bucketUrl)
|
||||
|
||||
/* eslint-enable lodash/prefer-lodash-method */
|
||||
|
||||
.get('body')
|
||||
.then(xml.parseStringAsync)
|
||||
.get('ListBucketResult')
|
||||
.then((bucketResult) => {
|
||||
return _.get(bucketResult, [ 'Contents' ], [])
|
||||
})
|
||||
.reduce((accumulator, entry) => {
|
||||
const [ name, version ] = _.split(_.first(entry.Key), '/')
|
||||
|
||||
if (name === S3_PACKAGE_NAME) {
|
||||
if (_.isNil(accumulator[version])) {
|
||||
accumulator[version] = 1
|
||||
} else {
|
||||
accumulator[version] += 1
|
||||
}
|
||||
}
|
||||
|
||||
return accumulator
|
||||
}, [])
|
||||
.then((versions) => {
|
||||
return _.keys(_.pickBy(versions, (occurrences) => {
|
||||
return occurrences >= NUMBER_OF_PACKAGES
|
||||
}))
|
||||
})
|
||||
.catch({
|
||||
code: 'ENOTFOUND'
|
||||
}, {
|
||||
code: 'ECONNRESET'
|
||||
}, {
|
||||
code: 'ECONNREFUSED'
|
||||
}, {
|
||||
code: 'EACCES'
|
||||
}, {
|
||||
code: 'ETIMEDOUT'
|
||||
}, {
|
||||
code: 'EHOSTDOWN'
|
||||
}, {
|
||||
code: 'EAI_AGAIN'
|
||||
}, {
|
||||
|
||||
// May happen when behind a proxy
|
||||
code: 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY'
|
||||
|
||||
}, {
|
||||
|
||||
// May happen when behind a proxy
|
||||
code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'
|
||||
|
||||
}, (error) => {
|
||||
throw errors.createUserError({
|
||||
title: 'Unable to check for updates',
|
||||
description: `We got an ${error.code} error in response`,
|
||||
code: 'UPDATE_USER_ERROR'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* @summary Check if a version satisfies a semver range
|
||||
* @function
|
||||
* @private
|
||||
*
|
||||
* @description
|
||||
* This function is a wrapper around `semver.satisfies`
|
||||
* to make it work fine with pre-release versions.
|
||||
*
|
||||
* @param {String} version - semver version
|
||||
* @param {String} range - semver range
|
||||
* @returns {Boolean} whether the version satisfies the range
|
||||
*
|
||||
* @example
|
||||
* if (semverSatisfies('1.0.0', '>=1.0.0')) {
|
||||
* console.log('The version satisfies the range');
|
||||
* }
|
||||
*/
|
||||
const semverSatisfies = (version, range) => {
|
||||
// The `semver` module refuses to apply ranges to prerelease versions
|
||||
// As a workaround, we drop the prerelease tags, if any, apply the range
|
||||
// on that, and keep using the prerelease tag from then on.
|
||||
// See https://github.com/npm/node-semver#prerelease-tags
|
||||
const strippedVersion = `${semver.major(version)}.${semver.minor(version)}.${semver.patch(version)}`
|
||||
|
||||
return semver.satisfies(strippedVersion, range)
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get the latest available version for a given release type
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {String} releaseType - release type
|
||||
* @param {Object} [options] - options
|
||||
* @param {String} [options.range] - semver range
|
||||
* @param {Boolean} [options.includeUnstableChannel=false] - include unstable channel
|
||||
* @fulfil {(String|undefined)} - latest version
|
||||
* @returns {Promise}
|
||||
*
|
||||
* @example
|
||||
* s3Packages.getLatestVersion(release.RELEASE_TYPE.PRODUCTION, {
|
||||
* range: '>=2.0.0',
|
||||
* includeUnstableChannel: true
|
||||
* }).then((latestVersion) => {
|
||||
* console.log(`The latest version is: ${latestVersion}`);
|
||||
* });
|
||||
*/
|
||||
exports.getLatestVersion = (releaseType, options = {}) => {
|
||||
// For manual testing purposes
|
||||
const ETCHER_FAKE_S3_LATEST_VERSION = process.env.ETCHER_FAKE_S3_LATEST_VERSION
|
||||
if (!_.isNil(ETCHER_FAKE_S3_LATEST_VERSION)) {
|
||||
if (release.getReleaseType(ETCHER_FAKE_S3_LATEST_VERSION) === releaseType) {
|
||||
return Bluebird.resolve(ETCHER_FAKE_S3_LATEST_VERSION)
|
||||
}
|
||||
|
||||
return Bluebird.resolve()
|
||||
}
|
||||
|
||||
const bucketUrl = exports.getBucketUrlFromReleaseType(releaseType)
|
||||
if (_.isNil(bucketUrl)) {
|
||||
return Bluebird.reject(new Error(`No bucket URL found for release type: ${releaseType}`))
|
||||
}
|
||||
|
||||
/* eslint-disable lodash/prefer-lodash-method */
|
||||
return exports.getRemoteVersions(bucketUrl).filter((version) => {
|
||||
/* eslint-enable lodash/prefer-lodash-method */
|
||||
if (_.some([
|
||||
|
||||
// This check allows us to ignore snapshot builds in production
|
||||
// buckets, and viceversa, which could have been uploaded by mistake.
|
||||
release.getReleaseType(version) !== releaseType,
|
||||
|
||||
!release.isStableRelease(version) && !options.includeUnstableChannel
|
||||
])) {
|
||||
return false
|
||||
}
|
||||
|
||||
return semverSatisfies(version, options.range || '*')
|
||||
}).then((versions) => {
|
||||
return _.last(versions.sort(semver.compare))
|
||||
})
|
||||
}
|
@ -17,6 +17,8 @@
|
||||
'use strict'
|
||||
|
||||
const _ = require('lodash')
|
||||
const Bluebird = require('bluebird')
|
||||
const request = Bluebird.promisifyAll(require('request'))
|
||||
const errors = require('./errors')
|
||||
|
||||
/**
|
||||
@ -156,3 +158,13 @@ exports.hasProps = (obj, props) => {
|
||||
return _.has(obj, prop)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get etcher configs stored online
|
||||
* @param {String} - url where config.json is stored
|
||||
*/
|
||||
// eslint-disable-next-line
|
||||
exports.getConfig = (configUrl) => {
|
||||
return request.getAsync(configUrl, { json: true })
|
||||
.get('body')
|
||||
}
|
||||
|
80
npm-shrinkwrap.json
generated
80
npm-shrinkwrap.json
generated
@ -1639,7 +1639,6 @@
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
},
|
||||
@ -1647,8 +1646,7 @@
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
|
||||
"dev": true
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2182,7 +2180,6 @@
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.7.tgz",
|
||||
"integrity": "sha512-5ix04IbXVIZ6nSRM4aZnwQfk40Td0D57WAl8LfhnICF6XwT4efCZYh0veOHvfDmgpbqE4ju5L5XEAMIcAe13Kw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bluebird": "^3.5.3"
|
||||
}
|
||||
@ -2455,8 +2452,7 @@
|
||||
"buffer-from": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||
},
|
||||
"buffer-xor": {
|
||||
"version": "1.0.3",
|
||||
@ -4424,6 +4420,57 @@
|
||||
"integrity": "sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g==",
|
||||
"dev": true
|
||||
},
|
||||
"electron-updater": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.0.6.tgz",
|
||||
"integrity": "sha512-JPGLME6fxJcHG8hX7HWFl6Aew6iVm0DkcrENreKa5SUJCHG+uUaAhxDGDt+YGcNkyx1uJ6eBGMvFxDTLUv67pg==",
|
||||
"requires": {
|
||||
"bluebird-lst": "^1.0.6",
|
||||
"builder-util-runtime": "~8.1.0",
|
||||
"fs-extra-p": "^7.0.0",
|
||||
"js-yaml": "^3.12.0",
|
||||
"lazy-val": "^1.0.3",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"pako": "^1.0.7",
|
||||
"semver": "^5.6.0",
|
||||
"source-map-support": "^0.5.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"builder-util-runtime": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.1.1.tgz",
|
||||
"integrity": "sha512-+ieS4PMB33vVE2S3ZNWBEQJ1zKmAs/agrBdh7XadE1lKLjrH4aXYuOh9OOGdxqIRldhlhNBaF+yKMMEFOdNVig==",
|
||||
"requires": {
|
||||
"bluebird-lst": "^1.0.6",
|
||||
"debug": "^4.1.1",
|
||||
"fs-extra-p": "^7.0.0",
|
||||
"sax": "^1.2.4"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.5.10",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz",
|
||||
"integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==",
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"electron-window": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-window/-/electron-window-0.8.1.tgz",
|
||||
@ -5194,8 +5241,7 @@
|
||||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
},
|
||||
"esquery": {
|
||||
"version": "1.0.1",
|
||||
@ -5881,7 +5927,6 @@
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra-p/-/fs-extra-p-7.0.1.tgz",
|
||||
"integrity": "sha512-yhd2OV0HnHt2oitlp+X9hl2ReX4X/7kQeL7/72qzPHTZj5eUPGzAKOvEglU02Fa1OeG2rSy/aKB4WGVaLiF8tw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bluebird-lst": "^1.0.7",
|
||||
"fs-extra": "^7.0.1"
|
||||
@ -5891,7 +5936,6 @@
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
|
||||
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"jsonfile": "^4.0.0",
|
||||
@ -7070,7 +7114,6 @@
|
||||
"version": "3.12.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz",
|
||||
"integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
@ -7142,7 +7185,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
@ -7203,8 +7245,7 @@
|
||||
"lazy-val": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.4.tgz",
|
||||
"integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q=="
|
||||
},
|
||||
"lazystream": {
|
||||
"version": "1.0.0",
|
||||
@ -7330,6 +7371,11 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash.frompairs/-/lodash.frompairs-4.0.1.tgz",
|
||||
"integrity": "sha1-vE5SB/onV8E25XNhTpZkUGsrG9I="
|
||||
},
|
||||
"lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
|
||||
},
|
||||
"lodash.kebabcase": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
|
||||
@ -8972,8 +9018,7 @@
|
||||
"pako": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.8.tgz",
|
||||
"integrity": "sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA=="
|
||||
},
|
||||
"parallel-transform": {
|
||||
"version": "1.1.0",
|
||||
@ -12576,8 +12621,7 @@
|
||||
"universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
|
||||
},
|
||||
"unpipe": {
|
||||
"version": "1.0.0",
|
||||
|
@ -20,7 +20,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make lint test sanity-checks",
|
||||
"start": "electron lib/start.js",
|
||||
"start": "./node_modules/.bin/electron .",
|
||||
"configure": "node-gyp configure",
|
||||
"build": "node-gyp build",
|
||||
"install": "node-gyp rebuild",
|
||||
@ -49,6 +49,7 @@
|
||||
"debug": "^3.1.0",
|
||||
"electron-is-running-in-asar": "^1.0.0",
|
||||
"etcher-sdk": "^2.0.1",
|
||||
"electron-updater": "4.0.6",
|
||||
"flexboxgrid": "^6.3.0",
|
||||
"immutable": "^3.8.1",
|
||||
"inactivity-timer": "^1.0.0",
|
||||
|
@ -1,450 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const m = require('mochainon')
|
||||
const _ = require('lodash')
|
||||
const units = require('../../../lib/shared/units')
|
||||
const updateNotifier = require('../../../lib/gui/app/components/update-notifier')
|
||||
|
||||
describe('Browser: updateNotifier', function () {
|
||||
describe('.UPDATE_NOTIFIER_SLEEP_DAYS', function () {
|
||||
it('should be an integer', function () {
|
||||
m.chai.expect(_.isInteger(updateNotifier.UPDATE_NOTIFIER_SLEEP_DAYS)).to.be.true
|
||||
})
|
||||
|
||||
it('should be greater than 0', function () {
|
||||
m.chai.expect(updateNotifier.UPDATE_NOTIFIER_SLEEP_DAYS > 0).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
describe('.shouldCheckForUpdates()', function () {
|
||||
const UPDATE_NOTIFIER_SLEEP_MS = units.daysToMilliseconds(updateNotifier.UPDATE_NOTIFIER_SLEEP_DAYS)
|
||||
|
||||
_.each([
|
||||
|
||||
// Given the `lastSleptUpdateNotifier` was never updated
|
||||
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: undefined,
|
||||
lastSleptUpdateNotifierVersion: undefined,
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: undefined,
|
||||
lastSleptUpdateNotifierVersion: undefined,
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: undefined,
|
||||
lastSleptUpdateNotifierVersion: undefined,
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: undefined,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: undefined,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0+6374412',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: undefined,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0+foo',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: undefined,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: undefined,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: undefined,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: undefined,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: undefined,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: undefined,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
|
||||
// Given the `lastSleptUpdateNotifier` was very recently updated
|
||||
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - 1000,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: false
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - 1000,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0+6374412',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - 1000,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0+foo',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - 1000,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - 1000,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - 1000,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - 1000,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - 1000,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - 1000,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
|
||||
// Given the `lastSleptUpdateNotifier` was updated in the future
|
||||
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + 1000,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: false
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + 1000,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0+6374412',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + 1000,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0+foo',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + 1000,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + 1000,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + 1000,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + 1000,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + 1000,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + 1000,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
|
||||
// Given the `lastSleptUpdateNotifier` was updated far in the future
|
||||
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + UPDATE_NOTIFIER_SLEEP_MS + 1000,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: false
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + UPDATE_NOTIFIER_SLEEP_MS + 1000,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0+6374412',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + UPDATE_NOTIFIER_SLEEP_MS + 1000,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0+foo',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + UPDATE_NOTIFIER_SLEEP_MS + 1000,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + UPDATE_NOTIFIER_SLEEP_MS + 1000,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + UPDATE_NOTIFIER_SLEEP_MS + 1000,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + UPDATE_NOTIFIER_SLEEP_MS + 1000,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + UPDATE_NOTIFIER_SLEEP_MS + 1000,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() + UPDATE_NOTIFIER_SLEEP_MS + 1000,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
|
||||
// Given the `lastSleptUpdateNotifier` was updated long ago
|
||||
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - UPDATE_NOTIFIER_SLEEP_MS - 1000,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - UPDATE_NOTIFIER_SLEEP_MS - 1000,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0+6374412',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - UPDATE_NOTIFIER_SLEEP_MS - 1000,
|
||||
lastSleptUpdateNotifierVersion: '1.0.0+foo',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - UPDATE_NOTIFIER_SLEEP_MS - 1000,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - UPDATE_NOTIFIER_SLEEP_MS - 1000,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - UPDATE_NOTIFIER_SLEEP_MS - 1000,
|
||||
lastSleptUpdateNotifierVersion: '0.0.0',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - UPDATE_NOTIFIER_SLEEP_MS - 1000,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - UPDATE_NOTIFIER_SLEEP_MS - 1000,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0+6374412'
|
||||
},
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
options: {
|
||||
lastSleptUpdateNotifier: Date.now() - UPDATE_NOTIFIER_SLEEP_MS - 1000,
|
||||
lastSleptUpdateNotifierVersion: '99.9.9',
|
||||
currentVersion: '1.0.0+foo'
|
||||
},
|
||||
expected: true
|
||||
}
|
||||
|
||||
], (testCase) => {
|
||||
it(_.join([
|
||||
`should return ${testCase.expected} if`,
|
||||
`lastSleptUpdateNotifier=${testCase.options.lastSleptUpdateNotifier},`,
|
||||
`lastSleptUpdateNotifierVersion=${testCase.options.lastSleptUpdateNotifierVersion}, and`,
|
||||
`currentVersion=${testCase.options.currentVersion}`
|
||||
], ' '), function () {
|
||||
m.chai.expect(updateNotifier.shouldCheckForUpdates(testCase.options)).to.equal(testCase.expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 resin.io
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const m = require('mochainon')
|
||||
const _ = require('lodash')
|
||||
const release = require('../../lib/shared/release')
|
||||
|
||||
describe('Shared: Release', function () {
|
||||
describe('.RELEASE_TYPE', function () {
|
||||
it('should be a plain object', function () {
|
||||
m.chai.expect(_.isPlainObject(release.RELEASE_TYPE)).to.be.true
|
||||
})
|
||||
|
||||
it('should contain keys with different values', function () {
|
||||
const keys = _.keys(release.RELEASE_TYPE)
|
||||
const uniqueValues = _.uniq(_.values(release.RELEASE_TYPE))
|
||||
m.chai.expect(_.size(keys)).to.equal(_.size(uniqueValues))
|
||||
})
|
||||
})
|
||||
|
||||
describe('.getReleaseType()', function () {
|
||||
it('should return the unknown release type if the version is not valid semver', function () {
|
||||
const releaseType = release.getReleaseType('foo.bar')
|
||||
m.chai.expect(releaseType).to.equal(release.RELEASE_TYPE.UNKNOWN)
|
||||
})
|
||||
|
||||
describe('given the version has a short git commit hash build number', function () {
|
||||
it('should return the snapshot release type', function () {
|
||||
const releaseType = release.getReleaseType('1.0.0+6374412')
|
||||
m.chai.expect(releaseType).to.equal(release.RELEASE_TYPE.SNAPSHOT)
|
||||
})
|
||||
|
||||
it('should return the snapshot release type if the version has a pre release tag', function () {
|
||||
const releaseType = release.getReleaseType('1.0.0-beta.19+6374412')
|
||||
m.chai.expect(releaseType).to.equal(release.RELEASE_TYPE.SNAPSHOT)
|
||||
})
|
||||
})
|
||||
|
||||
describe('given the version has a long git commit hash build number', function () {
|
||||
it('should return the snapshot release type', function () {
|
||||
const releaseType = release.getReleaseType('1.0.0+6374412554b034799bfc6e13b4e39c3f5e6386e6')
|
||||
m.chai.expect(releaseType).to.equal(release.RELEASE_TYPE.SNAPSHOT)
|
||||
})
|
||||
|
||||
it('should return the snapshot release type if the version has a pre release tag', function () {
|
||||
const releaseType = release.getReleaseType('1.0.0-beta.19+6374412554b034799bfc6e13b4e39c3f5e6386e6')
|
||||
m.chai.expect(releaseType).to.equal(release.RELEASE_TYPE.SNAPSHOT)
|
||||
})
|
||||
})
|
||||
|
||||
describe('given the version has no build number', function () {
|
||||
it('should return the production release type', function () {
|
||||
const releaseType = release.getReleaseType('1.0.0')
|
||||
m.chai.expect(releaseType).to.equal(release.RELEASE_TYPE.PRODUCTION)
|
||||
})
|
||||
|
||||
it('should return the production release type if the version has a pre release tag', function () {
|
||||
const releaseType = release.getReleaseType('1.0.0-beta.19')
|
||||
m.chai.expect(releaseType).to.equal(release.RELEASE_TYPE.PRODUCTION)
|
||||
})
|
||||
})
|
||||
|
||||
describe('given a build number that is not a git commit hash', function () {
|
||||
it('should return the unknown release type', function () {
|
||||
const releaseType = release.getReleaseType('1.0.0+foo')
|
||||
m.chai.expect(releaseType).to.equal(release.RELEASE_TYPE.UNKNOWN)
|
||||
})
|
||||
|
||||
it('should return the unknown release type if the version has a pre release tag', function () {
|
||||
const releaseType = release.getReleaseType('1.0.0-beta.19+foo')
|
||||
m.chai.expect(releaseType).to.equal(release.RELEASE_TYPE.UNKNOWN)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.isStableRelease()', function () {
|
||||
it('should return true if given a production stable version', function () {
|
||||
m.chai.expect(release.isStableRelease('1.0.0')).to.be.true
|
||||
})
|
||||
|
||||
it('should return false if given a production release candidate version', function () {
|
||||
m.chai.expect(release.isStableRelease('1.0.0-rc.2')).to.be.false
|
||||
})
|
||||
|
||||
it('should return false if given a production beta version', function () {
|
||||
m.chai.expect(release.isStableRelease('1.0.0-beta.1')).to.be.false
|
||||
})
|
||||
|
||||
it('should return false if given a snapshot stable version', function () {
|
||||
m.chai.expect(release.isStableRelease('1.0.0+6374412')).to.be.false
|
||||
})
|
||||
|
||||
it('should return false if given a snapshot release candidate version', function () {
|
||||
m.chai.expect(release.isStableRelease('1.0.0-rc.2+6374412')).to.be.false
|
||||
})
|
||||
|
||||
it('should return false if given a snapshot beta version', function () {
|
||||
m.chai.expect(release.isStableRelease('1.0.0-beta.1+6374412')).to.be.false
|
||||
})
|
||||
})
|
||||
})
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user