chore: ensure yarn is installed before launching fiddle (#452)

This commit is contained in:
Vlad Hashimoto
2020-10-09 23:30:20 +03:00
committed by GitHub
parent 2cb8e23bc2
commit 0bc8389c6c
4 changed files with 147 additions and 64 deletions
+24 -8
View File
@@ -10,7 +10,8 @@ export interface PMOperationOptions {
packageManager: IPackageManager;
}
export let isInstalled: boolean | null = null;
export let isNpmInstalled: boolean | null = null;
export let isYarnInstalled: boolean | null = null;
/* add other modules to automatically ignore here */
/* perhaps we can expose this to the settings module?*/
@@ -33,22 +34,37 @@ const isUnique = (item: any, idx: number, arr: Array<any>): boolean => {
};
/**
* Checks if npm is installed by checking if a binary
* Checks if package manager is installed by checking if a binary
* with that name can be found.
*/
export async function getIsNpmInstalled(
export async function getIsPackageManagerInstalled(
packageManager: IPackageManager,
ignoreCache?: boolean,
): Promise<boolean> {
if (isInstalled !== null && !ignoreCache) return isInstalled;
if (packageManager === 'npm' && isNpmInstalled !== null && !ignoreCache)
return isNpmInstalled;
if (packageManager === 'yarn' && isYarnInstalled !== null && !ignoreCache)
return isYarnInstalled;
const command = process.platform === 'win32' ? 'where.exe npm' : 'which npm';
const command =
process.platform === 'win32'
? `where.exe ${packageManager}`
: `which ${packageManager}`;
try {
await exec(process.cwd(), command);
return (isInstalled = true);
if (packageManager === 'npm') {
return (isNpmInstalled = true);
} else {
return (isYarnInstalled = true);
}
} catch (error) {
console.warn(`getIsNpmInstalled: "${command}" failed.`, error);
return (isInstalled = false);
console.warn(`getIsPackageManagerInstalled: "${command}" failed.`, error);
if (packageManager === 'npm') {
return (isNpmInstalled = false);
} else {
return (isYarnInstalled = false);
}
}
}
+12 -9
View File
@@ -9,7 +9,7 @@ import { getElectronBinaryPath, getIsDownloaded } from './binary';
import { ipcRendererManager } from './ipc';
import {
findModulesInEditors,
getIsNpmInstalled,
getIsPackageManagerInstalled,
installModules,
packageRun,
PMOperationOptions,
@@ -124,10 +124,13 @@ export class Runner {
this.appState.isConsoleShowing = true;
pushOutput(`📦 ${strings[0]} current Fiddle...`);
if (!(await getIsNpmInstalled())) {
let message = `Error: Could not find npm. Fiddle requires Node.js and npm `;
const packageManager = this.appState.packageManager;
const pmInstalled = await getIsPackageManagerInstalled(packageManager);
if (!pmInstalled) {
let message = `Error: Could not find ${packageManager}. Fiddle requires Node.js and npm or yarn `;
message += `to compile packages. Please visit https://nodejs.org to install `;
message += `Node.js and npm.`;
message += `Node.js and npm, or https://classic.yarnpkg.com/lang/en/ `;
message += `to install Yarn`;
this.appState.pushOutput(message, { isNotPre: true });
return false;
@@ -141,8 +144,6 @@ export class Runner {
);
if (!dir) return false;
const packageManager = this.appState.packageManager;
// Files are now saved to temp, let's install Forge and dependencies
if (!(await this.packageInstall({ dir, packageManager }))) return false;
@@ -177,14 +178,16 @@ export class Runner {
const { pushOutput } = this.appState;
if (modules && modules.length > 0) {
if (!(await getIsNpmInstalled())) {
const packageManager = pmOptions.packageManager;
const pmInstalled = await getIsPackageManagerInstalled(packageManager);
if (!pmInstalled) {
let message = `The ${maybePlural(`module`, modules)} ${modules.join(
', ',
)} need to be installed, `;
message += `but we could not find npm. Fiddle requires Node.js and npm `;
message += `but we could not find ${packageManager}. Fiddle requires Node.js and npm `;
message += `to support the installation of modules not included in `;
message += `Electron. Please visit https://nodejs.org to install Node.js `;
message += `and npm.`;
message += `and npm, or https://classic.yarnpkg.com/lang/en/ to install Yarn`;
pushOutput(message, { isNotPre: true });
return;
+105 -42
View File
@@ -1,6 +1,6 @@
import {
findModulesInEditors,
getIsNpmInstalled,
getIsPackageManagerInstalled,
installModules,
packageRun,
} from '../../src/renderer/npm';
@@ -26,64 +26,127 @@ describe('npm', () => {
}
`;
describe('getIsNpmInstalled()', () => {
beforeEach(() => {
jest.resetModuleRegistry();
describe('getIsPackageManagerInstalled()', () => {
describe('npm()', () => {
beforeEach(() => {
jest.resetModuleRegistry();
});
afterEach(() => resetPlatform());
it('returns true if npm installed', async () => {
overridePlatform('darwin');
(exec as jest.Mock).mockReturnValueOnce(
Promise.resolve('/usr/bin/fake-npm'),
);
const result = await getIsPackageManagerInstalled('npm');
expect(result).toBe(true);
expect((exec as jest.Mock).mock.calls[0][1]).toBe('which npm');
});
it('returns true if npm installed', async () => {
overridePlatform('win32');
(exec as jest.Mock).mockReturnValueOnce(
Promise.resolve('/usr/bin/fake-npm'),
);
const result = await getIsPackageManagerInstalled('npm', true);
expect(result).toBe(true);
expect((exec as jest.Mock).mock.calls[0][1]).toBe('where.exe npm');
});
it('returns false if npm not installed', async () => {
overridePlatform('darwin');
(exec as jest.Mock).mockReturnValueOnce(
Promise.reject('/usr/bin/fake-npm'),
);
const result = await getIsPackageManagerInstalled('npm', true);
expect(result).toBe(false);
expect((exec as jest.Mock).mock.calls[0][1]).toBe('which npm');
});
it('uses the cache', async () => {
(exec as jest.Mock).mockReturnValueOnce(
Promise.resolve('/usr/bin/fake-npm'),
);
const one = await getIsPackageManagerInstalled('npm', true);
expect(one).toBe(true);
expect(exec as jest.Mock).toHaveBeenCalledTimes(1);
const two = await getIsPackageManagerInstalled('npm');
expect(two).toBe(true);
expect(exec as jest.Mock).toHaveBeenCalledTimes(1);
});
});
afterEach(() => resetPlatform());
describe('yarn()', () => {
beforeEach(() => {
jest.resetModuleRegistry();
});
it('returns true if npm installed', async () => {
overridePlatform('darwin');
afterEach(() => resetPlatform());
(exec as jest.Mock).mockReturnValueOnce(
Promise.resolve('/usr/bin/fake-npm'),
);
it('returns true if yarn installed', async () => {
overridePlatform('darwin');
const result = await getIsNpmInstalled();
(exec as jest.Mock).mockReturnValueOnce(
Promise.resolve('/usr/bin/fake-yarn'),
);
expect(result).toBe(true);
expect((exec as jest.Mock).mock.calls[0][1]).toBe('which npm');
});
const result = await getIsPackageManagerInstalled('yarn');
it('returns true if npm installed', async () => {
overridePlatform('win32');
expect(result).toBe(true);
expect((exec as jest.Mock).mock.calls[0][1]).toBe('which yarn');
});
(exec as jest.Mock).mockReturnValueOnce(
Promise.resolve('/usr/bin/fake-npm'),
);
it('returns true if yarn installed', async () => {
overridePlatform('win32');
const result = await getIsNpmInstalled(true);
(exec as jest.Mock).mockReturnValueOnce(
Promise.resolve('/usr/bin/fake-yarn'),
);
expect(result).toBe(true);
expect((exec as jest.Mock).mock.calls[0][1]).toBe('where.exe npm');
});
const result = await getIsPackageManagerInstalled('yarn', true);
it('returns false if npm not installed', async () => {
overridePlatform('darwin');
expect(result).toBe(true);
expect((exec as jest.Mock).mock.calls[0][1]).toBe('where.exe yarn');
});
(exec as jest.Mock).mockReturnValueOnce(
Promise.reject('/usr/bin/fake-npm'),
);
it('returns false if yarn not installed', async () => {
overridePlatform('darwin');
const result = await getIsNpmInstalled(true);
(exec as jest.Mock).mockReturnValueOnce(
Promise.reject('/usr/bin/fake-yarn'),
);
expect(result).toBe(false);
expect((exec as jest.Mock).mock.calls[0][1]).toBe('which npm');
});
const result = await getIsPackageManagerInstalled('yarn', true);
it('uses the cache', async () => {
(exec as jest.Mock).mockReturnValueOnce(
Promise.resolve('/usr/bin/fake-npm'),
);
expect(result).toBe(false);
expect((exec as jest.Mock).mock.calls[0][1]).toBe('which yarn');
});
const one = await getIsNpmInstalled(true);
expect(one).toBe(true);
expect(exec as jest.Mock).toHaveBeenCalledTimes(1);
it('uses the cache', async () => {
(exec as jest.Mock).mockReturnValueOnce(
Promise.resolve('/usr/bin/fake-yarn'),
);
const two = await getIsNpmInstalled();
expect(two).toBe(true);
expect(exec as jest.Mock).toHaveBeenCalledTimes(1);
const one = await getIsPackageManagerInstalled('yarn', true);
expect(one).toBe(true);
expect(exec as jest.Mock).toHaveBeenCalledTimes(1);
const two = await getIsPackageManagerInstalled('yarn');
expect(two).toBe(true);
expect(exec as jest.Mock).toHaveBeenCalledTimes(1);
});
});
});
+6 -5
View File
@@ -6,7 +6,7 @@ import { getIsDownloaded } from '../../src/renderer/binary';
import { ipcRendererManager } from '../../src/renderer/ipc';
import {
findModulesInEditors,
getIsNpmInstalled,
getIsPackageManagerInstalled,
installModules,
packageRun,
} from '../../src/renderer/npm';
@@ -35,7 +35,7 @@ describe('Runner component', () => {
mockChild = new MockChildProcess();
ipcRendererManager.removeAllListeners();
(getIsNpmInstalled as jest.Mock).mockReturnValue(true);
(getIsPackageManagerInstalled as jest.Mock).mockReturnValue(true);
store = {
version: '2.0.2',
@@ -45,6 +45,7 @@ describe('Runner component', () => {
pushOutput: jest.fn(),
clearConsole: jest.fn(),
pushError: jest.fn(),
packageManager: 'npm',
get currentElectronVersion() {
return mockVersions['2.0.2'];
},
@@ -270,7 +271,7 @@ describe('Runner component', () => {
});
it('does attempt a forge operation if npm is not installed', async () => {
(getIsNpmInstalled as jest.Mock).mockReturnValueOnce(false);
(getIsPackageManagerInstalled as jest.Mock).mockReturnValueOnce(false);
expect(await instance.performForgeOperation(ForgeCommands.MAKE)).toBe(
false,
@@ -280,7 +281,7 @@ describe('Runner component', () => {
describe('installModulesForEditor()', () => {
it('does not attempt installation if npm is not installed', async () => {
(getIsNpmInstalled as jest.Mock).mockReturnValueOnce(false);
(getIsPackageManagerInstalled as jest.Mock).mockReturnValueOnce(false);
(findModulesInEditors as jest.Mock).mockReturnValueOnce(['fake-module']);
await instance.installModulesForEditor(
@@ -298,7 +299,7 @@ describe('Runner component', () => {
});
it('does attempt installation if npm is installed', async () => {
(getIsNpmInstalled as jest.Mock).mockReturnValueOnce(true);
(getIsPackageManagerInstalled as jest.Mock).mockReturnValueOnce(true);
(findModulesInEditors as jest.Mock).mockReturnValueOnce(['fake-module']);
await instance.installModulesForEditor(