Skip to content

chore: update workflow to support PHP 8.4 #83

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/deptrac.yml
Original file line number Diff line number Diff line change
@@ -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:
4 changes: 2 additions & 2 deletions .github/workflows/phpcpd.yml
Original file line number Diff line number Diff line change
@@ -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/
19 changes: 16 additions & 3 deletions .github/workflows/phpcsfixer.yml
Original file line number Diff line number Diff line change
@@ -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' }}
2 changes: 1 addition & 1 deletion .github/workflows/phpstan.yml
Original file line number Diff line number Diff line change
@@ -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
22 changes: 19 additions & 3 deletions .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
@@ -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: |
2 changes: 1 addition & 1 deletion .github/workflows/psalm.yml
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion .github/workflows/rector.yml
Original file line number Diff line number Diff line change
@@ -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
184 changes: 184 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
parameters:
ignoreErrors:
-
message: '#^Call to an undefined method CodeIgniter\\View\\RendererInterface\:\:renderFragments\(\)\.$#'
identifier: method.notFound
count: 1
path: src/Common.php

-
message: '''
#^Call to deprecated method __construct\(\) of class CodeIgniter\\HTTP\\Response\:
4\.5\.0 The param \$config is no longer used\.$#
'''
identifier: method.deprecated
count: 2
path: src/Config/Services.php

-
message: '#^Call to an undefined method CodeIgniter\\View\\RendererInterface\:\:parseFragments\(\)\.$#'
identifier: method.notFound
count: 1
path: src/View/View.php

-
message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertArrayHasKey\(\) with ''_ci_previous_url'' and non\-empty\-array will always evaluate to true\.$#'
identifier: method.alreadyNarrowedType
count: 2
path: tests/CodeIgniterTest.php

-
message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertSame\(\) with ''https\://example\.com…'' and ''https\://example\.com…'' will always evaluate to false\.$#'
identifier: method.impossibleType
count: 1
path: tests/CodeIgniterTest.php

-
message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertSame\(\) with ''https\://example\.com…'' and ''https\://example\.com…'' will always evaluate to true\.$#'
identifier: method.alreadyNarrowedType
count: 1
path: tests/CodeIgniterTest.php

-
message: '''
#^Call to deprecated method __construct\(\) of class CodeIgniter\\HTTP\\Response\:
4\.5\.0 The param \$config is no longer used\.$#
'''
identifier: method.deprecated
count: 1
path: tests/HTTP/RedirectResponseTest.php

-
message: '''
#^Call to deprecated method __construct\(\) of class CodeIgniter\\HTTP\\Response\:
4\.5\.0 The param \$config is no longer used\.$#
'''
identifier: method.deprecated
count: 1
path: tests/HTTP/ResponseTest.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 2
path: tests/_support/Views/complex/include.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 2
path: tests/_support/Views/complex/layout.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 5
path: tests/_support/Views/complex/view1.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 2
path: tests/_support/Views/complex/view2.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 2
path: tests/_support/Views/complex/view3.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 1
path: tests/_support/Views/default_include.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 2
path: tests/_support/Views/huge/include.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 4
path: tests/_support/Views/huge/layout.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 6
path: tests/_support/Views/huge/view.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 3
path: tests/_support/Views/layout.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 5
path: tests/_support/Views/many/layout.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 9
path: tests/_support/Views/many/view1.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 4
path: tests/_support/Views/view_fragment.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 1
path: tests/_support/Views/view_fragment_error.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 4
path: tests/_support/Views/view_fragment_in_view_fragment.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 2
path: tests/_support/Views/view_included_2.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 3
path: tests/_support/Views/view_with_include_1.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 3
path: tests/_support/Views/view_with_include_2.php

-
message: '#^Variable \$testString might not be defined\.$#'
identifier: variable.undefined
count: 1
path: tests/_support/Views/with_decorator.php

