Skip to content

Commit 4f3d24d

Browse files
committed
ci: make the workflow install the dependencies it analyses
Three problems, all of which made the pipeline's result depend on something other than the code under test. **The dependency cache was frozen.** The cache key was `composer-${{ runner.os }}-${{ hashFiles('composer.lock') }}`, but composer.lock is in .gitignore, so hashFiles() returned the empty string and the key was the constant `composer-Linux-` on every branch and every run. GitHub cache entries are immutable per key, so the first run ever to save one froze `vendor` for good, and the analysis jobs — which only restore the cache and never install — have been analysing those versions ever since. The key is now hashed from the composer.json files, so widening a constraint invalidates it. That is why PHPStan reported `Point.php:109` on one PR and not on the next commit of the same branch: the two runs restored different vendors. The call site is guarded now, so the analysis no longer depends on which brick/math is installed. The mask is as wide as the longer operand and can never be empty; the guard is there because that cannot be proven statically. **Rector renamed `expectExceptionMessage()` to `expectExceptionMessageIsOrContains()`** in 125 places, because it resolves PHPUnit from composer and gets 13. But `castor phpunit` runs `phpunit-11`, pinned because the PHP 8.2 image ships nothing newer, and that method only exists from PHPUnit 12. Every one of those call sites died with `Call to undefined method`. The rename is reverted and `RenameMethodRector` is skipped under tests/; it made no other change there. The pin has to stay while the matrix tests PHP 8.2. Verified with `phpunit-11`, the binary CI runs, rather than the newer one in vendor/bin: 777 tests, 0 failures.
1 parent 9a97e9b commit 4f3d24d

49 files changed

Lines changed: 137 additions & 129 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.ci-tools/rector.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Rector\Doctrine\Set\DoctrineSetList;
77
use Rector\PHPUnit\CodeQuality\Rector\Class_\PreferPHPUnitThisCallRector;
88
use Rector\PHPUnit\Set\PHPUnitSetList;
9+
use Rector\Renaming\Rector\MethodCall\RenameMethodRector;
910
use Rector\Set\ValueObject\LevelSetList;
1011
use Rector\Set\ValueObject\SetList;
1112
use Rector\ValueObject\PhpVersion;
@@ -36,6 +37,7 @@
3637
);
3738
$builder->withSkip([
3839
PreferPHPUnitThisCallRector::class,
40+
RenameMethodRector::class => [__DIR__ . '/../tests'],
3941
__DIR__ . '/../src/Library/Core/JWKSet.php',
4042
__DIR__ . '/../src/Bundle/JoseFramework/DependencyInjection/Source/KeyManagement/JWKSource.php',
4143
__DIR__ . '/../src/Bundle/JoseFramework/DependencyInjection/Source/KeyManagement/JWKSetSource.php',

‎.github/workflows/ci.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ jobs:
4646
- uses: actions/checkout@v5
4747

4848
- id: cache-key-generator
49-
run: echo "key=composer-${{ runner.os }}-${{ hashFiles('composer.lock') }}" >> $GITHUB_OUTPUT
49+
run: echo "key=composer-${{ runner.os }}-${{ hashFiles('composer.json', 'src/*/composer.json') }}" >> $GITHUB_OUTPUT
5050

5151
- uses: actions/cache@v4
5252
with:

‎src/Library/Core/Util/Ecc/Point.php‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Jose\Component\Core\Util\Ecc;
66

77
use Brick\Math\BigInteger;
8+
use InvalidArgumentException;
89
use function strlen;
910
use const STR_PAD_LEFT;
1011

@@ -99,14 +100,19 @@ private static function cswapBoolean(bool $a, bool $b, int $cond): array
99100
}
100101

101102
/**
103+
* The mask is as wide as the longer of the two operands, so it is never empty; the guard is there because
104+
* `BigInteger::fromBase()` requires a non-empty string and the width cannot be proven statically.
105+
*
102106
* @return array{BigInteger, BigInteger}
103107
*/
104108
private static function cswapBigInteger(BigInteger $sa, BigInteger $sb, int $cond): array
105109
{
106110
$size = max(strlen($sa->toBase(2)), strlen($sb->toBase(2)));
107-
$mask = (string) (1 - $cond);
108-
$mask = str_pad('', $size, $mask, STR_PAD_LEFT);
109-
$mask = BigInteger::fromBase($mask, 2);
111+
$bits = str_pad('', $size, (string) (1 - $cond), STR_PAD_LEFT);
112+
if ($bits === '') {
113+
throw new InvalidArgumentException('Unable to compute the mask');
114+
}
115+
$mask = BigInteger::fromBase($bits, 2);
110116
$taA = $sa->and($mask);
111117
$taB = $sb->and($mask);
112118
$sa = $sa->xor($sb)

‎tests/Bundle/JoseFramework/Functional/Serializer/JWEEncoderTest.php‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public function theJWEEncoderThrowsOnNonExistingRecipient(string $serializerId):
8787

8888
['jwe' => $jwe] = self::createJWE();
8989

90-
$this->expectExceptionMessageIsOrContains(sprintf('Cannot encode JWE to %s format.', 'jwe_compact'));
90+
$this->expectExceptionMessage(sprintf('Cannot encode JWE to %s format.', 'jwe_compact'));
9191
$serializer->encode($jwe, 'jwe_compact', [
9292
'recipient_index' => 2,
9393
]);
@@ -129,7 +129,7 @@ public function theJWEEncoderShouldThrowOnUnsupportedFormatWhenEncoding(): void
129129

130130
['jwe' => $jwe] = self::createJWE();
131131

132-
$this->expectExceptionMessageIsOrContains('Cannot encode JWE to jwe_json_flattened format.');
132+
$this->expectExceptionMessage('Cannot encode JWE to jwe_json_flattened format.');
133133
$serializer->encode($jwe, 'jwe_json_flattened');
134134
}
135135

@@ -159,7 +159,7 @@ public function theJWEEncoderShouldThrowOnUnsupportedFormatWhenDecoding(): void
159159

160160
['jwe_json_flattened' => $jweString] = self::createJWE();
161161

162-
$this->expectExceptionMessageIsOrContains('Cannot decode JWE from jwe_json_flattened format.');
162+
$this->expectExceptionMessage('Cannot decode JWE from jwe_json_flattened format.');
163163
$serializer->decode($jweString, 'jwe_json_flattened');
164164
}
165165

