Skip to content

Commit

Permalink
feat(ignore patterns): add "ignorePatterns" config option (#2848)
Browse files Browse the repository at this point in the history
Add the ability to specify `ignorePatterns` in your Stryker configuration. This replaces `files` option which is now deprecated.

By specifying `ignorePatterns` you choose which files should not be copied to the Sandbox directory (inside the `.stryker-tmp` directory). This effectively excludes them from being used during mutation testing.

For example:

```json
{
  "ignorePatterns": ["dist"]
}
```

This will discover all files in your current working directory, _except_ for files matching the `"dist"` pattern. Stryker uses [.gitignore](https://git-scm.com/docs/gitignore) rules to resolve these patterns.

Stryker always adds `['.git', 'node_modules', '/reports', 'stryker.log', '.stryker-tmp']` when resolving these patterns. If you really want them in your sandbox, you can un-ignore them using a `!` prefix in your pattern, for example:

```json
{
  "ignorePatterns": ["!node_modules"]
}
```

The `ignorePatterns` is now also the default way files are discovered. Previously, Stryker used `git ls-files --others --exclude-standard --cached --exclude .stryker-tmp` to discover files by default. This had some limitations:

* ❌ It only worked inside a git repository and you had to have `git` installed. If not, you got an error and had to use `files`
* ❌ If a `.gitignore`'d file is needed to run your tests, you needed to fall back on `files`. 

Specifying `files` is now deprecated, but still works for the time being. Stryker will rewrite your file patterns internally to ignore patterns.

Closes #1593
Closes #2739

BREAKING CHANGE: Stryker will no longer use a git command to determine which files belong to your project. Instead, it will rely on sane defaults. You can change this behavior by defining [`ignorePatterns`](https://stryker-mutator.io/docs/stryker-js/configuration/#ignorepatterns-string).

BREAKING CHANGE: The `files` configuration option is deprecated and will be removed in a future release. Please use [`ignorePatterns`](https://stryker-mutator.io/docs/stryker-js/configuration/#ignorepatterns-string) instead.

This:

```json
{
  "files": ["foo.js"]
}
```

Is equivalent to:

```json
{
  "ignorePatterns": ["**", "!foo.js"]
}
```
  • Loading branch information
nicojs committed May 3, 2021
1 parent 40f9a1d commit a69992c
Show file tree
Hide file tree
Showing 17 changed files with 613 additions and 487 deletions.
22 changes: 13 additions & 9 deletions docs/configuration.md
Expand Up @@ -126,21 +126,25 @@ Set the log level that Stryker uses to write to the "stryker.log" file. Possible

### `files` [`string[]`]

Default: result of `git ls-files --others --exclude-standard --cached --exclude .stryker-tmp`<br />
Default: `undefined`<br />
Command line: `[--files|-f] src/**/*.js,a.js,test/**/*.js`<br />
Config file: `"files": ["src/**/*.js", "!src/**/index.js", "test/**/*.js"]`

With `files`, you can choose which files should be included in your test runner sandbox.
This is normally not needed as it defaults to all files not ignored by git.
Try it out yourself with this command: `git ls-files --others --exclude-standard --cached --exclude .stryker-tmp`.
**DEPRECATED**. Please use [`ignorePatterns`](#ignorepatterns-string) instead.

If you do need to override `files` (for example: when your project does not live in a git repository),
you can override the files here.
### `ignorePatterns` [`string[]`]

When using the command line, the list can only contain a comma separated list of globbing expressions.
When using the config file you can provide an array with `string`s
Default: `[]`<br />
Command line: `--ignorePatterns dist,coverage`<br />
Config file: `"ignorePatterns": ["dist", "coverage"]`<br />

Specify the patterns to all files or directories that are not used to run your tests and thus should _not be copied_ to the sandbox directory for mutation testing. Each patterns in this array should be a [`.gitignore`-style glob pattern](https://git-scm.com/docs/gitignore#_pattern_format).

You can *ignore* files by adding an exclamation mark (`!`) at the start of an expression.
These patterns are **always ignored**: `['node_modules', '.git', '/reports', '/stryker.log', '.stryker-tmp']`. Because Stryker always ignores these, you should rarely have to adjust the `"ignorePatterns"` setting at all. If you want to undo one of these ignore patterns, you can use the `!` prefix, for example: `['!node_modules']`.

If a glob pattern starts with `/`, the pattern is relative to the current working directory. For example, `/foo.js` matches to `foo.js` but not `subdir/foo.js`.

When using the command line, the list can only contain a comma separated list of globbing expressions.

### `inPlace` [`boolean`]

Expand Down
6 changes: 4 additions & 2 deletions e2e/test/grunt-stryker-test/Gruntfile.js
Expand Up @@ -18,13 +18,15 @@ module.exports = function (grunt) {
options: {
testRunner: 'karma',
logLevel: 'info',
fileLogLevel: 'warn',
concurrency: 2,
tempDirName: '.stryker-tmp-2'
tempDirName: '.stryker-tmp-2',
karma: { config: { files: [ 'sampleProject/**' ] }}
},
},
withConfigFile: {
options: {
configFile: './stryker.conf.js'
configFile: './stryker.grunt.conf.json'
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion e2e/test/grunt-stryker-test/package.json
Expand Up @@ -3,6 +3,8 @@
"version": "0.0.0",
"private": true,
"scripts": {
"test": "grunt test"
"pretest": "rimraf reports stryker.log",
"test": "grunt test",
"posttest": "mocha --no-config --require ../../tasks/ts-node-register.js verify/*.ts"
}
}
15 changes: 0 additions & 15 deletions e2e/test/grunt-stryker-test/stryker.conf.js

This file was deleted.

17 changes: 17 additions & 0 deletions e2e/test/grunt-stryker-test/stryker.grunt.conf.json
@@ -0,0 +1,17 @@
{
"$schema": "../../node_modules/@stryker-mutator/core/schema/stryker-schema.json",
"mutate": [
"sampleProject/src/**"
],
"karma": {
"config": {
"files": [
"sampleProject/**"
]
}
},
"testRunner": "karma",
"logLevel": "info",
"fileLogLevel": "warn",
"concurrency": 2
}
9 changes: 9 additions & 0 deletions e2e/test/grunt-stryker-test/verify/verify.ts
@@ -0,0 +1,9 @@
import { expect } from 'chai';
import fs from 'fs';

describe('grunt stryker test', () => {
it('should not log warnings', () => {
const logFileContents = fs.readFileSync('stryker.log', 'utf-8');
expect(logFileContents).empty;
});
});
1 change: 0 additions & 1 deletion e2e/test/use-stryker-programmatically/usingStryker.ts
Expand Up @@ -2,7 +2,6 @@ import Stryker from '@stryker-mutator/core';

new Stryker({
coverageAnalysis: 'off',
files: [],
mutate: [],
testRunner: 'mocha'
}).runMutationTest().then(() => console.log('done'));
17 changes: 9 additions & 8 deletions packages/api/schema/stryker-core.json
Expand Up @@ -253,7 +253,7 @@
"type": "number"
},
"maxTestRunnerReuse": {
"description": "Restart each forked threads after <n> runs. Not recommended unless you are experiencing memory leaks that you are unable to resolve. (default: 0)",
"description": "Restart each forked worker after <n> runs. Not recommended unless you are experiencing memory leaks that you are unable to resolve. (default: 0)",
"type": "number",
"default": 0
},
Expand Down Expand Up @@ -282,18 +282,19 @@
"$ref": "#/definitions/eventRecorderOptions",
"default": {}
},
"ignorePatterns": {
"description": "Specify the patterns to all files or directories that are not used to run your tests and thus should *not be copied* to the sandbox directory for mutation testing. Each patterns in this array should be a [`.gitignore`-style glob pattern](https://git-scm.com/docs/gitignore#_pattern_format).\n\nThese patterns are **always ignored**: `['node_modules', '.git', '/reports', '/stryker.log', '.stryker-tmp']`. Because Stryker always ignores these, you should rarely have to adjust the `\"ignorePatterns\"` setting at all. If you want to undo one of these ignore patterns, you can use the `!` prefix, for example: `['!node_modules']`.\n\nIf a glob pattern starts with `/`, the pattern is relative to the current working directory. For example, `/foo.js` matches to `foo.js` but not `subdir/foo.js`.\n\nWhen using the command line, the list can only contain a comma separated list of globbing expressions.",
"type": "array",
"items": {
"type": "string"
},
"default": []
},
"fileLogLevel": {
"description": "Set the log level that Stryker uses to write to the \"stryker.log\" file",
"$ref": "#/definitions/logLevel",
"default": "off"
},
"files": {
"description": "With `files` you can choose which files should be included in your test runner sandbox.\nThis is normally not needed as it defaults to all files not ignored by git.\nTry it out yourself with this command: `git ls-files --others --exclude-standard --cached --exclude .stryker-tmp`.\n\nIf you do need to override `files` (for example: when your project does not live in a git repository),\nyou can override the files here.\n\nWhen using the command line, the list can only contain a comma separated list of globbing expressions.\nWhen using the config file you can provide an array with `string`s",
"type": "array",
"items": {
"type": "string"
}
},
"inPlace": {
"type": "boolean",
"description": "Determines whether or not Stryker should mutate your files in place. Note: mutating your files in place is generally not needed for mutation testing, unless you have a dependency in your project that is really dependent on the file locations (like \"app-root-path\" for example).\n\nWhen `true`, Stryker will override your files, but it will keep a copy of the originals in the temp directory (using `tempDirName`) and it will place the originals back after it is done.\n\nWhen `false` (default) Stryker will work in the copy of your code inside the temp directory.",
Expand Down
21 changes: 20 additions & 1 deletion packages/core/src/config/options-validator.ts
Expand Up @@ -13,7 +13,7 @@ import { coreTokens } from '../di';
import { ConfigError } from '../errors';
import { isWarningEnabled } from '../utils/object-utils';
import { CommandTestRunner } from '../test-runner/command-test-runner';
import { MUTATION_RANGE_REGEX } from '../input';
import { IGNORE_PATTERN_CHARACTER, MUTATION_RANGE_REGEX } from '../input';

import { describeErrors } from './validation-errors';

Expand Down Expand Up @@ -70,6 +70,25 @@ export class OptionsValidator {
);
delete rawOptions.transpilers;
}
if (Array.isArray(rawOptions.files)) {
const ignorePatternsName = propertyPath<StrykerOptions>('ignorePatterns');
const isString = (uncertain: unknown): uncertain is string => typeof uncertain === 'string';
const files = rawOptions.files.filter(isString);
const newIgnorePatterns: string[] = [
'**',
...files.map((filePattern) =>
filePattern.startsWith(IGNORE_PATTERN_CHARACTER) ? filePattern.substr(1) : `${IGNORE_PATTERN_CHARACTER}${filePattern}`
),
];
delete rawOptions.files;
this.log.warn(
`DEPRECATED. Use of "files" is deprecated, please use "${ignorePatternsName}" instead (or remove "files" altogether will probably work as well). For now, rewriting them as ${JSON.stringify(
newIgnorePatterns
)}. See https://stryker-mutator.io/docs/stryker-js/configuration/#ignorepatterns-string`
);
const existingIgnorePatterns = Array.isArray(rawOptions[ignorePatternsName]) ? (rawOptions[ignorePatternsName] as unknown[]) : [];
rawOptions[ignorePatternsName] = [...newIgnorePatterns, ...existingIgnorePatterns];
}
}

private additionalValidation(options: StrykerOptions) {
Expand Down
9 changes: 3 additions & 6 deletions packages/core/src/input/input-file-collection.ts
@@ -1,5 +1,3 @@
import os from 'os';

import { File, MutationRange } from '@stryker-mutator/api/core';
import { Logger } from '@stryker-mutator/api/logging';
import { normalizeWhitespaces } from '@stryker-mutator/util';
Expand All @@ -15,12 +13,11 @@ export class InputFileCollection {
this.mutationRanges = mutationRangeToInstrument;
}

public logFiles(log: Logger): void {
public logFiles(log: Logger, ignoreRules: readonly string[]): void {
if (!this.files.length) {
log.warn(
`No files selected. Please make sure you either${os.EOL}` +
` (1) Run Stryker inside a Git repository; or${os.EOL}` +
' (2) Specify the `files` property in your Stryker configuration (`--files via command line`).'
normalizeWhitespaces(`No files found in directory ${process.cwd()} using ignore rules: ${JSON.stringify(ignoreRules)}.
Make sure you run Stryker from the root directory of your project with the correct "ignorePatterns".`)
);
} else {
if (this.filesToMutate.length) {
Expand Down

0 comments on commit a69992c

Please sign in to comment.