Beta versions support: SxS support, in-app env/instance display (#1606)
* Script for beta config; unique data dir, in-app env/type display To release a beta build, increment the version and add -beta-N to the end, then go through all the standard release activities. The prepare-build npm script then updates key bits of the package.json to ensure that the beta build can be installed alongside a production build. This includes a new name ('Signal Beta') and a different location for application data. Note: Beta builds can be installed alongside production builds. As part of this, a couple new bits of data are shown across the app: - Environment (development or test, not shown if production) - App Instance (disabled in production; used for multiple accounts) These are shown in: - The window title - both environment and app instance. You can tell beta builds because the app name, preceding these data bits, is different. - The about window - both environment and app instance. You can tell beta builds from the version number. - The header added to the debug log - just environment. The version number will tell us if it's a beta build, and app instance isn't helpful. * Turn on single-window mode in non-production modes Because it's really frightening when you see 'unable to read from db' errors in the console. * aply.sh: More instructions for initial setup and testing * Gruntfile: Get consistent with use of package.json datas * Linux: manually update desktop keys, since macros not available
This commit is contained in:
parent
a3fbb9a6aa
commit
c94d4efd18
13 changed files with 158 additions and 34 deletions
|
@ -8,6 +8,7 @@ install:
|
|||
- yarn install
|
||||
script:
|
||||
- yarn run generate
|
||||
- yarn prepare-build
|
||||
- ./node_modules/.bin/build --em.environment=$SIGNAL_ENV --config.mac.bundleVersion='$TRAVIS_BUILD_NUMBER' --publish=never
|
||||
- ./travis.sh
|
||||
env:
|
||||
|
|
18
Gruntfile.js
18
Gruntfile.js
|
@ -1,4 +1,5 @@
|
|||
var path = require('path');
|
||||
var packageJson = require('./package.json');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
'use strict';
|
||||
|
@ -204,23 +205,23 @@ module.exports = function(grunt) {
|
|||
},
|
||||
'test-release': {
|
||||
osx: {
|
||||
archive: 'mac/Signal.app/Contents/Resources/app.asar',
|
||||
appUpdateYML: 'mac/Signal.app/Contents/Resources/app-update.yml',
|
||||
exe: 'mac/Signal.app/Contents/MacOS/Signal'
|
||||
archive: 'mac/' + packageJson.productName + '.app/Contents/Resources/app.asar',
|
||||
appUpdateYML: 'mac/' + packageJson.productName + '.app/Contents/Resources/app-update.yml',
|
||||
exe: 'mac/' + packageJson.productName + '.app/Contents/MacOS/' + packageJson.productName
|
||||
},
|
||||
mas: {
|
||||
archive: 'mas/Signal.app/Contents/Resources/app.asar',
|
||||
appUpdateYML: 'mac/Signal.app/Contents/Resources/app-update.yml',
|
||||
exe: 'mas/Signal.app/Contents/MacOS/Signal'
|
||||
exe: 'mas/' + packageJson.productName + '.app/Contents/MacOS/' + packageJson.productName
|
||||
},
|
||||
linux: {
|
||||
archive: 'linux-unpacked/resources/app.asar',
|
||||
exe: 'linux-unpacked/signal-desktop'
|
||||
exe: 'linux-unpacked/' + packageJson.name
|
||||
},
|
||||
win: {
|
||||
archive: 'win-unpacked/resources/app.asar',
|
||||
appUpdateYML: 'win-unpacked/resources/app-update.yml',
|
||||
exe: 'win-unpacked/Signal.exe'
|
||||
exe: 'win-unpacked/' + packageJson.productName + '.exe'
|
||||
}
|
||||
},
|
||||
gitinfo: {} // to be populated by grunt gitinfo
|
||||
|
@ -273,7 +274,6 @@ module.exports = function(grunt) {
|
|||
require('mkdirp').sync('release');
|
||||
var fs = require('fs');
|
||||
var done = this.async();
|
||||
var package_json = grunt.config.get('pkg');
|
||||
var gitinfo = grunt.config.get('gitinfo');
|
||||
var https = require('https');
|
||||
|
||||
|
@ -281,7 +281,7 @@ module.exports = function(grunt) {
|
|||
var keyBase = 'WhisperSystems/Signal-Desktop';
|
||||
var sha = gitinfo.local.branch.current.SHA;
|
||||
var files = [{
|
||||
zip: 'signal-desktop-' + package_json.version + '.zip',
|
||||
zip: packageJson.name + '-' + packageJson.version + '.zip',
|
||||
extractedTo: 'linux'
|
||||
}];
|
||||
|
||||
|
@ -451,7 +451,7 @@ module.exports = function(grunt) {
|
|||
return app.client.getTitle();
|
||||
}).then(function (title) {
|
||||
// Verify the window's title
|
||||
assert.equal(title, 'Signal');
|
||||
assert.equal(title, packageJson.productName);
|
||||
console.log('title ok');
|
||||
}).then(function () {
|
||||
assert(app.chromeDriver.logLines.indexOf('NODE_ENV ' + environment) > -1);
|
||||
|
|
14
about.html
14
about.html
|
@ -30,6 +30,20 @@ a {
|
|||
document.write('v', window.config.version);
|
||||
</script>
|
||||
</div>
|
||||
<div>
|
||||
<script>
|
||||
var states = [];
|
||||
|
||||
if (window.config.environment !== 'production') {
|
||||
states.push(window.config.environment);
|
||||
}
|
||||
if (window.config.appInstance) {
|
||||
states.push(window.config.appInstance);
|
||||
}
|
||||
|
||||
document.write(states.join(' - '));
|
||||
</script>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://signal.org">signal.org</a>
|
||||
</div>
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
console.log('reading package.json');
|
||||
const jsonFile = fs.readFileSync(path.join(__dirname, '..', 'package.json'));
|
||||
const package_json = JSON.parse(jsonFile, 'utf-8');
|
||||
const environment = package_json.environment || process.env.NODE_ENV || 'development';
|
||||
const packageJson = require('../package.json');
|
||||
|
||||
console.log('configuring');
|
||||
|
||||
const environment = packageJson.environment || process.env.NODE_ENV || 'development';
|
||||
|
||||
// Set environment vars to configure node-config before requiring it
|
||||
process.env.NODE_ENV = environment;
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
const app = require('electron').app;
|
||||
const path = require('path');
|
||||
|
||||
const app = require('electron').app;
|
||||
const ElectronConfig = require('electron-config');
|
||||
|
||||
const config = require('./config');
|
||||
|
||||
|
||||
// use a separate data directory for development
|
||||
if (config.has('storageProfile')) {
|
||||
const userData = path.join(
|
||||
|
|
|
@ -16,6 +16,7 @@ build_script:
|
|||
- node build\grunt.js
|
||||
- type package.json | findstr /v certificateSubjectName > temp.json
|
||||
- move temp.json package.json
|
||||
- yarn prepare-build
|
||||
- node_modules\.bin\build --em.environment=%SIGNAL_ENV% --publish=never
|
||||
|
||||
test_script:
|
||||
|
|
30
aptly.sh
30
aptly.sh
|
@ -1,18 +1,40 @@
|
|||
#!/bin/bash
|
||||
# Setup:
|
||||
# Setup - creates the local repo which will be mirrored up to S3, then back-fill it. Your
|
||||
# future deploys will eliminate all old versions without these backfill steps:
|
||||
# aptly repo create signal-desktop
|
||||
# aptly mirror create -ignore-signatures backfill-mirror https://updates.signal.org/desktop/apt xenial
|
||||
# aptly mirror update -ignore-signatures backfill-mirror
|
||||
# aptly repo import backfill-mirror signal-desktop signal-desktop signal-desktop-beta
|
||||
# aptly repo show -with-packages signal-desktop
|
||||
#
|
||||
# First run on a machine - uncomment the first two 'aptly publish snapshot' commands,
|
||||
# comment the other two. Sets up the two publish channels, one local, one to S3.
|
||||
#
|
||||
# Testing - comment out the lines with s3:$ENDPOINT to publish only locally. To eliminate
|
||||
# effects of testing, remove package from repo, then move back to old snapshot:
|
||||
# aptly repo remove signal-desktop signal-desktop_1.0.35_amd64
|
||||
# aptly publish switch -gpg-key=57F6FB06 xenial signal-desktop_v1.0.34
|
||||
#
|
||||
# Release:
|
||||
# VERSION=X.X.X ./aptly.sh
|
||||
# NAME=signal-desktop(-beta) VERSION=X.X.X ./aptly.sh
|
||||
|
||||
echo "Releasing $NAME build version $VERSION"
|
||||
|
||||
REPO=signal-desktop
|
||||
DISTRO=xenial
|
||||
ENDPOINT=signal-desktop-apt # Matches endpoint name in .aptly.conf
|
||||
DEB_PATH=release
|
||||
SNAPSHOT=signal-desktop_v$VERSION
|
||||
GPG_KEYID=57F6FB06
|
||||
aptly repo add $REPO $DEB_PATH/$REPO\_$VERSION\_*.deb
|
||||
|
||||
aptly repo add $REPO release/$NAME\_$VERSION\_*.deb
|
||||
aptly snapshot create $SNAPSHOT from repo $REPO
|
||||
|
||||
# run these two only on first release to a given repo from a given machine
|
||||
# https://www.aptly.info/doc/aptly/publish/snapshot/
|
||||
# aptly publish snapshot -gpg-key=$GPG_KEYID $SNAPSHOT
|
||||
# aptly publish snapshot -gpg-key=$GPG_KEYID -config=.aptly.conf $SNAPSHOT s3:$ENDPOINT:
|
||||
|
||||
# these update already-published repos, run every time after that
|
||||
# https://www.aptly.info/doc/aptly/publish/switch/
|
||||
aptly publish switch -gpg-key=$GPG_KEYID $DISTRO $SNAPSHOT
|
||||
aptly publish switch -gpg-key=$GPG_KEYID -config=.aptly.conf $DISTRO s3:$ENDPOINT: $SNAPSHOT
|
||||
|
|
|
@ -14,6 +14,15 @@
|
|||
var initialLoadComplete = false;
|
||||
window.owsDesktopApp = {};
|
||||
|
||||
var title = window.config.name;
|
||||
if (window.config.environment !== 'production') {
|
||||
title += ' - ' + window.config.environment;
|
||||
}
|
||||
if (window.config.appInstance) {
|
||||
title += ' - ' + window.config.appInstance;
|
||||
}
|
||||
window.config.title = window.document.title = title;
|
||||
|
||||
// start a background worker for ecc
|
||||
textsecure.startWorker('js/libsignal-protocol-worker.js');
|
||||
Whisper.KeyChangeListener.init(textsecure.storage.protocol);
|
||||
|
|
|
@ -64,10 +64,10 @@
|
|||
|
||||
if (newUnreadCount > 0) {
|
||||
window.setBadgeCount(newUnreadCount);
|
||||
window.document.title = "Signal (" + newUnreadCount + ")";
|
||||
window.document.title = window.config.title + " (" + newUnreadCount + ")";
|
||||
} else {
|
||||
window.setBadgeCount(0);
|
||||
window.document.title = "Signal";
|
||||
window.document.title = window.config.title;
|
||||
}
|
||||
},
|
||||
startPruning: function() {
|
||||
|
|
|
@ -69,7 +69,12 @@ if (window.console) {
|
|||
// The mechanics of preparing a log for publish
|
||||
|
||||
function getHeader() {
|
||||
return window.navigator.userAgent + ' node/' + window.config.node_version;
|
||||
let header = window.navigator.userAgent;
|
||||
|
||||
header += ' node/' + window.config.node_version;
|
||||
header += ' env/' + window.config.environment;
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
function getLevel(level) {
|
||||
|
|
23
main.js
23
main.js
|
@ -3,7 +3,7 @@ const url = require('url');
|
|||
const os = require('os');
|
||||
|
||||
const _ = require('lodash');
|
||||
const electron = require('electron')
|
||||
const electron = require('electron');
|
||||
|
||||
const BrowserWindow = electron.BrowserWindow;
|
||||
const app = electron.app;
|
||||
|
@ -11,20 +11,26 @@ const ipc = electron.ipcMain;
|
|||
const Menu = electron.Menu;
|
||||
const shell = electron.shell;
|
||||
|
||||
const packageJson = require('./package.json');
|
||||
const autoUpdate = require('./app/auto_update');
|
||||
const windowState = require('./app/window_state');
|
||||
|
||||
|
||||
console.log('setting AUMID');
|
||||
app.setAppUserModelId('org.whispersystems.signal-desktop')
|
||||
const aumid = 'org.whispersystems.' + packageJson.name;
|
||||
console.log('setting AUMID to ' + aumid);
|
||||
app.setAppUserModelId(aumid);
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow;
|
||||
|
||||
const config = require("./app/config");
|
||||
|
||||
if (config.environment === 'production' && !process.mas) {
|
||||
// Very important to put before the single instance check, since it is based on the
|
||||
// userData directory.
|
||||
const userConfig = require('./app/user_config');
|
||||
|
||||
if (!process.mas) {
|
||||
console.log('making app single instance');
|
||||
var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
|
||||
// Someone tried to run a second instance, we should focus our window
|
||||
|
@ -36,16 +42,15 @@ if (config.environment === 'production' && !process.mas) {
|
|||
});
|
||||
|
||||
if (shouldQuit) {
|
||||
console.log('quitting');
|
||||
console.log('quitting; we are the second instance');
|
||||
app.quit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const userConfig = require('./app/user_config');
|
||||
const logging = require('./app/logging');
|
||||
|
||||
// this must be after we set up appPath in user_config.js
|
||||
// This must be after we set up appPath in user_config.js, so we know where logs go
|
||||
logging.initialize();
|
||||
const logger = logging.getLogger();
|
||||
|
||||
|
@ -60,6 +65,7 @@ function prepareURL(pathSegments) {
|
|||
protocol: 'file:',
|
||||
slashes: true,
|
||||
query: {
|
||||
name: packageJson.productName,
|
||||
locale: locale.name,
|
||||
version: app.getVersion(),
|
||||
buildExpiration: config.get('buildExpiration'),
|
||||
|
@ -69,6 +75,7 @@ function prepareURL(pathSegments) {
|
|||
environment: config.environment,
|
||||
node_version: process.versions.node,
|
||||
hostname: os.hostname(),
|
||||
appInstance: process.env.NODE_APP_INSTANCE,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
"build": "build --em.environment=$SIGNAL_ENV",
|
||||
"dist": "npm run generate && npm run build",
|
||||
"pack": "npm run generate && npm run build -- --dir",
|
||||
"prepare-build": "node prepare_build.js",
|
||||
"pack-prod": "SIGNAL_ENV=production npm run pack",
|
||||
"dist-prod": "SIGNAL_ENV=production npm run dist",
|
||||
"dist-prod-all": "SIGNAL_ENV=production npm run dist -- -mwl",
|
||||
|
@ -51,13 +52,13 @@
|
|||
"prep-release": "npm run generate && grunt prep-release && npm run build-release && npm run build-mas-release && grunt test-release",
|
||||
"release-mac": "npm run build-release -- -m --prepackaged release/mac/Signal.app --publish=always",
|
||||
"release-win": "npm run build-release -- -w --prepackaged release/windows --publish=always",
|
||||
"release-lin": "npm run build-release -- -l --prepackaged release/linux && VERSION=$npm_package_version ./aptly.sh",
|
||||
"release-lin": "npm run build-release -- -l --prepackaged release/linux && NAME=$npm_package_name VERSION=$npm_package_version ./aptly.sh",
|
||||
"release": "npm run release-mac && npm run release-win && npm run release-lin"
|
||||
},
|
||||
"build": {
|
||||
"appId": "org.whispersystems.signal-desktop",
|
||||
"mac": {
|
||||
"artifactName": "${productName}-mac-${version}.${ext}",
|
||||
"artifactName": "${name}-mac-${version}.${ext}",
|
||||
"category": "public.app-category.social-networking",
|
||||
"icon": "build/icons/mac/icon.icns",
|
||||
"publish": [
|
||||
|
@ -81,7 +82,7 @@
|
|||
},
|
||||
"win": {
|
||||
"asarUnpack": "node_modules/spellchecker/vendor/hunspell_dictionaries",
|
||||
"artifactName": "${productName}-win-${version}.${ext}",
|
||||
"artifactName": "${name}-win-${version}.${ext}",
|
||||
"certificateSubjectName": "Signal",
|
||||
"publisherName": "Signal (Quiet Riddle Ventures, LLC)",
|
||||
"icon": "build/icons/win/icon.ico",
|
||||
|
|
65
prepare_build.js
Normal file
65
prepare_build.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
const fs = require('fs');
|
||||
const _ = require('lodash');
|
||||
|
||||
const packageJson = require('./package.json');
|
||||
const version = packageJson.version;
|
||||
const beta = /beta/;
|
||||
|
||||
// You might be wondering why this file is necessary. It comes down to our desire to allow
|
||||
// side-by-side installation of production and beta builds. Electron-Builder uses
|
||||
// top-level data from package.json for many things, like the executable name, the
|
||||
// debian package name, the install directory under /opt on linux, etc. We tried
|
||||
// adding the ${channel} macro to these values, but Electron-Builder didn't like that.
|
||||
|
||||
if (!beta.test(version)) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('prepare_build: updating package.json for beta build');
|
||||
|
||||
// -------
|
||||
|
||||
const NAME_PATH = 'name';
|
||||
const PRODUCTION_NAME = 'signal-desktop';
|
||||
const BETA_NAME = 'signal-desktop-beta';
|
||||
|
||||
const PRODUCT_NAME_PATH = 'productName';
|
||||
const PRODUCTION_PRODUCT_NAME = 'Signal';
|
||||
const BETA_PRODUCT_NAME = 'Signal Beta';
|
||||
|
||||
const APP_ID_PATH = 'build.appId';
|
||||
const PRODUCTION_APP_ID = 'org.whispersystems.signal-desktop';
|
||||
const BETA_APP_ID = 'org.whispersystems.signal-desktop-beta';
|
||||
|
||||
const STARTUP_WM_CLASS_PATH = 'build.linux.desktop.StartupWMClass';
|
||||
const PRODUCTION_STARTUP_WM_CLASS = 'Signal';
|
||||
const BETA_STARTUP_WM_CLASS = 'Signal Beta';
|
||||
|
||||
|
||||
|
||||
// -------
|
||||
|
||||
function checkValue(object, objectPath, expected) {
|
||||
const actual = _.get(object, objectPath)
|
||||
if (actual !== expected) {
|
||||
throw new Error(objectPath + ' was ' + actual + '; expected ' + expected);
|
||||
}
|
||||
}
|
||||
|
||||
// ------
|
||||
|
||||
checkValue(packageJson, NAME_PATH, PRODUCTION_NAME);
|
||||
checkValue(packageJson, PRODUCT_NAME_PATH, PRODUCTION_PRODUCT_NAME);
|
||||
checkValue(packageJson, APP_ID_PATH, PRODUCTION_APP_ID);
|
||||
checkValue(packageJson, STARTUP_WM_CLASS_PATH, PRODUCTION_STARTUP_WM_CLASS);
|
||||
|
||||
// -------
|
||||
|
||||
_.set(packageJson, NAME_PATH, BETA_NAME);
|
||||
_.set(packageJson, PRODUCT_NAME_PATH, BETA_PRODUCT_NAME);
|
||||
_.set(packageJson, APP_ID_PATH, BETA_APP_ID);
|
||||
_.set(packageJson, STARTUP_WM_CLASS_PATH, BETA_STARTUP_WM_CLASS);
|
||||
|
||||
// -------
|
||||
|
||||
fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, ' '));
|
Loading…
Reference in a new issue