Skip to content

Support Laravel 12 - #1366

Open
LukeTowers wants to merge 71 commits into
developfrom
wip/1.3
Open

Support Laravel 12#1366
LukeTowers wants to merge 71 commits into
developfrom
wip/1.3

Conversation

@LukeTowers

@LukeTowers LukeTowers commented Jun 12, 2025

Copy link
Copy Markdown
Member

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
    • Added support for rotating encryption keys.
    • Added configurable application name, environment, locale, and password rehashing on login.
  • Bug Fixes
    • Updates now require SQLite 3.35 or newer to prevent incompatible migrations.
  • CLI Changes
    • Removed silent-mode options from asset, npm, and Vite commands.
    • Improved targeted test execution options.
  • Chores
    • Raised the minimum PHP version to 8.2 and upgraded the core framework.
  • Tests
    • Updated PHPUnit configuration and modernized test coverage.

wverhoogt and others added 30 commits April 3, 2024 09:45
Co-authored-by: Wim Verhoogt <wim@verbant.nl>
@LukeTowers
LukeTowers marked this pull request as ready for review July 27, 2025 14:39
@coderabbitai

coderabbitai Bot commented Oct 15, 2025

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The change raises PHP and Laravel requirements, modernizes CI and PHPUnit configuration, removes many CLI silent options, adds an SQLite minimum-version check, updates test bootstrapping and PHPUnit APIs, and applies namespace, fixture, configuration, and ignore-rule changes.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.42% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the pull request's primary change: adding Laravel 12 support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch wip/1.3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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.

Comment thread .github/workflows/tests.yml
Comment thread .github/workflows/tests.yml
Comment thread config/app.php
*/

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

Copy link
Copy Markdown

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 thread config/app.php
Comment thread modules/system/console/WinterTest.php
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
Copy Markdown

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
Copy Markdown

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.

@damsfx

damsfx commented Jan 14, 2026

Copy link
Copy Markdown
Contributor

@LukeTowers
Reminder for upgrade guide:
The cache key name has changed in Laravel 11 in order to remove magic prefixing in some cache drivers.

Example of difference for cache key name:

// Winter 1.2.x
acme_database_acme_cache:backend::brand.custom_css

// Winter 1.3.x
acme_database_acme_cachebackend::brand.custom_css

This may cause issues if the project shares the cache or session between projects under both versions of WinterCMS.

