fix(gitea) : propagate API errors instead of silently returning empty results

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 18:58:55 +01:00
parent 63e4af785e
commit 4c19b68156
5 changed files with 36 additions and 11 deletions

View File

@@ -61,7 +61,7 @@
<!-- Error state --> <!-- Error state -->
<div v-if="error" class="px-4 py-3"> <div v-if="error" class="px-4 py-3">
<p class="text-xs text-red-500">{{ $t('gitea.error') }}</p> <p class="text-xs text-red-500">{{ error }}</p>
</div> </div>
<!-- Create branch form (inline) --> <!-- Create branch form (inline) -->
@@ -248,7 +248,7 @@ const pullRequests = ref<GiteaPullRequest[]>([])
const isLoading = ref(true) const isLoading = ref(true)
const isLoadingPrs = ref(true) const isLoadingPrs = ref(true)
const isCreating = ref(false) const isCreating = ref(false)
const error = ref(false) const error = ref('')
const showCreateForm = ref(false) const showCreateForm = ref(false)
const expandedBranches = ref(new Set<string>()) const expandedBranches = ref(new Set<string>())
@@ -338,7 +338,7 @@ async function loadData() {
isLoading.value = true isLoading.value = true
isLoadingPrs.value = true isLoadingPrs.value = true
error.value = false error.value = ''
try { try {
branches.value = await listBranches(props.task.id) branches.value = await listBranches(props.task.id)
@@ -346,8 +346,8 @@ async function loadData() {
if (branches.value.length === 1) { if (branches.value.length === 1) {
expandedBranches.value.add(branches.value[0].name) expandedBranches.value.add(branches.value[0].name)
} }
} catch { } catch (e: any) {
error.value = true error.value = e?.data?.detail || e?.data?.['hydra:description'] || t('gitea.error')
} finally { } finally {
isLoading.value = false isLoading.value = false
} }

View File

@@ -12,6 +12,7 @@ use App\Repository\GiteaConfigurationRepository;
use Symfony\Component\String\Slugger\AsciiSlugger; use Symfony\Component\String\Slugger\AsciiSlugger;
use Symfony\Component\String\Slugger\SluggerInterface; use Symfony\Component\String\Slugger\SluggerInterface;
use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\HttpClientInterface;
use Throwable; use Throwable;
@@ -215,6 +216,22 @@ final readonly class GiteaApiService
} }
} }
private function extractGiteaError(HttpExceptionInterface $e): string
{
try {
$body = $e->getResponse()->getContent(false);
$data = json_decode($body, true);
if (is_array($data)) {
return $data['message'] ?? $data['error'] ?? $body;
}
return $body ?: 'Unknown Gitea error';
} catch (ExceptionInterface) {
return 'Gitea API error (HTTP '.$e->getResponse()->getStatusCode().')';
}
}
private function assertProjectHasRepo(Project $project): void private function assertProjectHasRepo(Project $project): void
{ {
if (!$project->hasGiteaRepo()) { if (!$project->hasGiteaRepo()) {
@@ -240,6 +257,10 @@ final readonly class GiteaApiService
$response = $this->httpClient->request($method, rtrim($config->getUrl(), '/').$path, $options); $response = $this->httpClient->request($method, rtrim($config->getUrl(), '/').$path, $options);
return $response->toArray(); return $response->toArray();
} catch (HttpExceptionInterface $e) {
$message = $this->extractGiteaError($e);
throw new GiteaApiException($message, $e->getResponse()->getStatusCode(), $e);
} catch (ExceptionInterface $e) { } catch (ExceptionInterface $e) {
throw new GiteaApiException('Gitea API error: '.$e->getMessage(), 0, $e); throw new GiteaApiException('Gitea API error: '.$e->getMessage(), 0, $e);
} }

View File

@@ -12,6 +12,7 @@ use App\Entity\Task;
use App\Exception\GiteaApiException; use App\Exception\GiteaApiException;
use App\Service\GiteaApiService; use App\Service\GiteaApiService;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
final readonly class GiteaBranchProvider implements ProviderInterface final readonly class GiteaBranchProvider implements ProviderInterface
{ {
@@ -40,8 +41,8 @@ final readonly class GiteaBranchProvider implements ProviderInterface
try { try {
$branches = $this->giteaApiService->listBranches($project, $taskCode); $branches = $this->giteaApiService->listBranches($project, $taskCode);
} catch (GiteaApiException) { } catch (GiteaApiException $e) {
return []; throw new BadRequestHttpException($e->getMessage(), $e);
} }
$result = []; $result = [];
@@ -58,6 +59,7 @@ final readonly class GiteaBranchProvider implements ProviderInterface
'date' => $c['commit']['author']['date'] ?? $c['created'] ?? '', 'date' => $c['commit']['author']['date'] ?? $c['created'] ?? '',
], $commits); ], $commits);
} catch (GiteaApiException) { } catch (GiteaApiException) {
// Commits fetch failure should not block branch listing
$dto->commits = []; $dto->commits = [];
} }

View File

@@ -11,6 +11,7 @@ use App\Entity\Task;
use App\Exception\GiteaApiException; use App\Exception\GiteaApiException;
use App\Service\GiteaApiService; use App\Service\GiteaApiService;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
final readonly class GiteaPullRequestProvider implements ProviderInterface final readonly class GiteaPullRequestProvider implements ProviderInterface
{ {
@@ -35,8 +36,8 @@ final readonly class GiteaPullRequestProvider implements ProviderInterface
try { try {
$prs = $this->giteaApiService->listPullRequests($project, $taskCode); $prs = $this->giteaApiService->listPullRequests($project, $taskCode);
} catch (GiteaApiException) { } catch (GiteaApiException $e) {
return []; throw new BadRequestHttpException($e->getMessage(), $e);
} }
return array_map(static function (array $pr): GiteaPullRequest { return array_map(static function (array $pr): GiteaPullRequest {

View File

@@ -9,6 +9,7 @@ use ApiPlatform\State\ProviderInterface;
use App\ApiResource\GiteaRepository; use App\ApiResource\GiteaRepository;
use App\Exception\GiteaApiException; use App\Exception\GiteaApiException;
use App\Service\GiteaApiService; use App\Service\GiteaApiService;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
final readonly class GiteaRepositoryProvider implements ProviderInterface final readonly class GiteaRepositoryProvider implements ProviderInterface
{ {
@@ -20,8 +21,8 @@ final readonly class GiteaRepositoryProvider implements ProviderInterface
{ {
try { try {
$repos = $this->giteaApiService->listRepositories(); $repos = $this->giteaApiService->listRepositories();
} catch (GiteaApiException) { } catch (GiteaApiException $e) {
return []; throw new BadRequestHttpException($e->getMessage(), $e);
} }
return array_map(static function (array $repo): GiteaRepository { return array_map(static function (array $repo): GiteaRepository {