fix: abort ShipIt installation attempt at the final mile if the app is running (#36130)

* fix: abort ShipIt installation attempt at the final mile if the app is running

* chore: remove only

* Update patches/squirrel.mac/fix_abort_installation_attempt_at_the_final_mile_if_the_app_is.patch

Co-authored-by: Jeremy Rose <jeremya@chromium.org>

* chore: update patches

* spec: make the ShipIt process lister helper more resilient

Co-authored-by: Jeremy Rose <jeremya@chromium.org>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
This commit is contained in:
Samuel Attard
2022-11-14 10:12:16 -08:00
committed by GitHub
parent 654e571512
commit d8bb172318
6 changed files with 191 additions and 28 deletions

View File

@@ -5,6 +5,7 @@ import * as express from 'express';
import * as fs from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import * as psList from 'ps-list';
import { AddressInfo } from 'net';
import { ifdescribe, ifit } from './spec-helpers';
import * as uuid from 'uuid';
@@ -95,6 +96,16 @@ ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch ===
return spawn(path.resolve(appPath, 'Contents/MacOS/Electron'), args);
};
const spawnAppWithHandle = (appPath: string, args: string[] = []) => {
return cp.spawn(path.resolve(appPath, 'Contents/MacOS/Electron'), args);
};
const getRunningShipIts = async (appPath: string) => {
const processes = await psList();
const activeShipIts = processes.filter(p => p.cmd?.includes('Squirrel.framework/Resources/ShipIt com.github.Electron.ShipIt') && p.cmd!.startsWith(appPath));
return activeShipIts;
};
const withTempDirectory = async (fn: (dir: string) => Promise<void>, autoCleanUp = true) => {
const dir = await fs.mkdtemp(path.resolve(os.tmpdir(), 'electron-update-spec-'));
try {
@@ -323,6 +334,71 @@ ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch ===
});
});
it('should abort the update if the application is still running when ShipIt kicks off', async () => {
await withUpdatableApp({
nextVersion: '2.0.0',
startFixture: 'update',
endFixture: 'update'
}, async (appPath, updateZipPath) => {
server.get('/update-file', (req, res) => {
res.download(updateZipPath);
});
server.get('/update-check', (req, res) => {
res.json({
url: `http://localhost:${port}/update-file`,
name: 'My Release Name',
notes: 'Theses are some release notes innit',
pub_date: (new Date()).toString()
});
});
enum FlipFlop {
INITIAL,
FLIPPED,
FLOPPED,
}
const shipItFlipFlopPromise = new Promise<void>((resolve) => {
let state = FlipFlop.INITIAL;
const checker = setInterval(async () => {
const running = await getRunningShipIts(appPath);
switch (state) {
case FlipFlop.INITIAL: {
if (running.length) state = FlipFlop.FLIPPED;
break;
}
case FlipFlop.FLIPPED: {
if (!running.length) state = FlipFlop.FLOPPED;
break;
}
}
if (state === FlipFlop.FLOPPED) {
clearInterval(checker);
resolve();
}
}, 500);
});
const launchResult = await launchApp(appPath, [`http://localhost:${port}/update-check`]);
const retainerHandle = spawnAppWithHandle(appPath, ['remain-open']);
logOnError(launchResult, () => {
expect(launchResult).to.have.property('code', 0);
expect(launchResult.out).to.include('Update Downloaded');
expect(requests).to.have.lengthOf(2);
expect(requests[0]).to.have.property('url', '/update-check');
expect(requests[1]).to.have.property('url', '/update-file');
expect(requests[0].header('user-agent')).to.include('Electron/');
expect(requests[1].header('user-agent')).to.include('Electron/');
});
await shipItFlipFlopPromise;
expect(requests).to.have.lengthOf(2, 'should not have relaunched the updated app');
expect(JSON.parse(await fs.readFile(path.resolve(appPath, 'Contents/Resources/app/package.json'), 'utf8')).version).to.equal('1.0.0', 'should still be the old version on disk');
retainerHandle.kill('SIGINT');
});
});
describe('with SquirrelMacEnableDirectContentsWrite enabled', () => {
let previousValue: any;

View File

@@ -15,28 +15,34 @@ autoUpdater.on('error', (err) => {
const urlPath = path.resolve(__dirname, '../../../../url.txt');
let feedUrl = process.argv[1];
if (!feedUrl || !feedUrl.startsWith('http')) {
feedUrl = `${fs.readFileSync(urlPath, 'utf8')}/${app.getVersion()}`;
if (feedUrl === 'remain-open') {
// Hold the event loop
setInterval(() => {});
} else {
fs.writeFileSync(urlPath, `${feedUrl}/updated`);
if (!feedUrl || !feedUrl.startsWith('http')) {
feedUrl = `${fs.readFileSync(urlPath, 'utf8')}/${app.getVersion()}`;
} else {
fs.writeFileSync(urlPath, `${feedUrl}/updated`);
}
autoUpdater.setFeedURL({
url: feedUrl
});
autoUpdater.checkForUpdates();
autoUpdater.on('update-available', () => {
console.log('Update Available');
});
autoUpdater.on('update-downloaded', () => {
console.log('Update Downloaded');
autoUpdater.quitAndInstall();
});
autoUpdater.on('update-not-available', () => {
console.error('No update available');
process.exit(1);
});
}
autoUpdater.setFeedURL({
url: feedUrl
});
autoUpdater.checkForUpdates();
autoUpdater.on('update-available', () => {
console.log('Update Available');
});
autoUpdater.on('update-downloaded', () => {
console.log('Update Downloaded');
autoUpdater.quitAndInstall();
});
autoUpdater.on('update-not-available', () => {
console.error('No update available');
process.exit(1);
});

View File

@@ -23,6 +23,7 @@
"mocha-junit-reporter": "^1.18.0",
"mocha-multi-reporters": "^1.1.7",
"pdfjs-dist": "^2.2.228",
"ps-list": "^7.0.0",
"q": "^1.5.1",
"send": "^0.16.2",
"sinon": "^9.0.1",

View File

@@ -73,10 +73,9 @@
dependencies:
"@types/node" "*"
abstract-socket@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/abstract-socket/-/abstract-socket-2.1.1.tgz#243a7e6e6ff65bb9eab16a22fa90699b91e528f7"
integrity sha512-YZJizsvS1aBua5Gd01woe4zuyYBGgSMeqDOB6/ChwdTI904KP6QGtJswXl4hcqWxbz86hQBe++HWV0hF1aGUtA==
"abstract-socket@github:saghul/node-abstractsocket#35b1b1491fabc04899bde5be3428abf5cf9cd528":
version "2.1.0"
resolved "https://codeload.github.com/saghul/node-abstractsocket/tar.gz/35b1b1491fabc04899bde5be3428abf5cf9cd528"
dependencies:
bindings "^1.2.1"
nan "^2.12.1"
@@ -303,7 +302,7 @@ dashdash@^1.12.0:
safe-buffer "^5.1.1"
xml2js "^0.4.17"
optionalDependencies:
abstract-socket "^2.0.0"
abstract-socket "github:saghul/node-abstractsocket#35b1b1491fabc04899bde5be3428abf5cf9cd528"
debug@2.6.9, debug@^2.2.0:
version "2.6.9"
@@ -937,6 +936,11 @@ performance-now@^2.1.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
ps-list@^7.0.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/ps-list/-/ps-list-7.2.0.tgz#3d110e1de8249a4b178c9b1cf2a215d1e4e42fc0"
integrity sha512-v4Bl6I3f2kJfr5o80ShABNHAokIgY+wFDTQfE+X3zWYgSGQOCBeYptLZUpoOALBqO5EawmDN/tjTldJesd0ujQ==
psl@^1.1.24:
version "1.9.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"