feat: 🎸 Update desktop through menu option

This commit is contained in:
Susmitha Girumala committed 2021-04-12 10:42:34 -04:00
1 parent 31682ffd85
commit 53270519cb
8 files changed
+260 -30

No files matched your search

+4 -1
View File
@@ -93,4 +93,7 @@ ember-dist/
ember-test/
# CLI
cli/
cli/
# Autoupdate
nextVersion/
+1 -1
View File
@@ -10,7 +10,7 @@ const artifactDestination = path.resolve(__dirname, '..', 'cli');
const downloadArtifact = version => {
const url = `https://releases.hashicorp.com/boundary/${version}/boundary_${version}_darwin_amd64.zip`;
return new Promise((resolve, reject) => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'boundary-artifact-'))
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'boundary-artifact-'));
console.log('Create tmp artifact directory: ', tmpDir);
const artifactFileName = url.split('/').pop();
+22 -22
View File
@@ -26,33 +26,33 @@ module.exports = {
}
},
packagerConfig: {
ignore: [
"/ember-test(/|$)",
"/tests(/|$)"
],
name: "Boundary",
appBundleId: "com.electron.boundary",
ignore: ['/ember-test(/|$)', '/tests(/|$)'],
name: 'Boundary',
appBundleId: 'com.electron.boundary',
// TODO: where should the client version number come from?
appVersion: `${formattedAppVersion}${formattedCLIVersion}\n`,
appCopyright: "Copyright © 2021 HashiCorp, Inc.",
icon: "./config/macos/icon.icns",
appCopyright: 'Copyright © 2021 HashiCorp, Inc.',
icon: './config/macos/icon.icns',
osxSign: {
identity: process.env.BOUNDARY_DESKTOP_SIGNING_IDENTITY,
"hardened-runtime": true,
entitlements: "./config/macos/entitlements.plist",
"entitlements-inherit": "./config/macos/entitlements.plist",
"signature-flags": "library"
}
'hardened-runtime': true,
entitlements: './config/macos/entitlements.plist',
'entitlements-inherit': './config/macos/entitlements.plist',
'signature-flags': 'library',
},
},
makers: [
{
name: "@electron-forge/maker-dmg",
name: '@electron-forge/maker-dmg',
config: {
title: "Boundary",
name: "boundary",
icon: "./config/macos/disk.icns",
background: "./config/macos/background.png"
}
}
]
}
title: 'Boundary',
name: 'boundary',
icon: './config/macos/disk.icns',
background: './config/macos/background.png',
},
},
{
name: '@electron-forge/maker-zip',
},
],
};
+2
View File
@@ -25,11 +25,13 @@
"electron-is-dev": "^1.2.0",
"electron-squirrel-startup": "^1.0.0",
"lookpath": "^1.1.0",
"node-html-parser": "^3.1.3",
"shell-quote": "^1.7.2"
},
"devDependencies": {
"@electron-forge/cli": "6.0.0-beta.54",
"@electron-forge/maker-dmg": "^6.0.0-beta.54",
"@electron-forge/maker-zip": "^6.0.0-beta.54",
"decompress": "^4.2.1",
"devtron": "^1.4.0",
"electron": "12.0.2"
+123
View File
@@ -0,0 +1,123 @@
const fs = require('fs');
const path = require('path');
const https = require('https');
const { parse } = require('node-html-parser');
const { autoUpdater, dialog } = require('electron');
const debug = process.env.DEBUG_APP_UPDATER
const releasesUrl = 'https://releases.hashicorp.com/boundary-desktop/';
const currentVersion = '1.0.0-beta';
// Query releases url to find latest version
const findLatestVersion = (url) => {
return new Promise((resolve, reject) => {
let data = '';
https.get(url, (response) => {
response.on('data', (chunk) => (data += chunk));
response.on('end', () => {
const html = parse(data);
// Ignore first link as it navigates to root
const fullVersion = html.querySelectorAll('a')[1].innerHTML;
resolve(fullVersion.split('_')[1]);
});
response.on('error', (err) => reject(err));
});
});
};
// Create update config using downloaded archive
const createAppUpdaterConfig = (url, version, destination) => {
if (debug) console.log(`[app-updater] url: ${url}, destination: ${destination}`);
const json = { url, version};
const config = JSON.stringify(json);
const configPath = `${destination}/feed.json`;
if (debug) console.log(`[app-updater] config: ${config}`);
fs.writeFileSync(configPath, config);
return configPath;
};
const downloadAndInstallUpdate = async (version) => {
const url = `${releasesUrl}boundary-desktop_${version}/boundary-desktop_${version}_darwin_amd64.zip`;
const destination = path.resolve(__dirname, '..', 'nextVersion');
if (!fs.existsSync(destination)) fs.mkdirSync(destination);
try {
let configPath;
if (debug) {
// Support hosted url and file paths
const location = process.env.LATEST_VERSION_LOCATION;
configPath = createAppUpdaterConfig(
location.match(/^https/i) ? location : `file://${location}`,
version,
destination
);
} else {
configPath = createAppUpdaterConfig(url, version, destination);
}
autoUpdater.on('update-downloaded', () => {
const dialogOpts = {
type: 'info',
buttons: ['Restart', 'Later'],
detail:
'A new version has been downloaded. Restart the application to apply the updates.',
};
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) autoUpdater.quitAndInstall(true, true);
});
});
autoUpdater.on('error', (e) => {
dialog.showErrorBox('Could not update', e.message);
});
if (debug) console.log('[app-updater] config:', configPath);
autoUpdater.setFeedURL(`file://${configPath}`);
autoUpdater.checkForUpdates();
} catch (e) {
dialog.showErrorBox('Could not update', e.message);
}
};
/**
* Configure inbuilt app updater to use a custom config file
* to download and install next available app version.
* TODO: download progress in dialog
* TODO: Read current version from app config
**/
module.exports = {
run: async () => {
let latestVersion;
if (debug) {
latestVersion = process.env.LATEST_VERSION_TAG;
} else {
latestVersion = await findLatestVersion(releasesUrl);
}
// Update not available - do nothing
if (latestVersion <= currentVersion) {
const dialogOpts = {
type: 'info',
icon: null,
detail: 'No updates available',
};
dialog.showMessageBox(dialogOpts);
return;
}
// Update is available - prompt for download
const dialogOpts = {
type: 'info',
buttons: ['Download', 'Later'],
icon: null,
detail: 'A new version is available for download',
};
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
downloadAndInstallUpdate(latestVersion);
}
});
},
};
+7 -5
View File
@@ -11,6 +11,7 @@ const {
BrowserWindow,
ipcMain,
Menu,
MenuItem,
} = require('electron');
require('./handlers.js');
@@ -18,7 +19,6 @@ const origin = require('./origin.js');
const { generateCSPHeader } = require('./content-security-policy.js');
const menu = require('./menu.js');
const isDev = require('electron-is-dev');
// Register the custom file protocol
@@ -101,11 +101,13 @@ app.on('ready', async () => {
}
}
// Configure menu in prod env
if (!isDev) {
const menuTemplate = Menu.buildFromTemplate(menu.generateMenuTemplate());
Menu.setApplicationMenu(menuTemplate);
// Configure dev tools menu
const menuTemplate = Menu.buildFromTemplate(menu.generateMenuTemplate());
if (isDev) {
const view = menuTemplate.getMenuItemById('view');
view.submenu.append(new MenuItem({ role: 'toggleDevTools' }));
}
Menu.setApplicationMenu(menuTemplate);
mainWindow = new BrowserWindow({
width: 1280,
+7
View File
@@ -1,4 +1,5 @@
const { shell } = require('electron');
const appUpdater = require('./app-updater.js');
const generateMenuTemplate = () => {
return [
@@ -7,6 +8,11 @@ const generateMenuTemplate = () => {
label: 'Boundary',
submenu: [
{ role: 'about' },
{
id: 'update',
label: 'Check for Updates',
click: async () => appUpdater.run(),
},
{ type: 'separator' },
{ role: 'services' },
{ type: 'separator' },
@@ -44,6 +50,7 @@ const generateMenuTemplate = () => {
},
// { role: 'viewMenu' }
{
id: 'view',
label: 'View',
submenu: [
{ role: 'reload' },
+94 -1
View File
@@ -155,6 +155,16 @@
optionalDependencies:
electron-installer-dmg "^3.0.0"
"@electron-forge/maker-zip@^6.0.0-beta.54":
version "6.0.0-beta.54"
resolved "https://registry.yarnpkg.com/@electron-forge/maker-zip/-/maker-zip-6.0.0-beta.54.tgz#83d322afd912587fd233e87c30339d8150f29bed"
integrity sha512-wbJhK1rDOCZMTtKrjvavT8R+Yi+v/6axsnTXvzbkzzMQ0xADKNslTwzO6mmbBJea4oIbYmQ44DRAjI21TNyQ/A==
dependencies:
"@electron-forge/maker-base" "6.0.0-beta.54"
"@electron-forge/shared-types" "6.0.0-beta.54"
cross-zip "^3.0.0"
fs-extra "^9.0.1"
"@electron-forge/plugin-base@6.0.0-beta.54":
version "6.0.0-beta.54"
resolved "https://registry.yarnpkg.com/@electron-forge/plugin-base/-/plugin-base-6.0.0-beta.54.tgz#1847eeee00e9558d61ef9ff7c2d7c9f5dbf1109c"
@@ -508,6 +518,11 @@ bluebird@^3.1.1, bluebird@^3.5.0:
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
boolbase@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
boolean@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.0.2.tgz#df1baa18b6a2b0e70840475e1d93ec8fe75b2570"
@@ -791,6 +806,29 @@ cross-spawn@^7.0.1:
shebang-command "^2.0.0"
which "^2.0.1"
cross-zip@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/cross-zip/-/cross-zip-3.1.0.tgz#2b7d33f2a893bf83e232ccbabf4c6c706f6b313c"
integrity sha512-aX02l0SD3KE27pMl69gkxDdDM5D3u9Ic4Je+2b1B2fP0dWnlWWY6ns2Vk5DEgCXJRhL3GasSpicNQRNbDkq0+w==
dependencies:
rimraf "^3.0.0"
css-select@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/css-select/-/css-select-3.1.2.tgz#d52cbdc6fee379fba97fb0d3925abbd18af2d9d8"
integrity sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==
dependencies:
boolbase "^1.0.0"
css-what "^4.0.0"
domhandler "^4.0.0"
domutils "^2.4.3"
nth-check "^2.0.0"
css-what@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-4.0.0.tgz#35e73761cab2eeb3d3661126b23d7aa0e8432233"
integrity sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A==
currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
@@ -956,6 +994,36 @@ devtron@^1.4.0:
highlight.js "^9.3.0"
humanize-plus "^1.8.1"
dom-serializer@^1.0.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.2.0.tgz#3433d9136aeb3c627981daa385fc7f32d27c48f1"
integrity sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==
dependencies:
domelementtype "^2.0.1"
domhandler "^4.0.0"
entities "^2.0.0"
domelementtype@^2.0.1, domelementtype@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
domhandler@^4.0.0, domhandler@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.1.0.tgz#c1d8d494d5ec6db22de99e46a149c2a4d23ddd43"
integrity sha512-/6/kmsGlMY4Tup/nGVutdrK9yQi4YjWVcVeoQmixpzjOUK1U7pQkvAPHBJeUxOgxF0J8f8lwCJSlCfD0V4CMGQ==
dependencies:
domelementtype "^2.2.0"
domutils@^2.4.3:
version "2.5.1"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.5.1.tgz#9b8e84b5d9f788499ae77506ea832e9b4f9aa1c0"
integrity sha512-hO1XwHMGAthA/1KL7c83oip/6UWo3FlUNIuWiWKltoiQ5oCOiqths8KknvY2jpOohUoUgnwa/+Rm7UpwpSbY/Q==
dependencies:
dom-serializer "^1.0.1"
domelementtype "^2.2.0"
domhandler "^4.1.0"
ds-store@^0.1.5:
version "0.1.6"
resolved "https://registry.yarnpkg.com/ds-store/-/ds-store-0.1.6.tgz#d1024ef746ed0c13f0f7fec85c7e858e8c4b7ca7"
@@ -1102,6 +1170,11 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
entities@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
env-paths@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43"
@@ -1614,6 +1687,11 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
he@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
highlight.js@^10.4.1, highlight.js@^9.3.0:
version "10.6.0"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.6.0.tgz#0073aa71d566906965ba6e1b7be7b2682f5e18b6"
@@ -2277,6 +2355,14 @@ node-gyp@^7.1.0:
tar "^6.0.2"
which "^2.0.2"
node-html-parser@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-3.1.3.tgz#987d39bc8df27bc70cbe3b4e9a31fd84f7454dfb"
integrity sha512-pCE2I5UY5iOBnWdJQkbYZSk+fyq2zepw0nsELpHQjVFyCzOeZhkMhnvKqGceKgzWsWx7EG4KtMqsy9Eklf5Thw==
dependencies:
css-select "^3.1.2"
he "1.2.0"
node-pre-gyp@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054"
@@ -2369,6 +2455,13 @@ npmlog@^4.0.2, npmlog@^4.1.2:
gauge "~2.7.3"
set-blocking "~2.0.0"
nth-check@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125"
integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==
dependencies:
boolbase "^1.0.0"
nugget@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0"
@@ -2943,7 +3036,7 @@ rimraf@^2.6.1, rimraf@^2.7.1:
dependencies:
glob "^7.1.3"
rimraf@^3.0.2:
rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==