diff --git a/CHANGELOG.md b/CHANGELOG.md index 44b83f2bd464..b49fa06a43bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Fixes +* `[jest-cli]` `jest --onlyChanged --changedFilesWithAncestor` now also works + with git. ([#5189](https://github.com/facebook/jest/pull/5189)) * `[jest-config]` fix unexpected condition to avoid infinite recursion in Windows platform. ([#5161](https://github.com/facebook/jest/pull/5161)) diff --git a/docs/CLI.md b/docs/CLI.md index 929bc25cedc3..dd8684517cc1 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -102,6 +102,11 @@ two times slower._ If you want to inspect the cache, use `--showConfig` and look at the `cacheDirectory` value. If you need to clear the cache, use `--clearCache`. +### `--changedFilesWithAncestor` + +When used together with `--onlyChanged` or `--watch`, it runs tests related to +the current changes and the changes made in the last commit. + ### `--ci` When this option is provided, Jest will assume it is running in a CI @@ -182,7 +187,8 @@ Write test results to a file when the `--json` option is also specified. ### `--lastCommit` -Will run all tests affected by file changes in the last commit made. +When used together with `--onlyChanged`, it will run all tests affected by file +changes in the last commit made. ### `--listTests` diff --git a/integration_tests/__tests__/jest_changed_files.test.js b/integration_tests/__tests__/jest_changed_files.test.js index e56cd6029dc5..759f246f49e8 100644 --- a/integration_tests/__tests__/jest_changed_files.test.js +++ b/integration_tests/__tests__/jest_changed_files.test.js @@ -175,6 +175,22 @@ test('gets changed files for git', async () => { .map(filePath => path.basename(filePath)) .sort(), ).toEqual(['file1.txt']); + + run(`${GIT} commit -am "test2"`, DIR); + + writeFiles(DIR, { + 'file4.txt': 'file4', + }); + + ({changedFiles: files} = await getChangedFilesForRoots(roots, { + withAncestor: true, + })); + // Returns files from current uncommitted state + the last commit + expect( + Array.from(files) + .map(filePath => path.basename(filePath)) + .sort(), + ).toEqual(['file1.txt', 'file4.txt']); }); test('gets changed files for hg', async () => { diff --git a/packages/jest-changed-files/src/git.js b/packages/jest-changed-files/src/git.js index 8057c5612462..ef02aaea3dbc 100644 --- a/packages/jest-changed-files/src/git.js +++ b/packages/jest-changed-files/src/git.js @@ -13,44 +13,59 @@ import type {Options, SCMAdapter} from 'types/ChangedFiles'; import path from 'path'; import childProcess from 'child_process'; +const findChangedFilesUsingCommand = async (args, cwd) => { + return new Promise((resolve, reject) => { + const child = childProcess.spawn('git', args, {cwd}); + let stdout = ''; + let stderr = ''; + child.stdout.on('data', data => (stdout += data)); + child.stderr.on('data', data => (stderr += data)); + child.on('error', e => reject(e)); + child.on('close', code => { + if (code === 0) { + stdout = stdout.trim(); + if (stdout === '') { + resolve([]); + } else { + resolve( + stdout + .split('\n') + .map(changedPath => path.resolve(cwd, changedPath)), + ); + } + } else { + reject(code + ': ' + stderr); + } + }); + }); +}; + const adapter: SCMAdapter = { findChangedFiles: async ( cwd: string, options?: Options, ): Promise> => { - if (options && options.withAncestor) { - throw new Error( - '`changedFilesWithAncestor` is not supported in git repos.', + if (options && options.lastCommit) { + return await findChangedFilesUsingCommand( + ['show', '--name-only', '--pretty=%b', 'HEAD'], + cwd, + ); + } else if (options && options.withAncestor) { + const changed = await findChangedFilesUsingCommand( + ['diff', '--name-only', 'HEAD^'], + cwd, + ); + const untracked = await findChangedFilesUsingCommand( + ['ls-files', '--other', '--exclude-standard'], + cwd, + ); + return changed.concat(untracked); + } else { + return await findChangedFilesUsingCommand( + ['ls-files', '--other', '--modified', '--exclude-standard'], + cwd, ); } - return new Promise((resolve, reject) => { - const args = - options && options.lastCommit - ? ['show', '--name-only', '--pretty=%b', 'HEAD'] - : ['ls-files', '--other', '--modified', '--exclude-standard']; - const child = childProcess.spawn('git', args, {cwd}); - let stdout = ''; - let stderr = ''; - child.stdout.on('data', data => (stdout += data)); - child.stderr.on('data', data => (stderr += data)); - child.on('error', e => reject(e)); - child.on('close', code => { - if (code === 0) { - stdout = stdout.trim(); - if (stdout === '') { - resolve([]); - } else { - resolve( - stdout - .split('\n') - .map(changedPath => path.resolve(cwd, changedPath)), - ); - } - } else { - reject(code + ': ' + stderr); - } - }); - }); }, getRoot: async (cwd: string): Promise => { diff --git a/packages/jest-cli/src/cli/args.js b/packages/jest-cli/src/cli/args.js index 2c09cfce60d1..f692493908ca 100644 --- a/packages/jest-cli/src/cli/args.js +++ b/packages/jest-cli/src/cli/args.js @@ -104,9 +104,8 @@ export const options = { }, changedFilesWithAncestor: { description: - 'When used together with `--onlyChanged`, it runs tests ' + - 'related to the current changes and the changes made in the last commit. ' + - '(NOTE: this only works for hg repos)', + 'When used together with `--onlyChanged` or `--watch`, it runs tests ' + + 'related to the current changes and the changes made in the last commit. ', type: 'boolean', }, ci: { @@ -268,8 +267,8 @@ export const options = { lastCommit: { default: undefined, description: - 'Will run all tests affected by file changes in the last ' + - 'commit made.', + 'When used together with `--onlyChanged`, it will run all tests ' + + 'affected by file changes in the last commit made.', type: 'boolean', }, listTests: {