Skip to content

Conversation

@LukeTowers
Copy link
Member

@LukeTowers LukeTowers commented Jun 12, 2025

All tests passing. Requires wintercms/storm#207. Replaces #1094

Remaining Tasks:

Breaking changes:

  • PHP 8.5 adds native array_first() and array_last() functions that do not match the signature provided by Winter's helper functions. If you are currently using either function in your code with two or three arguments (filter & default) you will need to switch to \Winter\Storm\Support\Arr::first() or \Winter\Storm\Support\Arr:last() instead.
  • The -s short flag for the --silent option on mix:compile, mix:create, mix:install, mix:watch, npm:install, npm:run, npm:update, npm:version, vite:compile, vite:create, vite:install, vite:watch has been removed as Symfony v7.2 added the --silent option to all commands by default which conflicted with our definition. You must use the full option --silent going forward.
  • static $defaultName in Console commands to support lazy loading is no longer used in Symfony\Console 7.2, use the AsCommand class attribute instead. We will need to update all first party plugins & modules to make use of that.
  • [ ]

Currently incompatible plugins:

All other Winter plugins have been tested and confirmed compatible (some with minor tweaks to their PHPUnit configs to remove deprecation warnings.

New Minimum Requirements:

  • PHP 8.2+
  • Composer 2.2+
  • curl 7.34.0+
  • SQLite 3.26.0+
  • PHPUnit 11.0 (when using the testing functionality)

Backwards Compatibility Fixes:

Upgrade Guides:

Summary by CodeRabbit

  • New Features

    • Support for multiple previous app encryption keys (key rotation).
    • Optional rehash-on-login setting for passwords.
  • Bug Fixes

    • SQLite minimum-version validation during updates to avoid incompatible migrations.
  • CLI Changes

    • Silent mode flags removed from asset/npm/vite commands; commands now show output.
    • Test runner options refined for targeted module/plugin runs.
  • Chores

    • Minimum PHP requirement raised to 8.2 and core framework upgraded.
  • Tests

    • PHPUnit and test infra modernized (schema, attributes, caching).

✏️ Tip: You can customize this high-level summary in your review settings.

wverhoogt and others added 30 commits April 3, 2024 09:45
Co-authored-by: Wim Verhoogt <[email protected]>
LukeTowers and others added 11 commits July 23, 2025 21:48
symfony/symfony#53632 made it so that the --silent option is now provided & managed by the symfony core itself which would have been all well and good, except for the fact that since symfony/symfony#24425 symfony has been persisting the selected verbosity layer in the environment. This means that if you have a test that calls a command with the --silent flag set, and then it's followed by a test that relies on the --silent flag not being set, that second test (and any future test that expects the --silent flag not to be set) will also fail.

This leads to all sorts of headaches around tests failing depending on the order they are run in, whether or not you're running a single test case or multiple, or even whether the environment you're running the tests in actually supports putenv().

Massive credit to @jaxwilko for finding the issue and coming up with the solution.
Laravel 12 changed the way that dependencies are injected. See https://laravel.com/docs/12.x/upgrade#container-class-dependency-resolution, laravel/framework#53522 (originally rejected in laravel/framework#33955).

Default values are now preferred over resolvable typehints.
@mjauvin
Copy link
Member

mjauvin commented Jul 26, 2025

Tests passing! 🎉

@LukeTowers LukeTowers marked this pull request as ready for review July 27, 2025 14:39
@coderabbitai
Copy link

coderabbitai bot commented Oct 15, 2025

Walkthrough

Raise PHP/Laravel requirements, modernize CI and PHPUnit configs, remove many CLI --silent options, add an SQLite minimum-version check in UpdateManager::update, update test bootstrapping and many tests for newer PHPUnit/Laravel facades/attributes, and apply assorted import/signature and minor fixture/.gitignore changes.

Changes

Cohort / File(s) Summary of changes
CI workflows
​.github/workflows/manifest.yml, ​.github/workflows/tests.yml
Replace env/template indirection with explicit PHP versions/extensions and GITHUB_TOKEN; pin actions (actions/checkout@v4); adjust PHP matrix to 8.2–8.4; remove several cache steps and legacy steps; update workflow targets and settings.
Platform & dependencies
composer.json, modules/*/composer.json (modules/backend/..., modules/cms/..., modules/system/...)
Bump PHP constraint to ^8.2, Laravel to ^12.0, align Winter deps to dev-wip/1.3, upgrade PHPUnit/dev deps to PHPUnit 11, add VCS repo for phpunit-arraysubset-asserts, remove minimum-stability.
PHPUnit configs & stubs
phpunit.xml, modules/*/phpunit.xml, modules/system/console/scaffold/test/phpunit.stub
Migrate to PHPUnit 10.5 schema (xsi:noNamespaceSchemaLocation), add cacheDirectory, rename backupStaticAttributes→backupStaticProperties, remove convert* flags, simplify/bootstrap/formatting.
App / hashing config
config/app.php, config/hashing.php
Add previous_keys config parsed from APP_PREVIOUS_KEYS, cast debug to (bool), add rehash_on_login => false in hashing config.
Backend updates & tests
modules/backend/controllers/Index.php, modules/backend/tests/*
Replace array_first with Arr::first, adjust imports, call parent::tearDown() after instance cleanup, and refactor WidgetMaker test to use an anonymous class with Controller property/constructor.
CMS module & tests
modules/cms/classes/ComponentManager.php, modules/cms/tests/*
Rework imports/namespaces, swap to Winter/Illuminate facades, convert docblock @depends to PHPUnit attributes, replace Request mock with anonymous Request subclass, and adjust Cache usage.
Remove silent CLI options (Mix/NPM/Vite)
modules/system/console/asset/mix/*, modules/system/console/asset/npm/*, modules/system/console/asset/vite/*
Remove `{--s
Update flow guard
modules/system/classes/UpdateManager.php
Add SQLite runtime guard: when using sqlite driver, verify server version ≥ 3.35 and throw an exception if older before proceeding with updates/migrations.
Console/Test runner changes
modules/system/console/WinterTest.php, modules/system/tests/bootstrap/*
Update WinterTest signature and skip/target handling; delegate createApplication to parent; bind Kernel to suppress shell verbosity; add new assertion helper and remove deprecated compatibility shims.
System tests modernizations
modules/system/tests/... (many files; see diff)
Switch tests to Winter/Laravel facades (DB/Log/File/Schema), convert dataProviders/depends to PHPUnit attributes (make providers static), add parent::tearDown() calls, reposition node_modules skip checks, and update migration test assertions to SchemaBuilder-based checks.
Fixtures & minor files
modules/system/tests/fixtures/.../Comments.php, .gitignore
Reorder Comments constructor parameters to require Users $users first and make CodeBase nullable second; add .phpunit.cache and *.code-workspace to .gitignore.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Admin as Admin/CLI
  participant UM as UpdateManager
  participant DB as Database Connection

  Admin->>UM: update()
  UM->>DB: getDriverName()
  alt driver == sqlite
    UM->>DB: getServerVersion()
    UM->>UM: compare >= 3.35
    alt version < 3.35
      UM-->>Admin: throw Exception (SQLite too old)
    else version OK
      UM->>UM: continue update/migrations
    end
  else other driver
    UM->>UM: continue update/migrations
  end
  UM-->>Admin: result or exception
Loading
sequenceDiagram
  autonumber
  actor Dev as Developer/CLI
  participant WT as WinterTest Command

  Dev->>WT: winter:test --configuration=... --module=... --plugin=...
  WT->>WT: build types map (modules, plugins) and counts
  WT->>WT: skip processing for empty targets
  loop each non-empty type
    WT->>WT: run tests for specified items
  end
  WT-->>Dev: aggregated results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Potential review focus areas:

  • PHPUnit config/schema migration and broad test attribute/provider conversions.
  • UpdateManager SQLite version check (correct exception class/message, unit tests).
  • Removal of --silent options where code still references the option (ensure no unexpected empty args or output changes).
  • Composer constraint bumps across root and modules (dependency resolution and compatibility).
  • CreateMigrationTest changes (SchemaBuilder assertions and type/index expectations).

Poem

A rabbit nudges the repo bright,
Bumps PHP, tunes CI overnight.
Silent flags hop far away,
Tests don attributes to play.
SQLite checked — the meadow’s right. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Support Laravel 12' directly and clearly describes the main objective of this pull request, which is to upgrade the codebase to support Laravel 12.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch wip/1.3

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63f2a3e and 58057d0.

📒 Files selected for processing (1)
  • modules/system/console/WinterTest.php (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • modules/system/console/WinterTest.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: windows-latest / PHP 8.3
  • GitHub Check: windows-latest / PHP 8.4
  • GitHub Check: ubuntu-latest / PHP 8.3
  • GitHub Check: windows-latest / PHP 8.2
  • GitHub Check: ubuntu-latest / PHP 8.4
  • GitHub Check: ubuntu-latest / PHP 8.2
  • GitHub Check: windows-latest / JavaScript

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (5)
.gitignore (1)

13-13: Deduplicate .phpunit.cache ignore entry

.phpunit.cache appears twice (Lines 13 and 35). Keep one under the PHPUnit section and remove the other.

Apply this diff to remove the duplicate in the "Other ignores" section:

- .phpunit.cache

Also applies to: 35-35

modules/system/tests/console/CreateMigrationTest.php (1)

68-72: Add a guard for missing columns to avoid null dereference

Fail fast with a clear message if a column isn’t found before accessing its fields.

-            $column = $tableColumns->where('name', $name)->first();
-
-            $this->assertEquals(array_get($definition, 'type'), $column['type_name']);
-            $this->assertEquals(array_get($definition, 'required', false), !$column['nullable']);
+            $column = $tableColumns->where('name', $name)->first();
+            $this->assertNotNull($column, "Column '{$name}' not found in table {$this->table}");
+
+            $this->assertEquals(array_get($definition, 'type'), $column['type_name']);
+            $this->assertEquals(array_get($definition, 'required', false), !$column['nullable']);
phpunit.xml (2)

6-6: Align schema with PHPUnit 11 (and across module configs).

Repo now targets PHPUnit 11; using the 10.5 XSD may be suboptimal. Please verify and update to the 11.x schema URL (and keep module phpunit.xml files consistent).

Would you confirm the exact PHPUnit 11 minor used and align the XSD accordingly?


21-33: Exclude test directories from coverage to avoid skewed metrics.

Current includes all of modules/, which will also count test files. Exclude modules/**/tests to keep coverage focused on source.

Apply this addition to the block:

       <file>./modules/system/routes.php</file>
+      <directory suffix=".php">./modules/backend/tests</directory>
+      <directory suffix=".php">./modules/cms/tests</directory>
+      <directory suffix=".php">./modules/system/tests</directory>
modules/cms/tests/classes/ControllerTest.php (1)

303-329: Prefer Request::create + headers over subclassing; also ensure swap is restored.

Subclassing Request works here, but:

  • Code calling getMethod()/isMethod() would bypass your overridden method().
  • Swapping the global Request without restoring can leak state between tests.

Refactor to construct a real POST with headers and restore the original in each test.

Proposed replacement for configAjaxRequestMock:

-    protected function configAjaxRequestMock($handler, $partials = false)
-    {
-        return new class($handler, $partials) extends \Illuminate\Http\Request {
-            protected $handler;
-            protected $partials;
-            public function __construct($handler, $partials)
-            {
-                $this->handler = $handler;
-                $this->partials = $partials;
-                parent::__construct();
-            }
-            public function ajax() { return true; }
-            public function method() { return 'POST'; }
-            public function header($key = null, $default = null)
-            {
-                return match ($key) {
-                    'X_WINTER_REQUEST_HANDLER'  => $this->handler,
-                    'X_WINTER_REQUEST_PARTIALS' => $this->partials,
-                    default => $default,
-                };
-            }
-        };
-    }
+    protected function configAjaxRequestMock($handler, $partials = '')
+    {
+        $request = \Illuminate\Http\Request::create('/', 'POST');
+        $request->headers->set('X_WINTER_REQUEST_HANDLER', $handler);
+        if ($partials !== '' && $partials !== false) {
+            $request->headers->set('X_WINTER_REQUEST_PARTIALS', $partials);
+        }
+        // Force ajax() true
+        $request->headers->set('X-Requested-With', 'XMLHttpRequest');
+        return $request;
+    }

And in tests using Request::swap(...), wrap with restore:

$original = app('request');
try {
    Request::swap($this->configAjaxRequestMock('onTest', 'ajax-result'));
    // ... run assertions ...
} finally {
    Request::swap($original);
}

Please verify no tests rely on the swapped Request persisting between tests.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a410951 and 83ff1cb.

📒 Files selected for processing (50)
  • .github/workflows/manifest.yml (1 hunks)
  • .github/workflows/tests.yml (3 hunks)
  • .gitignore (2 hunks)
  • composer.json (1 hunks)
  • config/app.php (4 hunks)
  • config/hashing.php (1 hunks)
  • modules/backend/composer.json (1 hunks)
  • modules/backend/controllers/Index.php (2 hunks)
  • modules/backend/phpunit.xml (1 hunks)
  • modules/backend/tests/classes/AuthManagerTest.php (2 hunks)
  • modules/backend/tests/traits/WidgetMakerTest.php (2 hunks)
  • modules/cms/classes/ComponentManager.php (1 hunks)
  • modules/cms/composer.json (1 hunks)
  • modules/cms/phpunit.xml (1 hunks)
  • modules/cms/tests/classes/CmsObjectTest.php (4 hunks)
  • modules/cms/tests/classes/ControllerTest.php (3 hunks)
  • modules/system/classes/UpdateManager.php (1 hunks)
  • modules/system/composer.json (1 hunks)
  • modules/system/console/WinterTest.php (4 hunks)
  • modules/system/console/asset/mix/MixCompile.php (0 hunks)
  • modules/system/console/asset/mix/MixCreate.php (0 hunks)
  • modules/system/console/asset/mix/MixInstall.php (0 hunks)
  • modules/system/console/asset/mix/MixWatch.php (0 hunks)
  • modules/system/console/asset/npm/NpmInstall.php (0 hunks)
  • modules/system/console/asset/npm/NpmRun.php (0 hunks)
  • modules/system/console/asset/npm/NpmUpdate.php (0 hunks)
  • modules/system/console/asset/npm/NpmVersion.php (0 hunks)
  • modules/system/console/asset/vite/ViteCompile.php (0 hunks)
  • modules/system/console/asset/vite/ViteCreate.php (0 hunks)
  • modules/system/console/asset/vite/ViteInstall.php (0 hunks)
  • modules/system/console/asset/vite/ViteWatch.php (0 hunks)
  • modules/system/console/scaffold/test/phpunit.stub (1 hunks)
  • modules/system/phpunit.xml (1 hunks)
  • modules/system/tests/ServiceProviderTest.php (2 hunks)
  • modules/system/tests/bootstrap/PluginTestCase.php (1 hunks)
  • modules/system/tests/bootstrap/TestCase.php (3 hunks)
  • modules/system/tests/classes/MediaLibraryTest.php (4 hunks)
  • modules/system/tests/classes/SourceManifestTest.php (2 hunks)
  • modules/system/tests/classes/VersionManagerTest.php (3 hunks)
  • modules/system/tests/console/CreateCommandTest.php (1 hunks)
  • modules/system/tests/console/CreateMigrationTest.php (2 hunks)
  • modules/system/tests/console/WinterUtilTest.php (1 hunks)
  • modules/system/tests/console/asset/mix/MixCreateTest.php (1 hunks)
  • modules/system/tests/console/asset/mix/MixInstallTest.php (1 hunks)
  • modules/system/tests/console/asset/npm/NpmInstallTest.php (1 hunks)
  • modules/system/tests/console/asset/npm/NpmUpdateTest.php (1 hunks)
  • modules/system/tests/console/asset/vite/ViteCreateTest.php (1 hunks)
  • modules/system/tests/console/asset/vite/ViteInstallTest.php (1 hunks)
  • modules/system/tests/fixtures/plugins/winter/tester/components/Comments.php (1 hunks)
  • phpunit.xml (1 hunks)
💤 Files with no reviewable changes (12)
  • modules/system/console/asset/npm/NpmUpdate.php
  • modules/system/console/asset/vite/ViteWatch.php
  • modules/system/console/asset/mix/MixCompile.php
  • modules/system/console/asset/mix/MixCreate.php
  • modules/system/console/asset/mix/MixInstall.php
  • modules/system/console/asset/mix/MixWatch.php
  • modules/system/console/asset/npm/NpmInstall.php
  • modules/system/console/asset/vite/ViteInstall.php
  • modules/system/console/asset/npm/NpmRun.php
  • modules/system/console/asset/npm/NpmVersion.php
  • modules/system/console/asset/vite/ViteCompile.php
  • modules/system/console/asset/vite/ViteCreate.php
🧰 Additional context used
🧬 Code graph analysis (16)
modules/system/tests/console/asset/mix/MixCreateTest.php (4)
modules/system/tests/console/asset/mix/MixInstallTest.php (1)
  • tearDown (201-212)
modules/system/tests/console/CreateCommandTest.php (1)
  • tearDown (36-42)
modules/system/tests/console/asset/vite/ViteCreateTest.php (1)
  • tearDown (217-235)
modules/system/tests/console/asset/mix/MixCompileTest.php (1)
  • tearDown (93-99)
modules/system/tests/console/WinterUtilTest.php (3)
modules/system/tests/console/asset/mix/MixInstallTest.php (1)
  • tearDown (201-212)
modules/system/tests/console/CreateCommandTest.php (1)
  • tearDown (36-42)
modules/system/tests/classes/SourceManifestTest.php (1)
  • tearDown (52-57)
modules/system/tests/console/CreateCommandTest.php (1)
modules/system/models/File.php (1)
  • File (15-98)
modules/system/tests/ServiceProviderTest.php (1)
modules/system/tests/bootstrap/PluginTestCase.php (1)
  • PluginTestCase (26-254)
modules/backend/tests/classes/AuthManagerTest.php (1)
modules/backend/classes/AuthManager.php (1)
  • AuthManager (14-289)
modules/system/tests/bootstrap/PluginTestCase.php (1)
modules/system/tests/bootstrap/TestCase.php (1)
  • createApplication (18-54)
modules/system/tests/classes/VersionManagerTest.php (1)
modules/system/tests/classes/MediaLibraryTest.php (2)
  • DataProvider (65-70)
  • DataProvider (72-77)
modules/system/tests/console/asset/vite/ViteCreateTest.php (9)
modules/system/tests/console/asset/mix/MixInstallTest.php (1)
  • tearDown (201-212)
modules/system/tests/console/asset/npm/NpmInstallTest.php (1)
  • tearDown (195-208)
modules/system/tests/console/asset/npm/NpmUpdateTest.php (1)
  • tearDown (90-103)
modules/system/tests/console/asset/vite/ViteInstallTest.php (1)
  • tearDown (212-223)
modules/system/tests/console/WinterUtilTest.php (1)
  • tearDown (80-99)
modules/system/tests/console/asset/mix/MixCreateTest.php (1)
  • tearDown (217-235)
modules/system/tests/classes/SourceManifestTest.php (1)
  • tearDown (52-57)
modules/system/tests/console/asset/mix/MixCompileTest.php (1)
  • tearDown (93-99)
modules/system/tests/console/asset/vite/ViteCompileTest.php (1)
  • tearDown (113-117)
modules/system/tests/console/asset/vite/ViteInstallTest.php (3)
modules/system/tests/console/asset/mix/MixInstallTest.php (1)
  • setUp (17-42)
modules/system/tests/console/asset/npm/NpmRunTest.php (1)
  • setUp (11-25)
modules/system/tests/console/asset/vite/ViteCompileTest.php (1)
  • setUp (13-33)
modules/system/tests/fixtures/plugins/winter/tester/components/Comments.php (1)
modules/cms/classes/CodeBase.php (1)
  • CodeBase (12-168)
modules/system/tests/classes/SourceManifestTest.php (3)
modules/system/tests/console/asset/mix/MixInstallTest.php (1)
  • tearDown (201-212)
modules/system/tests/console/asset/npm/NpmInstallTest.php (1)
  • tearDown (195-208)
modules/system/tests/console/WinterUtilTest.php (1)
  • tearDown (80-99)
modules/system/tests/classes/MediaLibraryTest.php (2)
modules/system/tests/classes/VersionManagerTest.php (1)
  • DataProvider (142-153)
modules/system/classes/MediaLibrary.php (1)
  • MediaLibrary (24-837)
modules/cms/tests/classes/ControllerTest.php (3)
modules/cms/facades/Cms.php (1)
  • Cms (10-21)
modules/cms/classes/Theme.php (1)
  • Theme (32-716)
modules/system/tests/bootstrap/TestCase.php (1)
  • TestCase (11-110)
modules/cms/classes/ComponentManager.php (1)
modules/system/classes/PluginManager.php (1)
  • PluginManager (30-1089)
modules/backend/controllers/Index.php (2)
modules/backend/facades/BackendMenu.php (1)
  • BackendMenu (30-41)
modules/backend/classes/NavigationManager.php (1)
  • listMainMenuItems (409-448)
modules/system/tests/console/CreateMigrationTest.php (1)
modules/system/tests/bootstrap/PluginTestCase.php (1)
  • PluginTestCase (26-254)
🪛 actionlint (1.7.8)
.github/workflows/tests.yml

36-36: the runner of "actions/setup-node@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: windows-latest / PHP 8.3
  • GitHub Check: windows-latest / PHP 8.2
  • GitHub Check: windows-latest / PHP 8.4
🔇 Additional comments (59)
.gitignore (1)

30-30: LGTM: add VS Code workspace ignore

*.code-workspace is a sensible addition.

modules/system/tests/console/CreateCommandTest.php (1)

6-6: LGTM! Proper facade namespace for Laravel 12.

The change correctly updates the File reference to use the Winter Storm facade, and the static method usage in tearDown() is appropriate for facade calls.

modules/cms/classes/ComponentManager.php (1)

1-8: LGTM! Import standardization improves clarity.

The updated imports now use fully qualified namespaces (Winter\Storm\Exception\SystemException, Winter\Storm\Support\Str) instead of short aliases, making dependencies explicit and improving code maintainability. All imported classes are properly used throughout the file:

  • PluginManager at line 61
  • SystemException at lines 109, 206
  • Str at lines 105, 115, 167, 234
modules/system/tests/console/asset/npm/NpmInstallTest.php (1)

29-31: LGTM! Ensures properties are initialized before potential skip.

Moving the node_modules check after path initialization prevents undefined typed property errors in tearDown() if the test is skipped.

modules/system/tests/console/asset/npm/NpmUpdateTest.php (1)

29-31: LGTM! Consistent with the pattern applied across npm tests.

Ensures properties are initialized before the skip check, preventing errors in tearDown().

modules/system/tests/console/asset/mix/MixInstallTest.php (1)

27-29: LGTM! Aligns with the updated test setup pattern.

Properties are now initialized before the skip check, ensuring tearDown() can safely access them.

modules/backend/tests/classes/AuthManagerTest.php (2)

5-5: LGTM!

The import statement is correctly added and necessary for the AuthManager class usage throughout the test file.


44-48: LGTM! Proper teardown sequence.

The order is correct: forgetting the singleton instance before calling parent::tearDown() ensures test-specific state is cleaned up before the parent's application context teardown, preventing potential issues with the instance accessing a destroyed context.

modules/system/tests/fixtures/plugins/winter/tester/components/Comments.php (1)

11-15: Constructor change verified as safe and correct—no instantiation sites affected.

The Comments component's constructor correctly accepts the Users dependency and properly calls parent::__construct($cmsObject, $properties), which matches the ComponentBase signature. Verification of the codebase found no direct instantiations or container resolutions of this component, confirming the change introduces no breaking changes to actual code usage. The component is registered in the test plugin but appears unused in current tests, making this a safe refactoring.

modules/system/classes/UpdateManager.php (1)

138-143: Fix exception type and remove unconventional semicolon; verify SQLite version requirement.

ApplicationException is already imported and consistently used throughout this file for similar errors. Replace the plain Exception at line 141, remove the semicolon after the closing brace at line 143, and add the detected version to the error message for better debugging:

             $connection = Schema::getConnection();
             if ($connection->getDriverName() === 'sqlite') {
-                if (version_compare($connection->getServerVersion(), '3.35', '<')) {
-                    throw new Exception("SQLite version minimum requirement not met (>= 3.35)");
+                $version = $connection->getServerVersion();
+                if (version_compare($version, '3.35', '<')) {
+                    throw new ApplicationException(
+                        "SQLite version {$version} does not meet the minimum requirement (>= 3.35)"
+                    );
                 }
-            };
+            }

However, verify that 3.35 is the correct minimum version. The PR description or related documentation should confirm whether the requirement is 3.26.0 or 3.35—adjust the version number in the code and error message accordingly.

modules/system/console/WinterTest.php (3)

12-12: LGTM!

The Config facade import is correctly added and used later in the file (line 250).


37-42: LGTM!

The command signature updates are syntactically correct. The = and =* syntax properly defines options that require values when provided and accept multiple values, respectively.


107-109: LGTM!

The empty target guard is a good defensive measure that prevents processing empty strings and avoids potential downstream issues.

modules/system/tests/console/CreateMigrationTest.php (2)

62-66: LGTM: Move to SchemaBuilder for introspection

Using getColumns/getIndexes and hasIndex on the schema builder is a solid replacement for Doctrine.


38-58: LGTM: Updated expected types align with platform mappings

tinyint for booleans, double precision, and varchar expectations look consistent with the builder’s normalized types.

modules/system/composer.json (1)

26-28: LGTM! Version constraints updated correctly.

The PHP and Laravel framework constraints have been appropriately updated to align with the PR's minimum requirements (PHP 8.2+ and Laravel 12).

modules/system/tests/console/asset/vite/ViteCreateTest.php (1)

233-234: LGTM! Proper tearDown sequence established.

Adding parent::tearDown() ensures the base class cleanup logic executes after removing test artifacts, following PHPUnit best practices. This change is consistent with similar improvements across other test files in this PR.

modules/cms/composer.json (1)

26-28: LGTM! Version constraints updated correctly.

The PHP and Laravel framework constraints have been appropriately updated to align with the PR's minimum requirements (PHP 8.2+ and Laravel 12).

modules/backend/composer.json (1)

26-28: LGTM! Version constraints updated correctly.

The PHP and Laravel framework constraints have been appropriately updated to align with the PR's minimum requirements (PHP 8.2+ and Laravel 12).

modules/backend/controllers/Index.php (1)

9-9: LGTM! Correctly addresses PHP 8.5 compatibility.

The change from array_first() to Arr::first() prevents conflicts with PHP 8.5's native array_first() function, which has a different signature than Winter's helper. Using the explicit class method ensures forward compatibility.

Based on PR objectives.

Also applies to: 77-77

modules/system/tests/console/asset/mix/MixCreateTest.php (1)

233-234: LGTM! Proper tearDown sequence established.

Adding parent::tearDown() ensures the base class cleanup logic executes after removing test artifacts, following PHPUnit best practices. This change is consistent with similar improvements across other test files in this PR.

modules/system/tests/console/WinterUtilTest.php (1)

97-98: LGTM! Proper tearDown sequence established.

Adding parent::tearDown() ensures the base class cleanup logic executes after all test-specific cleanup operations, following PHPUnit best practices. This change is consistent with similar improvements across other test files in this PR.

config/hashing.php (1)

52-63: LGTM! Laravel 11 password rehashing configuration added.

The rehash_on_login option has been added to support Laravel 11's automatic password rehashing feature. Setting it to false by default is appropriate, making this feature opt-in to avoid unexpected behavior changes during the framework upgrade.

modules/system/console/scaffold/test/phpunit.stub (1)

2-4: LGTM! PHPUnit configuration modernized correctly.

The removal of legacy PHPUnit attributes (backupGlobals, backupStaticAttributes, convertErrorsToExceptions, etc.) is appropriate for PHPUnit 10/11 compatibility. The essential bootstrap and colors attributes are retained.

.github/workflows/manifest.yml (2)

18-18: Verify the token change.

The environment variable changed from potentially using phpVersion, extensions, and key to using GITHUB_TOKEN (mapped from COMPOSER_GITHUB_TOKEN). Ensure that COMPOSER_GITHUB_TOKEN secret exists and has appropriate permissions for the manifest update workflow.


26-27: LGTM! Explicit version configuration improves clarity.

Hardcoding PHP version 8.4 and the extension list makes the workflow more explicit and easier to maintain compared to environment variables. The extension list is comprehensive for Winter CMS requirements.

modules/system/tests/classes/SourceManifestTest.php (2)

5-6: LGTM! Import organization improved.

Moving the imports earlier in the file improves code organization.


56-56: Essential: parent::tearDown() call added.

Adding the parent::tearDown() call is critical for PHPUnit 10+ compatibility. This ensures the parent class's cleanup logic executes properly, preventing potential test pollution or resource leaks.

modules/system/tests/console/asset/vite/ViteInstallTest.php (2)

15-15: Good: Property declaration added.

Explicitly declaring the $fixturePath property improves type safety and aligns with PHP 8.2+ best practices.


27-29: LGTM! Proper initialization order.

Moving the node_modules existence check to occur after fixturePath is initialized prevents potential issues with accessing an uninitialized property. This matches the pattern used in similar test classes like MixInstallTest.

modules/system/tests/classes/VersionManagerTest.php (3)

5-5: LGTM! DataProvider attribute imported.

Adding the DataProvider attribute import is required for PHPUnit 10+ attribute-based data provider syntax.


142-142: LGTM! Modern attribute syntax adopted.

Replacing the @dataProvider docblock with the #[DataProvider] attribute is the correct approach for PHPUnit 10+.


155-155: Required: Data provider method is now static.

PHPUnit 10+ requires data provider methods to be static. This change is mandatory for compatibility.

modules/backend/phpunit.xml (2)

2-9: LGTM! PHPUnit configuration modernized for version 10/11.

The changes correctly update the configuration:

  • Added XML schema namespace and reference for PHPUnit 10.5
  • Renamed backupStaticAttributes to backupStaticProperties (PHPUnit 10+ naming)
  • Added cacheDirectory for improved test caching
  • Removed deprecated conversion attributes

11-15: LGTM! Formatting standardized.

The testsuite block formatting is consistent with other PHPUnit configuration files in the codebase.

modules/backend/tests/traits/WidgetMakerTest.php (2)

12-17: LGTM! Property and constructor added for trait testing.

Adding the $controller property and constructor properly initializes the dependency required by the WidgetMaker trait. This improves the test fixture setup.


40-42: Required: Anonymous class replaces deprecated getObjectForTrait.

PHPUnit 10 removed the getObjectForTrait() method. Using an anonymous class with the trait is the correct modern approach for testing traits.

composer.json (5)

32-32: LGTM! PHP 8.2 required for Laravel 12.

Bumping the PHP requirement to ^8.2 is necessary for Laravel 12 compatibility and aligns with the PR objectives.


33-36: LGTM! Winter dependencies updated to 1.3 branch.

Switching Winter ecosystem dependencies from dev-develop to dev-wip/1.3 aligns with the PR's goal of supporting Laravel 12 in the 1.3 release branch.


37-37: LGTM! Laravel 12 framework adopted.

Upgrading from Laravel ^9.1 to ^12.0 is the core objective of this PR.


41-41: LGTM! PHPUnit 11 required.

Upgrading PHPUnit from ^9.5.8 to ^11.0 is necessary for PHP 8.2+ support and includes breaking changes addressed throughout the test suite.


46-53: Verify forked PHPUnit Arraysubset-Asserts dependency
File composer.json (lines 46–53)
• Confirm the add-phpunit-11-support branch in pieterocp/phpunit-arraysubset-asserts has recent commits and ongoing maintenance
• If it’s stale, switch to an official PHPUnit 11-compatible package or merge upstream fixes to avoid relying on an unmaintained fork

config/app.php (1)

5-29: Documentation updates look good.

The updated comments improve clarity and align with Laravel 12 conventions.

.github/workflows/tests.yml (3)

10-12: LGTM: Concurrency control properly configured.

The concurrency configuration will cancel in-progress test runs when new commits are pushed, which improves CI efficiency and aligns with the previous review suggestion.


27-27: LGTM: Checkout action updated to latest version.

Using actions/checkout@v4 is appropriate and ensures compatibility with current GitHub Actions infrastructure.

Also applies to: 77-77


69-69: LGTM: PHP version matrix updated for Laravel 12.

The matrix now includes PHP 8.2, 8.3, and 8.4, which aligns with the Laravel 12 and PHP 8.2+ requirements mentioned in the PR objectives.

modules/system/phpunit.xml (1)

2-9: LGTM: PHPUnit configuration updated for PHPUnit 10.5+.

The configuration changes are correct for PHPUnit 10/11 compatibility:

  • Added XML schema namespace and location
  • Replaced deprecated backupStaticAttributes with backupStaticProperties
  • Added cacheDirectory for improved test performance
  • Removed deprecated convertErrorsToExceptions, convertNoticesToExceptions, and convertWarningsToExceptions flags

These changes align with PHPUnit 10/11 requirements mentioned in the PR objectives.

modules/system/tests/classes/MediaLibraryTest.php (3)

7-7: LGTM: DataProvider attribute imported.

Adding the import for PHPUnit\Framework\Attributes\DataProvider is necessary for using the attribute-based data provider syntax in PHPUnit 10+.


24-38: LGTM: Data providers converted to static methods.

Converting invalidPathsProvider and validPathsProvider to static methods is required when using the #[DataProvider] attribute in PHPUnit 10+. The data itself remains unchanged and correct.

Also applies to: 40-63


65-65: LGTM: Data provider annotations migrated to attributes.

Replacing docblock @dataProvider annotations with #[DataProvider] attributes is the correct approach for PHPUnit 10+ and aligns with the broader PHPUnit modernization across the repository.

Also applies to: 72-72

modules/system/tests/bootstrap/PluginTestCase.php (1)

40-63: LGTM: Simplified by delegating to parent implementation.

The change to call parent::createApplication() is a good refactoring that reduces code duplication. The parent TestCase::createApplication() handles the common bootstrap logic (app initialization, cache driver, locale, encryption key, Kernel binding), while this method continues to handle plugin-specific setup (backend.auth singleton, database configuration, plugin path).

This aligns with the broader test infrastructure modernization in the Laravel 12 upgrade.

modules/system/tests/ServiceProviderTest.php (2)

5-7: LGTM: Explicit facade imports improve clarity.

Using explicit facade imports (Illuminate\Support\Facades\Log and Winter\Storm\Support\Facades\DB) rather than relying on global aliases is a good practice that improves code clarity and IDE support.


24-24: Verify the DB facade import and casing. Ensure that Winter\Storm\Support\Facades\DB exists and is correctly imported, and that no Db:: references remain in tests.

modules/cms/phpunit.xml (1)

2-9: LGTM: PHPUnit configuration updated for PHPUnit 10.5+.

The configuration changes mirror those in modules/system/phpunit.xml and are correct for PHPUnit 10/11 compatibility. The changes maintain consistency across module test configurations.

modules/cms/tests/classes/CmsObjectTest.php (2)

8-8: LGTM: Depends attribute imported.

Adding the import for PHPUnit\Framework\Attributes\Depends is necessary for using the attribute-based test dependency syntax in PHPUnit 10+.


240-240: LGTM: Test dependencies migrated to attributes.

Replacing docblock @depends annotations with #[Depends] attributes is the correct approach for PHPUnit 10+ and maintains the same test execution order and dependency relationships.

Also applies to: 267-267, 288-288

modules/cms/tests/classes/ControllerTest.php (2)

6-12: Imports modernization looks good.

Using facades and the shared TestCase aligns with the new bootstrap.


83-83: Good switch to Cache facade.

Consistent with the rest of the test suite. No issues.

modules/system/tests/bootstrap/TestCase.php (1)

87-109: Assertion shims are correct for PHPUnit 10/11.

Good compatibility wrappers to replace deprecated methods.

*/

'name' => env('APP_NAME', 'Winter CMS'),
'debug' => (bool) env('APP_DEBUG', true),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the default debug value in production.

Casting to boolean is correct, but the default value is true. In production environments, this should typically default to false to avoid exposing sensitive information. Consider if the default should be false instead of true for security best practices.


🌐 Web query:

What is the recommended default value for APP_DEBUG in Laravel 12 production environments?

💡 Result:

Set APP_DEBUG to false in production — e.g. APP_DEBUG=false. [1][2]

Sources:
[1] Laravel 12.x Configuration (Debug Mode).
[2] Laravel config example: 'debug' => env('APP_DEBUG', false).


Default APP_DEBUG to false in production
In config/app.php (line 49), change to:

'debug' => (bool) env('APP_DEBUG', false),

to prevent exposing sensitive information.

🤖 Prompt for AI Agents
In config/app.php around line 49, the APP_DEBUG default is currently true which
can leak sensitive info in production; change the env default to false by
updating the 'debug' line to use env('APP_DEBUG', false) so the application
defaults to non-debug mode unless explicitly enabled via environment.

Comment on lines +30 to +52
// Override the Kernel call method to prevent symfony shell verbosity breaking scripts.
// @see: https://github.com/symfony/symfony/pull/53632
// @see: https://github.com/symfony/symfony/pull/24425
$app->bind(Kernel::class, function (Application $app) {
return new class($app, $app->make(Dispatcher::class)) extends \Winter\Storm\Foundation\Console\Kernel
{
public function call($command, array $parameters = [], $outputBuffer = null)
{
$result = parent::call($command, $parameters, $outputBuffer);

$shellVerbosity = 0;

if (\function_exists('putenv')) {
@putenv('SHELL_VERBOSITY=' . $shellVerbosity);
}

$_ENV['SHELL_VERBOSITY'] = $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;

return $result;
}
};
});

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Kernel override likely ineffective after initial resolve; ensure the new instance is used.

You resolve/boot the Kernel on Line 22, then bind a replacement. Because the Kernel singleton is already instantiated, later resolves return the original instance, so call() won’t be overridden.

Apply one of these fixes right after bootstrapping:

-        $app->bind(Kernel::class, function (Application $app) {
-            return new class($app, $app->make(Dispatcher::class)) extends \Winter\Storm\Foundation\Console\Kernel {
+        // Replace the existing Kernel instance so Artisan uses our override.
+        $app->forgetInstance(Kernel::class);
+        $app->forgetInstance('Illuminate\Contracts\Console\Kernel'); // alias safety
+        $app->instance(Kernel::class, new class($app, $app->make(Dispatcher::class)) extends \Winter\Storm\Foundation\Console\Kernel {
             public function call($command, array $parameters = [], $outputBuffer = null)
             {
                 $result = parent::call($command, $parameters, $outputBuffer);
                 $shellVerbosity = 0;
                 if (\function_exists('putenv')) {
                     @putenv('SHELL_VERBOSITY=' . $shellVerbosity);
                 }
                 $_ENV['SHELL_VERBOSITY'] = $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;
                 return $result;
             }
-            };
-        });
+        });

Optionally also set SHELL_VERBOSITY=0 once in createApplication to cover non-Artisan paths.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In modules/system/tests/bootstrap/TestCase.php around lines 30 to 52, the Kernel
override is bound after the Kernel has already been resolved so the running
Kernel instance won’t use the new call() implementation; to fix this either (a)
replace the existing resolved instance immediately after bootstrapping using
$app->forgetInstance(Kernel::class) and then bind the anonymous class, or (b)
directly register the new Kernel instance via $app->instance(Kernel::class, new
class($app, $app->make(Dispatcher::class)) extends
\Winter\Storm\Foundation\Console\Kernel { ... }), and additionally set
SHELL_VERBOSITY=0 once in createApplication (or immediately after bootstrapping)
to cover non-Artisan execution paths.

Comment on lines +80 to +81
if ($indexColumns = array_get($indexName, $tableIndexes)) {
$this->assertTrue(in_array($name, $indexColumns));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix reversed array_get arguments; index membership never validated

Args are flipped, so $indexColumns is always null and the check is skipped. Correct it to actually validate index columns.

-                if ($indexColumns = array_get($indexName, $tableIndexes)) {
-                    $this->assertTrue(in_array($name, $indexColumns));
+                if ($indexColumns = array_get($tableIndexes, $indexName)) {
+                    $this->assertTrue(in_array($name, $indexColumns, true));
                 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ($indexColumns = array_get($indexName, $tableIndexes)) {
$this->assertTrue(in_array($name, $indexColumns));
if ($indexColumns = array_get($tableIndexes, $indexName)) {
$this->assertTrue(in_array($name, $indexColumns, true));
}
🤖 Prompt for AI Agents
In modules/system/tests/console/CreateMigrationTest.php around lines 80-81, the
call to array_get has its arguments reversed so $indexColumns is always null and
the membership assertion is skipped; swap the arguments to read
array_get($tableIndexes, $indexName) (optionally provide a default) so
$indexColumns actually contains the index columns, then run the existing
in_array assertion against that result.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants