Skip to content

Commit a0bec99

Browse files
committed
Use pcov => xdebug => phpdbg for phpunit code coverage
Right now we are only using phpdbg for phpunit code coverage. And it's causing some problems with latest (8.0, 8.1) php versions. Also, since phpunit 8, its code coverage tool supports pcov, that is the lighter and better alternative. And then, xdebug running in coverage mode has become way better in recent versions. So, with this patch applied, moodle-plugin-ci will look for the "best" code coverage alternative (pcov => xdebug => phpdbg) in every run. This guarantees that existing automations, not having pcov or xdebug available will continue fall-backing to phpdbg. But if any of the 2 extensions are available, we'll be using them. No matter of the above (fully automatic), it's also possible to configure the desired code coverage tool with 3 new options, in case it's needed to force any: - coverage-pcov - coverage-xdebug - coverage-phpdbg Added support to the '--verbose' option to be passed to phpunit (useful to debug options or see details about skipped tests). Includes modifications to both GHA docs and template to show the new options. And, also, changes to own CI tests to have both pcov and xdebug used all the time.
1 parent 3dc4ca6 commit a0bec99

File tree

9 files changed

+101
-13
lines changed

9 files changed

+101
-13
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ jobs:
1515
uses: shivammathur/setup-php@v2
1616
with:
1717
php-version: 7.3
18-
coverage: none
18+
# We want to verify that xdebug works for coverage. Once we only support
19+
# Moodle 3.10/PHPUnit 8 and up, we can switch our tests to pcov too.
20+
coverage: xdebug
1921

2022
- name: Initialise
2123
run: make init
@@ -65,7 +67,9 @@ jobs:
6567
with:
6668
php-version: ${{ matrix.php }}
6769
extensions: pgsql, zip, gd, xmlrpc, soap
68-
coverage: none
70+
# We want to verify that xdebug works for coverage. Once we only support
71+
# Moodle 3.10/PHPUnit 8 and up, we can switch our tests to pcov too.
72+
coverage: xdebug
6973

7074
- name: Initialise moodle-plugin-ci
7175
run: |

.travis.dist.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ env:
2828
before_install:
2929
- if [[ ${TRAVIS_PHP_VERSION:0:1} -gt 7 ]]; then pecl install xmlrpc-beta; fi
3030
- echo 'max_input_vars=5000' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
31+
# Don't disable xdebug if you want to get it used for code coverage.
3132
- phpenv config-rm xdebug.ini
33+
# Alternative (for Moodle 3.10 and up) is to use pcov. It can be installed using:
34+
# - pecl install pcov
3235
- cd ../..
3336
- composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3
3437
- export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH"

.travis.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ env:
2525
- MOODLE_BRANCH=master
2626

2727
before_install:
28-
- phpenv config-rm xdebug.ini
28+
# We want to verify that xdebug works for coverage. Once we only support
29+
# Moodle 3.10/PHPUnit 8 and up, we can switch our tests to pcov too.
30+
# - phpenv config-rm xdebug.ini
2931
- make init
3032
# Mimic how a Moodle plugin would be run.
3133
- cp -R tests/Fixture/moodle-local_ci ../moodle-local_ci
@@ -55,7 +57,7 @@ script:
5557
- moodle-plugin-ci mustache
5658
- moodle-plugin-ci grunt || [ "$MOODLE_BRANCH" == 'MOODLE_38_STABLE' ]
5759
- moodle-plugin-ci phpdoc
58-
- moodle-plugin-ci phpunit --coverage-text --fail-on-warning
60+
- moodle-plugin-ci phpunit --verbose --coverage-text --fail-on-warning
5961
- moodle-plugin-ci behat --profile default
6062
- moodle-plugin-ci behat --profile chrome
6163

Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ test-phpunit: check-init
1919
validate: check-init psalm check-docs
2020
$(FIXER) fix --dry-run --stop-on-violation
2121
$(COMPOSER) validate
22-
phpdbg --version
23-
phpdbg -d memory_limit=-1 -qrr $(PHPUNIT) --coverage-text
22+
XDEBUG_MODE=coverage $(PHPUNIT) --verbose --coverage-text
2423

2524
.PHONY:build
2625
build: build/moodle-plugin-ci.phar

