Skip to content

Commit a0a6a1a

Browse files
stainless-app[bot]yjp20
authored andcommitted
feat(cli): automatic streaming for paginated endpoints
1 parent 4d83172 commit a0a6a1a

File tree

15 files changed

+344
-152
lines changed

15 files changed

+344
-152
lines changed

cmd/stl/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func main() {
2222
fmt.Fprintf(os.Stderr, "%s %q: %d %s\n", apierr.Request.Method, apierr.Request.URL, apierr.Response.StatusCode, http.StatusText(apierr.Response.StatusCode))
2323
format := app.String("format-error")
2424
json := gjson.Parse(apierr.RawJSON())
25-
show_err := cmd.ShowJSON("Error", json, format, app.String("transform-error"))
25+
show_err := cmd.ShowJSON(os.Stdout, "Error", json, format, app.String("transform-error"))
2626
if show_err != nil {
2727
// Just print the original error:
2828
fmt.Fprintf(os.Stderr, "%s\n", err.Error())

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ require (
2020
github.com/tidwall/pretty v1.2.1
2121
github.com/urfave/cli-docs/v3 v3.0.0-alpha6
2222
github.com/urfave/cli/v3 v3.3.2
23+
golang.org/x/sys v0.38.0
2324
golang.org/x/term v0.37.0
2425
golang.org/x/text v0.24.0
2526
)
@@ -56,6 +57,5 @@ require (
5657
github.com/yuin/goldmark v1.7.8 // indirect
5758
github.com/yuin/goldmark-emoji v1.0.5 // indirect
5859
golang.org/x/net v0.33.0 // indirect
59-
golang.org/x/sync v0.13.0 // indirect
60-
golang.org/x/sys v0.38.0 // indirect
60+
golang.org/x/sync v0.15.0 // indirect
6161
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM
130130
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
131131
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
132132
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
133-
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
134-
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
133+
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
134+
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
135135
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
136136
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
137137
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

pkg/cmd/build.go

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ var buildsList = cli.Command{
172172
&requestflag.YAMLFlag{
173173
Name: "revision",
174174
Usage: "A config commit SHA used for the build",
175+
Value: requestflag.Value[any](map[string]any{}),
175176
Config: requestflag.RequestConfig{
176177
QueryPath: "revision",
177178
},
@@ -217,6 +218,7 @@ func handleBuildsCreate(ctx context.Context, cmd *cli.Command) error {
217218
client := stainless.NewClient(getDefaultRequestOptions(cmd)...)
218219

219220
unusedArgs := cmd.Args().Slice()
221+
220222
if len(unusedArgs) > 0 {
221223
return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs)
222224
}
@@ -314,7 +316,7 @@ func handleBuildsCreate(ctx context.Context, cmd *cli.Command) error {
314316
data := gjson.Parse(string(build.RawJSON()))
315317
format := cmd.Root().String("format")
316318
transform := cmd.Root().String("transform")
317-
if err := ShowJSON("builds create", data, format, transform); err != nil {
319+
if err := ShowJSON(os.Stdout, "builds create", data, format, transform); err != nil {
318320
return err
319321
}
320322

@@ -400,26 +402,24 @@ func handleBuildsRetrieve(ctx context.Context, cmd *cli.Command) error {
400402
if err != nil {
401403
return err
402404
}
405+
403406
var res []byte
404407
options = append(options, option.WithResponseBodyInto(&res))
405-
_, err = client.Builds.Get(
406-
ctx,
407-
requestflag.CommandRequestValue[string](cmd, "build-id"),
408-
options...,
409-
)
408+
_, err = client.Builds.Get(ctx, requestflag.CommandRequestValue[string](cmd, "build-id"), options...)
410409
if err != nil {
411410
return err
412411
}
413412

414-
json := gjson.Parse(string(res))
413+
obj := gjson.ParseBytes(res)
415414
format := cmd.Root().String("format")
416415
transform := cmd.Root().String("transform")
417-
return ShowJSON("builds retrieve", json, format, transform)
416+
return ShowJSON(os.Stdout, "builds retrieve", obj, format, transform)
418417
}
419418

420419
func handleBuildsList(ctx context.Context, cmd *cli.Command) error {
421420
client := stainless.NewClient(getDefaultRequestOptions(cmd)...)
422421
unusedArgs := cmd.Args().Slice()
422+
423423
if len(unusedArgs) > 0 {
424424
return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs)
425425
}
@@ -434,26 +434,37 @@ func handleBuildsList(ctx context.Context, cmd *cli.Command) error {
434434
if err != nil {
435435
return err
436436
}
437-
var res []byte
438-
options = append(options, option.WithResponseBodyInto(&res))
439-
_, err = client.Builds.List(
440-
ctx,
441-
params,
442-
options...,
443-
)
444-
if err != nil {
445-
return err
446-
}
447437

448-
json := gjson.Parse(string(res))
449438
format := cmd.Root().String("format")
450439
transform := cmd.Root().String("transform")
451-
return ShowJSON("builds list", json, format, transform)
440+
if format == "raw" {
441+
var res []byte
442+
options = append(options, option.WithResponseBodyInto(&res))
443+
_, err = client.Builds.List(ctx, params, options...)
444+
if err != nil {
445+
return err
446+
}
447+
obj := gjson.ParseBytes(res)
448+
return ShowJSON(os.Stdout, "builds list", obj, format, transform)
449+
} else {
450+
iter := client.Builds.ListAutoPaging(ctx, params, options...)
451+
return streamOutput("builds list", func(w *os.File) error {
452+
for iter.Next() {
453+
item := iter.Current()
454+
obj := gjson.Parse(item.RawJSON())
455+
if err := ShowJSON(w, "builds list", obj, format, transform); err != nil {
456+
return err
457+
}
458+
}
459+
return iter.Err()
460+
})
461+
}
452462
}
453463

454464
func handleBuildsCompare(ctx context.Context, cmd *cli.Command) error {
455465
client := stainless.NewClient(getDefaultRequestOptions(cmd)...)
456466
unusedArgs := cmd.Args().Slice()
467+
457468
if len(unusedArgs) > 0 {
458469
return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs)
459470
}
@@ -468,19 +479,16 @@ func handleBuildsCompare(ctx context.Context, cmd *cli.Command) error {
468479
if err != nil {
469480
return err
470481
}
482+
471483
var res []byte
472484
options = append(options, option.WithResponseBodyInto(&res))
473-
_, err = client.Builds.Compare(
474-
ctx,
475-
params,
476-
options...,
477-
)
485+
_, err = client.Builds.Compare(ctx, params, options...)
478486
if err != nil {
479487
return err
480488
}
481489

482-
json := gjson.Parse(string(res))
490+
obj := gjson.ParseBytes(res)
483491
format := cmd.Root().String("format")
484492
transform := cmd.Root().String("transform")
485-
return ShowJSON("builds compare", json, format, transform)
493+
return ShowJSON(os.Stdout, "builds compare", obj, format, transform)
486494
}

pkg/cmd/builddiagnostic.go

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package cmd
55
import (
66
"context"
77
"fmt"
8+
"os"
89

910
"github.com/stainless-api/stainless-api-cli/internal/apiquery"
1011
"github.com/stainless-api/stainless-api-cli/internal/requestflag"
@@ -79,20 +80,39 @@ func handleBuildsDiagnosticsList(ctx context.Context, cmd *cli.Command) error {
7980
if err != nil {
8081
return err
8182
}
82-
var res []byte
83-
options = append(options, option.WithResponseBodyInto(&res))
84-
_, err = client.Builds.Diagnostics.List(
85-
ctx,
86-
requestflag.CommandRequestValue[string](cmd, "build-id"),
87-
params,
88-
options...,
89-
)
90-
if err != nil {
91-
return err
92-
}
9383

94-
json := gjson.Parse(string(res))
9584
format := cmd.Root().String("format")
9685
transform := cmd.Root().String("transform")
97-
return ShowJSON("builds:diagnostics list", json, format, transform)
86+
if format == "raw" {
87+
var res []byte
88+
options = append(options, option.WithResponseBodyInto(&res))
89+
_, err = client.Builds.Diagnostics.List(
90+
ctx,
91+
requestflag.CommandRequestValue[string](cmd, "build-id"),
92+
params,
93+
options...,
94+
)
95+
if err != nil {
96+
return err
97+
}
98+
obj := gjson.ParseBytes(res)
99+
return ShowJSON(os.Stdout, "builds:diagnostics list", obj, format, transform)
100+
} else {
101+
iter := client.Builds.Diagnostics.ListAutoPaging(
102+
ctx,
103+
requestflag.CommandRequestValue[string](cmd, "build-id"),
104+
params,
105+
options...,
106+
)
107+
return streamOutput("builds:diagnostics list", func(w *os.File) error {
108+
for iter.Next() {
109+
item := iter.Current()
110+
obj := gjson.Parse(item.RawJSON())
111+
if err := ShowJSON(w, "builds:diagnostics list", obj, format, transform); err != nil {
112+
return err
113+
}
114+
}
115+
return iter.Err()
116+
})
117+
}
98118
}

pkg/cmd/buildtargetoutput.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package cmd
55
import (
66
"context"
77
"fmt"
8+
"os"
89

910
"github.com/stainless-api/stainless-api-cli/internal/apiquery"
1011
"github.com/stainless-api/stainless-api-cli/internal/requestflag"
@@ -70,6 +71,7 @@ var buildsTargetOutputsRetrieve = cli.Command{
7071
func handleBuildsTargetOutputsRetrieve(ctx context.Context, cmd *cli.Command) error {
7172
client := stainless.NewClient(getDefaultRequestOptions(cmd)...)
7273
unusedArgs := cmd.Args().Slice()
74+
7375
if len(unusedArgs) > 0 {
7476
return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs)
7577
}
@@ -83,13 +85,10 @@ func handleBuildsTargetOutputsRetrieve(ctx context.Context, cmd *cli.Command) er
8385
if err != nil {
8486
return err
8587
}
88+
8689
var res []byte
8790
options = append(options, option.WithResponseBodyInto(&res))
88-
_, err = client.Builds.TargetOutputs.Get(
89-
ctx,
90-
params,
91-
options...,
92-
)
91+
_, err = client.Builds.TargetOutputs.Get(ctx, params, options...)
9392
if err != nil {
9493
return err
9594
}
@@ -134,7 +133,7 @@ func handleBuildsTargetOutputsRetrieve(ctx context.Context, cmd *cli.Command) er
134133
json := gjson.Parse(res.RawJSON())
135134
format := cmd.Root().String("format")
136135
transform := cmd.Root().String("transform")
137-
if err := ShowJSON("builds:target_outputs retrieve", json, format, transform); err != nil {
136+
if err := ShowJSON(os.Stdout, "builds:target_outputs retrieve", json, format, transform); err != nil {
138137
return err
139138
}
140139
}

pkg/cmd/cmd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818

1919
var (
2020
Command *cli.Command
21-
OutputFormats = []string{"auto", "explore", "json", "pretty", "raw", "yaml"}
21+
OutputFormats = []string{"auto", "explore", "json", "jsonl", "pretty", "raw", "yaml"}
2222
)
2323

2424
func init() {

0 commit comments

Comments
 (0)