Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
219036c
chore: add new IPC to get fiddle start params from renderer
dsanders11 May 7, 2026
b44c80a
chore: remove unneeded // eslint-disable-next-line
dsanders11 May 7, 2026
3101b28
chore: refactor to start fiddle in main process
dsanders11 May 7, 2026
1a7446c
fix: change run button state to installing modules correctly
dsanders11 May 7, 2026
c627803
refactor: move plural-maybe.ts to common utils
dsanders11 May 7, 2026
5e4fdb9
chore: drop dead code
dsanders11 May 7, 2026
e4f6dec
Merge branch 'main' into build/refactor-start-fiddle-ipc
ckerr May 8, 2026
797af9b
Merge branch 'main' into build/refactor-start-fiddle-ipc
dsanders11 May 8, 2026
7ae3c84
Merge branch 'main' into build/refactor-start-fiddle-ipc
dsanders11 May 8, 2026
203f2e1
refactor: remove runner.stop wrapper method
dsanders11 May 8, 2026
201c809
chore: move push output helpers to utils
dsanders11 May 8, 2026
426b792
refactor: move bisect.ts to common utils
dsanders11 May 8, 2026
9787428
chore: move autobisect to main process
dsanders11 May 8, 2026
e4bec97
refactor(renderer): consolidate run and runFiddle
dsanders11 May 8, 2026
7c5e08f
chore: fixup starting fiddle during autobisect
dsanders11 May 8, 2026
9ffed57
refactor(renderer): do not call startFiddle from runFiddle
dsanders11 May 8, 2026
9e346c4
test: update test coverage
dsanders11 May 8, 2026
cd3fae1
chore: handle error case with getStartFiddleOptions
dsanders11 May 8, 2026
6c4a09f
fix: prevent simultaneous runs
dsanders11 May 8, 2026
06f434e
chore: dead code cleanup
dsanders11 May 8, 2026
433cba9
fix: restore security check in deleteUserData
dsanders11 May 8, 2026
057336f
fix: send fiddle stopped event on error
dsanders11 May 8, 2026
197c21e
fix: restore getFiles options
dsanders11 May 9, 2026
e34e3d1
Merge branch 'main' into build/refactor-start-fiddle-ipc
dsanders11 May 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions src/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
RunnableVersion,
SelectedLocalVersion,
SemVer,
StartFiddleParams,
StartFiddleOptions,
Version,
} from './interfaces';
import { App } from './renderer/app';
Expand Down Expand Up @@ -51,6 +51,10 @@ declare global {
type: 'fiddle-stopped',
listener: (code: number | null, signal: string | null) => void,
): void;
addEventListener(
type: 'is-auto-bisecting',
listener: (isAutoBisecting: boolean) => void,
): void;
addEventListener(
type: 'load-example',
listener: (exampleInfo: { path: string; tag: string }) => void,
Expand Down Expand Up @@ -93,14 +97,13 @@ declare global {
...names: Array<string>
): Promise<string>;
arch: string;
autobisectFiddle(versions: Array<RunnableVersion>): void;
blockAccelerators(acceleratorsToBlock: BlockableAccelerator[]): void;
cleanupDirectory(dir: string): Promise<boolean>;
confirmQuit(): void;
createThemeFile(
newTheme: FiddleTheme,
name?: string,
): Promise<LoadedFiddleTheme>;
deleteUserData(name: string): Promise<void>;
downloadVersion(
version: string,
opts?: Partial<DownloadVersionParams>,
Expand Down Expand Up @@ -143,6 +146,10 @@ declare global {
transforms: Array<FileTransformOperation>,
) => Promise<{ localPath?: string; files: Files }>,
);
onGetStartFiddleOptions(
callback: () => Promise<StartFiddleOptions>,
): void;
onSetVersion(callback: (version: string) => Promise<void>): void;
openThemeFolder(): Promise<void>;
packageRun(
{ dir, packageManager }: PMOperationOptions,
Expand All @@ -160,7 +167,7 @@ declare global {
setShowMeTemplate(template?: string): void;
showWarningDialog(messageOptions: MessageOptions): void;
showWindow(): void;
startFiddle(params: StartFiddleParams): Promise<void>;
startFiddle(): Promise<void>;
stopFiddle(): void;
themePath: string;
uncacheTypes(ver: RunnableVersion): Promise<void>;
Expand Down
15 changes: 9 additions & 6 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ export type FiddleEvent =
| 'electron-types-changed'
| 'execute-monaco-command'
| 'fiddle-runner-output'
| 'fiddle-modules-installed'
| 'fiddle-stopped'
| 'is-auto-bisecting'
| 'load-example'
| 'load-gist'
| 'make-fiddle'
Expand Down Expand Up @@ -288,14 +290,15 @@ export interface PackageJsonOptions {
includeDependencies?: boolean;
}

export interface StartFiddleParams {
localPath: string | undefined;
export interface StartFiddleOptions {
version: string;
enableElectronLogging: boolean;
isValidBuild: boolean; // If the localPath is a valid Electron build
version: string; // The user selected version
dir: string;
options: string[];
executionFlags: string[];
env: { [x: string]: string | undefined };
modules: Array<[string, string]>;
packageManager: IPackageManager;
useSocketFirewall: boolean;
isKeepingUserDataDirs: boolean;
}

export interface DownloadVersionParams {
Expand Down
8 changes: 6 additions & 2 deletions src/ipc-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,20 @@ export enum IpcEvents {
GET_ELECTRON_TYPES = 'GET_ELECTRON_TYPES',
UNWATCH_ELECTRON_TYPES = 'UNWATCH_ELECTRON_TYPES',
GET_NODE_TYPES = 'GET_NODE_TYPES',
CLEANUP_DIRECTORY = 'CLEANUP_DIRECTORY',
DELETE_USER_DATA = 'DELETE_USER_DATA',
SAVE_FILES_TO_TEMP = 'SAVE_FILES_TO_TEMP',
SAVED_LOCAL_FIDDLE = 'SAVED_LOCAL_FIDDLE',
GET_FILES = 'GET_FILES',
GET_START_FIDDLE_OPTIONS = 'GET_START_FIDDLE_OPTIONS',
SET_VERSION = 'SET_VERSION',
START_FIDDLE = 'START_FIDDLE',
STOP_FIDDLE = 'STOP_FIDDLE',
AUTOBISECT_FIDDLE = 'AUTOBISECT_FIDDLE',
IS_AUTO_BISECTING = 'IS_AUTO_BISECTING',
GET_VERSION_STATE = 'GET_VERSION_STATE',
DOWNLOAD_VERSION = 'DOWNLOAD_VERSION',
REMOVE_VERSION = 'REMOVE_VERSION',
FIDDLE_RUNNER_OUTPUT = 'FIDDLE_RUNNER_OUTPUT',
FIDDLE_MODULES_INSTALLED = 'FIDDLE_MODULES_INSTALLED',
FIDDLE_STOPPED = 'FIDDLE_STOPPED',
VERSION_DOWNLOAD_PROGRESS = 'VERSION_DOWNLOAD_PROGRESS',
VERSION_STATE_CHANGED = 'VERSION_STATE_CHANGED',
Expand Down Expand Up @@ -107,6 +110,7 @@ export const ipcMainEvents = [
IpcEvents.GET_RELEASED_VERSIONS,
IpcEvents.GET_USERNAME,
IpcEvents.STOP_FIDDLE,
IpcEvents.AUTOBISECT_FIDDLE,
IpcEvents.GET_VERSION_STATE,
] as const;

Expand Down
118 changes: 118 additions & 0 deletions src/main/autobisect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import type { IpcMainEvent, WebContents } from 'electron';

import { startFiddle } from './fiddle-core';
import { ipcMainManager } from './ipc';
import { pushOutputLine } from './utils/push-output';
import { setVersion } from './utils/set-version';
import { RunResult, RunnableVersion } from '../interfaces';
import { IpcEvents } from '../ipc-events';
import { Bisector } from '../utils/bisect';

const resultString: Record<RunResult, string> = Object.freeze({
[RunResult.FAILURE]: '❌ failed',
[RunResult.INVALID]: '❓ invalid',
[RunResult.SUCCESS]: '✅ passed',
});

/**
* Bisect the current fiddle across the specified versions.
*
* @param versions - versions to bisect
*/
async function autobisect(
webContents: WebContents,
versions: Array<RunnableVersion>,
) {
try {
ipcMainManager.send(IpcEvents.IS_AUTO_BISECTING, [true], webContents);
await autobisectImpl(webContents, versions);
} finally {
ipcMainManager.send(IpcEvents.IS_AUTO_BISECTING, [false], webContents);
}
}

async function autobisectImpl(
webContents: WebContents,
versions: Array<RunnableVersion>,
) {
const prefix = `Runner: autobisect`;

// precondition: can't bisect unless we have >= 2 versions
if (versions.length < 2) {
pushOutputLine(
webContents,
`${prefix} needs at least two Electron versions`,
);
return;
}

const results: Map<string, RunResult> = new Map();

const runVersion = async (version: string) => {
let result = results.get(version);
if (result === undefined) {
const pre = `${prefix} Electron ${version} -`;
pushOutputLine(webContents, `${pre} setting version`);
await setVersion(webContents, version);
pushOutputLine(webContents, `${pre} starting test`);
result = await startFiddle(webContents);
results.set(version, result);
pushOutputLine(
webContents,
`${pre} finished test ${resultString[result]}`,
);
}
return result;
};

const bisector = new Bisector(versions);
let targetVersion = bisector.getCurrentVersion();
let next;
while (true) {
const { version } = targetVersion;

const result = await runVersion(version);
if (result === RunResult.INVALID) {
return result;
}

next = bisector.continue(result === RunResult.SUCCESS);
if (Array.isArray(next)) {
break;
}

targetVersion = next;
}

const [good, bad] = next.map((v) => v.version);
const resultGood = await runVersion(good);
const resultBad = await runVersion(bad);
if (resultGood === resultBad) {
pushOutputLine(
webContents,
`${prefix} 'good' ${good} and 'bad' ${bad} both returned ${resultString[resultGood]}`,
);
return;
}

const msgs = [
`${prefix} complete`,
`${prefix} ${resultString[RunResult.SUCCESS]} ${good}`,
`${prefix} ${resultString[RunResult.FAILURE]} ${bad}`,
`${prefix} Commits between versions:`,
`https://github.com/electron/electron/compare/v${good}...v${bad}`,
];
msgs.forEach((msg) => pushOutputLine(webContents, msg));
}

/**
* Wire up the IPC handler so the renderer can trigger an autobisect.
*/
export function setupAutobisect(): void {
ipcMainManager.on(
IpcEvents.AUTOBISECT_FIDDLE,
(event: IpcMainEvent, versions: Array<RunnableVersion>) => {
autobisect(event.sender, versions).catch(console.error);
},
);
}
Loading
Loading