fix(core): silent failures when linking forge dependencies in tests (#3219)

This commit is contained in:
Ronnie Curtis 2023-04-27 07:28:35 +10:00 коммит произвёл GitHub
Родитель 6ac014e085
Коммит e5fc303734
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 95 добавлений и 29 удалений

Просмотреть файл

@ -51,7 +51,7 @@ yarn link:prepare
Then, you want to initialize a new project with the `electron-forge init` command (which is the
underlying CLI command for `create-electron-app`). To use the symlinks you created in the last step,
pass in the `LINK_FORGE_DEPENDENCIES_ON_INIT` environment variable.
pass in the `LINK_FORGE_DEPENDENCIES_ON_INIT=1` environment variable.
You can choose to run this command via your local build as shown below or run the production init
for versions 6.0.1 and up.

Просмотреть файл

@ -17,7 +17,8 @@
"lerna:publish": "lerna publish --force-publish --conventional-commits --no-changelog --exact",
"lint": "prettier --check . && eslint .",
"lint:fix": "prettier --write .",
"link:prepare": "lerna exec -- node ../../../tools/silent.js yarn link --link-folder ../../../.links --silent --no-bin-links",
"link:prepare": "lerna exec -- node ../../../tools/silent.js yarn link --silent --no-bin-links --link-folder ../../../.links",
"link:remove": "lerna exec -- node ../../../tools/silent.js yarn unlink --silent --no-bin-links --link-folder ../../../.links",
"test": "xvfb-maybe cross-env LINK_FORGE_DEPENDENCIES_ON_INIT=1 TS_NODE_PROJECT='./tsconfig.test.json' TS_NODE_FILES=1 mocha './tools/test-globber.ts'",
"test:fast": "xvfb-maybe cross-env LINK_FORGE_DEPENDENCIES_ON_INIT=1 TS_NODE_PROJECT='./tsconfig.test.json' TEST_FAST_ONLY=1 TS_NODE_FILES=1 mocha './tools/test-globber.ts'",
"test:slow": "xvfb-maybe cross-env LINK_FORGE_DEPENDENCIES_ON_INIT=1 TS_NODE_PROJECT='./tsconfig.test.json' TEST_SLOW_ONLY=1 TS_NODE_FILES=1 mocha './tools/test-globber.ts'",

Просмотреть файл

@ -0,0 +1,38 @@
import path from 'path';
import { safeYarnOrNpm, yarnOrNpmSpawn } from '@electron-forge/core-utils';
import { ForgeListrTask } from '@electron-forge/shared-types';
import debug from 'debug';
import { readRawPackageJson } from '../../util/read-package-json';
const d = debug('electron-forge:init:link');
/**
* Link local forge dependencies
*
* This allows developers working on forge itself to easily init
* a local template and have it use their local plugins / core / cli packages.
*
* Note: `yarn link:prepare` needs to run first before dependencies can be
* linked.
*/
export async function initLink<T>(dir: string, task?: ForgeListrTask<T>) {
const shouldLink = process.env.LINK_FORGE_DEPENDENCIES_ON_INIT;
if (shouldLink) {
d('Linking forge dependencies');
const packageJson = await readRawPackageJson(dir);
const packageManager = safeYarnOrNpm();
const linkFolder = path.resolve(__dirname, '..', '..', '..', '..', '..', '..', '.links');
for (const packageName of Object.keys(packageJson.devDependencies)) {
if (packageName.startsWith('@electron-forge/')) {
if (task) task.output = `${packageManager} link --link-folder ${linkFolder} ${packageName}`;
await yarnOrNpmSpawn(['link', '--link-folder', linkFolder, packageName], {
cwd: dir,
});
}
}
} else {
d('LINK_FORGE_DEPENDENCIES_ON_INIT is falsy. Skipping.');
}
}

Просмотреть файл

@ -1,12 +1,11 @@
import path from 'path';
import { safeYarnOrNpm, yarnOrNpmSpawn } from '@electron-forge/core-utils';
import { safeYarnOrNpm } from '@electron-forge/core-utils';
import { ForgeListrTask } from '@electron-forge/shared-types';
import debug from 'debug';
import fs from 'fs-extra';
import installDepList, { DepType, DepVersionRestriction } from '../../util/install-dependencies';
import { readRawPackageJson } from '../../util/read-package-json';
const d = debug('electron-forge:init:npm');
const corePackage = fs.readJsonSync(path.resolve(__dirname, '../../../package.json'));
@ -19,7 +18,7 @@ export const deps = ['electron-squirrel-startup'];
export const devDeps = [siblingDep('cli'), siblingDep('maker-squirrel'), siblingDep('maker-zip'), siblingDep('maker-deb'), siblingDep('maker-rpm')];
export const exactDevDeps = ['electron'];
export const initNPM = async (dir: string, task: ForgeListrTask<any>): Promise<void> => {
export const initNPM = async <T>(dir: string, task: ForgeListrTask<T>): Promise<void> => {
d('installing dependencies');
const packageManager = safeYarnOrNpm();
task.output = `${packageManager} install ${deps.join(' ')}`;
@ -34,19 +33,4 @@ export const initNPM = async (dir: string, task: ForgeListrTask<any>): Promise<v
task.output = `${packageManager} install --dev --exact ${packageName}`;
await installDepList(dir, [packageName], DepType.DEV, DepVersionRestriction.EXACT);
}
// This logic allows developers working on forge itself to easily init
// a local template and have it use their local plugins / core / cli packages
if (process.env.LINK_FORGE_DEPENDENCIES_ON_INIT) {
const packageJson = await readRawPackageJson(dir);
const linkFolder = path.resolve(__dirname, '..', '..', '..', '..', '..', '..', '.links');
for (const packageName of Object.keys(packageJson.devDependencies)) {
if (packageName.startsWith('@electron-forge/')) {
task.output = `${packageManager} link --link-folder ${linkFolder} ${packageName}`;
await yarnOrNpmSpawn(['link', '--link-folder', linkFolder, packageName], {
cwd: dir,
});
}
}
}
};

Просмотреть файл

@ -12,6 +12,7 @@ import { readRawPackageJson } from '../util/read-package-json';
import { findTemplate } from './init-scripts/find-template';
import { initDirectory } from './init-scripts/init-directory';
import { initGit } from './init-scripts/init-git';
import { initLink } from './init-scripts/init-link';
import { initNPM } from './init-scripts/init-npm';
const d = debug('electron-forge:init');
@ -108,6 +109,7 @@ export default async ({ dir = process.cwd(), interactive = false, copyCIFiles =
}
return await installDepList(dir, templateModule.dependencies || [], DepType.PROD, DepVersionRestriction.RANGE);
},
exitOnError: false,
},
{
title: 'Installing development dependencies',
@ -118,17 +120,32 @@ export default async ({ dir = process.cwd(), interactive = false, copyCIFiles =
}
await installDepList(dir, templateModule.devDependencies || [], DepType.DEV);
},
exitOnError: false,
},
{
title: 'Finalizing dependencies',
task: async (_, task) => {
await initNPM(dir, task);
return task.newListr([
{
title: 'Installing common dependencies',
task: async (_, task) => {
await initNPM(dir, task);
},
exitOnError: false,
},
{
title: process.env.LINK_FORGE_DEPENDENCIES_ON_INIT ? 'Linking forge dependencies' : 'Skip linking forge dependencies',
task: async (_, task) => {
await initLink(dir, task);
},
exitOnError: true,
},
]);
},
},
],
{
concurrent: false,
exitOnError: false,
}
);
},

