From 0ccc8278f2569e3e5d38e7358ba36a3ccd4bbf77 Mon Sep 17 00:00:00 2001 From: Luis Humberto Barrientos Zambrano Date: Thu, 22 Oct 2026 21:54:12 -0300 Subject: [PATCH] chore: require patched PHP versions --- .dockerignore | 4 ++++ .github/workflows/code-quality.yml | 12 ++++++---- .php-cs-fixer.php | 4 ++-- Dockerfile | 10 +++++++++ README.md | 19 ++++++++++++++++ compose.yaml | 13 +++++++++++ composer.json | 6 ++--- phpstan.neon | 3 ++- phpunit.xml.dist | 19 +++++++--------- src/ThrowableProcessor.php | 11 ++++++---- tests/LogTest.php | 35 ++++++++++++++---------------- tests/ThrowableProcessorTest.php | 8 +++---- 12 files changed, 96 insertions(+), 48 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 compose.yaml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4b413bd --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.git +vendor +.phpunit.result.cache +.php-cs-fixer.cache diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index abf53ba..8dee84e 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -6,9 +6,13 @@ on: pull_request: ~ jobs: - test-php-80: - name: Code quality PHP 8.0 + test: + name: Code quality PHP ${{ matrix.php-version }} runs-on: [ubuntu-latest] + strategy: + fail-fast: false + matrix: + php-version: ['8.2.35', '8.3.36', '8.4.27', '8.5.12'] steps: - name: Checkout uses: actions/checkout@v2 @@ -16,10 +20,10 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.0 + php-version: ${{ matrix.php-version }} coverage: xdebug - - name: Validate composer.json and composer.lock + - name: Validate Composer manifest run: composer validate --strict - name: Install dependencies diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index fba9b86..cbaec1d 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -8,8 +8,8 @@ $config ->setRules([ '@Symfony' => true, - '@PHP71Migration:risky' => true, - '@PHPUnit60Migration:risky' => true, + '@PHP7x1Migration:risky' => true, + '@PHPUnit6x0Migration:risky' => true, 'array_indentation' => true, 'array_syntax' => ['syntax' => 'short'], 'blank_line_after_opening_tag' => true, diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2e1375d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM php:8.5.12-cli + +RUN apt-get update \ + && apt-get install -y --no-install-recommends libzip-dev unzip \ + && docker-php-ext-install zip \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer + +WORKDIR /app diff --git a/README.md b/README.md index dcd0ce7..5dbcd96 100644 --- a/README.md +++ b/README.md @@ -77,3 +77,22 @@ Log::emergency('This is an emergency in the emergency channel', 'emergency'); ## Contributing Feel free to send your contributions as a PR. Make sure you update/write new tests to support your contribution. Please follow PSR-2. + +### Development with Docker + +The development container uses PHP 8.5.12, the latest patched version listed in the PHP security advisory. Docker and Docker Compose are required. The provided Netskope CA bundle is mounted read-only for Composer's TLS connections; set `NETSKOPE_CA_BUNDLE` if it is stored elsewhere. + +```sh +docker compose build +docker compose run --rm php php --version +docker compose run --rm php composer install +docker compose run --rm php composer test +``` + +Run other Composer commands in the same container, for example: + +```sh +docker compose run --rm php composer require vendor/package +``` + +The package requires PHP 8.2.35, 8.3.36, 8.4.27, or 8.5.12 (or a later patch release in those branches), so Composer will not install it on an official PHP release that predates the security fixes. diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..3ab0a9a --- /dev/null +++ b/compose.yaml @@ -0,0 +1,13 @@ +services: + php: + build: . + image: microlog-php:8.5.12 + working_dir: /app + volumes: + - .:/app + - ${NETSKOPE_CA_BUNDLE:-/Users/lhbarrientos/netskope/netskope-cert-bundle.pem}:/run/certs/netskope-ca-bundle.pem:ro + environment: + COMPOSER_CACHE_DIR: /tmp/composer-cache + COMPOSER_CAFILE: /run/certs/netskope-ca-bundle.pem + CURL_CA_BUNDLE: /run/certs/netskope-ca-bundle.pem + SSL_CERT_FILE: /run/certs/netskope-ca-bundle.pem diff --git a/composer.json b/composer.json index d8ea3a6..af8811c 100644 --- a/composer.json +++ b/composer.json @@ -6,13 +6,13 @@ "homepage": "https://github.com/linioit/microlog", "license": "BSD-3-Clause", "require": { - "php": "^7.4 || ^8.0", + "php": "~8.2.35 || ~8.3.36 || ~8.4.27 || ~8.5.12", "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "require-dev": { - "phpunit/phpunit": "^8.5", + "phpunit/phpunit": "^11.5", "friendsofphp/php-cs-fixer": "^3.6", - "phpstan/phpstan": "^0.12" + "phpstan/phpstan": "^2.1" }, "autoload": { "psr-4": { diff --git a/phpstan.neon b/phpstan.neon index da5b10b..87c05eb 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,6 @@ parameters: level: max - checkMissingIterableValueType: false paths: - src + ignoreErrors: + - identifier: missingType.iterableValue diff --git a/phpunit.xml.dist b/phpunit.xml.dist index bf26a6d..c1ff4be 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,22 +1,19 @@ - + requireCoverageMetadata="true" + beStrictAboutCoverageMetadata="true" + beStrictAboutOutputDuringTests="true"> ./tests - - + + ./src - - + + diff --git a/src/ThrowableProcessor.php b/src/ThrowableProcessor.php index 7e6236b..de8b110 100644 --- a/src/ThrowableProcessor.php +++ b/src/ThrowableProcessor.php @@ -4,17 +4,20 @@ namespace Linio\Component\Microlog; -use Throwable; - class ThrowableProcessor { + /** + * @param array{message: mixed, context: array} $record + * + * @return array{message: mixed, context: array} + */ public function __invoke(array $record): array { - if (!$record['message'] instanceof Throwable) { + if (!$record['message'] instanceof \Throwable) { return $record; } - /** @var Throwable $throwable */ + /** @var \Throwable $throwable */ $throwable = $record['message']; $record['message'] = $throwable->getMessage(); diff --git a/tests/LogTest.php b/tests/LogTest.php index 951bb14..f497f5b 100644 --- a/tests/LogTest.php +++ b/tests/LogTest.php @@ -4,49 +4,46 @@ namespace Linio\Component\Microlog; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; -use ReflectionProperty; +#[CoversClass(Log::class)] class LogTest extends TestCase { protected function tearDown(): void { - $reflection = new ReflectionProperty(Log::class, 'loggers'); - $reflection->setAccessible(true); + $reflection = new \ReflectionProperty(Log::class, 'loggers'); $reflection->setValue(null, [Log::DEFAULT_CHANNEL => new NullLogger()]); } - /** - * @dataProvider logLevelProvider - */ + #[DataProvider('logLevelProvider')] public function testItLogsMessages(string $level): void { $message = 'this is a test'; $context = ['test' => 'test context']; - $logger = $this->prophesize(LoggerInterface::class); - $logger->log($level, $message, $context)->shouldBeCalled(); + $logger = $this->createMock(LoggerInterface::class); + $logger->expects($this->once())->method('log')->with($level, $message, $context); - Log::setLoggerForChannel($logger->reveal(), Log::DEFAULT_CHANNEL); + Log::setLoggerForChannel($logger, Log::DEFAULT_CHANNEL); Log::{$level}($message, $context); } - /** - * @dataProvider logLevelProvider - */ + #[DataProvider('logLevelProvider')] public function testItLogsMessagesInANonDefaultChannel(string $level): void { $message = 'this is a test'; $channel = 'testChannel'; $context = ['test' => 'test context']; - $logger = $this->prophesize(LoggerInterface::class); - $logger->log($level, $message, $context)->shouldBeCalled(); + $logger = $this->createMock(LoggerInterface::class); + $logger->expects($this->once())->method('log')->with($level, $message, $context); - Log::setLoggerForChannel($logger->reveal(), $channel); + Log::setLoggerForChannel($logger, $channel); Log::{$level}($message, $context, $channel); } @@ -56,15 +53,15 @@ public function testItLogsWithAnArbitraryLevel(): void $message = 'this is a test'; $level = 'emergency'; - $logger = $this->prophesize(LoggerInterface::class); - $logger->log($level, $message, [])->shouldBeCalled(); + $logger = $this->createMock(LoggerInterface::class); + $logger->expects($this->once())->method('log')->with($level, $message, []); - Log::setLoggerForChannel($logger->reveal(), Log::DEFAULT_CHANNEL); + Log::setLoggerForChannel($logger, Log::DEFAULT_CHANNEL); Log::log($level, $message); } - public function logLevelProvider(): array + public static function logLevelProvider(): array { return [ ['debug'], diff --git a/tests/ThrowableProcessorTest.php b/tests/ThrowableProcessorTest.php index 095289d..b7167d2 100644 --- a/tests/ThrowableProcessorTest.php +++ b/tests/ThrowableProcessorTest.php @@ -4,10 +4,10 @@ namespace Linio\Component\Microlog; -use Exception; +use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -use Throwable; +#[CoversClass(ThrowableProcessor::class)] class ThrowableProcessorTest extends TestCase { public function testItDoesNotProcessMessagesThatAreNotThrowables(): void @@ -26,7 +26,7 @@ public function testItDoesNotProcessMessagesThatAreNotThrowables(): void public function testItProcessesMessagesThatAreThrowables(): void { $record = [ - 'message' => new Exception('Test Message'), + 'message' => new \Exception('Test Message'), 'context' => [], ]; @@ -34,6 +34,6 @@ public function testItProcessesMessagesThatAreThrowables(): void $actual = $processor($record); $this->assertSame('Test Message', $actual['message']); - $this->assertInstanceOf(Throwable::class, $actual['context']['exception']); + $this->assertInstanceOf(\Throwable::class, $actual['context']['exception']); } }