Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jest --changedFilesToContributeTo=origin/master #5188

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* `[jest-cli]` Make Jest exit without an error when no tests are found in the
case of `--lastCommit`, `--findRelatedTests`, or `--onlyChanged` options
having been passed to the CLI
* `[jest-cli]` Allow selectively running tests for code changed since arbitrary
revisions. ([#5188](https://github.com/facebook/jest/pull/5188))

### Fixes
* `[jest-cli]` Use `import-local` to support global Jest installations.
Expand All @@ -13,6 +15,8 @@
([#5289](https://github.com/facebook/jest/pull/5289))
* `[docs]` Update mention of the minimal version of node supported [#4947](https://github.com/facebook/jest/issues/4947)
* `[jest-cli]` Fix missing newline in console message ([#5308](https://github.com/facebook/jest/pull/5308))
* `[jest-cli]` `--lastCommit` and `--changedFilesWithAncestor` now take effect
even when `--onlyChanged` is not specified. ([#5307](https://github.com/facebook/jest/pull/5307))

### Chore & Maintenance

Expand Down
14 changes: 10 additions & 4 deletions docs/CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,16 @@ 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`.

### `--changedFilesToContributeTo`

When used together with `--onlyChanged` or `--watch`, it runs tests related the
changes since the provided revision. If the current branch is not a child of the
given commit, then only changes made locally will be tested.

### `--changedFilesWithAncestor`

When used together with `--onlyChanged` or `--watch`, it runs tests related to
the current changes and the changes made in the last commit.
Runs tests related to the current changes and the changes made in the last
commit. Behaves similarly to `--onlyChanged`.

### `--ci`

Expand Down Expand Up @@ -188,8 +194,8 @@ Write test results to a file when the `--json` option is also specified.

### `--lastCommit`

When used together with `--onlyChanged`, it will run all tests affected by file
changes in the last commit made.
Run all tests affected by file changes in the last commit made. Behaves
similarly to `--onlyChanged`.

### `--listTests`

Expand Down
64 changes: 64 additions & 0 deletions integration-tests/__tests__/jest_changed_files.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,37 @@ test('gets changed files for git', async () => {
.map(filePath => path.basename(filePath))
.sort(),
).toEqual(['file1.txt', 'file4.txt']);

run(`${GIT} add file4.txt`, DIR);
run(`${GIT} commit -m "test3"`, DIR);

({changedFiles: files} = await getChangedFilesForRoots(roots, {
toContributeTo: 'HEAD^^',
}));
// Returns files from the last 2 commits
expect(
Array.from(files)
.map(filePath => path.basename(filePath))
.sort(),
).toEqual(['file1.txt', 'file4.txt']);

run(`${GIT} checkout HEAD^^ -b feature-branch`, DIR);

writeFiles(DIR, {
'file5.txt': 'file5',
});
run(`${GIT} add file5.txt`, DIR);
run(`${GIT} commit -m "test5"`, DIR);

({changedFiles: files} = await getChangedFilesForRoots(roots, {
toContributeTo: 'master',
}));
// Returns files from this branch but not ones that only exist on master
expect(
Array.from(files)
.map(filePath => path.basename(filePath))
.sort(),
).toEqual(['file5.txt']);
});

test('gets changed files for hg', async () => {
Expand Down Expand Up @@ -261,4 +292,37 @@ test('gets changed files for hg', async () => {
.map(filePath => path.basename(filePath))
.sort(),
).toEqual(['file1.txt', 'file4.txt']);

run(`${HG} add file4.txt`, DIR);
run(`${HG} commit -m "test3"`, DIR);

({changedFiles: files} = await getChangedFilesForRoots(roots, {
toContributeTo: '-3',
}));
// Returns files from the last 2 commits
expect(
Array.from(files)
.map(filePath => path.basename(filePath))
.sort(),
).toEqual(['file1.txt', 'file4.txt']);

run(`${HG} bookmark master`, DIR);
// Back up and develop on a different branch
run(`${HG} checkout --rev=-2`, DIR);

writeFiles(DIR, {
'file5.txt': 'file5',
});
run(`${HG} add file5.txt`, DIR);
run(`${HG} commit -m "test4"`, DIR);

({changedFiles: files} = await getChangedFilesForRoots(roots, {
toContributeTo: 'master',
}));
// Returns files from this branch but not ones that only exist on master
expect(
Array.from(files)
.map(filePath => path.basename(filePath))
.sort(),
).toEqual(['file5.txt']);
});
25 changes: 18 additions & 7 deletions packages/jest-changed-files/src/git.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import type {Options, SCMAdapter} from 'types/ChangedFiles';
import path from 'path';
import childProcess from 'child_process';

const findChangedFilesUsingCommand = async (args, cwd) => {
const findChangedFilesUsingCommand = async (
args: Array<string>,
cwd: Path,
): Promise<Array<Path>> => {
return new Promise((resolve, reject) => {
const child = childProcess.spawn('git', args, {cwd});
let stdout = '';
Expand All @@ -30,6 +33,7 @@ const findChangedFilesUsingCommand = async (args, cwd) => {
resolve(
stdout
.split('\n')
.filter(s => s !== '')
.map(changedPath => path.resolve(cwd, changedPath)),
);
}
Expand All @@ -45,21 +49,28 @@ const adapter: SCMAdapter = {
cwd: string,
options?: Options,
): Promise<Array<Path>> => {
const toContributeTo: ?string =
options && (options.withAncestor ? 'HEAD^' : options.toContributeTo);

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^'],
} else if (toContributeTo) {
const committed = await findChangedFilesUsingCommand(
['log', '--name-only', '--pretty=%b', 'HEAD', `^${toContributeTo}`],
cwd,
);
const staged = await findChangedFilesUsingCommand(
['diff', '--cached', '--name-only'],
cwd,
);
const untracked = await findChangedFilesUsingCommand(
['ls-files', '--other', '--exclude-standard'],
const unstaged = await findChangedFilesUsingCommand(
['ls-files', '--other', '--modified', '--exclude-standard'],
cwd,
);
return changed.concat(untracked);
return [...committed, ...staged, ...unstaged];
} else {
return await findChangedFilesUsingCommand(
['ls-files', '--other', '--modified', '--exclude-standard'],
Expand Down
2 changes: 2 additions & 0 deletions packages/jest-changed-files/src/hg.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const adapter: SCMAdapter = {
let args = ['status', '-amnu'];
if (options && options.withAncestor) {
args.push('--rev', 'ancestor(.^)');
} else if (options && options.toContributeTo) {
args.push('--rev', `ancestor(., ${options.toContributeTo})`);
} else if (options && options.lastCommit === true) {
args = ['tip', '--template', '{files%"{file}\n"}'];
}
Expand Down
13 changes: 13 additions & 0 deletions packages/jest-cli/src/__tests__/cli/args.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ describe('check', () => {
);
});

it('raises an exception when lastCommit and watchAll are both specified', () => {
const argv: Argv = {lastCommit: true, watchAll: true};
expect(() => check(argv)).toThrow(
'Both --lastCommit and --watchAll were specified',
);
});

it('sets onlyChanged if lastCommit is specified', () => {
const argv: Argv = {lastCommit: true};
check(argv);
expect(argv.onlyChanged).toBe(true);
});

it('raises an exception if findRelatedTests is specified with no file paths', () => {
const argv: Argv = {_: [], findRelatedTests: true};
expect(() => check(argv)).toThrow(
Expand Down
40 changes: 29 additions & 11 deletions packages/jest-cli/src/cli/args.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,22 @@ export const check = (argv: Argv) => {
);
}

if (argv.onlyChanged && argv.watchAll) {
throw new Error(
'Both --onlyChanged and --watchAll were specified, but these two ' +
'options do not make sense together. Try the --watch option which ' +
'reruns only tests related to changed files.',
);
for (const key of [
'onlyChanged',
'lastCommit',
'changedFilesWithAncestor',
'changedFilesToContributeTo',
]) {
if (argv[key]) {
argv.onlyChanged = true;
}
if (argv[key] && argv.watchAll) {
throw new Error(
`Both --${key} and --watchAll were specified, but these two ` +
'options do not make sense together. Try the --watch option which ' +
'reruns only tests related to changed files.',
);
}
}

if (argv.findRelatedTests && argv._.length === 0) {
Expand Down Expand Up @@ -102,10 +112,18 @@ export const options = {
' dependency information.',
type: 'string',
},
changedFilesToContributeTo: {
description:
'Runs tests related the changes since the provided branch. If the ' +
'current branch has diverged from the given branch, then only changes ' +
'made locally will be tested. Behaves similarly to `--onlyChanged`.',
nargs: 1,
type: 'string',
},
changedFilesWithAncestor: {
description:
'When used together with `--onlyChanged` or `--watch`, it runs tests ' +
'related to the current changes and the changes made in the last commit. ',
'Runs tests related to the current changes and the changes made in the ' +
'last commit. Behaves similarly to `--onlyChanged`.',
type: 'boolean',
},
ci: {
Expand Down Expand Up @@ -267,8 +285,8 @@ export const options = {
lastCommit: {
default: undefined,
description:
'When used together with `--onlyChanged`, it will run all tests ' +
'affected by file changes in the last commit made.',
'Run all tests affected by file changes in the last commit made. ' +
'Behaves similarly to `--onlyChanged`.',
type: 'boolean',
},
listTests: {
Expand Down Expand Up @@ -353,7 +371,7 @@ export const options = {
description:
'Attempts to identify which tests to run based on which ' +
"files have changed in the current repository. Only works if you're " +
'running tests in a git repository at the moment.',
'running tests in a git or hg repository at the moment.',
type: 'boolean',
},
onlyFailures: {
Expand Down
1 change: 1 addition & 0 deletions packages/jest-cli/src/get_changed_files_promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default (
);
return getChangedFilesForRoots(allRootsForAllProjects, {
lastCommit: globalConfig.lastCommit,
toContributeTo: globalConfig.changedFilesToContributeTo,
withAncestor: globalConfig.changedFilesWithAncestor,
});
}
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ const getConfigs = (
return {
globalConfig: Object.freeze({
bail: options.bail,
changedFilesToContributeTo: options.changedFilesToContributeTo,
changedFilesWithAncestor: options.changedFilesWithAncestor,
collectCoverage: options.collectCoverage,
collectCoverageFrom: options.collectCoverageFrom,
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ export default function normalize(options: InitialOptions, argv: Argv) {
case 'bail':
case 'browser':
case 'cache':
case 'changedFilesToContributeTo':
case 'changedFilesWithAncestor':
case 'clearMocks':
case 'collectCoverage':
Expand Down
1 change: 1 addition & 0 deletions packages/jest-config/src/valid_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default ({
browser: false,
cache: true,
cacheDirectory: '/tmp/user/jest',
changedFilesToContributeTo: '',
changedFilesWithAncestor: false,
clearMocks: false,
collectCoverage: true,
Expand Down
1 change: 1 addition & 0 deletions test_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {GlobalConfig, ProjectConfig} from 'types/Config';

const DEFAULT_GLOBAL_CONFIG: GlobalConfig = {
bail: false,
changedFilesToContributeTo: '',
changedFilesWithAncestor: false,
collectCoverage: false,
collectCoverageFrom: [],
Expand Down
1 change: 1 addition & 0 deletions types/Argv.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type Argv = {|
browser: boolean,
cache: boolean,
cacheDirectory: string,
changedFilesToContributeTo: string,
changedFilesWithAncestor: boolean,
clearMocks: boolean,
ci: boolean,
Expand Down
1 change: 1 addition & 0 deletions types/ChangedFiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {Path} from 'types/Config';
export type Options = {|
lastCommit?: boolean,
withAncestor?: boolean,
toContributeTo?: string,
|};

export type ChangedFiles = Set<Path>;
Expand Down
2 changes: 2 additions & 0 deletions types/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export type InitialOptions = {
cacheDirectory?: Path,
clearMocks?: boolean,
changedFilesWithAncestor?: boolean,
changedFilesToContributeTo?: string,
collectCoverage?: boolean,
collectCoverageFrom?: Array<Glob>,
collectCoverageOnlyFrom?: {[key: string]: boolean},
Expand Down Expand Up @@ -157,6 +158,7 @@ export type SnapshotUpdateState = 'all' | 'new' | 'none';

export type GlobalConfig = {|
bail: boolean,
changedFilesToContributeTo: string,
changedFilesWithAncestor: boolean,
collectCoverage: boolean,
collectCoverageFrom: Array<Glob>,
Expand Down