Merge pull request #2736 from balena-io/electron-updater-2

Add electron autoupdater
This commit is contained in:
Lorenzo Alberto Maria Ambrosi 2019-04-22 09:08:08 +02:00 committed by GitHub
commit 2fa5426cf5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 136 additions and 2419 deletions

4
dev-app-update.yml Normal file
View File

@ -0,0 +1,4 @@
owner: balena-io
repo: etcher
provider: github
updaterCacheDirName: balena-etcher-updater

View File

@ -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(() => {

View File

@ -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')
}
})
}

View File

@ -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

View File

@ -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
}
/**

View File

@ -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>

View File

@ -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)

View File

@ -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' ]))
])
}

View File

@ -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))
})
}

View File

@ -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
View File

@ -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",

View File

@ -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",

View File

@ -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)
})
})
})
})

View File

@ -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