Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8934097
Fix invalid data provider key in external URL tests
jasonvarga Aug 8, 2026
fce32f0
Prevent ColorTest from leaking theme preferences
jasonvarga Aug 8, 2026
e51f533
Add Pest as the test runner
jasonvarga Aug 8, 2026
5b78d22
Shard PHP tests across four jobs in CI
jasonvarga Aug 8, 2026
597341a
Return the nav item when creating one without a display name
jasonvarga Aug 8, 2026
c314c34
Fall back to the handle when a form has no title
jasonvarga Aug 8, 2026
5fcbb3e
Restore the testbench skeleton between tests
jasonvarga Aug 8, 2026
d67d842
Stop MakeAddonTest running npm install against this repo
jasonvarga Aug 8, 2026
a72607a
Stop DuplicateFormTest writing users into the fixtures directory
jasonvarga Aug 8, 2026
2072e57
Create the blueprint ViewBlueprintListingTest needs
jasonvarga Aug 8, 2026
c403c7d
Create glide's temp directory in the non-glideable upload test
jasonvarga Aug 8, 2026
30572d4
Merge remote-tracking branch 'origin/testbench-teardown' into pest
jasonvarga Aug 9, 2026
db042d4
Merge remote-tracking branch 'origin/nav-null-bugs' into pest
jasonvarga Aug 9, 2026
2a30512
TEMP: disable fail-fast for validation run
jasonvarga Aug 9, 2026
9811425
Add throwaway Windows junction probe
jasonvarga Aug 9, 2026
3bd1ab2
Probe a candidate fix for junction traversal
jasonvarga Aug 9, 2026
bc499f7
Instrument the hasChildren override and probe a hand-rolled scan
jasonvarga Aug 9, 2026
9863756
Test whether clearstatcache rescues the hasChildren override
jasonvarga Aug 9, 2026
9951e14
Remove the probe
jasonvarga Aug 9, 2026
334ebaf
Stop the template fieldtype tests leaking into each other
jasonvarga Aug 9, 2026
f18f800
Traverse Windows junctions when scanning view paths
jasonvarga Aug 9, 2026
5513a27
Remove the stat calls from the test directory cleanup
jasonvarga Aug 9, 2026
61ea1e8
Merge remote-tracking branch 'origin/probe/windows-junctions' into pest
jasonvarga Aug 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 36 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,39 @@
contents: read

strategy:
fail-fast: false
matrix:
php: [8.3, 8.4, 8.5]
laravel: [12.*, 13.*]
stability: [prefer-lowest, prefer-stable]
os: [ubuntu-latest]
shard: [1, 2, 3, 4]
# An include entry that overrides an existing matrix key (os) creates a standalone
# combination rather than merging, so it wouldn't inherit the shard dimension.
# Windows is the slowest job, so each shard has to be listed explicitly.
include:
- os: windows-latest
php: 8.5
laravel: 12.*
stability: prefer-stable
shard: 1
- os: windows-latest
php: 8.5
laravel: 12.*
stability: prefer-stable
shard: 2
- os: windows-latest
php: 8.5
laravel: 12.*
stability: prefer-stable
shard: 3
- os: windows-latest
php: 8.5
laravel: 12.*
stability: prefer-stable
shard: 4

name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}
name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} - shard ${{ matrix.shard }}/4

steps:
- name: Checkout code
Expand Down Expand Up @@ -101,7 +122,19 @@

- name: Execute tests
if: steps.should-run-tests.outputs.result == 'true'
run: vendor/bin/phpunit
run: vendor/bin/pest --shard=${{ matrix.shard }}/4 --ci

Check warning on line 125 in .github/workflows/tests.yml

View workflow job for this annotation

GitHub Actions / zizmor / zizmor

template-injection

tests.yml:125: code injection via template expansion: may expand into attacker-controllable code

php-tests-result:
name: PHP tests
runs-on: ubuntu-latest
needs: [php-tests]
if: always()
permissions: {}

steps:
- name: Fail if any shard failed
if: needs.php-tests.result != 'success' && needs.php-tests.result != 'skipped'
run: exit 1