docs/CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
99
The format of this change log follows the advice given at [Keep a CHANGELOG](http://keepachangelog.com).
1010

1111
## [Unreleased]
12+
### Added
13+
- PHPUnit code coverage will now automatically fallback between `pcov` => `xdebug` => `phpdbg`, using the "best" one available in the system. Still, if needed to, any of them can be forced, given all their requirements are fulfilled, using the following new options of the 'phpunit' command: `--coverage-pcov`, `--coverage-xdebug` or `--coverage-phpdbg`.
14+
- ACTION SUGGESTED: Ensure that the `pcov` or `xdebug` extensions are installed in your environment to get 'moodle-plugin-ci' using them automatically.
1215

1316
## [3.2.6] - 2022-05-10
14-
### Changed
15-
- It is possible to specify more test execution options to the 'phpunit' command, such as "--fail-on-warning"
17+
### Added
18+
- It is possible to specify more test execution options to the 'phpunit' command, such as `--fail-on-incomplete`, `--fail-on-risky` and `--fail-on-skipped` and `--fail-on-warning`. For more information, see [PHPUnit documentation](https://phpunit.readthedocs.io).
1619

1720
### Fixed
1821
- Locally bundled [moodle-local_codechecker](https://github.com/moodlehq/moodle-local_codechecker) now works ok with recent (Moodle 3.11 and up) branches. A recent change in those versions was causing [some problems](https://tracker.moodle.org/browse/MDL-74704).

docs/CodeCoverage.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ title: Generating code coverage
66
Currently, code coverage is only generated for builds that are running on PHP7 or later. Code coverage generation
77
is significantly faster and easier to produce in PHP7.
88

9+
Code coverage will now automatically fallback between `pcov` => `xdebug` => `phpdbg`, using the "best" one available in the system. Still, if needed to, any of them can be forced, given all their requirements are fulfilled, using the following new options of the 'phpunit' command: `--coverage-pcov`, `--coverage-xdebug` or `--coverage-phpdbg`.
10+
911
The way you generate code coverage is to use one of the coverage options on the `phpunit` command. The currently
1012
available options are `--coverage-text` and `--coverage-clover`. The easiest way to start generating code coverage
1113
is to use the text option as that gets printed in the Travis CI logs. Example:

docs/GHAFileExplained.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ jobs:
5454
# another branch, total number of builds will become 12.
5555
# If you need to use PHP 7.0 and run phpunit coverage test, make sure you are
5656
# using ubuntu-16.04 virtual environment in this case to have phpdbg or
57-
# this version in the system.
57+
# this version in the system. See the "Setup PHP" step below for more details
58+
# about PHPUnit code coverage.
5859
strategy:
5960
fail-fast: false
6061
matrix:
@@ -94,6 +95,7 @@ jobs:
9495
php-version: ${{ matrix.php }}
9596
extensions: ${{ matrix.extensions }}
9697
ini-values: max_input_vars=5000
98+
# none to use phpdbg fallback. Specify pcov (Moodle 3.10 and up) or xdebug to use them instead.
9799
coverage: none
98100

99101
# Install this project into a directory called "ci", updating PATH and

gha.dist.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ jobs:
4646
php-version: ${{ matrix.php }}
4747
extensions: ${{ matrix.extensions }}
4848
ini-values: max_input_vars=5000
49+
# none to use phpdbg fallback. Specify pcov (Moodle 3.10 and up) or xdebug to use them instead.
4950
coverage: none
5051

5152
- name: Initialise moodle-plugin-ci

src/Command/PHPUnitCommand.php

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ protected function configure()
3131
->setDescription('Run PHPUnit on a plugin')
3232
->addOption('coverage-text', null, InputOption::VALUE_NONE, 'Generate and print code coverage report in text format')
3333
->addOption('coverage-clover', null, InputOption::VALUE_NONE, 'Generate code coverage report in Clover XML format')
34+
->addOption('coverage-pcov', null, InputOption::VALUE_NONE, 'Use the pcov extension to calculate code coverage')
35+
->addOption('coverage-xdebug', null, InputOption::VALUE_NONE, 'Use the xdebug extension to calculate code coverage')
36+
->addOption('coverage-phpdbg', null, InputOption::VALUE_NONE, 'Use the phpdbg binary to calculate code coverage')
3437
->addOption('fail-on-incomplete', null, InputOption::VALUE_NONE, 'Treat incomplete tests as failures')
3538
->addOption('fail-on-risky', null, InputOption::VALUE_NONE, 'Treat risky tests as failures')
3639
->addOption('fail-on-skipped', null, InputOption::VALUE_NONE, 'Treat skipped tests as failures')
@@ -52,7 +55,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
5255
}
5356

5457
$colors = $output->isDecorated() ? '--colors="always"' : '';
55-
$binary = $this->resolveBinary($input);
58+
$binary = $this->resolveBinary($input, $output);
5659
$options = $this->resolveOptions($input);
5760
$process = $this->execute->passThrough(
5861
sprintf('%s%s/vendor/bin/phpunit %s %s', $binary, $this->moodle->directory, $colors, $options),
@@ -78,6 +81,9 @@ private function resolveOptions(InputInterface $input)
7881
if ($this->supportsCoverage() && $input->getOption('coverage-clover')) {
7982
$options[] = sprintf('--coverage-clover %s/coverage.xml', getcwd());
8083
}
84+
if ($input->getOption('verbose')) {
85+
$options[] = '--verbose';
86+
}
8187
foreach (['fail-on-warning', 'fail-on-risky', 'fail-on-skipped', 'fail-on-warning'] as $option) {
8288
if ($input->getOption($option)) {
8389
$options[] = '--'.$option;
@@ -95,11 +101,12 @@ private function resolveOptions(InputInterface $input)
95101
/**
96102
* Use phpdbg if we are generating code coverage.
97103
*
98-
* @param InputInterface $input
104+
* @param InputInterface $input
105+
* @param OutputInterface $output
99106
*
100107
* @return string
101108
*/
102-
private function resolveBinary(InputInterface $input)
109+
private function resolveBinary(InputInterface $input, OutputInterface $output)
103110
{
104111
if (!$this->supportsCoverage()) {
105112
return '';
@@ -108,7 +115,19 @@ private function resolveBinary(InputInterface $input)
108115
return '';
109116
}
110117

111-
return 'phpdbg -d memory_limit=-1 -qrr ';
118+
// Depending on the coverage driver, selected return different values.
119+
switch ($this->resolveCoverageDriver($input, $output)) {
120+
case 'pcov':
121+
return 'php -dxdebug.mode=off -dpcov.enabled=1 -dpcov.directory=. '; // Enable pcov, disable xdebug, just in case.
122+
case 'xdebug':
123+
return 'php -dpcov.enabled=0 -dxdebug.mode=coverage '; // Enable xdebug, disable pcov, just in case.
124+
case 'phpdbg':
125+
return 'phpdbg -d memory_limit=-1 -qrr ';
126+
}
127+
// No suitable coverage driver found, disabling all candidates.
128+
$output->writeln('<error>No suitable driver found, disabling code coverage.</error>');
129+
130+
return 'php -dpcov.enabled=0 -dxdebug.mode=off ';
112131
}
113132

114133
/**
@@ -120,4 +139,57 @@ private function supportsCoverage()
120139
{
121140
return version_compare(PHP_VERSION, '7.0.0', '>=');
122141
}
142+
143+
/**
144+
* Given the current environment and options return the code coverage driver to use.
145+
*
146+
* @param InputInterface $input
147+
* @param OutputInterface $output
148+
*
149+
* @return string one of pcov, xdebug, phpdbg
150+
*/
151+
private function resolveCoverageDriver(InputInterface $input, OutputInterface $output)
152+
{
153+
// Let's see if any of the coverage drivers has been forced via command line options.
154+
if ($input->getOption('coverage-pcov')) {
155+
// Before accepting it, perform some checks and report.
156+
if (!extension_loaded('pcov')) {
157+
$output->writeln('<error>PHP pcov extension not available.</error>');
158+
159+
return '';
160+
}
161+
if ($this->moodle->getBranch() < 310) {
162+
$output->writeln('<error>PHP pcov coverage only can be used with Moodle 3.10 and up.</error>');
163+
164+
return '';
165+
}
166+
167+
return 'pcov';
168+
} elseif ($input->getOption('coverage-xdebug')) {
169+
// Before accepting it, perform some checks and report.
170+
if (!extension_loaded('xdebug')) {
171+
$output->writeln('<error>PHP xdebug extension not available.</error>');
172+
173+
return '';
174+
}
175+
176+
return 'xdebug';
177+
} elseif ($input->getOption('coverage-phpdbg')) {
178+
return 'phpdbg';
179+
}
180+
181+
// Arrived here, let's find the best (pcov => xdebug => phpdbg) available driver.
182+
183+
if (extension_loaded('pcov') && $this->moodle->getBranch() >= 310) {
184+
// If pcov is available and we are using Moodle 3.10 (PHPUnit 8.5) and up, let's use it.
185+
return 'pcov';
186+
}
187+
188+
if (extension_loaded('xdebug')) {
189+
// If xdebug is available, let's use it.
190+
return 'xdebug';
191+
}
192+
193+
return 'phpdbg'; // Fallback to phpdbg (bundled with php 7.0 and up) if none of the above are available.
194+
}
123195
}

0 commit comments

Comments
 (0)