From 2a2262471621d1c9dd6dce236a58d9336b6f7cbc Mon Sep 17 00:00:00 2001 From: Martin Komischke Date: Mon, 2 Feb 2026 09:36:26 +0100 Subject: [PATCH 1/6] add copilot instructions --- .github/copilot-instructions.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..46a0b74 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,24 @@ +# Copilot instructions for this repository + +Preferred behavior for running backend tests and quality checks: + +- Always run backend tests and QA inside the docker-compose "app" service so environment, PHP extensions and dependencies match the container. +- Prefer using the Makefile targets which already invoke the app service. Examples: + - make test # runs phpunit inside the app container + - make quality # runs composer qa inside the app container + +If running commands directly inside the container, run non-interactively (no -it) to avoid TTY allocation issues: + +- docker compose exec -T app bin/phpunit +- docker compose exec -T app composer qa +- docker compose exec -T app vendor/bin/phpstan analyse --memory-limit=1G +- docker compose exec -T app vendor/bin/php-cs-fixer fix +- docker compose exec -T app vendor/bin/deptrac analyse --report-uncovered + +Guidelines for Copilot CLI usage in this repo: + +- When asked to run tests or QA, prefer the Makefile targets (make test, make quality) executed in the repository root. +- If running inside a container is required, always target the "app" service and use `-T` for exec to run non-interactively. +- When proposing automation or CI commands, include explicit container commands using the "app" service so they work in the project's docker-compose setup. + +These instructions ensure consistent, reproducible test and QA runs by using the project's containerized environment. From 3213dc92e83c0170b29785669dc4b84479368b85 Mon Sep 17 00:00:00 2001 From: Martin Komischke Date: Mon, 2 Feb 2026 09:36:42 +0100 Subject: [PATCH 2/6] increase coverage with unit test --- .../Unit/SplitFairly/ExpenseTrackerTest.php | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 backend/tests/Unit/SplitFairly/ExpenseTrackerTest.php diff --git a/backend/tests/Unit/SplitFairly/ExpenseTrackerTest.php b/backend/tests/Unit/SplitFairly/ExpenseTrackerTest.php new file mode 100644 index 0000000..380bb8c --- /dev/null +++ b/backend/tests/Unit/SplitFairly/ExpenseTrackerTest.php @@ -0,0 +1,46 @@ +createMock(CurrentUserInterface::class); + $currentUser->method('getUuid')->willReturn('user-123'); + + $normalizedPayload = ['price' => (string)$price, 'what' => 'Coffee', 'type' => 'Groceries', 'location' => 'Starbucks']; + $normalizer = $this->createMock(NormalizerInterface::class); + $normalizer->expects($this->once())->method('toArray')->with($expense, ['id'])->willReturn($normalizedPayload); + + $eventStore = $this->createMock(EventStoreInterface::class); + $eventStore->expects($this->once())->method('persist')->with( + $this->callback(function (Event $event) use ($expense, $normalizedPayload): bool { + return $event->createdBy === 'user-123' + && $event->subjectType === 'Expense' + && $event->subjectId === $expense->getId()->toRfc4122() + && $event->eventType === 'tracked' + && $event->payload === $normalizedPayload; + }), + false + ); + + $tracker = new ExpenseTracker($eventStore, $normalizer, $currentUser); + + $tracker->track($expense); + } +} From d8488c00ecd4422f14afc83ad55a454f7280029b Mon Sep 17 00:00:00 2001 From: Martin Komischke Date: Mon, 2 Feb 2026 10:27:41 +0100 Subject: [PATCH 3/6] Dashboard: point coverage link to homer public path --- dashboard/assets/config.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dashboard/assets/config.yml b/dashboard/assets/config.yml index 4f31dfe..fec8b10 100644 --- a/dashboard/assets/config.yml +++ b/dashboard/assets/config.yml @@ -49,3 +49,8 @@ services: icon: "fa-brands fa-github" url: "https://github.com/makomweb/split-fairly" target: "_blank" + - name: "Code coverage" + subtitle: "PHPUnit coverage" + icon: "fa-solid fa-clipboard-check" + url: "http://localhost:8000/coverage/index.html" + target: "_blank" From 181205830791e728fa2023177be4348e3fb3edd0 Mon Sep 17 00:00:00 2001 From: Martin Komischke Date: Mon, 2 Feb 2026 10:33:10 +0100 Subject: [PATCH 4/6] Dashboard: expose coverage at /coverage by mounting to /www/coverage --- docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 19dd6ea..b797067 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -79,7 +79,7 @@ services: volumes: - ./dashboard/assets:/www/assets - ./backend/report:/www/public/report - - ./backend/coverage:/www/public/coverage + - ./backend/coverage:/www/coverage ports: - "8000:8080" user: "1000:1001" From 52a3f547e9baa33f48055339a1b8276147d09735 Mon Sep 17 00:00:00 2001 From: Martin Komischke Date: Mon, 2 Feb 2026 10:35:31 +0100 Subject: [PATCH 5/6] fixup! increase coverage with unit test --- backend/tests/Unit/SplitFairly/ExpenseTrackerTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/tests/Unit/SplitFairly/ExpenseTrackerTest.php b/backend/tests/Unit/SplitFairly/ExpenseTrackerTest.php index 380bb8c..9ee6ebe 100644 --- a/backend/tests/Unit/SplitFairly/ExpenseTrackerTest.php +++ b/backend/tests/Unit/SplitFairly/ExpenseTrackerTest.php @@ -23,17 +23,17 @@ public function test_tracks_expense_and_persists_event(): void $currentUser = $this->createMock(CurrentUserInterface::class); $currentUser->method('getUuid')->willReturn('user-123'); - $normalizedPayload = ['price' => (string)$price, 'what' => 'Coffee', 'type' => 'Groceries', 'location' => 'Starbucks']; + $normalizedPayload = ['price' => (string) $price, 'what' => 'Coffee', 'type' => 'Groceries', 'location' => 'Starbucks']; $normalizer = $this->createMock(NormalizerInterface::class); $normalizer->expects($this->once())->method('toArray')->with($expense, ['id'])->willReturn($normalizedPayload); $eventStore = $this->createMock(EventStoreInterface::class); $eventStore->expects($this->once())->method('persist')->with( $this->callback(function (Event $event) use ($expense, $normalizedPayload): bool { - return $event->createdBy === 'user-123' - && $event->subjectType === 'Expense' + return 'user-123' === $event->createdBy + && 'Expense' === $event->subjectType && $event->subjectId === $expense->getId()->toRfc4122() - && $event->eventType === 'tracked' + && 'tracked' === $event->eventType && $event->payload === $normalizedPayload; }), false From 8a35decdbdd51454016af6d117e9db00b1a21597 Mon Sep 17 00:00:00 2001 From: Martin Komischke Date: Mon, 2 Feb 2026 10:45:51 +0100 Subject: [PATCH 6/6] focus codecov on the core domain --- codecov.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..c56d6ac --- /dev/null +++ b/codecov.yml @@ -0,0 +1,14 @@ +# Limit Codecov reports to the SplitFairly namespace +coverage: + status: + project: + default: + target: 0 + precision: 2 + round: down +reports: + - name: SplitFairly + paths: + - backend/src/SplitFairly + # Only show this report on the Codecov UI + # see https://docs.codecov.com/docs/codecov-yaml#section-reports