js-tests:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -159,7 +192,7 @@
slack:
name: Slack Notification
runs-on: ubuntu-latest
needs: [php-tests, js-tests]
needs: [php-tests-result, js-tests]
permissions:
actions: read # required by workflow-conclusion-action to determine overall workflow status
if: always()
Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"laravel/socialite": "^5.28",
"mockery/mockery": "^1.6.10",
"orchestra/testbench": "^10.8 || ^11.0",
"pestphp/pest": "^4.7",
"phpstan/phpstan": "^2.2",
"phpunit/phpunit": "^12.5.23",
"spatie/laravel-ray": "^1.43.6"
Expand All @@ -67,7 +68,8 @@
"preferred-install": "dist",
"sort-packages": true,
"allow-plugins": {
"composer/package-versions-deprecated": true
"composer/package-versions-deprecated": true,
"pestphp/pest-plugin": true
}
},
"extra": {
Expand Down
4 changes: 3 additions & 1 deletion src/CP/Navigation/Nav.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ public function extend(Closure $callback)
*/
public function create($name)
{
$item = (new NavItem)->display($name);
$item = new NavItem;

$item->display($name);

$this->items[] = $item;

Expand Down
2 changes: 1 addition & 1 deletion src/Fieldtypes/TemplateFolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

use FilesystemIterator;
use RecursiveCallbackFilterIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use Statamic\Filesystem\RecursiveDirectoryIterator;
use Statamic\Support\Str;

class TemplateFolder extends Relationship
Expand Down
25 changes: 25 additions & 0 deletions src/Filesystem/RecursiveDirectoryIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Statamic\Filesystem;

class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
{
public function hasChildren(bool $allowLinks = false): bool
{
if (parent::hasChildren($allowLinks)) {
return true;
}

if (DIRECTORY_SEPARATOR !== '\\') {
return false;
}

// A Windows junction reports an lstat mode that is neither a link nor a
// directory, so the parent treats it as a leaf and FOLLOW_SYMLINKS never
// gets a look in. The parent has just lstat'd the path, and is_dir() would
// reuse that cached result, so the cache needs clearing before asking.
clearstatcache(true, $path = $this->getPathname());

return is_dir($path);
}
}
7 changes: 6 additions & 1 deletion src/Forms/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ public function handle($handle = null)
*/
public function title($title = null)
{
return $this->fluentlyGetOrSet('title')->args(func_get_args());
return $this
->fluentlyGetOrSet('title')
->getter(function ($title) {
return $title ?? ucfirst($this->handle);
})
->args(func_get_args());
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Http/Controllers/CP/API/TemplatesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
namespace Statamic\Http\Controllers\CP\API;

use RecursiveCallbackFilterIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use Statamic\Filesystem\RecursiveDirectoryIterator;
use Statamic\Http\Controllers\CP\CpController;
use Statamic\Support\Str;

Expand Down
44 changes: 44 additions & 0 deletions testbench.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Everything the test suite is known to write into the testbench skeleton
# (vendor/orchestra/testbench-core/laravel). Tests/TestCase clears these once per
# process before snapshotting the skeleton, so a suite run never inherits leftovers
# from a previous one. It's also what `vendor/bin/testbench package:purge-skeleton`
# removes.
purge:
directories:
- addons
- app/Actions
- app/Dictionaries
- app/Fieldtypes
- app/Modifiers
- app/Scopes
- app/Tags
- app/Widgets
- config/statamic
- public/diskimgroot
- public/glide
- public/imgcache
- public/static
- public/testimages
- public/vendor
- resources/addons
- resources/blueprints
- resources/content
- resources/css
- resources/dictionaries
- resources/fieldsets
- resources/forms
- resources/js
- resources/users
- storage/framework/testing/disks
- storage/statamic
files:
- app/Providers/AppServiceProvider.php
- composer.json.bak
- composer.lock
- package.json
- public/*.jpg
- resources/*.svg
- resources/preferences.yaml
- resources/sites.yaml
- storage/logs/*.log
- vite-cp.config.js
Loading
Loading