From 11caf1fc342f5c203c8b72f2023cad20a5c5780c Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 14:05:40 +0530 Subject: [PATCH 01/14] Fix Codecov badge by adding OIDC permission for tokenless upload The codecov-action v5 requires `id-token: write` to authenticate via OIDC when no CODECOV_TOKEN is provided. Without it the upload silently fails (fail_ci_if_error: false) leaving the badge as "unknown". The Codecov GitHub App is already installed on the WordPress org, so OIDC-based tokenless uploads work once this permission is granted. --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7da5c652..e2169f68 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -65,6 +65,8 @@ jobs: test-php: name: Test PHP ${{ matrix.php }} ${{ matrix.wp != '' && format( ' (WP {0}) ', matrix.wp ) || '' }} runs-on: ubuntu-24.04 + permissions: + id-token: write strategy: matrix: php: From 1497fe731c711c60cf11447982fe728807076976 Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 14:29:53 +0530 Subject: [PATCH 02/14] Enables OIDC for Codecov action Configures the Codecov GitHub Action to leverage OpenID Connect (OIDC) for authentication. This enhances security by utilizing GitHub's OIDC provider, removing the need for static tokens when uploading coverage reports. --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e2169f68..3a6c97f9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -136,7 +136,8 @@ jobs: if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de with: - file: tests/logs/clover.xml + use_oidc: true + files: tests/logs/clover.xml flags: phpunit fail_ci_if_error: false From fa58b7e117b912d2be89f928b62118ebbbfd924d Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 14:39:47 +0530 Subject: [PATCH 03/14] Prepares workflow for code coverage Adds necessary repository read permissions to the test job. Creates a dedicated directory for storing test logs and coverage reports. These adjustments are preparatory steps for integrating code coverage reporting. --- .github/workflows/test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3a6c97f9..067b343b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -66,6 +66,7 @@ jobs: name: Test PHP ${{ matrix.php }} ${{ matrix.wp != '' && format( ' (WP {0}) ', matrix.wp ) || '' }} runs-on: ubuntu-24.04 permissions: + contents: read id-token: write strategy: matrix: @@ -130,7 +131,9 @@ jobs: npm run env run cli wp core version - name: Test - run: npm run test + run: | + mkdir -p tests/logs + npm run test - name: Upload code coverage report if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} From 5e6556a139d2868e8ebb3f14df5b5e4b12e9160a Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 15:06:48 +0530 Subject: [PATCH 04/14] Enables Codecov report upload Introduces a new workflow step to extract the `clover.xml` code coverage report from the isolated test environment. This ensures the report is accessible on the GitHub Actions runner, allowing the `codecov-action` to successfully upload it. This step runs for PHP 8.3 and the latest WordPress versions. --- .github/workflows/test.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 067b343b..9d5b0fb0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -132,9 +132,16 @@ jobs: - name: Test run: | - mkdir -p tests/logs + npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- mkdir -p tests/logs npm run test + - name: Retrieve coverage report from container + if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} + continue-on-error: true + run: | + mkdir -p tests/logs + npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- cat tests/logs/clover.xml > tests/logs/clover.xml + - name: Upload code coverage report if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de From 91881c2e1bd4deae22eac168af2a0c77b33e2788 Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 15:14:09 +0530 Subject: [PATCH 05/14] Removes redundant coverage report retrieval The removed step incorrectly attempted to retrieve and process the code coverage report. The Codecov action can directly locate and upload coverage reports, making this step unnecessary and potentially confusing. Removing it streamlines the workflow. --- .github/workflows/test.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9d5b0fb0..550e70ed 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -135,13 +135,6 @@ jobs: npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- mkdir -p tests/logs npm run test - - name: Retrieve coverage report from container - if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} - continue-on-error: true - run: | - mkdir -p tests/logs - npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- cat tests/logs/clover.xml > tests/logs/clover.xml - - name: Upload code coverage report if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de From ba3d8a20675ed75630358caf97edde878849d606 Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 15:26:09 +0530 Subject: [PATCH 06/14] Fix coverage file retrieval via docker exec on persistent container MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tests-cli container (ephemeral, runs PHPUnit) and tests-wordpress container (persistent) share the same named Docker volume at /var/www/html. PHPUnit writes clover.xml into this volume. Use docker exec on the running tests-wordpress container to cat the file to stdout and redirect it to the host — this bypasses the unreliable bind-mount passthrough and avoids the ephemeral-container state-sharing problem that caused the previous approach to fail. --- .github/workflows/test.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 550e70ed..86a7d368 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -135,6 +135,16 @@ jobs: npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- mkdir -p tests/logs npm run test + - name: Retrieve coverage report from container + if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} + continue-on-error: true + run: | + mkdir -p tests/logs + docker exec \ + $(docker ps --filter "name=tests-wordpress" --format "{{.Names}}" | head -1) \ + cat /var/www/html/wp-content/plugins/two-factor/tests/logs/clover.xml \ + > tests/logs/clover.xml + - name: Upload code coverage report if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de From 07a7398a3d3e85347d931cd66f53b870aae23a2f Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 15:43:08 +0530 Subject: [PATCH 07/14] Add debug step to diagnose coverage report content and xdebug mode Temporary diagnostic: prints clover.xml size, first 30 lines, and xdebug mode from tests-cli to identify why CI coverage shows 0%. --- .github/workflows/test.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 86a7d368..8c2fb210 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -145,6 +145,17 @@ jobs: cat /var/www/html/wp-content/plugins/two-factor/tests/logs/clover.xml \ > tests/logs/clover.xml + - name: Debug coverage report + if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} + continue-on-error: true + run: | + echo "=== clover.xml file size ===" + wc -c tests/logs/clover.xml || echo "File not found" + echo "=== clover.xml first 30 lines ===" + head -30 tests/logs/clover.xml || echo "Cannot read file" + echo "=== xdebug mode in tests-cli ===" + npm run env run tests-cli -- php -r "echo xdebug_info();" 2>&1 | grep -i "mode\|coverage" || echo "xdebug info unavailable" + - name: Upload code coverage report if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de From e6bcc880f4428bdcdc283d628f5023d8b06b4963 Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 15:48:30 +0530 Subject: [PATCH 08/14] Ensure robust code coverage report retrieval and upload Refines the workflow to reliably retrieve and upload `clover.xml` coverage reports from the Docker container. Adds detailed error checking for container existence and report file integrity. Clarifies the rationale behind creating `tests/logs` inside the container and using `docker exec` for retrieval. Removes `continue-on-error` to enforce stricter validation during report retrieval. Ensures Codecov upload only proceeds if a valid coverage report file exists. --- .github/workflows/test.yml | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8c2fb210..3eee3672 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -132,32 +132,45 @@ jobs: - name: Test run: | + # Create tests/logs inside the container (uid=1000) so PHPUnit can write coverage + # reports to the shared Docker volume. The host runner (uid=1001) cannot create a + # writable directory here due to the UID mismatch with the container user. npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- mkdir -p tests/logs npm run test - name: Retrieve coverage report from container if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} - continue-on-error: true run: | + # PHPUnit writes clover.xml inside the tests-wordpress Docker volume. We use + # docker exec (not wp-env run) because wp-env run creates a new ephemeral container + # that does not share the named volume state where PHPUnit wrote its output. + # The tests-wordpress container shares the volume and is guaranteed to be running. + CONTAINER=$(docker ps --filter "name=tests-wordpress" --format "{{.Names}}" | head -1) + if [ -z "$CONTAINER" ]; then + echo "Error: tests-wordpress container not found" + exit 1 + fi mkdir -p tests/logs - docker exec \ - $(docker ps --filter "name=tests-wordpress" --format "{{.Names}}" | head -1) \ + docker exec "$CONTAINER" \ cat /var/www/html/wp-content/plugins/two-factor/tests/logs/clover.xml \ > tests/logs/clover.xml + if [ ! -s tests/logs/clover.xml ]; then + echo "Error: clover.xml is empty or was not retrieved" + exit 1 + fi + echo "Coverage report retrieved: $(wc -c < tests/logs/clover.xml) bytes" - name: Debug coverage report if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} continue-on-error: true run: | - echo "=== clover.xml file size ===" - wc -c tests/logs/clover.xml || echo "File not found" echo "=== clover.xml first 30 lines ===" - head -30 tests/logs/clover.xml || echo "Cannot read file" + head -30 tests/logs/clover.xml echo "=== xdebug mode in tests-cli ===" npm run env run tests-cli -- php -r "echo xdebug_info();" 2>&1 | grep -i "mode\|coverage" || echo "xdebug info unavailable" - name: Upload code coverage report - if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} + if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' && hashFiles('tests/logs/clover.xml') != '' }} uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de with: use_oidc: true From 2513a33aed0bf7ac4ff6eaed839dab7690383374 Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 15:58:09 +0530 Subject: [PATCH 09/14] Streamlines CI coverage report handling Removes the explicit `docker exec` command for retrieving the `clover.xml` coverage report. The `tests/logs` directory is bind-mounted from the workspace into the Docker container, making the `clover.xml` file directly accessible on the host runner after PHPUnit completes. This makes the manual retrieval step redundant. --- .github/workflows/test.yml | 39 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3eee3672..d602b7e2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -132,42 +132,25 @@ jobs: - name: Test run: | - # Create tests/logs inside the container (uid=1000) so PHPUnit can write coverage - # reports to the shared Docker volume. The host runner (uid=1001) cannot create a - # writable directory here due to the UID mismatch with the container user. + # Create tests/logs inside the container so PHPUnit can write coverage reports. + # The plugin directory is bind-mounted from the workspace, so PHPUnit writing to + # tests/logs/clover.xml inside the container also writes to the workspace path on + # the host runner. The directory must be created by the container user (uid=1000) + # to be writable; creating it on the runner (uid=1001) would cause a permissions + # mismatch and prevent PHPUnit from writing coverage output. npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- mkdir -p tests/logs npm run test - - name: Retrieve coverage report from container + - name: Verify coverage report if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} run: | - # PHPUnit writes clover.xml inside the tests-wordpress Docker volume. We use - # docker exec (not wp-env run) because wp-env run creates a new ephemeral container - # that does not share the named volume state where PHPUnit wrote its output. - # The tests-wordpress container shares the volume and is guaranteed to be running. - CONTAINER=$(docker ps --filter "name=tests-wordpress" --format "{{.Names}}" | head -1) - if [ -z "$CONTAINER" ]; then - echo "Error: tests-wordpress container not found" - exit 1 - fi - mkdir -p tests/logs - docker exec "$CONTAINER" \ - cat /var/www/html/wp-content/plugins/two-factor/tests/logs/clover.xml \ - > tests/logs/clover.xml if [ ! -s tests/logs/clover.xml ]; then - echo "Error: clover.xml is empty or was not retrieved" + echo "Error: tests/logs/clover.xml is missing or empty. Coverage was not generated." exit 1 fi - echo "Coverage report retrieved: $(wc -c < tests/logs/clover.xml) bytes" - - - name: Debug coverage report - if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} - continue-on-error: true - run: | - echo "=== clover.xml first 30 lines ===" - head -30 tests/logs/clover.xml - echo "=== xdebug mode in tests-cli ===" - npm run env run tests-cli -- php -r "echo xdebug_info();" 2>&1 | grep -i "mode\|coverage" || echo "xdebug info unavailable" + echo "Coverage report found: $(wc -c < tests/logs/clover.xml) bytes" + echo "=== clover.xml project summary (first 10 lines) ===" + head -10 tests/logs/clover.xml - name: Upload code coverage report if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' && hashFiles('tests/logs/clover.xml') != '' }} From 3d9317b6f5ec94e9d1429a80a6fadec56cc2fd75 Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 19:16:11 +0530 Subject: [PATCH 10/14] Fetches coverage report from test container The `clover.xml` coverage report is generated inside the `tests-wordpress` container, but the plugin directory is not bind-mounted to the host. Previously, this meant the report was inaccessible for upload. This update uses `docker cp` to retrieve the `clover.xml` report from the container to the host filesystem after tests complete. This ensures the report is available for the Codecov upload step. Includes additional checks to confirm XDebug mode and verify the integrity of the retrieved coverage report. --- .github/workflows/test.yml | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d602b7e2..d5654a56 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -132,25 +132,34 @@ jobs: - name: Test run: | - # Create tests/logs inside the container so PHPUnit can write coverage reports. - # The plugin directory is bind-mounted from the workspace, so PHPUnit writing to - # tests/logs/clover.xml inside the container also writes to the workspace path on - # the host runner. The directory must be created by the container user (uid=1000) - # to be writable; creating it on the runner (uid=1001) would cause a permissions - # mismatch and prevent PHPUnit from writing coverage output. npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- mkdir -p tests/logs npm run test - - name: Verify coverage report + - name: Retrieve coverage report from container if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} run: | - if [ ! -s tests/logs/clover.xml ]; then - echo "Error: tests/logs/clover.xml is missing or empty. Coverage was not generated." + # PHPUnit writes clover.xml into the named Docker volume shared between the + # tests-wordpress and tests-cli containers. The plugin directory is NOT bind-mounted + # from the workspace in CI, so the file does not appear on the host filesystem after + # npm run test. We use docker cp (not 'docker exec cat > file') because docker cp is + # an atomic Docker API call that reads from the container's merged filesystem without + # a shell redirect that would pre-truncate the destination and cause a self-overwrite. + CONTAINER=$(docker ps --filter "name=tests-wordpress" --format "{{.Names}}" | head -1) + if [ -z "$CONTAINER" ]; then + echo "Error: tests-wordpress container not found" exit 1 fi - echo "Coverage report found: $(wc -c < tests/logs/clover.xml) bytes" - echo "=== clover.xml project summary (first 10 lines) ===" + mkdir -p tests/logs + docker cp "$CONTAINER:/var/www/html/wp-content/plugins/two-factor/tests/logs/clover.xml" tests/logs/clover.xml + echo "=== xdebug mode reported by tests-wordpress ===" + docker exec "$CONTAINER" php -r "echo ini_get('xdebug.mode') . PHP_EOL;" + echo "=== clover.xml size and summary ===" + wc -c tests/logs/clover.xml head -10 tests/logs/clover.xml + if [ ! -s tests/logs/clover.xml ]; then + echo "Error: clover.xml is empty — coverage was not generated" + exit 1 + fi - name: Upload code coverage report if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' && hashFiles('tests/logs/clover.xml') != '' }} From 367f8049cc5ccb37e20856e6da56faa5326e4f05 Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 19:31:06 +0530 Subject: [PATCH 11/14] Ensures robust code coverage generation in CI Updates Composer install to use `--ignore-platform-req=php` on PHP 8.x, ensuring PHPUnit 9.6 is installed for compatible code coverage. Explicitly enables Xdebug coverage mode and passes `--coverage-clover` to PHPUnit within `wp-env` for the coverage matrix cell, guaranteeing reliable report generation. Refines comments regarding atomic file retrieval via `docker cp`. --- .github/workflows/test.yml | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d5654a56..e91a9f2a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -123,7 +123,16 @@ jobs: - name: Composer install run: | rm composer.lock || true # We need to install fresh. - npm run composer install + # On PHP 8+, the composer.json platform override (php: 7.2.24) causes PHPUnit 8.5 to + # be installed. PHPUnit 8.5 explicitly refuses to generate code coverage on PHP 8 with + # the message "This version of PHPUnit does not support code coverage on PHP 8". Pass + # --ignore-platform-req=php so Composer resolves against the actual PHP runtime and + # installs PHPUnit 9.6, which supports coverage on PHP 8.x. + if [[ "${WP_ENV_PHP_VERSION}" == 8.* ]]; then + npm run composer -- install --ignore-platform-req=php + else + npm run composer install + fi - name: Versions run: | @@ -133,17 +142,26 @@ jobs: - name: Test run: | npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- mkdir -p tests/logs - npm run test + # For the coverage matrix cell, set XDEBUG_MODE=coverage explicitly via env var + # (Xdebug 3 feature) rather than relying on the ini configuration that wp-env + # applies to persistent containers — ephemeral wp-env run containers may not + # inherit it. Pass --coverage-clover in addition to what phpunit.xml.dist configures + # so the clover output is guaranteed regardless of XML config format differences + # between PHPUnit versions. + if [[ "${{ matrix.php }}" == "8.3" && "${{ matrix.wp }}" == "latest" ]]; then + npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- \ + sh -c 'XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text --coverage-clover tests/logs/clover.xml' + else + npm run test + fi - name: Retrieve coverage report from container if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} run: | - # PHPUnit writes clover.xml into the named Docker volume shared between the - # tests-wordpress and tests-cli containers. The plugin directory is NOT bind-mounted - # from the workspace in CI, so the file does not appear on the host filesystem after - # npm run test. We use docker cp (not 'docker exec cat > file') because docker cp is - # an atomic Docker API call that reads from the container's merged filesystem without - # a shell redirect that would pre-truncate the destination and cause a self-overwrite. + # PHPUnit writes clover.xml into the Docker volume shared between tests-cli and + # tests-wordpress. We use docker cp (not 'docker exec cat > file') because docker cp + # is an atomic Docker API call that avoids a shell redirect pre-truncating the + # destination — which would zero-out the file before cat can read it. CONTAINER=$(docker ps --filter "name=tests-wordpress" --format "{{.Names}}" | head -1) if [ -z "$CONTAINER" ]; then echo "Error: tests-wordpress container not found" @@ -151,9 +169,9 @@ jobs: fi mkdir -p tests/logs docker cp "$CONTAINER:/var/www/html/wp-content/plugins/two-factor/tests/logs/clover.xml" tests/logs/clover.xml - echo "=== xdebug mode reported by tests-wordpress ===" + echo "=== xdebug mode in tests-wordpress ===" docker exec "$CONTAINER" php -r "echo ini_get('xdebug.mode') . PHP_EOL;" - echo "=== clover.xml size and summary ===" + echo "=== clover.xml size and first 10 lines ===" wc -c tests/logs/clover.xml head -10 tests/logs/clover.xml if [ ! -s tests/logs/clover.xml ]; then From 68452bdb19fc88dbbe1cd87750b991f95794dc18 Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 19:42:18 +0530 Subject: [PATCH 12/14] Adjusts `wp-env` coverage command Refactors the `wp-env` test command for PHP 8.3 and `latest` WordPress to ensure `XDEBUG_MODE=coverage` is correctly applied. Directly calls `wp-env` instead of using `npm run` to prevent argument re-splitting, which previously hindered accurate coverage generation. --- .github/workflows/test.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e91a9f2a..a229f567 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -149,8 +149,11 @@ jobs: # so the clover output is guaranteed regardless of XML config format differences # between PHPUnit versions. if [[ "${{ matrix.php }}" == "8.3" && "${{ matrix.wp }}" == "latest" ]]; then - npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- \ - sh -c 'XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text --coverage-clover tests/logs/clover.xml' + # Call wp-env directly (not via npm run) to avoid npm re-splitting the argument + # list. env sets XDEBUG_MODE=coverage and execs composer, which resolves phpunit + # from vendor/bin — the same path used by npm run test. + ./node_modules/.bin/wp-env run tests-cli --env-cwd=wp-content/plugins/two-factor \ + -- env XDEBUG_MODE=coverage composer test else npm run test fi From e8a91807414cd17fd65afea8ccef5a58f4d08cf5 Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sat, 28 Mar 2026 19:54:41 +0530 Subject: [PATCH 13/14] Streamlines CI coverage generation Removes a conditional test execution path, allowing `npm run test` to consistently handle code coverage collection across all test matrix configurations, including PHP 8.3 with the latest WordPress. Eliminates unnecessary debugging output for `xdebug.mode` and `clover.xml` content to declutter CI logs. Refines comments for improved clarity regarding Composer platform requirements and `docker cp` usage. --- .github/workflows/test.yml | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a229f567..5288e7d1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -123,11 +123,9 @@ jobs: - name: Composer install run: | rm composer.lock || true # We need to install fresh. - # On PHP 8+, the composer.json platform override (php: 7.2.24) causes PHPUnit 8.5 to - # be installed. PHPUnit 8.5 explicitly refuses to generate code coverage on PHP 8 with - # the message "This version of PHPUnit does not support code coverage on PHP 8". Pass - # --ignore-platform-req=php so Composer resolves against the actual PHP runtime and - # installs PHPUnit 9.6, which supports coverage on PHP 8.x. + # The composer.json platform override (php: 7.2.24) installs PHPUnit 8.5, which does + # not support code coverage on PHP 8. Use --ignore-platform-req=php on PHP 8+ so + # Composer installs PHPUnit 9.6, which supports coverage on PHP 8.x. if [[ "${WP_ENV_PHP_VERSION}" == 8.* ]]; then npm run composer -- install --ignore-platform-req=php else @@ -142,29 +140,15 @@ jobs: - name: Test run: | npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- mkdir -p tests/logs - # For the coverage matrix cell, set XDEBUG_MODE=coverage explicitly via env var - # (Xdebug 3 feature) rather than relying on the ini configuration that wp-env - # applies to persistent containers — ephemeral wp-env run containers may not - # inherit it. Pass --coverage-clover in addition to what phpunit.xml.dist configures - # so the clover output is guaranteed regardless of XML config format differences - # between PHPUnit versions. - if [[ "${{ matrix.php }}" == "8.3" && "${{ matrix.wp }}" == "latest" ]]; then - # Call wp-env directly (not via npm run) to avoid npm re-splitting the argument - # list. env sets XDEBUG_MODE=coverage and execs composer, which resolves phpunit - # from vendor/bin — the same path used by npm run test. - ./node_modules/.bin/wp-env run tests-cli --env-cwd=wp-content/plugins/two-factor \ - -- env XDEBUG_MODE=coverage composer test - else - npm run test - fi + npm run test - name: Retrieve coverage report from container if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} run: | # PHPUnit writes clover.xml into the Docker volume shared between tests-cli and - # tests-wordpress. We use docker cp (not 'docker exec cat > file') because docker cp - # is an atomic Docker API call that avoids a shell redirect pre-truncating the - # destination — which would zero-out the file before cat can read it. + # tests-wordpress. Use docker cp (not 'docker exec cat > file'): docker cp is an + # atomic API call that avoids a shell redirect pre-truncating the destination file, + # which would zero it out before cat can read it (self-overwrite). CONTAINER=$(docker ps --filter "name=tests-wordpress" --format "{{.Names}}" | head -1) if [ -z "$CONTAINER" ]; then echo "Error: tests-wordpress container not found" @@ -172,11 +156,6 @@ jobs: fi mkdir -p tests/logs docker cp "$CONTAINER:/var/www/html/wp-content/plugins/two-factor/tests/logs/clover.xml" tests/logs/clover.xml - echo "=== xdebug mode in tests-wordpress ===" - docker exec "$CONTAINER" php -r "echo ini_get('xdebug.mode') . PHP_EOL;" - echo "=== clover.xml size and first 10 lines ===" - wc -c tests/logs/clover.xml - head -10 tests/logs/clover.xml if [ ! -s tests/logs/clover.xml ]; then echo "Error: clover.xml is empty — coverage was not generated" exit 1 From 83f5ee50f16f2aa3ada343afc270b2ccc7b4430e Mon Sep 17 00:00:00 2001 From: Nimesh Date: Sun, 29 Mar 2026 12:36:57 +0530 Subject: [PATCH 14/14] Removes redundant coverage report retrieval The coverage report (clover.xml) is now directly accessible on the runner environment. This eliminates the need for an explicit step to copy it from the Docker container, simplifying the CI workflow. --- .github/workflows/test.yml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5288e7d1..af29ea8f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -142,25 +142,6 @@ jobs: npm run env run tests-cli --env-cwd=wp-content/plugins/two-factor -- mkdir -p tests/logs npm run test - - name: Retrieve coverage report from container - if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' }} - run: | - # PHPUnit writes clover.xml into the Docker volume shared between tests-cli and - # tests-wordpress. Use docker cp (not 'docker exec cat > file'): docker cp is an - # atomic API call that avoids a shell redirect pre-truncating the destination file, - # which would zero it out before cat can read it (self-overwrite). - CONTAINER=$(docker ps --filter "name=tests-wordpress" --format "{{.Names}}" | head -1) - if [ -z "$CONTAINER" ]; then - echo "Error: tests-wordpress container not found" - exit 1 - fi - mkdir -p tests/logs - docker cp "$CONTAINER:/var/www/html/wp-content/plugins/two-factor/tests/logs/clover.xml" tests/logs/clover.xml - if [ ! -s tests/logs/clover.xml ]; then - echo "Error: clover.xml is empty — coverage was not generated" - exit 1 - fi - - name: Upload code coverage report if: ${{ matrix.php == '8.3' && matrix.wp == 'latest' && hashFiles('tests/logs/clover.xml') != '' }} uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de