feat(gitea): typed error mapping from http status

This commit is contained in:
Mathias Bergqvist
2026-05-04 21:26:29 +02:00
parent 2ecffd1b7a
commit d564cdcae3
2 changed files with 68 additions and 0 deletions

34
internal/gitea/errors.go Normal file
View File

@@ -0,0 +1,34 @@
package gitea
import (
"errors"
"fmt"
)
var (
ErrPermissionDenied = errors.New("permission denied")
ErrNotFound = errors.New("not found")
ErrConflict = errors.New("conflict")
ErrValidation = errors.New("validation failed")
ErrUpstream = errors.New("upstream gitea error")
)
// MapStatus returns nil for 2xx, otherwise a typed error wrapping the response body.
func MapStatus(status int, body []byte) error {
if status >= 200 && status < 300 {
return nil
}
switch {
case status == 401, status == 403:
return fmt.Errorf("%w: %s", ErrPermissionDenied, body)
case status == 404:
return fmt.Errorf("%w: %s", ErrNotFound, body)
case status == 409:
return fmt.Errorf("%w: %s", ErrConflict, body)
case status == 422:
return fmt.Errorf("%w: %s", ErrValidation, body)
case status >= 500:
return fmt.Errorf("%w (status %d)", ErrUpstream, status)
}
return fmt.Errorf("unexpected status %d: %s", status, body)
}

View File

@@ -0,0 +1,34 @@
package gitea_test
import (
"errors"
"testing"
"gitea.d-ma.be/mathias/gitea-mcp/internal/gitea"
"github.com/stretchr/testify/assert"
)
func TestMapStatus(t *testing.T) {
cases := []struct {
status int
want error
}{
{401, gitea.ErrPermissionDenied},
{403, gitea.ErrPermissionDenied},
{404, gitea.ErrNotFound},
{409, gitea.ErrConflict},
{422, gitea.ErrValidation},
{500, gitea.ErrUpstream},
{502, gitea.ErrUpstream},
{200, nil},
{299, nil},
}
for _, tc := range cases {
got := gitea.MapStatus(tc.status, []byte(`{"message":"x"}`))
if tc.want == nil {
assert.NoError(t, got)
} else {
assert.True(t, errors.Is(got, tc.want), "status %d", tc.status)
}
}
}