‎tests/Bundle/JoseFramework/Functional/Serializer/JWSEncoderTest.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public function theJWSSerializerShouldThrowOnUnsupportedFormatWhenEncoding(): vo
123123

124124
['jws' => $jws] = static::createJWS();
125125

126-
$this->expectExceptionMessageIsOrContains('Cannot encode JWS to jws_json_flattened format.');
126+
$this->expectExceptionMessage('Cannot encode JWS to jws_json_flattened format.');
127127
$serializer->encode($jws, 'jws_json_flattened');
128128
}
129129

@@ -154,7 +154,7 @@ public function theJWSSerializerShouldThrowOnUnsupportedFormatWhenDecoding(): vo
154154

155155
$jwsString = '{"payload":"SGVsbG8gV29ybGQh","protected":"eyJhbGciOiJIUzI1NiJ9","signature":"ZIKPsa3NtNoACjvh6fhfg6PZgmKiuss_9sDPtMZxtNU"}';
156156

157-
$this->expectExceptionMessageIsOrContains('Cannot decode JWS from jws_json_flattened format.');
157+
$this->expectExceptionMessage('Cannot decode JWS from jws_json_flattened format.');
158158
$serializer->decode($jwsString, 'jws_json_flattened');
159159
}
160160

‎tests/Component/Checker/AlgorithmHeaderCheckerTest.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ final class AlgorithmHeaderCheckerTest extends TestCase
1818
public function anAlgorithmMustBeAString(): void
1919
{
2020
$this->expectException(InvalidHeaderException::class);
21-
$this->expectExceptionMessageIsOrContains('"alg" must be a string.');
21+
$this->expectExceptionMessage('"alg" must be a string.');
2222

2323
$checker = new AlgorithmChecker(['foo']);
2424
$checker->checkHeader(1);
@@ -28,7 +28,7 @@ public function anAlgorithmMustBeAString(): void
2828
public function theAlgorithmHeaderIsNotAllowed(): void
2929
{
3030
$this->expectException(InvalidHeaderException::class);
31-
$this->expectExceptionMessageIsOrContains('Unsupported algorithm.');
31+
$this->expectExceptionMessage('Unsupported algorithm.');
3232

3333
$checker = new AlgorithmChecker(['foo']);
3434
$checker->checkHeader('bar');

‎tests/Component/Checker/AudienceClaimCheckerTest.php‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ final class AudienceClaimCheckerTest extends TestCase
1818
public function anAudienceClaimMustBeAStringOrAnArrayOfStrings(): void
1919
{
2020
$this->expectException(InvalidClaimException::class);
21-
$this->expectExceptionMessageIsOrContains('Bad audience.');
21+
$this->expectExceptionMessage('Bad audience.');
2222

2323
$checker = new AudienceChecker('foo');
2424
$checker->checkClaim(1);
@@ -28,7 +28,7 @@ public function anAudienceClaimMustBeAStringOrAnArrayOfStrings(): void
2828
public function theAudienceClaimIsNotKnown(): void
2929
{
3030
$this->expectException(InvalidClaimException::class);
31-
$this->expectExceptionMessageIsOrContains('Bad audience.');
31+
$this->expectExceptionMessage('Bad audience.');
3232

3333
$checker = new AudienceChecker('foo');
3434
$checker->checkClaim('bar');
@@ -38,7 +38,7 @@ public function theAudienceClaimIsNotKnown(): void
3838
public function theAudienceClaimListDoesNotContainTheCurrentAudience(): void
3939
{
4040
$this->expectException(InvalidClaimException::class);
41-
$this->expectExceptionMessageIsOrContains('Bad audience.');
41+
$this->expectExceptionMessage('Bad audience.');
4242

4343
$checker = new AudienceChecker('foo');
4444
$checker->checkClaim(['bar']);

‎tests/Component/Checker/AudienceHeaderCheckerTest.php‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ final class AudienceHeaderCheckerTest extends TestCase
1818
public function anAudienceHeaderMustBeAStringOrAnArrayOfStrings(): void
1919
{
2020
$this->expectException(InvalidHeaderException::class);
21-
$this->expectExceptionMessageIsOrContains('Bad audience.');
21+
$this->expectExceptionMessage('Bad audience.');
2222

2323
$checker = new AudienceChecker('foo');
2424
$checker->checkHeader(1);
@@ -28,7 +28,7 @@ public function anAudienceHeaderMustBeAStringOrAnArrayOfStrings(): void
2828
public function theAudienceHeaderIsNotKnown(): void
2929
{
3030
$this->expectException(InvalidHeaderException::class);
31-
$this->expectExceptionMessageIsOrContains('Bad audience.');
31+
$this->expectExceptionMessage('Bad audience.');
3232

3333
$checker = new AudienceChecker('foo');
3434
$checker->checkHeader('bar');
@@ -38,7 +38,7 @@ public function theAudienceHeaderIsNotKnown(): void
3838
public function theAudienceHeaderListDoesNotContainTheCurrentAudience(): void
3939
{
4040
$this->expectException(InvalidHeaderException::class);
41-
$this->expectExceptionMessageIsOrContains('Bad audience.');
41+
$this->expectExceptionMessage('Bad audience.');
4242

4343
$checker = new AudienceChecker('foo');
4444
$checker->checkHeader(['bar']);

‎tests/Component/Checker/CallableCheckerTest.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ final class CallableCheckerTest extends TestCase
2020
public function theCallableIsCallable(): void
2121
{
2222
$this->expectException(InvalidArgumentException::class);
23-
$this->expectExceptionMessageIsOrContains('The $callable argument must be a callable.');
23+
$this->expectExceptionMessage('The $callable argument must be a callable.');
2424

2525
new CallableChecker('foo', 'not_a_callable');
2626
}

‎tests/Component/Checker/ClaimCheckerManagerFactoryTest.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function theAliasListOfTheClaimCheckerManagerFactoryIsAvailable(): void
3333
public function theAliasDoesNotExist(): void
3434
{
3535
$this->expectException(InvalidArgumentException::class);
36-
$this->expectExceptionMessageIsOrContains('The claim checker with the alias "foo" is not supported.');
36+
$this->expectExceptionMessage('The claim checker with the alias "foo" is not supported.');
3737

3838
$this->getClaimCheckerManagerFactory()
3939
->create(['foo']);
@@ -71,7 +71,7 @@ public function iCanCheckValidPayloadClaims(): void
7171
public function theMandatoryClaimsAreNotSet(): void
7272
{
7373
$this->expectException(MissingMandatoryClaimException::class);
74-
$this->expectExceptionMessageIsOrContains('The following claims are mandatory: bar.');
74+
$this->expectExceptionMessage('The following claims are mandatory: bar.');
7575

7676
$clock = new MockClock();
7777
$now = $clock->now()

0 commit comments

Comments
 (0)