-
message: '#^Variable \$this might not be defined\.$#'
identifier: variable.undefined
count: 7
path: tests/_support/Views/with_fragment.php

-
message: '#^Variable \$testString might not be defined\.$#'
identifier: variable.undefined
count: 1
path: tests/_support/Views/without_decorator.php
6 changes: 2 additions & 4 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
includes:
- phpstan-baseline.neon
parameters:
tmpDir: build/phpstan
level: 5
@@ -10,10 +12,6 @@ parameters:
- src/Debug/Toolbar.php
- src/Views/*
ignoreErrors:
- '#Variable \$testString might not be defined.#'
- '#Variable \$this might not be defined.#'
- '#Call to an undefined method CodeIgniter\\View\\RendererInterface::renderFragments\(\).#'
- '#Call to an undefined method CodeIgniter\\View\\RendererInterface::parseFragments\(\).#'
universalObjectCratesClasses:
- CodeIgniter\Entity
- CodeIgniter\Entity\Entity
1 change: 1 addition & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
cacheDirectory="build/psalm/"
findUnusedBaselineEntry="true"
findUnusedCode="false"
ensureOverrideAttribute="false"
>
<projectFiles>
<directory name="src/" />
2 changes: 1 addition & 1 deletion src/CodeIgniter.php
Original file line number Diff line number Diff line change
@@ -72,7 +72,7 @@ public function storePreviousURL($uri)
$uri->getAuthority(),
$uri->getPath(),
$uri->getQuery(),
$uri->getFragment()
$uri->getFragment(),
));
}
}
2 changes: 1 addition & 1 deletion src/Config/Services.php
Original file line number Diff line number Diff line change
@@ -92,7 +92,7 @@ public static function incomingrequest(?App $config = null, bool $getShared = tr
$config,
AppServices::uri(),
'php://input',
new UserAgent()
new UserAgent(),
);
}

6 changes: 3 additions & 3 deletions src/Debug/Toolbar.php
Original file line number Diff line number Diff line change
@@ -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
'/<head>/',
'<head>' . $script,
$response->getBody(),
1
)
1,
),
);

return;
2 changes: 1 addition & 1 deletion src/HTTP/HtmxTrait.php
Original file line number Diff line number Diff line change
@@ -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),
));
}

2 changes: 1 addition & 1 deletion src/HTTP/RedirectResponse.php
Original file line number Diff line number Diff line change
@@ -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('');
4 changes: 2 additions & 2 deletions src/View/ErrorModalDecorator.php
Original file line number Diff line number Diff line change
@@ -19,14 +19,14 @@ public static function decorate(string $html): string
$script = sprintf(
'<script %s id="htmxErrorModalScript">%s</script>',
csp_script_nonce(),
file_get_contents(__DIR__ . '/error_modal_decorator.js')
file_get_contents(__DIR__ . '/error_modal_decorator.js'),
);

$html = preg_replace(
'/<\/head>/',
$script . '</head>',
$html,
1
1,
);
}

4 changes: 2 additions & 2 deletions src/View/ToolbarDecorator.php
Original file line number Diff line number Diff line change
@@ -19,14 +19,14 @@ public static function decorate(string $html): string
$script = sprintf(
'<script %s id="htmxToolbarScript">%s</script>',
csp_script_nonce(),
file_get_contents(__DIR__ . '/toolbar_decorator.js')
file_get_contents(__DIR__ . '/toolbar_decorator.js'),
);

$html = preg_replace(
'/<\/head>/',
$script . '</head>',
$html,
1
1,
);
}

21 changes: 18 additions & 3 deletions src/View/View.php
Original file line number Diff line number Diff line change
@@ -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;
10 changes: 5 additions & 5 deletions tests/HTTP/ResponseTest.php
Original file line number Diff line number Diff line change
@@ -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'),
);
}

34 changes: 16 additions & 18 deletions tests/View/ViewTest.php
Original file line number Diff line number Diff line change
@@ -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', []);