Skip to content

Commit 6a17872

Browse files
chore(pkgsiteapi): update client to v1 OpenAPI spec (#27)
1 parent 6fb573e commit 6a17872

7 files changed

Lines changed: 1173 additions & 623 deletions

File tree

internal/pkgsite/client.go

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -252,25 +252,107 @@ func resultError(statusCode int, status string, body []byte, resp *http.Response
252252
return Result{Error: &APIError{StatusCode: statusCode, Status: status, Message: message, Body: raw}, UpstreamURL: requestURL(resp), FromCache: fromCache(resp)}
253253
}
254254

255-
func paginatedItems(page *pkgsiteapi.PaginatedResponse) []map[string]any {
256-
if page == nil || page.Items == nil {
255+
func paginatedItems(page any) []map[string]any {
256+
switch page := page.(type) {
257+
case *pkgsiteapi.PaginatedResponseModuleVersion:
258+
if page == nil {
259+
return nil
260+
}
261+
return objectItems(page.Items)
262+
case *pkgsiteapi.PaginatedResponsePackageInfo:
263+
if page == nil {
264+
return nil
265+
}
266+
return objectItems(page.Items)
267+
case *pkgsiteapi.PaginatedResponseSearchResult:
268+
if page == nil {
269+
return nil
270+
}
271+
return objectItems(page.Items)
272+
case *pkgsiteapi.PaginatedResponseSymbol:
273+
if page == nil {
274+
return nil
275+
}
276+
return objectItems(page.Items)
277+
case *pkgsiteapi.PaginatedResponseVulnerability:
278+
if page == nil {
279+
return nil
280+
}
281+
return objectItems(page.Items)
282+
case *pkgsiteapi.PaginatedResponseString:
283+
if page == nil || page.Items == nil {
284+
return nil
285+
}
286+
items := make([]map[string]any, 0, len(*page.Items))
287+
for _, item := range *page.Items {
288+
items = append(items, map[string]any{"path": item})
289+
}
290+
return items
291+
default:
257292
return nil
258293
}
259-
return *page.Items
260294
}
261295

262-
func pagination(page *pkgsiteapi.PaginatedResponse, count int) map[string]any {
296+
func pagination(page any, count int) map[string]any {
263297
total := count
264298
next := ""
265-
if page != nil {
266-
if page.Total != nil {
267-
total = *page.Total
299+
pageTotal, pageNext := pageMetadata(page)
300+
if pageTotal != nil {
301+
total = *pageTotal
302+
}
303+
if pageNext != nil {
304+
next = *pageNext
305+
}
306+
return map[string]any{"total": total, "displayedItems": count, "startAt": 0, "nextStartAt": nil, "upstreamNextPageToken": next}
307+
}
308+
309+
func pageMetadata(page any) (total *int, next *string) {
310+
switch page := page.(type) {
311+
case *pkgsiteapi.PaginatedResponseModuleVersion:
312+
if page != nil {
313+
return page.Total, page.NextPageToken
314+
}
315+
case *pkgsiteapi.PaginatedResponsePackageInfo:
316+
if page != nil {
317+
return page.Total, page.NextPageToken
268318
}
269-
if page.NextPageToken != nil {
270-
next = *page.NextPageToken
319+
case *pkgsiteapi.PaginatedResponseSearchResult:
320+
if page != nil {
321+
return page.Total, page.NextPageToken
322+
}
323+
case *pkgsiteapi.PaginatedResponseSymbol:
324+
if page != nil {
325+
return page.Total, page.NextPageToken
326+
}
327+
case *pkgsiteapi.PaginatedResponseVulnerability:
328+
if page != nil {
329+
return page.Total, page.NextPageToken
330+
}
331+
case *pkgsiteapi.PaginatedResponseString:
332+
if page != nil {
333+
return page.Total, page.NextPageToken
271334
}
272335
}
273-
return map[string]any{"total": total, "displayedItems": count, "startAt": 0, "nextStartAt": nil, "upstreamNextPageToken": next}
336+
return nil, nil
337+
}
338+
339+
func objectItems[T any](items *[]T) []map[string]any {
340+
if items == nil {
341+
return nil
342+
}
343+
result := make([]map[string]any, 0, len(*items))
344+
for _, item := range *items {
345+
value := map[string]any{}
346+
data, err := json.Marshal(item)
347+
if err != nil {
348+
continue
349+
}
350+
if err := json.Unmarshal(data, &value); err != nil {
351+
continue
352+
}
353+
result = append(result, value)
354+
}
355+
return result
274356
}
275357

276358
func optionalString(v string) *string {

internal/pkgsite/client_test.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,9 @@ func TestClientSearchSuccessFromFakeUpstream(t *testing.T) {
186186
"total": 1,
187187
"items": []map[string]any{
188188
{
189-
"name": "uuid",
190-
"path": "github.com/google/uuid",
191-
"modulePath": "github.com/google/uuid",
192-
"version": "v1.6.0",
189+
"packagePath": "github.com/google/uuid",
190+
"modulePath": "github.com/google/uuid",
191+
"version": "v1.6.0",
193192
},
194193
},
195194
})
@@ -211,7 +210,7 @@ func TestClientSearchSuccessFromFakeUpstream(t *testing.T) {
211210
"symbol": "",
212211
"count": 1,
213212
})
214-
assertItemNames(t, got.Items, []string{"uuid"})
213+
assertItemPackagePaths(t, got.Items, []string{"github.com/google/uuid"})
215214
assertPagination(t, got, 1, 1, "")
216215
}
217216

@@ -225,9 +224,9 @@ func TestClientSearchSingleResultSchedulesPackageWarm(t *testing.T) {
225224
writeJSON(t, w, http.StatusOK, map[string]any{
226225
"total": 1,
227226
"items": []map[string]any{{
228-
"path": "github.com/google/uuid",
229-
"modulePath": "github.com/google/uuid",
230-
"version": "v1.6.0",
227+
"packagePath": "github.com/google/uuid",
228+
"modulePath": "github.com/google/uuid",
229+
"version": "v1.6.0",
231230
}},
232231
})
233232
}, WithWarmer(warmer))
@@ -251,8 +250,8 @@ func TestClientSearchMultipleResultsDoesNotWarm(t *testing.T) {
251250
writeJSON(t, w, http.StatusOK, map[string]any{
252251
"total": 2,
253252
"items": []map[string]any{
254-
{"path": "example.com/one"},
255-
{"path": "example.com/two"},
253+
{"packagePath": "example.com/one"},
254+
{"packagePath": "example.com/two"},
256255
},
257256
})
258257
}, WithWarmer(warmer))
@@ -319,7 +318,7 @@ func TestClientUpstream4xxReturnsStructuredResultError(t *testing.T) {
319318
name: "module not found",
320319
status: http.StatusNotFound,
321320
body: map[string]any{
322-
"code": "not_found",
321+
"code": http.StatusNotFound,
323322
"message": "module not found",
324323
},
325324
callFunc: func(t *testing.T, client *Client) (Result, error) {
@@ -331,7 +330,7 @@ func TestClientUpstream4xxReturnsStructuredResultError(t *testing.T) {
331330
name: "search bad request",
332331
status: http.StatusBadRequest,
333332
body: map[string]any{
334-
"code": "bad_request",
333+
"code": http.StatusBadRequest,
335334
"message": "missing query",
336335
},
337336
callFunc: func(t *testing.T, client *Client) (Result, error) {
@@ -367,7 +366,7 @@ func TestClientUpstream4xxReturnsStructuredResultError(t *testing.T) {
367366
if !json.Valid(got.Error.Body) {
368367
t.Fatalf("Result.Error.Body is not valid JSON: %q", string(got.Error.Body))
369368
}
370-
for _, want := range []string{tt.body["code"].(string), tt.body["message"].(string)} {
369+
for _, want := range []string{fmt.Sprint(tt.body["code"]), tt.body["message"].(string)} {
371370
if !strings.Contains(got.Error.Message, want) {
372371
t.Fatalf("message %q does not contain %q", got.Error.Message, want)
373372
}
@@ -623,6 +622,22 @@ func assertItemNames(t testing.TB, items []map[string]any, want []string) {
623622
}
624623
}
625624

625+
func assertItemPackagePaths(t testing.TB, items []map[string]any, want []string) {
626+
t.Helper()
627+
628+
got := make([]string, 0, len(items))
629+
for _, item := range items {
630+
path, ok := item["packagePath"].(string)
631+
if !ok {
632+
t.Fatalf("item package path = %#v, want string", item["packagePath"])
633+
}
634+
got = append(got, path)
635+
}
636+
if !slices.Equal(got, want) {
637+
t.Fatalf("item package paths = %#v, want %#v", got, want)
638+
}
639+
}
640+
626641
func assertItemPaths(t testing.TB, items []map[string]any, want []string) {
627642
t.Helper()
628643

internal/pkgsite/pagination_test.go

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ func TestPaginationMetadata(t *testing.T) {
1212

1313
tests := []struct {
1414
name string
15-
page *pkgsiteapi.PaginatedResponse
15+
page any
1616
count int
1717
want map[string]any
1818
}{
1919
{
2020
name: "upstream total and next token",
21-
page: &pkgsiteapi.PaginatedResponse{
21+
page: &pkgsiteapi.PaginatedResponseSymbol{
2222
NextPageToken: new("next-page-token"),
2323
Total: new(42),
2424
},
@@ -45,7 +45,7 @@ func TestPaginationMetadata(t *testing.T) {
4545
},
4646
{
4747
name: "missing upstream token is empty string",
48-
page: &pkgsiteapi.PaginatedResponse{},
48+
page: &pkgsiteapi.PaginatedResponseSymbol{},
4949
count: 0,
5050
want: map[string]any{
5151
"total": 0,
@@ -74,16 +74,16 @@ func TestPaginatedItems(t *testing.T) {
7474

7575
tests := []struct {
7676
name string
77-
page *pkgsiteapi.PaginatedResponse
77+
page any
7878
want []map[string]any
7979
}{
8080
{name: "nil page", page: nil, want: nil},
81-
{name: "nil items", page: &pkgsiteapi.PaginatedResponse{}, want: nil},
81+
{name: "nil items", page: &pkgsiteapi.PaginatedResponseSymbol{}, want: nil},
8282
{
8383
name: "items",
84-
page: &pkgsiteapi.PaginatedResponse{Items: &[]map[string]any{
85-
{"name": "Config"},
86-
{"name": "Token"},
84+
page: &pkgsiteapi.PaginatedResponseSymbol{Items: &[]pkgsiteapi.Symbol{
85+
{Name: new("Config")},
86+
{Name: new("Token")},
8787
}},
8888
want: []map[string]any{
8989
{"name": "Config"},
@@ -103,3 +103,64 @@ func TestPaginatedItems(t *testing.T) {
103103
})
104104
}
105105
}
106+
107+
func TestPaginatedItemsUsesGeneratedModels(t *testing.T) {
108+
t.Parallel()
109+
110+
tests := []struct {
111+
name string
112+
page any
113+
want []map[string]any
114+
}{
115+
{
116+
name: "module versions",
117+
page: &pkgsiteapi.PaginatedResponseModuleVersion{Items: &[]pkgsiteapi.ModuleVersion{{
118+
ModulePath: new("example.com/module"), LatestVersion: new("v1.2.3"),
119+
}}},
120+
want: []map[string]any{{"modulePath": "example.com/module", "latestVersion": "v1.2.3"}},
121+
},
122+
{
123+
name: "package info",
124+
page: &pkgsiteapi.PaginatedResponsePackageInfo{Items: &[]pkgsiteapi.PackageInfo{{
125+
Path: new("example.com/module/pkg"), Name: new("pkg"),
126+
}}},
127+
want: []map[string]any{{"name": "pkg", "path": "example.com/module/pkg"}},
128+
},
129+
{
130+
name: "search results",
131+
page: &pkgsiteapi.PaginatedResponseSearchResult{Items: &[]pkgsiteapi.SearchResult{{
132+
PackagePath: new("example.com/module/pkg"), ModulePath: new("example.com/module"),
133+
}}},
134+
want: []map[string]any{{"modulePath": "example.com/module", "packagePath": "example.com/module/pkg"}},
135+
},
136+
{
137+
name: "symbols",
138+
page: &pkgsiteapi.PaginatedResponseSymbol{Items: &[]pkgsiteapi.Symbol{{
139+
Name: new("Config"), Kind: new("Type"),
140+
}}},
141+
want: []map[string]any{{"kind": "Type", "name": "Config"}},
142+
},
143+
{
144+
name: "vulnerabilities",
145+
page: &pkgsiteapi.PaginatedResponseVulnerability{Items: &[]pkgsiteapi.Vulnerability{{
146+
Id: new("GO-2026-0001"), Summary: new("example vulnerability"),
147+
}}},
148+
want: []map[string]any{{"id": "GO-2026-0001", "summary": "example vulnerability"}},
149+
},
150+
{
151+
name: "strings",
152+
page: &pkgsiteapi.PaginatedResponseString{Items: &[]string{"example.com/importer"}},
153+
want: []map[string]any{{"path": "example.com/importer"}},
154+
},
155+
}
156+
157+
for _, tt := range tests {
158+
t.Run(tt.name, func(t *testing.T) {
159+
t.Parallel()
160+
161+
if got := paginatedItems(tt.page); !reflect.DeepEqual(got, tt.want) {
162+
t.Fatalf("paginatedItems() = %#v, want %#v", got, tt.want)
163+
}
164+
})
165+
}
166+
}

0 commit comments

Comments
 (0)