diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ef78c06e85d..cdd35606e198 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ - `[babel-plugin-jest-hoist]` Use `denylist` instead of the deprecated `blacklist` for Babel 8 support ([#14109](https://github.com/jestjs/jest/pull/14109)) - `[expect]` Check error instance type for `toThrow/toThrowError` ([#14576](https://github.com/jestjs/jest/pull/14576)) - `[jest-changed-files]` Print underlying errors when VCS commands fail ([#15052](https://github.com/jestjs/jest/pull/15052)) +- `[jest-changed-files]` Abort `sl root` call if output resembles a steam locomotive ([#15053](https://github.com/jestjs/jest/pull/15053)) - `[jest-circus]` [**BREAKING**] Prevent false test failures caused by promise rejections handled asynchronously ([#14315](https://github.com/jestjs/jest/pull/14315)) - `[jest-circus]` Replace recursive `makeTestResults` implementation with iterative one ([#14760](https://github.com/jestjs/jest/pull/14760)) - `[jest-circus]` Omit `expect.hasAssertions()` errors if a test already has errors ([#14866](https://github.com/jestjs/jest/pull/14866)) diff --git a/packages/jest-changed-files/src/sl.ts b/packages/jest-changed-files/src/sl.ts index 4230e3485290..09f7162107ed 100644 --- a/packages/jest-changed-files/src/sl.ts +++ b/packages/jest-changed-files/src/sl.ts @@ -16,6 +16,9 @@ import type {SCMAdapter} from './types'; */ const env = {...process.env, HGPLAIN: '1'}; +// Whether `sl` is a steam locomotive or not +let isSteamLocomotive = false; + const adapter: SCMAdapter = { findChangedFiles: async (cwd, options) => { const includePaths = options.includePaths ?? []; @@ -42,8 +45,29 @@ const adapter: SCMAdapter = { }, getRoot: async cwd => { + if (isSteamLocomotive) { + return null; + } + try { - const result = await execa('sl', ['root'], {cwd, env}); + const subprocess = execa('sl', ['root'], {cwd, env}); + + // Check if we're calling sl (steam locomotive) instead of sl (sapling) + // by looking for the escape character in the first chunk of data. + if (subprocess.stdout) { + subprocess.stdout.once('data', (data: Buffer | string) => { + data = Buffer.isBuffer(data) ? data.toString() : data; + if (data.codePointAt(0) === 27) { + subprocess.cancel(); + isSteamLocomotive = true; + } + }); + } + + const result = await subprocess; + if (result.killed && isSteamLocomotive) { + return null; + } return result.stdout; } catch {