From af41f2b9d6cd62063da69c55f490eb92acc48798 Mon Sep 17 00:00:00 2001 From: James Brooks Date: Tue, 18 Feb 2025 12:33:29 +0000 Subject: [PATCH 1/7] Support Laravel 12 --- .github/workflows/run-tests.yml | 2 +- composer.json | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index da93cf6b..c1a46df5 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -56,7 +56,7 @@ jobs: fail-fast: false matrix: php: [8.4, 8.3, 8.2] - laravel: [11.x] + laravel: [12.x, 11.x] stability: [prefer-lowest, prefer-stable] name: Static Analysis - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} diff --git a/composer.json b/composer.json index 789da0f2..73eab0c0 100644 --- a/composer.json +++ b/composer.json @@ -25,12 +25,12 @@ "filament/filament": "^4.0", "filament/spatie-laravel-settings-plugin": "^4.0", "guzzlehttp/guzzle": "^7.8", - "illuminate/cache": "^11.35.0", - "illuminate/console": "^11.35.0", - "illuminate/database": "^11.35.0", - "illuminate/events": "^11.35.0", - "illuminate/queue": "^11.35.0", - "illuminate/support": "^11.35.0", + "illuminate/cache": "^11.35.0|^12.0", + "illuminate/console": "^11.35.0|^12.0", + "illuminate/database": "^11.35.0|^12.0", + "illuminate/events": "^11.35.0|^12.0", + "illuminate/queue": "^11.35.0|^12.0", + "illuminate/support": "^11.35.0|^12.0", "laravel/sanctum": "^4.0", "nesbot/carbon": "^2.70", "spatie/laravel-data": "^4.11", @@ -47,7 +47,7 @@ "laravel/mcp": "^0.5", "laravel/pail": "^1.1", "laravel/pint": "^1.24", - "orchestra/testbench": "^9.15.1", + "orchestra/testbench": "^9.15.1|^10.0", "pestphp/pest": "^3.8", "pestphp/pest-plugin-laravel": "^3.0", "pestphp/pest-plugin-livewire": "*", From d8df76715eb32679c51396f84b9dea990c1e5bde Mon Sep 17 00:00:00 2001 From: James Brooks Date: Tue, 18 Feb 2025 12:41:27 +0000 Subject: [PATCH 2/7] wip --- .github/workflows/run-tests.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index c1a46df5..29c0dfab 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -112,7 +112,7 @@ jobs: fail-fast: false matrix: php: [8.4, 8.3, 8.2] - laravel: [11.x] + laravel: [12.x, 11.x] stability: [prefer-lowest, prefer-stable] name: Tests - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - MySQL 8.0 @@ -182,7 +182,7 @@ jobs: fail-fast: false matrix: php: [8.4, 8.3, 8.2] - laravel: [11.x] + laravel: [12.x, 11.x] stability: [prefer-lowest, prefer-stable] name: Tests - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - PostgreSQL 13 @@ -251,8 +251,8 @@ jobs: strategy: fail-fast: false matrix: - php: [ 8.3, 8.2 ] - laravel: [ 11.x ] + php: [8.4, 8.3, 8.2] + laravel: [12.x, 11.x] stability: [ prefer-lowest, prefer-stable ] name: Tests - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - PostgreSQL 14 @@ -321,8 +321,8 @@ jobs: strategy: fail-fast: false matrix: - php: [ 8.3, 8.2 ] - laravel: [ 11.x ] + php: [8.4, 8.3, 8.2] + laravel: [12.x, 11.x] stability: [ prefer-lowest, prefer-stable ] name: Tests - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - PostgreSQL 15 @@ -379,8 +379,8 @@ jobs: strategy: fail-fast: false matrix: - php: [ 8.3, 8.2 ] - laravel: [ 11.x ] + php: [8.4, 8.3, 8.2] + laravel: [12.x, 11.x] stability: [ prefer-lowest, prefer-stable ] name: Tests - P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - SQLite From de319ded65e8219e49c256b5b79e8820684d1954 Mon Sep 17 00:00:00 2001 From: James Brooks Date: Tue, 18 Feb 2025 12:43:34 +0000 Subject: [PATCH 3/7] wip --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 73eab0c0..f46c728a 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "illuminate/queue": "^11.35.0|^12.0", "illuminate/support": "^11.35.0|^12.0", "laravel/sanctum": "^4.0", - "nesbot/carbon": "^2.70", + "nesbot/carbon": "^2.70|^3.0", "spatie/laravel-data": "^4.11", "spatie/laravel-query-builder": "^5.5", "spatie/laravel-settings": "^3.2", From a0537e79d28f91146dac86832f3830320a0a1156 Mon Sep 17 00:00:00 2001 From: James Brooks Date: Mon, 24 Feb 2025 21:40:27 +0000 Subject: [PATCH 4/7] Update query builder --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f46c728a..e8660ab4 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "laravel/sanctum": "^4.0", "nesbot/carbon": "^2.70|^3.0", "spatie/laravel-data": "^4.11", - "spatie/laravel-query-builder": "^5.5", + "spatie/laravel-query-builder": "^6.3.1", "spatie/laravel-settings": "^3.2", "spatie/laravel-webhook-server": "^3.8", "timacdonald/json-api": "^1.0.0-beta.4", From 0a9c3701ba78b841f71b8b6bce0c821dbabe8e5f Mon Sep 17 00:00:00 2001 From: James Brooks Date: Sun, 11 May 2025 21:39:35 +0100 Subject: [PATCH 5/7] wip --- .phpintel/ea3e1b9b012b6dac60aa2cf1d153c95a | Bin 0 -> 1270 bytes .phpintel/index | Bin 0 -> 149 bytes composer.json | 11 +++++++++- .../Controllers/Api/IncidentController.php | 20 +++++++++++------- src/Models/Incident.php | 15 +++++++++++++ tests/Feature/Api/IncidentTest.php | 20 ++++++++++++------ 6 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 .phpintel/ea3e1b9b012b6dac60aa2cf1d153c95a create mode 100644 .phpintel/index diff --git a/.phpintel/ea3e1b9b012b6dac60aa2cf1d153c95a b/.phpintel/ea3e1b9b012b6dac60aa2cf1d153c95a new file mode 100644 index 0000000000000000000000000000000000000000..4865270540261c710a5cde7e058997ec5b3d5619 GIT binary patch literal 1270 zcmZvb+f&m}5XK9o-0zBtHv(3TRT}Vq#|n%xQ}sbRo|lXhlEsaNB%5=><$)RhbT_9- zTT1hibKUQ^-|qQWwy9*E(U2)7OQn*37zc0&p^`K#cwVBi7~$VvKlEq>+mqN)NEPvg z*R7U>L|T8GLy*>XW$XYbPDB0NrRGNg6CV5`wxfi)K#p6*POXVovrD-w5lMR~D zx1Hp-q*$*X#UhU{GSPx2IP#^x?+3m*r9~Y$PWJ;2d?`Jn%O(zE8Ar7E zk(1C8R&W%@a2zMZJV$Lbo8Nx!?)=*Oy4`H;?0%;!$gDUeHh9yj)h3PXs~JBKjKG)5 zhz<-V2%=-~3_o;()B{=14_R~-+u3Z=HRL3gZMtrXagJ0?fKrf(ZeST4oW})R#0>Ce z0hm?sAPrr*)kBzhz?Fp)x}9UKp2uotNQE=9!?A+XID@me+@oaVO4u(T754(I<^pTy z1-27#6m%py3Ttfzo9>u4RZU&3s^=(&?sA4U-801!N2FhmGfkupqqIIt5#q=wCRy4CNcyrlWt~OZ+kE1cr~vfgXt1dJ+Fr~2qo** zH0JDpHU`_&(z_RJ+AMe;vrSKWZF;J0de+bQTra=K-D`{Xx%V=6uRwk^2swLv+?xEV zPwDkw<{b!NP-)*3%x{_bT|eM^4Y-v9dOAiQ;Dp{m%HWTh*qI+z{=Q Gp#C4*U`&z# literal 0 HcmV?d00001 diff --git a/.phpintel/index b/.phpintel/index new file mode 100644 index 0000000000000000000000000000000000000000..ccb53243fbd045fe84f67b600b4cb3b0a071dde8 GIT binary patch literal 149 zcmZXMy$-@45P(s1Ht{K3>^+0&Vh2YPmJS3iq2>gRyT-}HN0-IP`TP0UH=C0?8e^s$ zmWWx$lC>2gY`mFy>u#OFU9br}{1XMn5)pzA3H2OGLy#8Ws#-hwr2?0_!2fcnsj~I% W(5IfLyfAi&)`-HpnfJ;1b@&2fb}}*m literal 0 HcmV?d00001 diff --git a/composer.json b/composer.json index e8660ab4..505e8776 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "laravel/sanctum": "^4.0", "nesbot/carbon": "^2.70|^3.0", "spatie/laravel-data": "^4.11", - "spatie/laravel-query-builder": "^6.3.1", + "spatie/laravel-query-builder": "^6.3", "spatie/laravel-settings": "^3.2", "spatie/laravel-webhook-server": "^3.8", "timacdonald/json-api": "^1.0.0-beta.4", @@ -46,6 +46,7 @@ "laravel/boost": "^2.0", "laravel/mcp": "^0.5", "laravel/pail": "^1.1", +<<<<<<< HEAD "laravel/pint": "^1.24", "orchestra/testbench": "^9.15.1|^10.0", "pestphp/pest": "^3.8", @@ -53,6 +54,14 @@ "pestphp/pest-plugin-livewire": "*", "pestphp/pest-plugin-type-coverage": "^3.3", "psalm/plugin-laravel": "^3.14" +======= + "laravel/pint": "^1.21", + "orchestra/testbench": "^9.5.1|^10.0", + "pestphp/pest": "^3.8", + "pestphp/pest-plugin-laravel": "^3.7", + "pestphp/pest-plugin-livewire": "^v3.0", + "pestphp/pest-plugin-type-coverage": "^3.5" +>>>>>>> 965f5cd (wip) }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/src/Http/Controllers/Api/IncidentController.php b/src/Http/Controllers/Api/IncidentController.php index f8be581f..f966ec72 100644 --- a/src/Http/Controllers/Api/IncidentController.php +++ b/src/Http/Controllers/Api/IncidentController.php @@ -13,6 +13,8 @@ use Dedoc\Scramble\Attributes\Group; use Dedoc\Scramble\Attributes\QueryParameter; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Http\Request; +use Illuminate\Http\Resources\Json\AnonymousResourceCollection; use Illuminate\Http\Response; use Illuminate\Routing\Controller; use Spatie\QueryBuilder\AllowedFilter; @@ -38,22 +40,24 @@ class IncidentController extends Controller */ #[QueryParameter('per_page', 'How many items to show per page.', type: 'int', default: 15, example: 20)] #[QueryParameter('page', 'Which page to show.', type: 'int', example: 2)] - public function index() + public function index(Request $request) { - $query = Incident::query() - ->when(! request('sort'), function (Builder $builder) { - $builder->orderByDesc('created_at'); - }); +// $query = Incident::query() +// ->when(!$request->has('sort'), function (Builder $builder) { +// $builder->orderByDesc('created_at'); +// }); - $incidents = QueryBuilder::for($query) + $incidents = QueryBuilder::for(Incident::query()) ->allowedIncludes(self::ALLOWED_INCLUDES) ->allowedFilters([ 'name', AllowedFilter::exact('status'), - 'occurred_at', + AllowedFilter::scope('occurs_after'), + AllowedFilter::scope('occurs_before'), + AllowedFilter::scope('occurs_on'), ]) ->allowedSorts(['name', 'status', 'id']) - ->simplePaginate(request('per_page', 15)); + ->simplePaginate($request->input('per_page', 15)); return IncidentResource::collection($incidents); } diff --git a/src/Models/Incident.php b/src/Models/Incident.php index b28fc9e3..83840337 100644 --- a/src/Models/Incident.php +++ b/src/Models/Incident.php @@ -171,6 +171,21 @@ public function scopeStickied(Builder $query): void $query->where('stickied', true); } + public function scopeOccursAfter(Builder $query, $date): void + { + $query->where('occurred_at', '>=', $date); + } + + public function scopeOccursBefore(Builder $query, $date): void + { + $query->where('occurred_at', '<=', $date); + } + + public function scopeOccursOn(Builder $query, $date): void + { + $query->whereDate('occurred_at', $date); + } + /** * @return Attribute */ diff --git a/tests/Feature/Api/IncidentTest.php b/tests/Feature/Api/IncidentTest.php index 286eac36..7ff74663 100644 --- a/tests/Feature/Api/IncidentTest.php +++ b/tests/Feature/Api/IncidentTest.php @@ -13,6 +13,7 @@ use function Pest\Laravel\getJson; use function Pest\Laravel\postJson; use function Pest\Laravel\putJson; +use function Pest\Laravel\withoutExceptionHandling; it('can list incidents', function () { Incident::factory(2)->create(); @@ -147,19 +148,26 @@ it('can filter incidents by occurred at date', function () { Incident::factory(20)->create([ - 'occurred_at' => '2019-01-01', + 'occurred_at' => '2019-01-01 00:00:00', ]); $incident = Incident::factory()->create([ - 'occurred_at' => '2023-01-01', + 'occurred_at' => '2025-01-01 00:00:00', ]); - $query = http_build_query([ + withoutExceptionHandling(); + + dd(route('cachet.api.incidents.index', [ 'filter' => [ - 'occurred_at' => '2023-01-01', + 'occurs_after' => '2024-12-31', ], - ]); + ])); - $response = getJson('/status/api/incidents?'.$query); + $response = getJson(route('cachet.api.incidents.index', [ + 'filter' => [ + 'occurs_after' => '2024-12-31', + ], + ])) + ->assertOk(); $response->assertJsonCount(1, 'data'); $response->assertJsonPath('data.0.attributes.id', $incident->id); From be6c3ad71a8cbf866b4c95d4fc2fc0e980b6700f Mon Sep 17 00:00:00 2001 From: James Brooks Date: Thu, 25 Jun 2026 09:26:54 +0100 Subject: [PATCH 6/7] Fix tests for Laravel 12 support - Resolve unresolved composer.json merge conflict - Register QueryBuilderServiceProvider in tests so API filters/sorts apply - Remove leftover dd()/withoutExceptionHandling() in IncidentTest - Restore default created_at desc ordering via defaultSort on incidents - Use absolute diffInMinutes in MetricPoint::withinThreshold (Carbon 3 signed diff) - Make created_at fillable on MetricPoint so timestamps can be set - Update CreateMetricPoint test assertion for Carbon 3 isSameAs signature Co-Authored-By: Claude Opus 4.8 (1M context) --- composer.json | 15 +++------------ src/Http/Controllers/Api/IncidentController.php | 10 ++-------- src/Models/MetricPoint.php | 3 ++- tests/Feature/Api/IncidentTest.php | 9 --------- tests/TestCase.php | 2 ++ .../Unit/Actions/Metric/CreateMetricPointTest.php | 2 +- 6 files changed, 10 insertions(+), 31 deletions(-) diff --git a/composer.json b/composer.json index 505e8776..94bd1160 100644 --- a/composer.json +++ b/composer.json @@ -46,22 +46,13 @@ "laravel/boost": "^2.0", "laravel/mcp": "^0.5", "laravel/pail": "^1.1", -<<<<<<< HEAD "laravel/pint": "^1.24", "orchestra/testbench": "^9.15.1|^10.0", "pestphp/pest": "^3.8", - "pestphp/pest-plugin-laravel": "^3.0", - "pestphp/pest-plugin-livewire": "*", - "pestphp/pest-plugin-type-coverage": "^3.3", - "psalm/plugin-laravel": "^3.14" -======= - "laravel/pint": "^1.21", - "orchestra/testbench": "^9.5.1|^10.0", - "pestphp/pest": "^3.8", "pestphp/pest-plugin-laravel": "^3.7", - "pestphp/pest-plugin-livewire": "^v3.0", - "pestphp/pest-plugin-type-coverage": "^3.5" ->>>>>>> 965f5cd (wip) + "pestphp/pest-plugin-livewire": "^3.0", + "pestphp/pest-plugin-type-coverage": "^3.5", + "psalm/plugin-laravel": "^3.14" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/src/Http/Controllers/Api/IncidentController.php b/src/Http/Controllers/Api/IncidentController.php index f966ec72..6879f40b 100644 --- a/src/Http/Controllers/Api/IncidentController.php +++ b/src/Http/Controllers/Api/IncidentController.php @@ -12,9 +12,7 @@ use Cachet\Models\Incident; use Dedoc\Scramble\Attributes\Group; use Dedoc\Scramble\Attributes\QueryParameter; -use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Request; -use Illuminate\Http\Resources\Json\AnonymousResourceCollection; use Illuminate\Http\Response; use Illuminate\Routing\Controller; use Spatie\QueryBuilder\AllowedFilter; @@ -42,11 +40,6 @@ class IncidentController extends Controller #[QueryParameter('page', 'Which page to show.', type: 'int', example: 2)] public function index(Request $request) { -// $query = Incident::query() -// ->when(!$request->has('sort'), function (Builder $builder) { -// $builder->orderByDesc('created_at'); -// }); - $incidents = QueryBuilder::for(Incident::query()) ->allowedIncludes(self::ALLOWED_INCLUDES) ->allowedFilters([ @@ -56,7 +49,8 @@ public function index(Request $request) AllowedFilter::scope('occurs_before'), AllowedFilter::scope('occurs_on'), ]) - ->allowedSorts(['name', 'status', 'id']) + ->allowedSorts(['name', 'status', 'id', 'created_at']) + ->defaultSort('-created_at') ->simplePaginate($request->input('per_page', 15)); return IncidentResource::collection($incidents); diff --git a/src/Models/MetricPoint.php b/src/Models/MetricPoint.php index fd2e1007..43c2f29c 100644 --- a/src/Models/MetricPoint.php +++ b/src/Models/MetricPoint.php @@ -45,6 +45,7 @@ class MetricPoint extends Model protected $fillable = [ 'value', 'counter', + 'created_at', ]; public function calculatedValue(): Attribute @@ -96,7 +97,7 @@ public function withinThreshold(int $threshold, string|int|DateTime|null $timest $now ??= Carbon::parse($timestamp); - return $this->created_at->startOfMinute()->diffInMinutes($now->startOfMinute()) < $threshold; + return $this->created_at->startOfMinute()->diffInMinutes($now->startOfMinute(), true) < $threshold; } /** diff --git a/tests/Feature/Api/IncidentTest.php b/tests/Feature/Api/IncidentTest.php index 7ff74663..411d6389 100644 --- a/tests/Feature/Api/IncidentTest.php +++ b/tests/Feature/Api/IncidentTest.php @@ -13,7 +13,6 @@ use function Pest\Laravel\getJson; use function Pest\Laravel\postJson; use function Pest\Laravel\putJson; -use function Pest\Laravel\withoutExceptionHandling; it('can list incidents', function () { Incident::factory(2)->create(); @@ -154,14 +153,6 @@ 'occurred_at' => '2025-01-01 00:00:00', ]); - withoutExceptionHandling(); - - dd(route('cachet.api.incidents.index', [ - 'filter' => [ - 'occurs_after' => '2024-12-31', - ], - ])); - $response = getJson(route('cachet.api.incidents.index', [ 'filter' => [ 'occurs_after' => '2024-12-31', diff --git a/tests/TestCase.php b/tests/TestCase.php index 1a85fc85..f6835536 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -16,6 +16,7 @@ use Livewire\LivewireServiceProvider; use Orchestra\Testbench\Concerns\WithWorkbench; use Orchestra\Testbench\TestCase as Orchestra; +use Spatie\QueryBuilder\QueryBuilderServiceProvider; abstract class TestCase extends Orchestra { @@ -42,6 +43,7 @@ protected function getPackageProviders($app) BladeHeroiconsServiceProvider::class, WidgetsServiceProvider::class, ScrambleServiceProvider::class, + QueryBuilderServiceProvider::class, ]); // Laravel apps register providers in alphabetical order, so we do the same here for consistency. diff --git a/tests/Unit/Actions/Metric/CreateMetricPointTest.php b/tests/Unit/Actions/Metric/CreateMetricPointTest.php index 2e8f4eae..0e51b753 100644 --- a/tests/Unit/Actions/Metric/CreateMetricPointTest.php +++ b/tests/Unit/Actions/Metric/CreateMetricPointTest.php @@ -106,7 +106,7 @@ expect($point) ->toBeInstanceOf(MetricPoint::class) - ->created_at->isSameAs(Carbon::parse($timestamp)); + ->created_at->toDateTimeString()->toBe(Carbon::parse($timestamp)->toDateTimeString()); })->with([ now()->addWeek()->startOfMinute()->unix(), now()->subHour()->startOfMinute()->toAtomString(), From c1aa84a1e71ba61d0e9cccdc5eeccdebe30a42ec Mon Sep 17 00:00:00 2001 From: James Brooks Date: Thu, 25 Jun 2026 09:36:06 +0100 Subject: [PATCH 7/7] Raise timacdonald/json-api minimum to beta.10 beta.9 and earlier serialize resource fields flat instead of nesting them under `attributes`, breaking the JSON:API response shape the API tests assert. Only surfaced on the prefer-lowest CI matrix. Co-Authored-By: Claude Opus 4.8 (1M context) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 94bd1160..301394fc 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,7 @@ "spatie/laravel-query-builder": "^6.3", "spatie/laravel-settings": "^3.2", "spatie/laravel-webhook-server": "^3.8", - "timacdonald/json-api": "^1.0.0-beta.4", + "timacdonald/json-api": "^1.0.0-beta.10", "twig/twig": "^3.0" }, "require-dev": {