> $issuesByState */ public function __construct(private readonly array $issuesByState) { } public function listIssues(string $owner, string $repo, string $state): array { return $this->issuesByState[$state] ?? []; } } final class CodebergSyncServiceTest extends TestCase { public function testSyncCreatesBacklogAndDoneTickets(): void { $tickets = new TicketRepository(Database::inMemory()); $client = new FakeCodebergClient([ 'open' => [ ['number' => 1, 'title' => 'Offenes Issue', 'body' => 'Beschreibung', 'labels' => [['name' => 'bug', 'color' => 'ff0000']]], ], 'closed' => [ ['number' => 2, 'title' => 'Geschlossenes Issue', 'body' => null, 'labels' => []], ], ]); (new CodebergSyncService($client, $tickets, 'fds2610', 'monitor'))->sync(); $backlog = $tickets->all('backlog'); $done = $tickets->all('done'); self::assertCount(1, $backlog); self::assertSame('Offenes Issue', $backlog[0]['title']); self::assertSame('bug', $backlog[0]['type']); self::assertSame('#ff0000', $backlog[0]['color']); self::assertSame('codeberg', $backlog[0]['source']); self::assertCount(1, $done); self::assertSame('Geschlossenes Issue', $done[0]['title']); self::assertNull($done[0]['type']); self::assertNull($done[0]['color']); } public function testSyncNormalizesLabelColorRegardlessOfLeadingHash(): void { $tickets = new TicketRepository(Database::inMemory()); $client = new FakeCodebergClient([ 'open' => [ ['number' => 1, 'title' => 'Mit Raute', 'body' => null, 'labels' => [['name' => 'bug', 'color' => '#00ff00']]], ], 'closed' => [], ]); (new CodebergSyncService($client, $tickets, 'fds2610', 'monitor'))->sync(); self::assertSame('#00ff00', $tickets->all('backlog')[0]['color']); } public function testSyncDoesNotResetManuallyMovedTicket(): void { $tickets = new TicketRepository(Database::inMemory()); $client = new FakeCodebergClient([ 'open' => [['number' => 1, 'title' => 'Issue', 'body' => null, 'labels' => []]], 'closed' => [], ]); $service = new CodebergSyncService($client, $tickets, 'fds2610', 'monitor'); $service->sync(); $ticket = $tickets->findByExternalRef('1'); $tickets->update((int) $ticket['id'], ['column' => 'qa']); $service->sync(); $stillQa = $tickets->findByExternalRef('1'); self::assertSame('qa', $stillQa['column_name']); } /** @return array */ public static function labelColumnProvider(): array { return [ 'automate -> bereit' => ['automate', 'bereit'], 'wip -> in_arbeit' => ['wip', 'in_arbeit'], 'testing -> testing' => ['testing', 'testing'], ]; } /** @dataProvider labelColumnProvider */ public function testSyncMapsOpenIssueLabelToBoardColumn(string $label, string $expectedColumn): void { $tickets = new TicketRepository(Database::inMemory()); $client = new FakeCodebergClient([ 'open' => [ ['number' => 1, 'title' => 'Issue', 'body' => null, 'labels' => [['name' => $label, 'color' => 'ff0000']]], ], 'closed' => [], ]); (new CodebergSyncService($client, $tickets, 'fds2610', 'monitor'))->sync(); $ticket = $tickets->findByExternalRef('1'); self::assertSame($expectedColumn, $ticket['column_name']); } public function testSyncMovesTicketBetweenAutomatedColumnsWhenLabelChanges(): void { $tickets = new TicketRepository(Database::inMemory()); $client = new FakeCodebergClient([ 'open' => [ ['number' => 1, 'title' => 'Issue', 'body' => null, 'labels' => [['name' => 'automate', 'color' => 'ff0000']]], ], 'closed' => [], ]); $service = new CodebergSyncService($client, $tickets, 'fds2610', 'monitor'); $service->sync(); self::assertSame('bereit', $tickets->findByExternalRef('1')['column_name']); $client = new FakeCodebergClient([ 'open' => [ ['number' => 1, 'title' => 'Issue', 'body' => null, 'labels' => [['name' => 'wip', 'color' => 'ff0000']]], ], 'closed' => [], ]); (new CodebergSyncService($client, $tickets, 'fds2610', 'monitor'))->sync(); self::assertSame('in_arbeit', $tickets->findByExternalRef('1')['column_name']); } public function testSyncClosesTicketFromAnyAutomatedColumnIntoDone(): void { $tickets = new TicketRepository(Database::inMemory()); $client = new FakeCodebergClient([ 'open' => [ ['number' => 1, 'title' => 'Issue', 'body' => null, 'labels' => [['name' => 'testing', 'color' => 'ff0000']]], ], 'closed' => [], ]); $service = new CodebergSyncService($client, $tickets, 'fds2610', 'monitor'); $service->sync(); self::assertSame('testing', $tickets->findByExternalRef('1')['column_name']); $client = new FakeCodebergClient([ 'open' => [], 'closed' => [ ['number' => 1, 'title' => 'Issue', 'body' => null, 'labels' => [['name' => 'testing', 'color' => 'ff0000']]], ], ]); (new CodebergSyncService($client, $tickets, 'fds2610', 'monitor'))->sync(); self::assertSame('done', $tickets->findByExternalRef('1')['column_name']); } }