fix: skip phpcs when no PHP files changed, handle filenames with spaces#22
Conversation
When CHANGED_FILES is empty (no PHP files in the PR), phpcs was called with no file arguments. Depending on the repo phpcs.xml, this either produced a non-JSON error string (failing jq validation → exit 1) or scanned the entire codebase unintentionally. Also switches from bare variable expansion to xargs so filenames containing spaces are passed as individual arguments rather than being split on whitespace. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ec48262 to
be43506
Compare
| fi | ||
|
|
||
| # Run phpcs — use xargs so filenames with spaces are handled correctly | ||
| JSON_REPORT=$(echo \"${{ env.CHANGED_FILES }}\" | xargs -d '\n' vendor/bin/phpcs --report=json -q) |
There was a problem hiding this comment.
I think escaping quotes produces something like "file1.php file2.php" and PHPCS will treat it as a single argument. I'm not a bash expert, but Claude suggests printf '%s\n' "$CHANGED_FILES" | xargs -d '\n'.
| - name: Get list of changed files | ||
| id: files | ||
| run: | | ||
| echo "CHANGED_FILES=$(git diff --name-only --diff-filter=AM ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- . ':!tests' | grep '\.php$' | tr '\n' ' ')" >> $GITHUB_ENV | ||
| { | ||
| echo 'CHANGED_FILES<<EOF' | ||
| git diff --name-only --diff-filter=AM ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- . ':!tests' | grep '\.php$' || true | ||
| echo EOF | ||
| } >> $GITHUB_ENV |
There was a problem hiding this comment.
Maybe we can detect this super-early after the actions/checkout@v4 step and gate the rest of the steps with an if step condition?
- Move changed files detection right after checkout so expensive steps (setup-php, composer-install) are skipped entirely when no PHP files changed - Gate all remaining steps with has_php_files output instead of an early exit inside the shell script - Use printf + xargs -d newline instead of echo with escaped quotes so filenames containing spaces are passed as single arguments to phpcs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
shvlv
left a comment
There was a problem hiding this comment.
@WayneRocha it looks good from my side. Did you try it on the real PR?
Let's await other folks review.
|
@shvlv I only runned the phpcs commands on my machine (PR images), but I couldn't run the github workflow itself locally. |
Co-authored-by: Volodymyr Shelmuk <shvv86@gmail.com>
You can create a PR and use |
|
All the refered PR's are for test. Will be closed later, but reviews can se them to know if it's working well |
redscar
left a comment
There was a problem hiding this comment.
This looks great. I see that you fixed file names with spaces and a few other pieces as well. Do you have a small list of scenarios this fixes?
|
@redscar Basically...
Nothing elaborated, only guarantee that the phpcs CI don't error anymore on our PR's |
…ode (#23) ## Problem After #22 merged, phpcs CI still fails incorrectly when violations are found. `xargs` translates phpcs exit code `1` (violations found) into exit code `123`. GitHub Actions runs steps with `bash -e` by default, so when `xargs` returns `123` the step dies immediately — reviewdog never runs, no inline comments are posted, and the job fails with a cryptic exit code instead of the actual violations. **Practical impact:** - PRs with real phpcs violations get a job failure with exit code 123 and no inline comments - Developers have no idea what they need to fix ## Fix Replace `printf | xargs` with `mapfile` to read `CHANGED_FILES` into a bash array. This: - Gives us phpcs's **real exit code** (0 = clean, 1 = violations) instead of xargs's 123 - Uses `|| PHPCS_EXIT_CODE=$?` to prevent `bash -e` from killing the step before reviewdog runs - Still correctly handles **filenames with spaces** (each array element is one file path) ```bash # Before JSON_REPORT=$(printf '%s\n' "$CHANGED_FILES" | xargs -d '\n' vendor/bin/phpcs --report=json -q) PHPCS_EXIT_CODE=$? # always 123 when violations found, never 1 # After mapfile -t FILES <<< "$CHANGED_FILES" PHPCS_EXIT_CODE=0 JSON_REPORT=$(vendor/bin/phpcs --report=json -q "${FILES[@]}") || PHPCS_EXIT_CODE=$? ``` ## Test PRs All affected repos have test PRs pointing to `fix/phpcs-xargs-exit-code` (updated from #22 test PRs). ## Examples the-events-calendar/the-events-calendar#5676 the-events-calendar/tribe-common#2939 the-events-calendar/event-tickets#4280 More in #22
…de (#24) ## Problem After #22 and #23, the phpcs job still fails on PRs that introduce **no new violations**. The `Run reviewdog` step ends with: ```bash exit $PHPCS_EXIT_CODE ``` So the job's pass/fail is driven by **phpcs's** exit code. But phpcs scans the whole changed file, so its exit code reflects **every** issue in that file — including pre-existing ones on lines the PR never touched. `reviewdog`, by contrast, runs with `-filter-mode=added` and only reports/fails on issues introduced on the PR's **added lines**. The two disagree, and the job exits on the phpcs code. ### Reproduction — the-events-calendar#5687 "clean" test (`bf090fc`) From the job log: ``` mapfile -t FILES <<< "src/functions/views/provider.php" ##[error]Process completed with exit code 2. ``` - phpcs scanned `provider.php`, found pre-existing issues → exited **2**. - Those issues are **not** on the PR's added lines, so reviewdog filtered them out → **no inline comment** ("No bot display"). - Then `exit $PHPCS_EXIT_CODE` ran `exit 2` → **job failed anyway**. `#22`/`#23` focused on faithfully *preserving* the phpcs exit code — which is exactly the value that should **not** gate the job. ## Fix - Run phpcs with `--report=checkstyle` and pipe straight to reviewdog (`-f=checkstyle`), dropping the `jq` transform. - **Exit with reviewdog's exit code, not phpcs's.** `-filter-mode=added -fail-level=any` means reviewdog exits `1` only when it reports a violation on a line this PR changed. - Keep a guard: if phpcs produces **no** checkstyle output *and* exits non-zero, it genuinely failed to run (bad standard, parse error, …) → fail the job with phpcs's code. ```bash set +e CHECKSTYLE_REPORT=$(vendor/bin/phpcs --report=checkstyle -q "${FILES[@]}") PHPCS_EXIT_CODE=$? set -e if [ -z "$CHECKSTYLE_REPORT" ] && [ "$PHPCS_EXIT_CODE" -ne 0 ]; then echo "phpcs failed to run (exit code $PHPCS_EXIT_CODE)" exit "$PHPCS_EXIT_CODE" fi REVIEWDOG_EXIT_CODE=0 echo "$CHECKSTYLE_REPORT" \ | reviewdog -f=checkstyle -name="phpcs" -filter-mode="added" -fail-level=any -reporter=github-pr-review \ || REVIEWDOG_EXIT_CODE=$? exit "$REVIEWDOG_EXIT_CODE" ``` ## Expected behavior across the-events-calendar#5687 test commits | Commit | Introduces new violations? | reviewdog comment | Job | |---|---|---|---| | Test 1 / Test 2 | yes | posted | **fails** ✅ | | Test 3 (clean) | no (pre-existing only) | none | **passes** ✅ | ## Test PR the-events-calendar#5687 repointed to `@fix/phpcs-reviewdog-exit-code` to re-run all three scenarios. Created by claude 🤖
When CHANGED_FILES is empty (no PHP files in the PR), phpcs was called with no file arguments. Depending on the repo phpcs.xml, this either produced a non-JSON error string (failing jq validation → exit 1) or scanned the entire codebase unintentionally.
Also switches from bare variable expansion to xargs so filenames containing spaces are passed as individual arguments rather than being split on whitespace.
Additional context:
https://lw.slack.com/archives/C09T9KPV9HV/p1782497266594449
Troubleshooting Screenshots