From d763bdb44916429c5ca7b085324c0c61be090295 Mon Sep 17 00:00:00 2001 From: michalsn Date: Thu, 6 Mar 2025 21:26:23 +0100 Subject: [PATCH 1/3] chore: update workflow to support PHP 8.4 --- .github/workflows/deptrac.yml | 5 ++++- .github/workflows/phpcpd.yml | 4 ++-- .github/workflows/phpcsfixer.yml | 19 ++++++++++++++++--- .github/workflows/phpstan.yml | 2 +- .github/workflows/phpunit.yml | 22 +++++++++++++++++++--- .github/workflows/psalm.yml | 2 +- .github/workflows/rector.yml | 2 +- psalm.xml | 1 + 8 files changed, 45 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deptrac.yml b/.github/workflows/deptrac.yml index 5ef4dea..6cfa1a7 100644 --- a/.github/workflows/deptrac.yml +++ b/.github/workflows/deptrac.yml @@ -18,6 +18,9 @@ on: - 'depfile.yaml' - '.github/workflows/deptrac.yml' +permissions: + contents: read + jobs: build: name: Dependency Tracing @@ -31,7 +34,7 @@ jobs: - name: Set up PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.1' + php-version: '8.2' extensions: intl, json, mbstring, xml coverage: none env: diff --git a/.github/workflows/phpcpd.yml b/.github/workflows/phpcpd.yml index 57b56fe..cd4194e 100644 --- a/.github/workflows/phpcpd.yml +++ b/.github/workflows/phpcpd.yml @@ -27,10 +27,10 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.1' + php-version: '8.2' tools: phpcpd extensions: dom, mbstring coverage: none - name: Detect duplicate code - run: phpcpd app/ tests/ + run: phpcpd src/ diff --git a/.github/workflows/phpcsfixer.yml b/.github/workflows/phpcsfixer.yml index 9ac8b7f..b77bcec 100644 --- a/.github/workflows/phpcsfixer.yml +++ b/.github/workflows/phpcsfixer.yml @@ -14,11 +14,22 @@ on: - '**.php' - '.github/workflows/phpcsfixer.yml' +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + jobs: build: - name: Coding Standards + name: PHP ${{ matrix.php-versions }} Coding Standards runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, '[ci skip]')" + if: (! contains(github.event.head_commit.message, '[ci skip]')) + strategy: + fail-fast: false + matrix: + php-versions: ['8.1', '8.2', '8.4'] steps: - name: Checkout @@ -27,7 +38,7 @@ jobs: - name: Set up PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.1' + php-version: ${{ matrix.php-versions }} extensions: json, tokenizer coverage: none env: @@ -53,3 +64,5 @@ jobs: - name: Check code for standards compliance run: vendor/bin/php-cs-fixer fix --verbose --ansi --dry-run --using-cache=no --diff + env: + PHP_CS_FIXER_IGNORE_ENV: ${{ matrix.php-versions == '8.4' }} diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 85d1265..906b642 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -26,7 +26,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['8.1', '8.2', '8.3'] + php-versions: ['8.1', '8.4'] steps: - name: Checkout diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index e7300f3..3ed4806 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -20,14 +20,30 @@ on: jobs: main: - name: PHP ${{ matrix.php-versions }} Unit Tests + name: PHP ${{ matrix.php-versions }} runs-on: ubuntu-latest if: "!contains(github.event.head_commit.message, '[ci skip]')" strategy: matrix: - php-versions: ['8.1', '8.2', '8.3'] + php-versions: ['8.1', '8.2', '8.3', '8.4'] steps: + - name: Free Disk Space (Ubuntu) + uses: jlumbroso/free-disk-space@main + with: + # this might remove tools that are actually needed, + # if set to "true" but frees about 6 GB + tool-cache: false + + # all of these default to true, but feel free to set to + # "false" if necessary for your workflow + android: true + dotnet: true + haskell: true + large-packages: false + docker-images: true + swap-storage: true + - name: Checkout uses: actions/checkout@v4 @@ -65,7 +81,7 @@ jobs: TERM: xterm-256color TACHYCARDIA_MONITOR_GA: enabled - - if: matrix.php-versions == '8.0' + - if: matrix.php-versions == '8.2' name: Run Coveralls continue-on-error: true run: | diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index 1d3c7cb..a5cb6ad 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -31,7 +31,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.1' + php-version: '8.2' tools: phpstan, phpunit extensions: intl, json, mbstring, xml coverage: none diff --git a/.github/workflows/rector.yml b/.github/workflows/rector.yml index 29e22ba..f863318 100644 --- a/.github/workflows/rector.yml +++ b/.github/workflows/rector.yml @@ -26,7 +26,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['8.1', '8.2', '8.3'] + php-versions: ['8.2', '8.4'] steps: - name: Checkout diff --git a/psalm.xml b/psalm.xml index 696215c..59dcd90 100644 --- a/psalm.xml +++ b/psalm.xml @@ -9,6 +9,7 @@ cacheDirectory="build/psalm/" findUnusedBaselineEntry="true" findUnusedCode="false" + ensureOverrideAttribute="false" > From 6b4dea50d5972252fa477beeccd030ff2c94074e Mon Sep 17 00:00:00 2001 From: michalsn Date: Thu, 6 Mar 2025 21:26:52 +0100 Subject: [PATCH 2/3] cs fix --- src/CodeIgniter.php | 2 +- src/Config/Services.php | 2 +- src/Debug/Toolbar.php | 6 +++--- src/HTTP/HtmxTrait.php | 2 +- src/HTTP/RedirectResponse.php | 2 +- src/View/ErrorModalDecorator.php | 4 ++-- src/View/ToolbarDecorator.php | 4 ++-- tests/HTTP/ResponseTest.php | 10 +++++----- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/CodeIgniter.php b/src/CodeIgniter.php index 46da283..953cbd6 100644 --- a/src/CodeIgniter.php +++ b/src/CodeIgniter.php @@ -72,7 +72,7 @@ public function storePreviousURL($uri) $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), - $uri->getFragment() + $uri->getFragment(), )); } } diff --git a/src/Config/Services.php b/src/Config/Services.php index 196aae0..4123bfc 100644 --- a/src/Config/Services.php +++ b/src/Config/Services.php @@ -92,7 +92,7 @@ public static function incomingrequest(?App $config = null, bool $getShared = tr $config, AppServices::uri(), 'php://input', - new UserAgent() + new UserAgent(), ); } diff --git a/src/Debug/Toolbar.php b/src/Debug/Toolbar.php index 0056589..14c599e 100644 --- a/src/Debug/Toolbar.php +++ b/src/Debug/Toolbar.php @@ -43,7 +43,7 @@ public function prepare(?RequestInterface $request = null, ?ResponseInterface $r $stats['startTime'], $stats['totalTime'], $request, - $response + $response, ); helper('filesystem'); @@ -91,8 +91,8 @@ public function prepare(?RequestInterface $request = null, ?ResponseInterface $r '//', '' . $script, $response->getBody(), - 1 - ) + 1, + ), ); return; diff --git a/src/HTTP/HtmxTrait.php b/src/HTTP/HtmxTrait.php index fb58050..15ab51a 100644 --- a/src/HTTP/HtmxTrait.php +++ b/src/HTTP/HtmxTrait.php @@ -29,7 +29,7 @@ private function validateSwap(string $option, string $field = 'swap'): bool 'Option "%s" is not a valid variable for %s. A valid option has to be one of: %s', $option, $field, - implode(', ', $this->swapOptions) + implode(', ', $this->swapOptions), )); } diff --git a/src/HTTP/RedirectResponse.php b/src/HTTP/RedirectResponse.php index 7ed6796..8e5531f 100644 --- a/src/HTTP/RedirectResponse.php +++ b/src/HTTP/RedirectResponse.php @@ -19,7 +19,7 @@ public function hxLocation( ?string $target = null, ?string $swap = null, ?array $values = null, - ?array $headers = null + ?array $headers = null, ): RedirectResponse { if (str_starts_with($path, 'http://') || str_starts_with($path, 'https://')) { $path = (string) service('uri', $path, false)->withScheme('')->setHost(''); diff --git a/src/View/ErrorModalDecorator.php b/src/View/ErrorModalDecorator.php index 980f1aa..450e9f3 100644 --- a/src/View/ErrorModalDecorator.php +++ b/src/View/ErrorModalDecorator.php @@ -19,14 +19,14 @@ public static function decorate(string $html): string $script = sprintf( '', csp_script_nonce(), - file_get_contents(__DIR__ . '/error_modal_decorator.js') + file_get_contents(__DIR__ . '/error_modal_decorator.js'), ); $html = preg_replace( '/<\/head>/', $script . '', $html, - 1 + 1, ); } diff --git a/src/View/ToolbarDecorator.php b/src/View/ToolbarDecorator.php index 7766d9c..c471e2c 100644 --- a/src/View/ToolbarDecorator.php +++ b/src/View/ToolbarDecorator.php @@ -19,14 +19,14 @@ public static function decorate(string $html): string $script = sprintf( '', csp_script_nonce(), - file_get_contents(__DIR__ . '/toolbar_decorator.js') + file_get_contents(__DIR__ . '/toolbar_decorator.js'), ); $html = preg_replace( '/<\/head>/', $script . '', $html, - 1 + 1, ); } diff --git a/tests/HTTP/ResponseTest.php b/tests/HTTP/ResponseTest.php index c7ac42d..be7b8a6 100644 --- a/tests/HTTP/ResponseTest.php +++ b/tests/HTTP/ResponseTest.php @@ -90,7 +90,7 @@ public function testTriggerClientEvent(): void $this->assertSame( '{"showMessage":""}', - $this->response->getHeaderLine('HX-Trigger') + $this->response->getHeaderLine('HX-Trigger'), ); } @@ -100,7 +100,7 @@ public function testTriggerClientEventAndPassDetails(): void $this->assertSame( '{"showMessage":{"level":"info","message":"Here Is A Message"}}', - $this->response->getHeaderLine('HX-Trigger') + $this->response->getHeaderLine('HX-Trigger'), ); } @@ -111,7 +111,7 @@ public function testTriggerClientEventAndPassDetailsMultipleCalls(): void $this->assertSame( '{"event1":"A message","event2":"Another message"}', - $this->response->getHeaderLine('HX-Trigger') + $this->response->getHeaderLine('HX-Trigger'), ); } @@ -121,7 +121,7 @@ public function testTriggerClientEventWithSettle(): void $this->assertSame( '{"showMessage":""}', - $this->response->getHeaderLine('HX-Trigger-After-Settle') + $this->response->getHeaderLine('HX-Trigger-After-Settle'), ); } @@ -131,7 +131,7 @@ public function testTriggerClientEventWithSwap(): void $this->assertSame( '{"showMessage":""}', - $this->response->getHeaderLine('HX-Trigger-After-Swap') + $this->response->getHeaderLine('HX-Trigger-After-Swap'), ); } From 7f79fbae7ed019e3a68d44af8e972e986bacb5c7 Mon Sep 17 00:00:00 2001 From: michalsn Date: Thu, 6 Mar 2025 21:35:40 +0100 Subject: [PATCH 3/3] view class updates for CI 4.6 compatibility --- src/View/View.php | 21 ++++++++++++++++++--- tests/View/ViewTest.php | 34 ++++++++++++++++------------------ 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/View/View.php b/src/View/View.php index 039a9cd..aba2b93 100644 --- a/src/View/View.php +++ b/src/View/View.php @@ -224,10 +224,25 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n $output = $this->decorateOutput($output); - $this->logPerformance($this->renderVars['start'], microtime(true), $this->renderVars['view']); + $this->logPerformance( + $this->renderVars['start'], + microtime(true), + $this->renderVars['view'], + ); + + // Check if DebugToolbar is enabled. + $filters = service('filters'); + $requiredAfterFilters = $filters->getRequiredFilters('after')[0]; + if (in_array('toolbar', $requiredAfterFilters, true)) { + $debugBarEnabled = true; + } else { + $afterFilters = $filters->getFiltersClass()['after']; + $debugBarEnabled = in_array(DebugToolbar::class, $afterFilters, true); + } - if (($this->debug && (! isset($options['debug']) || $options['debug'] === true)) - && in_array(DebugToolbar::class, service('filters')->getFiltersClass()['after'], true) + if ( + $this->debug && $debugBarEnabled + && (! isset($options['debug']) || $options['debug'] === true) && empty($this->renderVars['options']['fragments']) ) { $toolbarCollectors = config(Toolbar::class)->collectors; diff --git a/tests/View/ViewTest.php b/tests/View/ViewTest.php index 3514e75..df6bb44 100644 --- a/tests/View/ViewTest.php +++ b/tests/View/ViewTest.php @@ -34,7 +34,7 @@ protected function setUp(): void public function testRenderViewData(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $view->setVar('testString1', 'Hello World'); $view->setVar('testString2', 'Hello World'); @@ -45,8 +45,6 @@ public function testRenderViewData(): void public function testRenderViewDataWithDebug(): void { - service('filters')->enableFilters(['toolbar'], 'after'); - $view = new View($this->config, $this->viewsDir, $this->loader); $view->setVar('testString1', 'Hello World'); @@ -61,7 +59,7 @@ public function testRenderViewDataWithDebug(): void public function testRenderViewFragment(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $view->setVar('testString1', 'Hello World'); $view->setVar('testString2', 'Hello World'); @@ -72,7 +70,7 @@ public function testRenderViewFragment(): void public function testRenderViewFragmentInViewFragment(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $view->setVar('testString1', 'Hello World'); $view->setVar('testString2', 'Hello World'); @@ -83,7 +81,7 @@ public function testRenderViewFragmentInViewFragment(): void public function testRenderViewFragments(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $view->setVar('testString1', 'Hello World'); $view->setVar('testString2', 'Hello World'); @@ -94,7 +92,7 @@ public function testRenderViewFragments(): void public function testRenderViewFragmentsWithInclude(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $view->setVar('testString1', 'Hello World'); $expected = "Hello World, fragment1!\nview included\n"; @@ -104,7 +102,7 @@ public function testRenderViewFragmentsWithInclude(): void public function testRenderViewFragmentsFromInclude(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $view->setVar('testString1', 'Hello World'); $view->setVar('testString2', 'Hello World'); @@ -115,7 +113,7 @@ public function testRenderViewFragmentsFromInclude(): void public function testRenderDefaultInclude(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $expected = "view included\n"; @@ -124,7 +122,7 @@ public function testRenderDefaultInclude(): void public function testRenderViewDataWithLayout(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $view->setVar('testString1', 'Hello World'); $view->setVar('testString2', 'Hello World'); @@ -135,7 +133,7 @@ public function testRenderViewDataWithLayout(): void public function testRenderViewFragmentWithLayout(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $view->setVar('testString1', 'Hello World'); $view->setVar('testString2', 'Hello World'); @@ -146,7 +144,7 @@ public function testRenderViewFragmentWithLayout(): void public function testRenderViewFragmentsWithLayout(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $view->setVar('testString1', 'Hello World'); $view->setVar('testString2', 'Hello World'); @@ -157,7 +155,7 @@ public function testRenderViewFragmentsWithLayout(): void public function testRenderViewFragmentFromLayout(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $expected = 'Page bottom'; @@ -166,7 +164,7 @@ public function testRenderViewFragmentFromLayout(): void public function testRenderViewFragmentDoesntExists(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $view->setVar('testString1', 'Hello World'); $view->setVar('testString2', 'Hello World'); @@ -177,7 +175,7 @@ public function testRenderViewFragmentDoesntExists(): void public function testRenderViewFragmentBroken(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $view->setVar('testString1', 'Hello World'); $expected = ''; @@ -188,7 +186,7 @@ public function testRenderViewFragmentBroken(): void public function testRenderViewFragmentWithCache(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $view->setVar('testString1', 'Hello World'); $view->setVar('testString2', 'Hello World'); @@ -204,7 +202,7 @@ public function testRenderViewFragmentWithCache(): void public function testRendersThrowsExceptionIfFileNotFound(): void { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $this->expectException(ViewException::class); $view->setVar('testString', 'Hello World'); @@ -214,7 +212,7 @@ public function testRendersThrowsExceptionIfFileNotFound(): void public function testParseFragmentsNoMatch() { - $view = new View($this->config, $this->viewsDir, $this->loader); + $view = new View($this->config, $this->viewsDir, $this->loader, false); $obj = $this->getPrivateMethodInvoker($view, 'parseFragments'); $result = $obj('output data', []);