austinderrick added a commit to austinderrick/winter that referenced this pull request Jun 1, 2026
Builds on the Laravel 12 work (wintercms#1366). Bumps laravel/framework ^12 -> ^13
and PHP ^8.2 -> ^8.3 in the root and modules/{system,backend,cms}.

Points winter/storm and the three modules at the Laravel 13 branch
(dev-wip/1.3-laravel-13). Adds path repositories for the in-repo modules so
composer resolves the Laravel 13 module manifests locally (the published
split packages still pin Laravel 12), and a VCS repository for the Storm
Laravel 13 branch. CI matrices dropped to PHP 8.3/8.4. No module code
changes were required (all system/backend/cms suites pass on Laravel 13).
austinderrick added a commit to austinderrick/winter that referenced this pull request Jun 1, 2026
Builds on the Laravel 12 work (wintercms#1366). Bumps laravel/framework ^12 -> ^13
and PHP ^8.2 -> ^8.3 in the root and modules/{system,backend,cms}.

Points winter/storm and the three modules at the Laravel 13 branch
(dev-wip/1.3-laravel-13). Adds path repositories for the in-repo modules so
composer resolves the Laravel 13 module manifests locally (the published
split packages still pin Laravel 12), and a VCS repository for the Storm
Laravel 13 branch. CI matrices dropped to PHP 8.3/8.4. No module code
changes were required (all system/backend/cms suites pass on Laravel 13).
austinderrick added a commit to austinderrick/winter that referenced this pull request Jun 1, 2026
Builds on the Laravel 12 work (wintercms#1366). Bumps laravel/framework ^12 -> ^13
and PHP ^8.2 -> ^8.3 in the root and modules/{system,backend,cms}.

Points winter/storm and the three modules at the Laravel 13 branch
(dev-wip/1.3-laravel-13). Adds path repositories for the in-repo modules so
composer resolves the Laravel 13 module manifests locally (the published
split packages still pin Laravel 12), and a VCS repository for the Storm
Laravel 13 branch. CI matrices dropped to PHP 8.3/8.4. No module code
changes were required (all system/backend/cms suites pass on Laravel 13).
# Conflicts:
#	.github/workflows/tests.yml
#	.gitignore
#	modules/backend/controllers/Index.php
#	modules/system/tests/fixtures/plugins/winter/tester/components/Comments.php
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
.github/workflows/manifest.yml (1)

18-18: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Scope the Composer credential and use the supported setup-php input.

Line [18] exposes secrets.COMPOSER_GITHUB_TOKEN to every step in the job. GitHub job-level environment variables apply to all steps. (docs.github.com)

shivammathur/setup-php@v2 supports the github-token input and deprecates the GITHUB_TOKEN environment-variable authentication path. (github.com) Move the secret to that input, or use step-scoped COMPOSER_AUTH for Composer. Composer documents COMPOSER_AUTH for this purpose. (getcomposer.org)

Proposed fix
-    env:
-      GITHUB_TOKEN: ${{ secrets.COMPOSER_GITHUB_TOKEN }}
...
         with:
           php-version: 8.4
           extensions: curl, fileinfo, gd, mbstring, openssl, pdo, pdo_sqlite, sqlite3, xml, zip
+          github-token: ${{ secrets.COMPOSER_GITHUB_TOKEN }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/manifest.yml at line 18, Remove the job-level GITHUB_TOKEN
assignment in the manifest workflow and pass secrets.COMPOSER_GITHUB_TOKEN
through the setup-php step’s supported github-token input, or scope it to the
Composer step via COMPOSER_AUTH. Ensure the credential is unavailable to
unrelated job steps.

Source: MCP tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/tests.yml:
- Around line 26-27: Disable persistent checkout credentials in both checkout
steps: add persist-credentials: false to the frontend job checkout at
.github/workflows/tests.yml lines 26-27 and the PHPUnit job checkout at lines
76-77.

In `@modules/system/classes/UpdateManager.php`:
- Around line 138-143: Update the SQLite version threshold in the connection
check around Schema::getConnection() from 3.35 to 3.26.0, preserving rejection
below the Laravel 12 minimum and acceptance at or above it. Add boundary
coverage confirming 3.25.x is rejected and 3.26.0 is accepted.

---

Nitpick comments:
In @.github/workflows/manifest.yml:
- Line 18: Remove the job-level GITHUB_TOKEN assignment in the manifest workflow
and pass secrets.COMPOSER_GITHUB_TOKEN through the setup-php step’s supported
github-token input, or scope it to the Composer step via COMPOSER_AUTH. Ensure
the credential is unavailable to unrelated job steps.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ad802038-e21e-45bd-9383-89eba97ef876

📥 Commits

Reviewing files that changed from the base of the PR and between a56ef40 and 2056633.

📒 Files selected for processing (53)
  • .github/workflows/manifest.yml
  • .github/workflows/tests.yml
  • .gitignore
  • composer.json
  • config/app.php
  • config/hashing.php
  • modules/backend/composer.json
  • modules/backend/controllers/Index.php
  • modules/backend/phpunit.xml
  • modules/backend/tests/classes/AuthManagerTest.php
  • modules/backend/tests/classes/ControllerPostbackTest.php
  • modules/backend/tests/traits/WidgetMakerTest.php
  • modules/cms/classes/ComponentManager.php
  • modules/cms/composer.json
  • modules/cms/phpunit.xml
  • modules/cms/tests/classes/CmsObjectTest.php
  • modules/cms/tests/classes/ControllerPostbackTest.php
  • modules/cms/tests/classes/ControllerTest.php
  • modules/cms/tests/classes/ThemeTest.php
  • modules/system/classes/UpdateManager.php
  • modules/system/composer.json
  • modules/system/console/WinterTest.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/npm/NpmRun.php
  • modules/system/console/asset/npm/NpmUpdate.php
  • modules/system/console/asset/npm/NpmVersion.php
  • modules/system/console/asset/vite/ViteCompile.php
  • modules/system/console/asset/vite/ViteCreate.php
  • modules/system/console/asset/vite/ViteInstall.php
  • modules/system/console/asset/vite/ViteWatch.php
  • modules/system/console/scaffold/test/phpunit.stub
  • modules/system/phpunit.xml
  • modules/system/tests/ServiceProviderTest.php
  • modules/system/tests/bootstrap/PluginTestCase.php
  • modules/system/tests/bootstrap/TestCase.php
  • modules/system/tests/classes/MediaLibraryTest.php
  • modules/system/tests/classes/SourceManifestTest.php
  • modules/system/tests/classes/VersionManagerTest.php
  • modules/system/tests/console/CreateCommandTest.php
  • modules/system/tests/console/CreateMigrationTest.php
  • modules/system/tests/console/WinterUtilTest.php
  • modules/system/tests/console/asset/mix/MixCreateTest.php
  • modules/system/tests/console/asset/mix/MixInstallTest.php
  • modules/system/tests/console/asset/npm/NpmInstallTest.php
  • modules/system/tests/console/asset/npm/NpmUpdateTest.php
  • modules/system/tests/console/asset/vite/ViteCreateTest.php
  • modules/system/tests/console/asset/vite/ViteInstallTest.php
  • modules/system/tests/fixtures/plugins/winter/tester/components/Comments.php
  • phpunit.xml
💤 Files with no reviewable changes (12)
  • modules/system/console/asset/mix/MixWatch.php
  • modules/system/console/asset/mix/MixCompile.php
  • modules/system/console/asset/mix/MixCreate.php
  • modules/system/console/asset/npm/NpmInstall.php
  • modules/system/console/asset/vite/ViteCompile.php
  • modules/system/console/asset/vite/ViteWatch.php
  • modules/system/console/asset/mix/MixInstall.php
  • modules/system/console/asset/npm/NpmUpdate.php
  • modules/system/console/asset/vite/ViteCreate.php
  • modules/system/console/asset/npm/NpmVersion.php
  • modules/system/console/asset/npm/NpmRun.php
  • modules/system/console/asset/vite/ViteInstall.php
🚧 Files skipped from review as they are similar to previous changes (30)
  • modules/system/tests/classes/VersionManagerTest.php
  • modules/system/tests/console/asset/npm/NpmUpdateTest.php
  • modules/backend/tests/classes/AuthManagerTest.php
  • modules/system/tests/console/WinterUtilTest.php
  • modules/system/console/scaffold/test/phpunit.stub
  • phpunit.xml
  • modules/cms/classes/ComponentManager.php
  • modules/system/tests/console/asset/vite/ViteInstallTest.php
  • modules/cms/tests/classes/CmsObjectTest.php
  • modules/system/tests/classes/SourceManifestTest.php
  • modules/system/tests/console/asset/vite/ViteCreateTest.php
  • modules/backend/controllers/Index.php
  • .gitignore
  • modules/system/tests/console/CreateCommandTest.php
  • modules/system/composer.json
  • modules/cms/tests/classes/ControllerTest.php
  • modules/system/tests/console/asset/mix/MixCreateTest.php
  • modules/system/tests/bootstrap/PluginTestCase.php
  • config/hashing.php
  • modules/system/tests/fixtures/plugins/winter/tester/components/Comments.php
  • modules/backend/phpunit.xml
  • modules/system/phpunit.xml
  • modules/system/tests/console/asset/mix/MixInstallTest.php
  • modules/cms/composer.json
  • modules/system/tests/classes/MediaLibraryTest.php
  • modules/system/tests/ServiceProviderTest.php
  • modules/cms/phpunit.xml
  • modules/backend/composer.json
  • config/app.php
  • modules/system/tests/console/asset/npm/NpmInstallTest.php

Comment on lines 26 to +27
- name: Checkout changes
uses: actions/checkout@v3

- name: Setup extension cache
id: extcache
uses: shivammathur/cache-extensions@v1
with:
php-version: ${{ env.phpVersion }}
extensions: ${{ env.extensions }}
key: ${{ env.key }}

- name: Cache extensions
uses: actions/cache@v3
with:
path: ${{ steps.extcache.outputs.dir }}
key: ${{ steps.extcache.outputs.key }}
restore-keys: ${{ steps.extcache.outputs.key }}
uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Disable persistent checkout credentials in both jobs. Both actions/checkout steps leave the workflow token in local Git configuration while later commands execute repository and dependency code.

  • .github/workflows/tests.yml#L26-L27: add persist-credentials: false to the frontend job checkout step.
  • .github/workflows/tests.yml#L76-L77: add persist-credentials: false to the PHPUnit job checkout step.
Proposed fix
       - name: Checkout changes
         uses: actions/checkout@v4
+        with:
+          persist-credentials: false
📝 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
- name: Checkout changes
uses: actions/checkout@v3
- name: Setup extension cache
id: extcache
uses: shivammathur/cache-extensions@v1
with:
php-version: ${{ env.phpVersion }}
extensions: ${{ env.extensions }}
key: ${{ env.key }}
- name: Cache extensions
uses: actions/cache@v3
with:
path: ${{ steps.extcache.outputs.dir }}
key: ${{ steps.extcache.outputs.key }}
restore-keys: ${{ steps.extcache.outputs.key }}
uses: actions/checkout@v4
- name: Checkout changes
uses: actions/checkout@v4
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.29.0)

[warning] 26-27: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

📍 Affects 1 file
  • .github/workflows/tests.yml#L26-L27 (this comment)
  • .github/workflows/tests.yml#L76-L77
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/tests.yml around lines 26 - 27, Disable persistent
checkout credentials in both checkout steps: add persist-credentials: false to
the frontend job checkout at .github/workflows/tests.yml lines 26-27 and the
PHPUnit job checkout at lines 76-77.

Source: Linters/SAST tools

Comment on lines +138 to +143
$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)");
}
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify Laravel 12's documented SQLite requirement.
curl -fsSL https://laravel.com/docs/12.x/database |
  grep -oE 'SQLite 3\.26\.0\+' | head -n 1

# Locate current SQLite-version validation and coverage without executing code.
rg -n -C 4 'getServerVersion|SQLite version minimum|version_compare' \
  modules/system/classes/UpdateManager.php modules/system/tests

Repository: wintercms/winter

Length of output: 1041


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Repository files matching composer/lock/package manifests:"
git ls-files | rg '(^composer\.json$|^composer\.lock$|composer\..+\.json$|^modules/system/classes/UpdateManager\.php$|^modules/system/tests/.*UpdateManager.*\.php$|UpdateManagerTestCase)'

echo
echo "composer.json require hints:"
python3 - <<'PY'
import json
for path in ['composer.json', 'composer.lock']:
    try:
        data=json.load(open(path))
    except Exception as e:
        print(f"{path}: unreadable or invalid JSON ({e})")
        continue
    if path == 'composer.json':
        print(path, data.get('require', {}).get('laravel/framework'), data.get('require-dev', {}).get('laravel/framework'))
    else:
        for p in data.get('packages', [])+data.get('packages-dev', []):
            if p.get('name') in {'laravel/framework', 'laravel/laravel'}:
                print(path, p.get('name'), p.get('version'), p.get('require',{}).get('ext-sqlite3'))
PY

echo
echo "UpdateManager relevant section:"
sed -n '1,190p' modules/system/classes/UpdateManager.php

echo
echo "Search for SQLite version tests/references:"
rg -n -C 3 '3\.35|3\.26|SQLite version|getServerVersion|version_compare' modules tests composer.json composer.lock || true

echo
echo "SQLite version_compare behavior for relevant boundary inputs:"
python3 - <<'PY'
def cmp_like_php(a,b):
    import re
    def parse(v):
        pts=re.split(r'[-.]+', str(v))
        out=[]
        for i,v in enumerate(pts):
            if i>=3: break
            out.append(int(v))
        while len(out)<3:
            out.append(0)
        return tuple(out)
    x=parse(a); y=parse(b)
    return 1 if x>y else (-1 if x<y else 0)
for v in ['3.25.9', '3.26.0', '3.34.9', '3.35.0', '3.35.1']:
    print(f"{v} compared to 3.35: {cmp_like_php(v,'3.35')} ({"< 3.35" if cmp_like_php(v,'3.35') == -1 else ">= 3.35"})")
PY

Repository: wintercms/winter

Length of output: 28534


Use the Laravel 12 SQLite minimum version.

This check rejects supported SQLite 3.26.0 through 3.34.x installations before migrations run. Laravel 12 documents SQLite 3.26.0+; change version_compare(..., '3.35', '<') to version_compare(..., '3.26.0', '<') and add boundary coverage for 3.25.x and 3.26.0.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modules/system/classes/UpdateManager.php` around lines 138 - 143, Update the
SQLite version threshold in the connection check around Schema::getConnection()
from 3.35 to 3.26.0, preserving rejection below the Laravel 12 minimum and
acceptance at or above it. Add boundary coverage confirming 3.25.x is rejected
and 3.26.0 is accepted.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
austinderrick added a commit to austinderrick/winter that referenced this pull request Aug 19, 2026
Builds on the Laravel 12 work (wintercms#1366). Bumps laravel/framework ^12 -> ^13
and PHP ^8.2 -> ^8.3 in the root and modules/{system,backend,cms}.

Points winter/storm and the three modules at the Laravel 13 branch
(dev-wip/1.3-laravel-13). Adds path repositories for the in-repo modules so
composer resolves the Laravel 13 module manifests locally (the published
split packages still pin Laravel 12), and a VCS repository for the Storm
Laravel 13 branch. CI matrices dropped to PHP 8.3/8.4. No module code
changes were required (all system/backend/cms suites pass on Laravel 13).
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