Skip to content

Commit

Permalink
Add PHPStan, improve CI workflow (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
pulzarraider authored Feb 4, 2025
1 parent 89d2cee commit e71d9d9
Show file tree
Hide file tree
Showing 16 changed files with 164 additions and 72 deletions.
58 changes: 41 additions & 17 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,65 @@ on:

jobs:
build:
name: PHP ${{ matrix.php-version }} Sf ${{ matrix.symfony-version }}
runs-on: ubuntu-latest

strategy:
matrix:
php-version:
- '8.2'
- '8.3'
platform: [ubuntu-latest]
name: PHP ${{ matrix.php-version }}
runs-on: ubuntu-latest
include:
- php-version: 8.2
symfony-version: 5.4.*
- php-version: 8.3
symfony-version: 5.4.*
- php-version: 8.2
symfony-version: 6.4.*
- php-version: 8.3
symfony-version: 6.4.*
- php-version: 8.4
symfony-version: 6.4.*
- php-version: 8.2
symfony-version: 7.2.*
- php-version: 8.3
symfony-version: 7.2.*
- php-version: 8.4
symfony-version: 7.2.*

steps:
- uses: actions/checkout@v2
- uses: nanasess/setup-php@master
- name: "Checkout"
uses: actions/checkout@v4

- name: "Setup PHP"
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
tools: composer:v2

- name: Validate composer.json
run: composer validate

- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}-${{ matrix.php-version }}
key: composer-${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('**/composer.json') }}-${{ matrix.symfony-version }}
restore-keys: |
${{ runner.os }}-composer-
composer-${{ runner.os }}-${{ matrix.php-version }}-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress --no-suggest --no-ansi --no-interaction --no-scripts
env:
SYMFONY_REQUIRE: ${{ matrix.symfony-version }}
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer update --prefer-dist --no-progress --no-ansi --no-interaction --no-scripts

- name: Run unit tests
run: vendor/bin/phpunit

- name: Run style tests
run: vendor/bin/ecs check -vv

- name: Run static analyse tests
run: vendor/bin/psalm --php-version=${{ matrix.php-version }}
- name: Run static analyse phpstan
run: vendor/bin/phpstan analyse --error-format=github

- name: Run unit tests
run: vendor/bin/phpunit
- name: Run static analyse psalm
run: vendor/bin/psalm --php-version=${{ matrix.php-version }}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ framework:
```
### Step 3: Configure Symfony Messenger
```yaml
# config/packages/messenger.yaml

Expand Down Expand Up @@ -129,6 +130,7 @@ petit_press_gps_messenger:
Can be very useful when used together with [subscription filters](https://cloud.google.com/pubsub/docs/subscription-message-filter).

### Step 6: Create topics from config

```bash
bin/console messenger:setup-transports
```
9 changes: 7 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,14 @@
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"vimeo/psalm": "^5.0",
"vimeo/psalm": "^6.0",
"symfony/yaml": "^5.4|^6.0|^7.0",
"symplify/easy-coding-standard": "^11.1"
"symplify/easy-coding-standard": "^11.1",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-symfony": "^2.0",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"phpstan/phpstan-strict-rules": "^2.0"
},
"autoload": {
"psr-4": { "PetitPress\\GpsMessengerBundle\\": "src" }
Expand Down
11 changes: 11 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
includes:
- vendor/phpstan/phpstan-deprecation-rules/rules.neon
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon
- vendor/phpstan/phpstan-symfony/extension.neon

parameters:
paths:
- src
- tests
level: 9
22 changes: 22 additions & 0 deletions src/Transport/GpsConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,33 @@ final class GpsConfiguration implements GpsConfigurationInterface
private bool $topicCreationEnabled;
private string $subscriptionName;
private bool $subscriptionCreationEnabled;

/**
* @var array<string, mixed>
*/
private array $clientConfig;

/**
* @var array<string, mixed>
*/
private array $topicOptions;

/**
* @var array<string, mixed>
*/
private array $subscriptionOptions;

/**
* @var array<string, mixed>
*/
private array $subscriptionPullOptions;

/**
* @param array<string, mixed> $clientConfig
* @param array<string, mixed> $topicOptions
* @param array<string, mixed> $subscriptionOptions
* @param array<string, mixed> $subscriptionPullOptions
*/
public function __construct(
string $topicName,
bool $topicCreationEnabled,
Expand Down
4 changes: 4 additions & 0 deletions src/Transport/GpsConfigurationInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,25 @@ public function isSubscriptionCreationEnabled(): bool;

/**
* @see PubSubClient constructor options
* @return array<string, mixed>
*/
public function getClientConfig(): array;

/**
* @see Topic::create options
* @return array<string, mixed>
*/
public function getTopicOptions(): array;

/**
* @see Subscription::create options
* @return array<string, mixed>
*/
public function getSubscriptionOptions(): array;

/**
* @see Subscription::pull options
* @return array<string, mixed>
*/
public function getSubscriptionPullOptions(): array;
}
12 changes: 10 additions & 2 deletions src/Transport/GpsConfigurationResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,18 +118,26 @@ function (OptionsResolver $pullResolver): void {
);
}

/**
* @param array<string, mixed> $options
*
* @return array<int|string, mixed>
*/
private function getMergedOptions(string $dsn, array $options): array
{
$dnsOptions = [];
$parsedDnsOptions = parse_url($dsn);

$dsnQueryOptions = $parsedDnsOptions['query'] ?? null;
if ($dsnQueryOptions) {
if ($dsnQueryOptions !== null && $dsnQueryOptions !== '') {
parse_str($dsnQueryOptions, $dnsOptions);
}

$dnsPathOption = $parsedDnsOptions['path'] ?? null;
if ($dnsPathOption) {
if ($dnsPathOption !== null && $dnsPathOption !== '') {
if (! isset($dnsOptions['topic']) || ! is_array($dnsOptions['topic'])) {
$dnsOptions['topic'] = [];
}
$dnsOptions['topic']['name'] = substr($dnsPathOption, 1);
}

Expand Down
3 changes: 3 additions & 0 deletions src/Transport/GpsConfigurationResolverInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@ interface GpsConfigurationResolverInterface
public const DEFAULT_TOPIC_NAME = 'messages';
public const DEFAULT_MAX_MESSAGES_PULL = 10;

/**
* @param array<string, mixed> $options
*/
public function resolve(string $dsn, array $options): GpsConfigurationInterface;
}
1 change: 1 addition & 0 deletions src/Transport/GpsReceiver.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ private function getGpsReceivedStamp(Envelope $envelope): GpsReceivedStamp
private function createEnvelopeFromPubSubMessage(Message $message): Envelope
{
try {
/** @var array<string, mixed> $rawData */
$rawData = json_decode($message->data(), true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $exception) {
throw new MessageDecodingFailedException($exception->getMessage(), 0, $exception);
Expand Down
9 changes: 7 additions & 2 deletions src/Transport/GpsTransportFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,19 @@ public function __construct(
}

/**
* {@inheritdoc}
* @param array<mixed> $options
*
* @return GpsTransport
*/
public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface
{
$options = $this->gpsConfigurationResolver->resolve($dsn, $options);

$clientConfig = $options->getClientConfig();
if ($this->cache instanceof CacheItemPoolInterface) {
if (! is_array($clientConfig['credentialsConfig'])) {
$clientConfig['credentialsConfig'] = [];
}
$clientConfig['credentialsConfig']['authCache'] ??= $this->cache;
}
if (isset($this->forcedTransport)) {
Expand All @@ -53,7 +58,7 @@ public function createTransport(string $dsn, array $options, SerializerInterface
}

/**
* {@inheritdoc}
* @param array<mixed> $options
*/
public function supports(string $dsn, array $options): bool
{
Expand Down
22 changes: 11 additions & 11 deletions tests/DependencyInjection/PetitPressGpsMessengerExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ public function testSimpleConfiguration(): void
$config = $this->getSimpleConfig();
$loader->load([$config], $this->configuration);

$this->assertTrue($this->configuration->hasDefinition(GpsTransportFactory::class));
static::assertTrue($this->configuration->hasDefinition(GpsTransportFactory::class));
$gpsTransportFactoryDefinition = $this->configuration->getDefinition(GpsTransportFactory::class);
$cacheArgument = $gpsTransportFactoryDefinition->getArgument(1);
$this->assertInstanceOf(Reference::class, $cacheArgument);
$this->assertEquals('cache.app', (string) $cacheArgument);
static::assertInstanceOf(Reference::class, $cacheArgument);
static::assertEquals('cache.app', (string) $cacheArgument);
}

/**
Expand All @@ -50,22 +50,22 @@ public function testFullConfiguration(): void
$config = $this->getFullConfig();
$loader->load([$config], $this->configuration);

$this->assertTrue($this->configuration->hasDefinition(GpsTransportFactory::class));
static::assertTrue($this->configuration->hasDefinition(GpsTransportFactory::class));
$gpsTransportFactoryDefinition = $this->configuration->getDefinition(GpsTransportFactory::class);
$cacheArgument = $gpsTransportFactoryDefinition->getArgument(1);
$this->assertInstanceOf(Reference::class, $cacheArgument);
$this->assertEquals('foo', (string) $cacheArgument);
static::assertInstanceOf(Reference::class, $cacheArgument);
static::assertEquals('foo', (string) $cacheArgument);
}

/**
* @return mixed
* @return array<string, mixed>
*/
private function getFullConfig()
private function getFullConfig(): array
{
$yaml = <<<EOF
auth_cache: 'foo'
EOF;

/** @var array<string, mixed> */
return (new Parser())->parse($yaml);
}

Expand All @@ -77,9 +77,9 @@ public function testConfigurationWithDisabledAuthCache(): void
$config = $this->getDisabledCacheConfig();
$loader->load([$config], $this->configuration);

$this->assertTrue($this->configuration->hasDefinition(GpsTransportFactory::class));
static::assertTrue($this->configuration->hasDefinition(GpsTransportFactory::class));
$gpsTransportFactoryDefinition = $this->configuration->getDefinition(GpsTransportFactory::class);
$this->assertNull($gpsTransportFactoryDefinition->getArgument(1));
static::assertNull($gpsTransportFactoryDefinition->getArgument(1));
}

/**
Expand Down
6 changes: 5 additions & 1 deletion tests/Transport/GpsConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ protected function setUp(): void

/**
* @dataProvider dataProvider
* @param array<string, mixed> $options
*/
public function testResolve(string $dsn, array $options, GpsConfigurationInterface $expectedConfiguration): void
{
$configuration = $this->gpsConfigurationResolver->resolve($dsn, $options);
$this->assertEquals($expectedConfiguration, $configuration);
static::assertEquals($expectedConfiguration, $configuration);
}

/**
* @return array<string, mixed>
*/
public static function dataProvider(): array
{
return [
Expand Down
6 changes: 3 additions & 3 deletions tests/Transport/GpsReceiverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,19 @@ public function testItRejects(): void
$gpsMessage = new Message(['data' => '']);

$this->gpsConfigurationMock
->expects($this->once())
->expects(static::once())
->method('getSubscriptionName')
->willReturn(self::SUBSCRIPTION_NAME)
;

$this->subscriptionMock
->expects($this->once())
->expects(static::once())
->method('modifyAckDeadline')
->with($gpsMessage, 0)
;

$this->pubSubClientMock
->expects($this->once())
->expects(static::once())
->method('subscription')
->with(self::SUBSCRIPTION_NAME)
->willReturn($this->subscriptionMock)
Expand Down
Loading

0 comments on commit e71d9d9

Please sign in to comment.