Klick auf den PO oeffnet ein Modal, in dem sich die Projekte (Owner/Repo + Farbe), aus denen der Codeberg-Sync liest, hinzufuegen, bearbeiten und loeschen lassen - Icon-Schaltflaechen mit Tooltip statt Textbuttons. Die Projektliste war bisher eine Umgebungsvariable (CODEBERG_REPOS, Issue #26) und wandert dafuer in eine neue Tabelle repo_configs (Migration 003_repo_configs.sql, geseedet mit den bisherigen drei Default-Projekten); CodebergSyncService liest sie ueber RepoConfigRepository bei jedem Lauf frisch ein, damit eine Aenderung im laufenden --watch-Prozess ohne Neustart wirkt. Neue Endpunkte GET/POST/PATCH/DELETE /api/v1/repo-configs, Schreiben hinter X-Admin-Key wie die Agenten-Registrierung; das Frontend fragt den Key bei der ersten Aenderung per Prompt ab und merkt ihn sich im lokalen Speicher. office-modal.js bekommt dafuer einen Oeffnen-Token (isCurrentModal()), damit ein verspaetet aufloesender Request nach dem Oeffnen eines anderen Modals nicht dessen Inhalt ueberschreibt. Schliesst #27
99 lines
3.1 KiB
PHP
99 lines
3.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Monitor\Api\Tests\Repository;
|
|
|
|
use InvalidArgumentException;
|
|
use Monitor\Api\Db\Database;
|
|
use Monitor\Api\Http\NotFoundException;
|
|
use Monitor\Api\Repository\RepoConfigRepository;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class RepoConfigRepositoryTest extends TestCase
|
|
{
|
|
private RepoConfigRepository $repository;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$db = Database::inMemory();
|
|
$db->pdo()->exec('DELETE FROM repo_configs');
|
|
$this->repository = new RepoConfigRepository($db);
|
|
}
|
|
|
|
public function testAllIsEmptyWithoutConfiguredProjects(): void
|
|
{
|
|
self::assertSame([], $this->repository->all());
|
|
}
|
|
|
|
public function testCreateNormalizesColorAndAppendsAtEndOfSortOrder(): void
|
|
{
|
|
$first = $this->repository->create(['owner' => 'fds2610', 'repo' => 'monitor', 'color' => 'fbca04']);
|
|
$second = $this->repository->create(['owner' => 'fds2610', 'repo' => 'Steuerkram', 'color' => '#28A745']);
|
|
|
|
self::assertSame('#fbca04', $first['color']);
|
|
self::assertSame('#28A745', $second['color']);
|
|
self::assertSame([$first['id'], $second['id']], array_map(
|
|
static fn (array $r): int => (int) $r['id'],
|
|
$this->repository->all()
|
|
));
|
|
}
|
|
|
|
public function testCreateRejectsMissingOwnerOrRepo(): void
|
|
{
|
|
$this->expectException(InvalidArgumentException::class);
|
|
|
|
$this->repository->create(['owner' => '', 'repo' => 'monitor', 'color' => '#fbca04']);
|
|
}
|
|
|
|
public function testCreateRejectsInvalidColor(): void
|
|
{
|
|
$this->expectException(InvalidArgumentException::class);
|
|
|
|
$this->repository->create(['owner' => 'fds2610', 'repo' => 'monitor', 'color' => 'nicht-hex']);
|
|
}
|
|
|
|
public function testCreateRejectsDuplicateOwnerRepo(): void
|
|
{
|
|
$this->repository->create(['owner' => 'fds2610', 'repo' => 'monitor', 'color' => '#fbca04']);
|
|
|
|
$this->expectException(InvalidArgumentException::class);
|
|
$this->repository->create(['owner' => 'fds2610', 'repo' => 'monitor', 'color' => '#000000']);
|
|
}
|
|
|
|
public function testUpdateChangesFields(): void
|
|
{
|
|
$repo = $this->repository->create(['owner' => 'fds2610', 'repo' => 'monitor', 'color' => '#fbca04']);
|
|
|
|
$updated = $this->repository->update((int) $repo['id'], [
|
|
'owner' => 'fds2610',
|
|
'repo' => 'monitor',
|
|
'color' => '#000000',
|
|
]);
|
|
|
|
self::assertSame('#000000', $updated['color']);
|
|
}
|
|
|
|
public function testUpdateUnknownIdThrowsNotFound(): void
|
|
{
|
|
$this->expectException(NotFoundException::class);
|
|
|
|
$this->repository->update(999, ['owner' => 'a', 'repo' => 'b', 'color' => '#000000']);
|
|
}
|
|
|
|
public function testDeleteRemovesEntry(): void
|
|
{
|
|
$repo = $this->repository->create(['owner' => 'fds2610', 'repo' => 'monitor', 'color' => '#fbca04']);
|
|
|
|
$this->repository->delete((int) $repo['id']);
|
|
|
|
self::assertSame([], $this->repository->all());
|
|
}
|
|
|
|
public function testDeleteUnknownIdThrowsNotFound(): void
|
|
{
|
|
$this->expectException(NotFoundException::class);
|
|
|
|
$this->repository->delete(999);
|
|
}
|
|
}
|