Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: register-local-version protocol command #1652

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
8 changes: 8 additions & 0 deletions src/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ declare global {
type: 'open-template',
listener: (name: string, editorValues: EditorValues) => void,
): void;
addEventListener(
type: 'register-local-version',
listener: (info: {
name: string;
path: string;
version: string;
}) => void,
): void;
addEventListener(
type: 'saved-local-fiddle',
listener: (filePath: string) => void,
Expand Down
2 changes: 2 additions & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export type FileTransformOperation = 'dotfiles' | 'forge';
export enum VersionSource {
remote = 'remote',
local = 'local',
pullRequest = 'pull-request',
}

export enum GistActionType {
Expand Down Expand Up @@ -186,6 +187,7 @@ export type FiddleEvent =
| 'open-template'
| 'package-fiddle'
| 'redo-in-editor'
| 'register-local-version'
| 'run-fiddle'
| 'save-fiddle-gist'
| 'saved-local-fiddle'
Expand Down
1 change: 1 addition & 0 deletions src/ipc-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export enum IpcEvents {
SHOW_WELCOME_TOUR = 'SHOW_WELCOME_TOUR',
CLEAR_CONSOLE = 'CLEAR_CONSOLE',
LOAD_LOCAL_VERSION_FOLDER = 'LOAD_LOCAL_VERSION_FOLDER',
REGISTER_LOCAL_VERSION_FOLDER = 'REGISTER_LOCAL_VERSION_FOLDER',
BISECT_COMMANDS_TOGGLE = 'BISECT_COMMANDS_TOGGLE',
BEFORE_QUIT = 'BEFORE_QUIT',
CONFIRM_QUIT = 'CONFIRM_QUIT',
Expand Down
11 changes: 1 addition & 10 deletions src/main/dialogs.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import * as path from 'node:path';

import { Installer } from '@electron/fiddle-core';
import { BrowserWindow, dialog } from 'electron';
import * as fs from 'fs-extra';

import { ipcMainManager } from './ipc';
import { isValidElectronPath } from './utils/local-version';
import { SelectedLocalVersion } from '../interfaces';
import { IpcEvents } from '../ipc-events';

Expand All @@ -31,14 +30,6 @@ function makeLocalName(folderPath: string): string {
return `${leader} - ${buildType}`;
}

/**
* Verifies if the local electron path is valid
*/
function isValidElectronPath(folderPath: string): boolean {
const execPath = Installer.getExecPath(folderPath);
return fs.existsSync(execPath);
}

/**
* Listens to IPC events related to dialogs and message boxes
*/
Expand Down
33 changes: 33 additions & 0 deletions src/main/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { app } from 'electron';
import { openFiddle } from './files';
import { ipcMainManager } from './ipc';
import { isDevMode } from './utils/devmode';
import { isValidElectronPath } from './utils/local-version';
import { getOrCreateMainWindow } from './windows';
import { IpcEvents } from '../ipc-events';

Expand Down Expand Up @@ -65,6 +66,38 @@ const handlePotentialProtocolLaunch = (url: string) => {
return;
}
break;
// electron-fiddle://register-local-version/?name={name}&path={path}&version={version}
case 'register-local-version': {
if (pathParts.length === 1) {
const name = parsed.searchParams.get('name');
const localPath = parsed.searchParams.get('path');
const version = parsed.searchParams.get('version');

if (!(name && localPath && version)) {
console.debug('register-local-version: Missing params');
return;
}

if (!isValidElectronPath(localPath)) {
console.debug(`register-local-version: Invalid path ${localPath}`);
return;
}

const toAdd = {
name,
path: localPath,
version,
};

console.debug('register-local-version: Registering version', toAdd);

ipcMainManager.send(IpcEvents.REGISTER_LOCAL_VERSION_FOLDER, [toAdd]);
} else {
// Invalid
return;
}
break;
}
default:
return;
}
Expand Down
11 changes: 11 additions & 0 deletions src/main/utils/local-version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as fs from 'fs';
samuelmaddock marked this conversation as resolved.
Show resolved Hide resolved

import { Installer } from '@electron/fiddle-core';

/**
* Verifies if the local electron path is valid
*/
export function isValidElectronPath(folderPath: string): boolean {
const execPath = Installer.getExecPath(folderPath);
return fs.existsSync(execPath);
}
1 change: 1 addition & 0 deletions src/preload/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const channelMapping: Record<FiddleEvent, IpcEvents> = {
'open-settings': IpcEvents.OPEN_SETTINGS,
'open-template': IpcEvents.FS_OPEN_TEMPLATE,
'package-fiddle': IpcEvents.FIDDLE_PACKAGE,
'register-local-version': IpcEvents.REGISTER_LOCAL_VERSION_FOLDER,
'redo-in-editor': IpcEvents.REDO_IN_EDITOR,
'run-fiddle': IpcEvents.FIDDLE_RUN,
'saved-local-fiddle': IpcEvents.SAVED_LOCAL_FIDDLE,
Expand Down
18 changes: 18 additions & 0 deletions src/renderer/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
PACKAGE_NAME,
PackageJsonOptions,
SetFiddleOptions,
Version,
} from '../interfaces';
import { defaultDark, defaultLight } from '../themes-defaults';

Expand Down Expand Up @@ -137,6 +138,7 @@ export class App {
this.setupTitleListeners();
this.setupUnloadListeners();
this.setupTypeListeners();
this.setupProtocolListeners();

window.ElectronFiddle.sendReady();

Expand Down Expand Up @@ -310,4 +312,20 @@ export class App {
};
});
}