Просмотреть файл

@ -2,6 +2,7 @@ import assert from 'assert';
import { execSync } from 'child_process';
import path from 'path';
import { yarnOrNpmSpawn } from '@electron-forge/core-utils';
import { createDefaultCertificate } from '@electron-forge/maker-appx';
import { ForgeConfig, IForgeResolvableMaker } from '@electron-forge/shared-types';
import { ensureTestDirIsNonexistent, expectLintToPass, expectProjectPathExists } from '@electron-forge/test-utils';
@ -39,6 +40,10 @@ for (const nodeInstaller of ['npm', 'yarn']) {
describe(`electron-forge API (with installer=${nodeInstaller})`, () => {
let dir: string;
before(async () => {
await yarnOrNpmSpawn(['link:prepare']);
});
const beforeInitTest = (params?: Partial<InitOptions>, beforeInit?: BeforeInitFunction) => {
before(async () => {
dir = await ensureTestDirIsNonexistent();
@ -217,12 +222,20 @@ for (const nodeInstaller of ['npm', 'yarn']) {
await fs.remove(dir);
});
});
after(async () => {
await yarnOrNpmSpawn(['link:remove']);
});
});
}
describe('Electron Forge API', () => {
let dir: string;
before(async () => {
await yarnOrNpmSpawn(['link:prepare']);
});
describe('after init', () => {
let devCert: string;
@ -484,4 +497,8 @@ describe('Electron Forge API', () => {
after(() => fs.remove(dir));
});
after(async () => {
await yarnOrNpmSpawn(['link:remove']);
});
});

Просмотреть файл

@ -7,11 +7,13 @@ import glob from 'fast-glob';
import fs from 'fs-extra';
import { api } from '../../../api/core';
import { initLink } from '../../../api/core/src/api/init-scripts/init-link';
describe('WebpackTypeScriptTemplate', () => {
let dir: string;
before(async () => {
await yarnOrNpmSpawn(['link:prepare']);
dir = await testUtils.ensureTestDirIsNonexistent();
});
@ -74,6 +76,11 @@ describe('WebpackTypeScriptTemplate', () => {
await yarnOrNpmSpawn(['install'], {
cwd: dir,
});
// Installing deps removes symlinks that were added at the start of this
// spec via `api.init`. So we should re-link local forge dependencies
// again.
await initLink(dir);
});
after(() => {
@ -89,6 +96,7 @@ describe('WebpackTypeScriptTemplate', () => {
});
after(async () => {
await yarnOrNpmSpawn(['link:remove']);
await fs.remove(dir);
});
});

Просмотреть файл

@ -1,12 +1,13 @@
const cp = require('child_process');
/**
* Silences warnings and other stdio logs produced from commands
*
* It does not silence errors.
*/
const { spawn } = require('@malept/cross-spawn-promise');
const [cmd, ...args] = process.argv.slice(2);
const child = cp.spawn(cmd, args, {
spawn(cmd, args, {
stdio: 'pipe',
});
child.on('exit', (code, signal) => {
if (signal) process.exit(1);
else process.exit(code);
});