From 4c601519451c5d3701bec6b3470cecce6f97ad07 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Sat, 14 Aug 2021 14:39:00 -0700 Subject: [PATCH] fix(core): add support for finding electron for npm 7 workspaces (#2446) --- .../api/core/src/util/electron-version.ts | 16 +-- .../core/test/fast/electron-version_spec.ts | 132 +++++++++++------- .../node_modules/electron/package.json | 4 + .../fixture/npm-workspace/package-lock.json | 0 .../test/fixture/npm-workspace/package.json | 5 + .../packages/subpackage/.gitkeep | 0 6 files changed, 96 insertions(+), 61 deletions(-) create mode 100644 packages/api/core/test/fixture/npm-workspace/node_modules/electron/package.json create mode 100644 packages/api/core/test/fixture/npm-workspace/package-lock.json create mode 100644 packages/api/core/test/fixture/npm-workspace/package.json create mode 100644 packages/api/core/test/fixture/npm-workspace/packages/subpackage/.gitkeep diff --git a/packages/api/core/src/util/electron-version.ts b/packages/api/core/src/util/electron-version.ts index c32da3011c..7c4b690dd8 100644 --- a/packages/api/core/src/util/electron-version.ts +++ b/packages/api/core/src/util/electron-version.ts @@ -3,7 +3,7 @@ import findUp from 'find-up'; import fs from 'fs-extra'; import path from 'path'; import semver from 'semver'; -import yarnOrNpm, { hasYarn } from './yarn-or-npm'; +import yarnOrNpm from './yarn-or-npm'; const d = debug('electron-forge:electron-version'); @@ -22,13 +22,13 @@ async function findAncestorNodeModulesPath( dir: string, packageName: string, ): Promise { - if (hasYarn()) { - const yarnLockPath = await findUp('yarn.lock', { cwd: dir, type: 'file' }); - if (yarnLockPath) { - const nodeModulesPath = path.join(path.dirname(yarnLockPath), 'node_modules', packageName); - if (await fs.pathExists(nodeModulesPath)) { - return nodeModulesPath; - } + d('Looking for a lock file to indicate the root of the repo'); + const lockPath = await findUp(['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml'], { cwd: dir, type: 'file' }); + if (lockPath) { + d(`Found lock file: ${lockPath}`); + const nodeModulesPath = path.join(path.dirname(lockPath), 'node_modules', packageName); + if (await fs.pathExists(nodeModulesPath)) { + return nodeModulesPath; } } diff --git a/packages/api/core/test/fast/electron-version_spec.ts b/packages/api/core/test/fast/electron-version_spec.ts index 0f12a4bd81..582fd4dd85 100644 --- a/packages/api/core/test/fast/electron-version_spec.ts +++ b/packages/api/core/test/fast/electron-version_spec.ts @@ -4,7 +4,6 @@ import os from 'os'; import path from 'path'; import { getElectronModulePath, getElectronVersion, updateElectronDependency } from '../../src/util/electron-version'; import { devDeps, exactDevDeps } from '../../src/api/init-scripts/init-npm'; -import { hasYarn } from '../../src/util/yarn-or-npm'; describe('updateElectronDependency', () => { it('adds an Electron dep if one does not already exist', () => { @@ -76,33 +75,46 @@ describe('getElectronVersion', () => { return expect(await getElectronVersion('', packageJSON)).to.be.equal('1.0.0'); }); - it('works with a non-exact version and yarn workspaces', async () => { - const fixtureDir = path.resolve(__dirname, '..', 'fixture', 'yarn-workspace', 'packages', 'subpackage'); - const packageJSON = { - devDependencies: { electron: '^4.0.4' }, - }; - if (hasYarn()) { + describe('with yarn workspaces', () => { + before(() => { + process.env.NODE_INSTALLER = 'yarn'; + }); + + it('works with a non-exact version', async () => { + const fixtureDir = path.resolve(__dirname, '..', 'fixture', 'yarn-workspace', 'packages', 'subpackage'); + const packageJSON = { + devDependencies: { electron: '^4.0.4' }, + }; + expect(await getElectronVersion(fixtureDir, packageJSON)).to.be.equal('4.0.9'); - } else { - expect(getElectronVersion(fixtureDir, packageJSON)).to.eventually.be.rejectedWith('Cannot find the package'); - } + }); + + after(() => { + delete process.env.NODE_INSTALLER; + }); }); }); describe('getElectronModulePath', () => { - let tempDir: string; - before(async () => { - tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'electron-forge-test-')); - }); - it('fails without devDependencies', () => expect(getElectronModulePath('', {})).to.eventually.be.rejectedWith('does not have any devDependencies')); it('fails without electron devDependencies', () => expect(getElectronModulePath('', { devDependencies: {} })).to.eventually.be.rejectedWith('Electron packages in devDependencies')); - it('fails with no electron installed', async () => { - const fixtureDir = path.resolve(__dirname, '..', 'fixture', 'dummy_app'); - await fs.copy(fixtureDir, tempDir); - return expect(getElectronModulePath(tempDir, { devDependencies: { electron: '^4.0.2' } })).to.eventually.be.rejectedWith('Cannot find the package'); + describe('with no electron installed', () => { + let tempDir: string; + before(async () => { + tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'electron-forge-test-')); + }); + + it('throws an error saying it cannot find electron', async () => { + const fixtureDir = path.resolve(__dirname, '..', 'fixture', 'dummy_app'); + await fs.copy(fixtureDir, tempDir); + return expect(getElectronModulePath(tempDir, { devDependencies: { electron: '^4.0.2' } })).to.eventually.be.rejectedWith('Cannot find the package'); + }); + + after(async () => { + await fs.remove(tempDir); + }); }); it('works with electron', () => { @@ -110,50 +122,64 @@ describe('getElectronModulePath', () => { return expect(getElectronModulePath(fixtureDir, { devDependencies: { electron: '^4.0.2' } })).to.eventually.equal(path.join(fixtureDir, 'node_modules', 'electron')); }); - it('works with yarn workspaces', async () => { - const workspaceDir = path.resolve(__dirname, '..', 'fixture', 'yarn-workspace'); - const fixtureDir = path.join(workspaceDir, 'packages', 'subpackage'); - const packageJSON = { - devDependencies: { electron: '^4.0.4' }, - }; + describe('with npm workspaces', () => { + before(() => { + process.env.NODE_INSTALLER = 'npm'; + }); + + it('finds the top-level electron module', async () => { + const workspaceDir = path.resolve(__dirname, '..', 'fixture', 'npm-workspace'); + const fixtureDir = path.join(workspaceDir, 'packages', 'subpackage'); + const packageJSON = { + devDependencies: { electron: '^4.0.4' }, + }; - if (hasYarn()) { expect(await getElectronModulePath(fixtureDir, packageJSON)).to.be.equal(path.join(workspaceDir, 'node_modules', 'electron')); - } else { - expect(getElectronModulePath(fixtureDir, packageJSON)).to.eventually.be.rejectedWith('Cannot find the package'); - } + }); + + after(() => { + delete process.env.NODE_INSTALLER; + }); }); - it('works when yarn workspaces create additional node_modules folder inside package', async () => { - const workspaceDir = path.resolve(__dirname, '..', 'fixture', 'yarn-workspace'); - const fixtureDir = path.join(workspaceDir, 'packages', 'with-node-modules'); - const packageJSON = { - devDependencies: { electron: '^4.0.4' }, - }; + describe('with yarn workspaces', () => { + before(() => { + process.env.NODE_INSTALLER = 'yarn'; + }); + + it('finds the top-level electron module', async () => { + const workspaceDir = path.resolve(__dirname, '..', 'fixture', 'yarn-workspace'); + const fixtureDir = path.join(workspaceDir, 'packages', 'subpackage'); + const packageJSON = { + devDependencies: { electron: '^4.0.4' }, + }; - if (hasYarn()) { expect(await getElectronModulePath(fixtureDir, packageJSON)).to.be.equal(path.join(workspaceDir, 'node_modules', 'electron')); - } else { - expect(getElectronModulePath(fixtureDir, packageJSON)).to.eventually.be.rejectedWith('Cannot find the package'); - } - }); + }); - it('works with yarn workspaces in ala nohoist mode', async () => { - const workspaceDir = path.resolve(__dirname, '..', 'fixture', 'yarn-workspace'); - const fixtureDir = path.join(workspaceDir, 'packages', 'electron-folder-in-node-modules'); - const packageJSON = { - devDependencies: { electron: '^13.0.0' }, - }; + it('finds the top-level electron module despite the additional node_modules folder inside the package', async () => { + const workspaceDir = path.resolve(__dirname, '..', 'fixture', 'yarn-workspace'); + const fixtureDir = path.join(workspaceDir, 'packages', 'with-node-modules'); + const packageJSON = { + devDependencies: { electron: '^4.0.4' }, + }; + + expect(await getElectronModulePath(fixtureDir, packageJSON)).to.be.equal(path.join(workspaceDir, 'node_modules', 'electron')); + }); + + it('finds the correct electron module in nohoist mode', async () => { + const workspaceDir = path.resolve(__dirname, '..', 'fixture', 'yarn-workspace'); + const fixtureDir = path.join(workspaceDir, 'packages', 'electron-folder-in-node-modules'); + const packageJSON = { + devDependencies: { electron: '^13.0.0' }, + }; - if (hasYarn()) { expect(await getElectronModulePath(fixtureDir, packageJSON)).to.be.equal(path.join(fixtureDir, 'node_modules', 'electron')); expect(await getElectronModulePath(fixtureDir, packageJSON)).not.to.be.equal(path.join(workspaceDir, 'node_modules', 'electron')); - } else { - expect(getElectronModulePath(fixtureDir, packageJSON)).to.eventually.be.rejectedWith('Cannot find the package'); - } - }); + }); - after(async () => { - await fs.remove(tempDir); + after(() => { + delete process.env.NODE_INSTALLER; + }); }); }); diff --git a/packages/api/core/test/fixture/npm-workspace/node_modules/electron/package.json b/packages/api/core/test/fixture/npm-workspace/node_modules/electron/package.json new file mode 100644 index 0000000000..6af1f25522 --- /dev/null +++ b/packages/api/core/test/fixture/npm-workspace/node_modules/electron/package.json @@ -0,0 +1,4 @@ +{ + "name": "electron", + "version": "4.0.9" +} diff --git a/packages/api/core/test/fixture/npm-workspace/package-lock.json b/packages/api/core/test/fixture/npm-workspace/package-lock.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/api/core/test/fixture/npm-workspace/package.json b/packages/api/core/test/fixture/npm-workspace/package.json new file mode 100644 index 0000000000..4fbfcc3533 --- /dev/null +++ b/packages/api/core/test/fixture/npm-workspace/package.json @@ -0,0 +1,5 @@ +{ + "workspaces": [ + "packages/subpackage" + ] +} diff --git a/packages/api/core/test/fixture/npm-workspace/packages/subpackage/.gitkeep b/packages/api/core/test/fixture/npm-workspace/packages/subpackage/.gitkeep new file mode 100644 index 0000000000..e69de29bb2