Reuse ListSentryOrganizations in Sentry driver

SentryDriver.resolveOrgSlug duplicated the same /organizations/?member=true
call already implemented in ListSentryOrganizations, which is consumed by
the OAuth org picker. Delegating to the shared helper prevents the two
call sites from drifting (response shape, header set, pagination) and
keeps the driver focused on member listing.

Pure refactor: no behavior change. Add an httptest-backed smoke test
covering the empty-stored-slug path end-to-end through ListAccounts so
the auto-discovery flow stays exercised after the refactor.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
This commit is contained in:
Aurélien Sibiril
2026-05-28 19:21:05 +02:00
parent 5e78b11f08
commit 036cd3306e
2 changed files with 35 additions and 22 deletions

View File

@@ -64,29 +64,9 @@ func NewSentryDriver(httpClient *http.Client, orgSlug string) *SentryDriver {
}
func (d *SentryDriver) resolveOrgSlug(ctx context.Context) (string, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://sentry.io/api/0/organizations/?member=true", nil)
orgs, err := ListSentryOrganizations(ctx, d.httpClient)
if err != nil {
return "", fmt.Errorf("cannot create sentry organizations request: %w", err)
}
req.Header.Set("Accept", "application/json")
resp, err := d.httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("cannot fetch sentry organizations: %w", err)
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("cannot fetch sentry organizations: status %d", resp.StatusCode)
}
var orgs []struct {
Slug string `json:"slug"`
}
if err := json.NewDecoder(resp.Body).Decode(&orgs); err != nil {
return "", fmt.Errorf("cannot decode sentry organizations response: %w", err)
return "", fmt.Errorf("cannot resolve sentry organization slug: %w", err)
}
if len(orgs) == 0 {

View File

@@ -16,6 +16,8 @@ package drivers
import (
"context"
"net/http"
"net/http/httptest"
"os"
"testing"
@@ -45,3 +47,34 @@ func TestSentryDriver(t *testing.T) {
assert.NotEmpty(t, r.ExternalID)
assert.NotEmpty(t, r.Role)
}
func TestSentryDriverListAccountsAutoDiscoversSlug(t *testing.T) {
t.Parallel()
const discoveredSlug = "discovered-org"
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
switch r.URL.Path {
case "/api/0/organizations/":
assert.Equal(t, "true", r.URL.Query().Get("member"))
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`[{"slug":"` + discoveredSlug + `","name":"Discovered Org"}]`))
case "/api/0/organizations/" + discoveredSlug + "/members":
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`[{"id":"42","email":"alice@example.com","name":"Alice","orgRole":"member"}]`))
default:
t.Errorf("unexpected request to %s", r.URL.Path)
w.WriteHeader(http.StatusNotFound)
}
}))
defer srv.Close()
client := &http.Client{Transport: &hostRewriter{target: srv.URL}}
records, err := NewSentryDriver(client, "").ListAccounts(context.Background())
require.NoError(t, err)
require.Len(t, records, 1)
assert.Equal(t, "alice@example.com", records[0].Email)
}