From 152347989438df5b49728e9a48e8a20600c9db9b Mon Sep 17 00:00:00 2001 From: merceyz Date: Thu, 18 Jul 2024 01:40:07 +0200 Subject: [PATCH 1/3] fix(cli): ensure terminating due to an empty event loop counts as an error --- .yarn/versions/3a4fece1.yml | 23 +++++++++++++++++++++++ packages/yarnpkg-cli/sources/lib.ts | 5 +++++ 2 files changed, 28 insertions(+) create mode 100644 .yarn/versions/3a4fece1.yml diff --git a/.yarn/versions/3a4fece1.yml b/.yarn/versions/3a4fece1.yml new file mode 100644 index 000000000000..86b828aea491 --- /dev/null +++ b/.yarn/versions/3a4fece1.yml @@ -0,0 +1,23 @@ +releases: + "@yarnpkg/cli": patch + +declined: + - "@yarnpkg/plugin-compat" + - "@yarnpkg/plugin-constraints" + - "@yarnpkg/plugin-dlx" + - "@yarnpkg/plugin-essentials" + - "@yarnpkg/plugin-init" + - "@yarnpkg/plugin-interactive-tools" + - "@yarnpkg/plugin-nm" + - "@yarnpkg/plugin-npm-cli" + - "@yarnpkg/plugin-pack" + - "@yarnpkg/plugin-patch" + - "@yarnpkg/plugin-pnp" + - "@yarnpkg/plugin-pnpm" + - "@yarnpkg/plugin-stage" + - "@yarnpkg/plugin-typescript" + - "@yarnpkg/plugin-version" + - "@yarnpkg/plugin-workspace-tools" + - "@yarnpkg/builder" + - "@yarnpkg/core" + - "@yarnpkg/doctor" diff --git a/packages/yarnpkg-cli/sources/lib.ts b/packages/yarnpkg-cli/sources/lib.ts index 281d5f3d9344..9bc351fa4996 100644 --- a/packages/yarnpkg-cli/sources/lib.ts +++ b/packages/yarnpkg-cli/sources/lib.ts @@ -187,6 +187,11 @@ export async function runExit(argv: Array, {cwd = ppath.cwd(), selfPath, const cli = getBaseCli({cwd, pluginConfiguration}); try { + // The exit code is set to an error code before the CLI runs so that + // if the event loop becomes empty and node terminates without + // finishing the execution of this function it counts as an error. + // https://github.com/yarnpkg/berry/issues/6398 + process.exitCode = 42; process.exitCode = await run(cli, argv, {selfPath, pluginConfiguration}); } catch (error) { Cli.defaultContext.stdout.write(cli.error(error)); From 2c04e2a7d285480fe7814e1a0bdcff3358003ab0 Mon Sep 17 00:00:00 2001 From: merceyz Date: Thu, 18 Jul 2024 02:33:17 +0200 Subject: [PATCH 2/3] test: add a test --- .../sources/commands/install.test.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.ts b/packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.ts index f9bbf062f888..1965a3ef2ecd 100644 --- a/packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.ts +++ b/packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.ts @@ -900,5 +900,29 @@ describe(`Commands`, () => { }); }), ); + + test(`it should exit with an error code after an unexpected empty event loop`, + makeTemporaryEnv({}, async ({path, run}) => { + await xfs.writeFilePromise(ppath.join(path, `plugin.cjs`), ` +module.exports = { + name: 'test', + factory() { + return { + hooks: { + afterAllInstalled: () => new Promise(() => {}), + }, + }; + }, +}; +`); + await xfs.writeJsonPromise(ppath.join(path, Filename.rc), { + plugins: [`./plugin.cjs`], + }); + + await expect(run(`install`)).rejects.toMatchObject({ + code: 42, + }); + }), + ); }); }); From cd36b255b7cd1f1f5daa602e90128c86fcdbb329 Mon Sep 17 00:00:00 2001 From: merceyz Date: Thu, 18 Jul 2024 03:18:08 +0200 Subject: [PATCH 3/3] fix: write a message to inform the user about what is going on --- .../pkg-tests-specs/sources/commands/install.test.ts | 1 + packages/yarnpkg-cli/sources/lib.ts | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.ts b/packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.ts index 1965a3ef2ecd..345eb98a2545 100644 --- a/packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.ts +++ b/packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.ts @@ -921,6 +921,7 @@ module.exports = { await expect(run(`install`)).rejects.toMatchObject({ code: 42, + stdout: expect.stringContaining(`Yarn is terminating due to an unexpected empty event loop`), }); }), ); diff --git a/packages/yarnpkg-cli/sources/lib.ts b/packages/yarnpkg-cli/sources/lib.ts index 9bc351fa4996..2ff6c8148025 100644 --- a/packages/yarnpkg-cli/sources/lib.ts +++ b/packages/yarnpkg-cli/sources/lib.ts @@ -186,6 +186,12 @@ export async function getCli({cwd = ppath.cwd(), pluginConfiguration = getPlugin export async function runExit(argv: Array, {cwd = ppath.cwd(), selfPath, pluginConfiguration}: {cwd: PortablePath, selfPath: PortablePath | null, pluginConfiguration: PluginConfiguration}) { const cli = getBaseCli({cwd, pluginConfiguration}); + function unexpectedTerminationHandler() { + Cli.defaultContext.stdout.write(`ERROR: Yarn is terminating due to an unexpected empty event loop.\nPlease report this issue at https://github.com/yarnpkg/berry/issues.`); + } + + process.once(`beforeExit`, unexpectedTerminationHandler); + try { // The exit code is set to an error code before the CLI runs so that // if the event loop becomes empty and node terminates without @@ -197,6 +203,7 @@ export async function runExit(argv: Array, {cwd = ppath.cwd(), selfPath, Cli.defaultContext.stdout.write(cli.error(error)); process.exitCode = 1; } finally { + process.off(`beforeExit`, unexpectedTerminationHandler); await xfs.rmtempPromise(); } }