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

git-diff-filter ignored when no changes to src/ #1599

Closed
ndench opened this issue Oct 27, 2021 · 4 comments · Fixed by #1600
Closed

git-diff-filter ignored when no changes to src/ #1599

ndench opened this issue Oct 27, 2021 · 4 comments · Fixed by #1600

Comments

@ndench
Copy link

ndench commented Oct 27, 2021

Question Answer
Infection version 0.25.3
Test Framework version PHPUnit 9.5.10
PHP version 8.0.5
Platform Ubuntu
Github Repo -

In our repo, we have PHP code in src/ and TypeScript in assets/. It's very common for branches to contain no changes to src/. For branches that contain src/ changes, the git-diff-filter works great, and cuts ~4m from our build time. However for branches that don't; the filter is ignored and all mutations are generated.

Looking at the GitDiffFileProvider and running the underlying command on the different branches we get something like this:

With src/ changes:

$ git diff origin/main --diff-filter=AM --name-only | grep src/ | paste -sd ","
src/App/Controller/ListController.php,src/App/Services/AppValidator.php

Without src/

$ git diff origin/main --diff-filter=AM --name-only | grep src/ | paste -sd ","

We run infection with the following command after manually running our test suite with coverage:

php vendor/bin/infection --min-covered-msi=100 --min-msi=100 --coverage=build/infection --threads=$(shell nproc) --show-mutations --skip-initial-tests  --git-diff-filter=AM --git-diff-base=origin/${GITHUB_BASE_REF} --ignore-msi-with-no-mutations --no-progress --logger-github

Looking at

if ($this->filters !== []) {
it appears that no src/ changes is treated the same as not specifying any filters. Is there a way we make the SourceFileFilter differentiate between these two cases?

@maks-rafalko
Copy link
Member

maks-rafalko commented Oct 27, 2021

Hello

but what do you expect from Infection when only typescript files are changed in assets?

  1. do you expect Infection to be executed against typescript files? (resulting to 0 mutations and returning zero code thanks to --ignore-msi-with-no-mutations)
  2. do you expect Infection to not be executed at all?
  3. do you expect Infection to be executed for all the files?

As a workaround, if you choose the point 1, without any changes on Infection side, you can prepare a diff yourself and do not run Infection if only assets files are changed. See https://infection.github.io/guide/how-to.html#How-to-run-Infection-only-for-changed-files

other solution is to provide new option for Infection to grep not by hardcoded src/, but by any pattern. In your case it would by | grep -E 'src|assets'

for example:

--git-diff-source='src|assets'

@ndench
Copy link
Author

ndench commented Oct 27, 2021

I expected option 1 to occur, ie. it runs git diff sees that no files are changed and thus generates no mutations.
Although I'm not entirely sure what the practical difference is between option 1 and 2, the result is that infection does not mutations right?

Option 3 is what is currently happening, so that's not what I would have expected.

I think the suggestion of providing a git-diff-source is good, because it allows people to use the git diff filter if they're code is in a non-standard location. However, skipping all mutations if no files are modified is the best solution here IMO as this issue would also present if only README.md or some config files were modified as well.

@maks-rafalko
Copy link
Member

maks-rafalko commented Oct 27, 2021

This indeed requires more thinking, but I will put 2 ideas for future so they can be analyzed:

  1. if we would introduce --dig-diff-source, the end user would pass '' (empty string there) so that changing README.md will be in the list of filtered files, and Infection will be executed under the hood with --filter=README.md, which will result to 0 mutations. This is what is requested/expected by the author of this issue
  2. we can throw an exception (like NoCodeToMutate) if grep returns empty result and immediately stop Infection with 0 exit code, here

return (string) shell_exec(

I like the second idea for the simplicity. It will be a BC break, but since we are on 0.x, I don't think it's an issue. The first idea will not breack BC.

maks-rafalko added a commit that referenced this issue Oct 27, 2021
…rns empty result (no files to be mutated)

Fixes #1599

This will improve the speed of CI builds and immediately stop Infection execution.

Example: if `README.md` is updated on the root of the folder, we don't want/need to run Infection against the whole project.
@maks-rafalko
Copy link
Member

See #1600 if it helps

maks-rafalko added a commit that referenced this issue Oct 28, 2021
…rns empty result (#1600)

* Use Symfony's `Process::fromShellCommandLin()` to execute a command

* Stop Infection execution with `0` exit code when git diff filter returns empty result (no files to be mutated)

* Stop Infection execution with `0` exit code when git diff filter returns empty result (no files to be mutated)

Fixes #1599

This will improve the speed of CI builds and immediately stop Infection execution.

Example: if `README.md` is updated on the root of the folder, we don't want/need to run Infection against the whole project.

* Depending on OS, check command line differently

https://www.php.net/manual/en/function.escapeshellarg.php

> On Windows, escapeshellarg() instead replaces percent signs, exclamation marks (delayed variable substitution) and double quotes with spaces and adds double quotes around the string.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants