Skip to content

Commit a110b68

Browse files
authored
Merge pull request #672 from phparkitect/claude/lowest-dependency-test-matrix-e7cxf3
Test the lowest allowed dependency set in CI
2 parents 587d279 + 835bf37 commit a110b68

5 files changed

Lines changed: 73 additions & 9 deletions

File tree

‎.github/workflows/build.yml‎

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ jobs:
1717
fail-fast: false
1818
matrix:
1919
php-versions: [ '8.0', '8.1', '8.2', '8.3', '8.4', '8.5' ]
20+
dependencies: [ 'highest' ]
21+
include:
22+
# The lowest allowed dependency set needs to be verified only once, and the
23+
# oldest supported PHP is where consumers are most likely to end up with it.
24+
- php-versions: '8.0'
25+
dependencies: 'lowest'
26+
27+
name: "PHP ${{ matrix.php-versions }} (${{ matrix.dependencies }} deps)"
2028

2129
steps:
2230
- uses: actions/checkout@v7
@@ -40,20 +48,35 @@ jobs:
4048
path: |
4149
vendor
4250
tools/psalm/vendor
43-
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
51+
# composer.lock is not committed, so it cannot take part in the cache key:
52+
# the installed set depends on the PHP version and on the resolution
53+
# strategy, and both must be part of the key to keep the caches separate
54+
key: ${{ runner.os }}-php-${{ matrix.php-versions }}-${{ matrix.dependencies }}-${{ hashFiles('composer.json') }}
4455
restore-keys: |
45-
${{ runner.os }}-php-
56+
${{ runner.os }}-php-${{ matrix.php-versions }}-${{ matrix.dependencies }}-
4657
4758
- name: Install dependencies
59+
if: ${{ matrix.dependencies == 'highest' }}
4860
run: composer install --prefer-dist
4961

62+
# Without a committed composer.lock every other job resolves to the newest
63+
# allowed release, so the lower bounds declared in composer.json are never
64+
# exercised. This job installs the other end of those ranges: the set a
65+
# consumer with older pinned dependencies actually gets.
66+
- name: Install lowest allowed dependencies
67+
if: ${{ matrix.dependencies == 'lowest' }}
68+
run: composer update --prefer-dist --prefer-lowest --prefer-stable
69+
5070
# Psalm 6 needs PHP >= 8.1 to run; the analysis target stays 8.0 (phpVersion in psalm.xml)
5171
- name: Static Analysis
5272
if: ${{ matrix.php-versions == '8.1' }}
5373
run: |
5474
composer install --prefer-dist -d tools/psalm
5575
tools/psalm/vendor/bin/psalm --no-cache
5676
77+
# Both dependency sets report coverage: code that supports one version of a
78+
# dependency is dead code under the other one, so a single set can never cover
79+
# all of src. Codecov merges the two reports, and codecov.yml waits for both.
5780
- name: Test with coverage
5881
if: ${{ matrix.php-versions == '8.0' }}
5982
run: ./bin/phpunit -d memory_limit=-1 --coverage-clover clover.xml
@@ -67,6 +90,7 @@ jobs:
6790
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
6891
with:
6992
token: ${{ secrets.CODECOV_TOKEN }}
93+
flags: ${{ matrix.dependencies }}
7094

7195
phar:
7296
runs-on: "ubuntu-22.04"

‎CONTRIBUTING.md‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,22 @@ make csfix # run code style fixer
5050
make psalm # run static analysis
5151
```
5252

53+
### Testing against the lowest allowed dependencies
54+
55+
`composer.lock` is not committed, so `composer install` always gives you the
56+
newest release allowed by `composer.json`. Arkitect is installed as a dependency
57+
of other projects, though, where the resolver often picks something older, so CI
58+
also runs the test suite against the lower bound of every declared constraint.
59+
60+
To reproduce that job locally:
61+
62+
```shell
63+
composer update --prefer-lowest --prefer-stable
64+
make test
65+
composer update # restore the newest allowed dependencies
66+
```
67+
68+
If a change needs a feature that is not in the lowest allowed version of a
69+
dependency, raise the constraint in `composer.json` instead of working around
70+
it.
71+

‎codecov.yml‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,27 @@ comment:
2929
layout: "reach, diff, flags, files"
3030
behavior: default
3131
require_changes: false
32+
# Same reason as codecov.notify.after_n_builds below.
33+
after_n_builds: 2
3234

33-
# Wait for the (single) coverage upload before computing the status, so the
34-
# check doesn't run against a partial report.
35+
# Wait for both coverage uploads before computing the status, so the check
36+
# doesn't run against a partial report. The build uploads one report per
37+
# dependency set (see the `flags` below): the code supporting one version of a
38+
# dependency is dead code under the other, so only the merge of the two reports
39+
# describes the coverage of src.
3540
codecov:
3641
require_ci_to_pass: true
3742
notify:
3843
wait_for_ci: true
44+
after_n_builds: 2
45+
46+
# The flags exist to tell the two uploads apart, not to gate them separately:
47+
# neither dependency set covers src on its own, so a per-flag status would be
48+
# meaningless. Nothing is carried forward from older commits either, both
49+
# reports are uploaded on every build.
50+
flag_management:
51+
default_rules:
52+
carryforward: false
3953

4054
ignore:
4155
- "tests"

‎composer.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,16 @@
2323
],
2424
"require": {
2525
"php": "^8.0",
26-
"nikic/php-parser": "~5",
26+
"nikic/php-parser": "^5.3",
2727
"ondram/ci-detector": "^4.2",
28-
"phpstan/phpdoc-parser": "^1.2|^2.0",
28+
"phpstan/phpdoc-parser": "^1.20|^2.0",
2929
"symfony/console": "^5.4|^6.0|^7.0|^8.0",
3030
"symfony/finder": "^5.4|^6.0|^7.0|^8.0",
3131
"webmozart/assert": "^1.12|^2.0"
3232
},
3333
"require-dev": {
3434
"friendsofphp/php-cs-fixer": "^3.95",
35-
"mikey179/vfsstream": "^1.6",
35+
"mikey179/vfsstream": "^1.6.8",
3636
"phpspec/prophecy": "^1.10",
3737
"phpspec/prophecy-phpunit": "^2.5",
3838
"phpunit/phpunit": "^9.6|^10.0|^11.0",

‎src/Analyzer/DocblockParserFactory.php‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,19 @@
1212
class DocblockParserFactory
1313
{
1414
/**
15+
* Psalm only ever sees one of the two installed versions of phpstan/phpdoc-parser,
16+
* so the constructor calls of the other branch always look wrong to it.
17+
*
1518
* @psalm-suppress TooFewArguments
19+
* @psalm-suppress TooManyArguments
1620
* @psalm-suppress InvalidArgument
1721
*/
1822
public static function create(): DocblockParser
1923
{
2024
$phpDocParser = null;
2125
$phpDocLexer = null;
2226

23-
// this if is to allow using v 1.2 or v2
27+
// this if is to allow using v1 or v2
2428
if (class_exists(ParserConfig::class)) {
2529
$parserConfig = new ParserConfig(['lines' => true]);
2630
$constExprParser = new ConstExprParser($parserConfig);
@@ -30,7 +34,10 @@ public static function create(): DocblockParser
3034
} else {
3135
$typeParser = new TypeParser();
3236
$constExprParser = new ConstExprParser();
33-
$phpDocParser = new PhpDocParser($typeParser, $constExprParser);
37+
// on v1 line numbers are opt-in through $usedAttributes, the 5th constructor
38+
// argument: without it every node reports no line and violations would be
39+
// reported on the wrong line
40+
$phpDocParser = new PhpDocParser($typeParser, $constExprParser, false, false, ['lines' => true]);
3441
$phpDocLexer = new Lexer();
3542
}
3643

0 commit comments

Comments
 (0)