Farbe verwaister Tickets zuruecksetzen statt Projektfarbe zu behalten

Wenn ein Projekt im Projekte-Modal entfernt oder umbenannt wurde, hat
CodebergSyncService dessen Tickets nicht mehr angefasst - sie blieben
also dauerhaft in der alten Projektfarbe eingefaerbt, obwohl es dafuer
gar kein Projekt mehr gab (Issue #34). sync() setzt die Farbe solcher
Tickets nun nach jedem Lauf auf NULL zurueck, wodurch das Kanban die
Standardfarbe statt der veralteten Projektfarbe zeigt.

Schließt #34
This commit is contained in:
fds2610-bot 2026-08-04 11:07:56 +02:00
parent edf71d1892
commit ce8862014f
4 changed files with 87 additions and 1 deletions

View file

@ -170,6 +170,33 @@ final class TicketRepository
]);
}
/**
* Loescht die Projektfarbe von Tickets, deren Quell-Projekt nicht (mehr) in $slugs steht
* (Issue #34: nach Entfernen/Umbenennen eines Projekts im Projekte-Modal blieben dessen
* Tickets dauerhaft in dessen alter Farbe eingefaerbt, weil CodebergSyncService sie ab
* dann gar nicht mehr anfasst). Tickets ohne Projektbezug (repo = NULL, z.B. per API
* angelegt) bleiben unberuehrt.
*
* @param string[] $slugs - aktuell konfigurierte "owner/repo"-Werte.
*/
public function clearColorForReposNotIn(array $slugs): void
{
if ($slugs === []) {
$this->db->pdo()->exec(
"UPDATE tickets SET color = NULL WHERE repo IS NOT NULL AND color IS NOT NULL"
);
return;
}
$placeholders = implode(', ', array_fill(0, count($slugs), '?'));
$stmt = $this->db->pdo()->prepare(
"UPDATE tickets SET color = NULL
WHERE repo IS NOT NULL AND color IS NOT NULL AND repo NOT IN ($placeholders)"
);
$stmt->execute($slugs);
}
/**
* Billiger "Fingerabdruck" (Anzahl + juengster Aenderungszeitpunkt) fuer den SSE-Endpoint
* (Realtime\ChangeFeed, F13) - aendert sich bei jedem Anlegen/Verschieben eines Tickets.

View file

@ -42,9 +42,19 @@ final class CodebergSyncService
*/
public function sync(): void
{
foreach ($this->repoConfigs->all() as $repoConfig) {
$repoConfigs = $this->repoConfigs->all();
foreach ($repoConfigs as $repoConfig) {
$this->syncRepo($repoConfig['owner'], $repoConfig['repo'], $repoConfig['color']);
}
// Issue #34: Tickets aus zwischenzeitlich entfernten oder umbenannten Projekten werden
// oben nicht mehr angefasst und wuerden sonst dauerhaft in der alten, nicht mehr
// zutreffenden Projektfarbe angezeigt.
$this->tickets->clearColorForReposNotIn(array_map(
static fn (array $repoConfig): string => $repoConfig['owner'] . '/' . $repoConfig['repo'],
$repoConfigs
));
}
private function syncRepo(string $owner, string $repo, string $color): void

View file

@ -164,4 +164,33 @@ final class TicketRepositoryTest extends TestCase
self::assertSame($this->repository->fingerprint(), $this->repository->fingerprint());
}
public function testClearColorForReposNotInRemovesColorFromOrphanedRepo(): void
{
$kept = $this->repository->create(['title' => 'A', 'repo' => 'fds2610/monitor', 'color' => '#fbca04']);
$orphaned = $this->repository->create(['title' => 'B', 'repo' => 'fds2610/altes-projekt', 'color' => '#3b82f6']);
$this->repository->clearColorForReposNotIn(['fds2610/monitor']);
self::assertSame('#fbca04', $this->repository->find((int) $kept['id'])['color']);
self::assertNull($this->repository->find((int) $orphaned['id'])['color']);
}
public function testClearColorForReposNotInIgnoresTicketsWithoutRepo(): void
{
$manual = $this->repository->create(['title' => 'API-Ticket', 'color' => '#ffffff']);
$this->repository->clearColorForReposNotIn(['fds2610/monitor']);
self::assertSame('#ffffff', $this->repository->find((int) $manual['id'])['color']);
}
public function testClearColorForReposNotInClearsAllColorsWhenNoRepoConfigured(): void
{
$ticket = $this->repository->create(['title' => 'B', 'repo' => 'fds2610/altes-projekt', 'color' => '#3b82f6']);
$this->repository->clearColorForReposNotIn([]);
self::assertNull($this->repository->find((int) $ticket['id'])['color']);
}
}

View file

@ -117,6 +117,26 @@ final class CodebergSyncServiceTest extends TestCase
self::assertSame('#28a745', $steuerkramTicket['color']);
}
public function testSyncClearsColorOfTicketsFromRemovedProject(): void
{
$tickets = new TicketRepository(Database::inMemory());
$client = self::clientForMonitor([
'open' => [['number' => 1, 'title' => 'Issue', 'body' => null, 'labels' => []]],
'closed' => [],
]);
(new CodebergSyncService($client, $tickets, self::repoConfigsFor([self::MONITOR_REPO])))->sync();
self::assertSame('#fbca04', $tickets->findByExternalRef('1', self::MONITOR_SLUG)['color']);
// Projekt wurde im Projekte-Modal entfernt (Issue #34): der naechste Sync-Lauf sieht
// es nicht mehr in repoConfigsFor() und darf das verwaiste Ticket nicht laenger blau
// faerben, obwohl es kein Projekt mit dieser Farbe mehr gibt.
$client = new FakeCodebergClient([]);
(new CodebergSyncService($client, $tickets, self::repoConfigsFor([])))->sync();
self::assertNull($tickets->findByExternalRef('1', self::MONITOR_SLUG)['color']);
}
public function testSyncDoesNotResetManuallyMovedTicket(): void
{
$tickets = new TicketRepository(Database::inMemory());