public setupProtocolListeners() {
window.ElectronFiddle.addEventListener(
'register-local-version',
({ name, path, version }) => {
const toAdd: Version = {
localPath: path,
version,
name,
};

this.state.addLocalVersion(toAdd);
this.state.setVersion(version);
},
);
}
}
10 changes: 8 additions & 2 deletions src/renderer/versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,16 @@ export function getElectronVersions(): Array<RunnableVersion> {
export function addLocalVersion(input: Version): Array<Version> {
const versions = getLocalVersions();

if (!versions.find((v) => v.localPath === input.localPath)) {
versions.push(input);
// Replace existing local version if it exists
const existingVersionIndex = versions.findIndex(
(v) => v.localPath === input.localPath,
);
if (existingVersionIndex > -1) {
versions.splice(existingVersionIndex, 1);
}

versions.push(input);

saveLocalVersions(versions);

return versions;
Expand Down
64 changes: 64 additions & 0 deletions tests/main/protocol-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

import * as fs from 'node:fs';
import * as path from 'node:path';

import { app } from 'electron';
import { mocked } from 'jest-mock';
Expand All @@ -13,11 +14,16 @@ import {
listenForProtocolHandler,
setupProtocolHandler,
} from '../../src/main/protocol';
import { isValidElectronPath } from '../../src/main/utils/local-version';
import { getOrCreateMainWindow, mainIsReady } from '../../src/main/windows';
import { overridePlatform, resetPlatform } from '../utils';

jest.mock('node:fs');

jest.mock('../../src/main/utils/local-version', () => ({
isValidElectronPath: jest.fn(),
}));

describe('protocol', () => {
const oldArgv = [...process.argv];

Expand Down Expand Up @@ -192,5 +198,63 @@ describe('protocol', () => {
await new Promise(process.nextTick);
expect(mainWindow.focus).toHaveBeenCalled();
});

it('handles registering local version url', () => {
mocked(isValidElectronPath).mockReturnValueOnce(true);

overridePlatform('darwin');
listenForProtocolHandler();

const handler = mocked(app.on).mock.calls[0][1];
const url = new URL('electron-fiddle://register-local-version/');
const params = {
name: 'test',
path: path.resolve(__dirname),
version: '35.0.0-local',
};
const keys = Object.keys(params) as Array<keyof typeof params>;
keys.forEach((k) => {
url.searchParams.append(k, params[k]);
});
handler({}, url.href);

expect(ipcMainManager.send).toHaveBeenCalledWith(
IpcEvents.REGISTER_LOCAL_VERSION_FOLDER,
[params],
);
});

it('handles registering local version without valid path', () => {
mocked(isValidElectronPath).mockReturnValueOnce(false);

overridePlatform('darwin');
listenForProtocolHandler();

const handler = mocked(app.on).mock.calls[0][1];
const url = new URL('electron-fiddle://register-local-version/');
const params = {
name: 'test',
path: path.resolve(__dirname),
version: '35.0.0-local',
};
const keys = Object.keys(params) as Array<keyof typeof params>;
keys.forEach((k) => {
url.searchParams.append(k, params[k]);
});
handler({}, url.href);

expect(ipcMainManager.send).not.toHaveBeenCalled();
});

it('handles registering local version with missing params', () => {
overridePlatform('darwin');
listenForProtocolHandler();

const handler = mocked(app.on).mock.calls[0][1];
const url = new URL('electron-fiddle://register-local-version/');
handler({}, url.href);

expect(ipcMainManager.send).not.toHaveBeenCalled();
});
});
});
30 changes: 30 additions & 0 deletions tests/renderer/app-spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,36 @@ describe('App component', () => {
});
});

describe('setupProtocolListeners()', () => {
it('handles registering new versions', () => {
const addEventListenerMock = window.ElectronFiddle
.addEventListener as any;
addEventListenerMock.mockClear();

app.setupProtocolListeners();

expect(addEventListenerMock).toHaveBeenCalledWith(
'register-local-version',
expect.anything(),
);

const callback = addEventListenerMock.mock.calls[0][1];
const addVersion = {
name: 'new-version',
path: '/version/build/path',
version: '123.0.0-local',
};
callback(addVersion);

expect(app.state.addLocalVersion).toHaveBeenCalledWith({
name: addVersion.name,
localPath: addVersion.path,
version: addVersion.version,
});
expect(app.state.setVersion).toHaveBeenCalledWith(addVersion.version);
});
});

describe('prompting to confirm replacing an unsaved fiddle', () => {
// make a second fiddle that differs from the first
const editorValues = createEditorValues();
Expand Down