Skip to content

Commit bd118b2

Browse files
committed
fix(operations): updated pagination pattern
Updated the list commands to support the new upstream go-fastly behavior
1 parent c93cf80 commit bd118b2

4 files changed

Lines changed: 78 additions & 167 deletions

File tree

pkg/commands/apisecurity/discoveredoperations/discoveredoperations_test.go

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -196,55 +196,6 @@ func TestListCommand(t *testing.T) {
196196
testutil.RunCLIScenarios(t, []string{apisecurity.CommandName, root.CommandName, "list"}, scenarios)
197197
}
198198

199-
func TestListCommandWithPagination(t *testing.T) {
200-
scenarios := []testutil.CLIScenario{
201-
{
202-
Name: "validate --page flag",
203-
Args: fmt.Sprintf("--service-id %s --page 1", serviceID),
204-
Client: &http.Client{
205-
Transport: &testutil.MockRoundTripper{
206-
Response: &http.Response{
207-
StatusCode: http.StatusOK,
208-
Status: http.StatusText(http.StatusOK),
209-
Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(listResponse))),
210-
},
211-
},
212-
},
213-
WantOutput: listDiscoveredOperationsOutput,
214-
},
215-
{
216-
Name: "validate --per-page flag",
217-
Args: fmt.Sprintf("--service-id %s --per-page 50", serviceID),
218-
Client: &http.Client{
219-
Transport: &testutil.MockRoundTripper{
220-
Response: &http.Response{
221-
StatusCode: http.StatusOK,
222-
Status: http.StatusText(http.StatusOK),
223-
Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(listResponse))),
224-
},
225-
},
226-
},
227-
WantOutput: listDiscoveredOperationsOutput,
228-
},
229-
{
230-
Name: "validate --page and --per-page together",
231-
Args: fmt.Sprintf("--service-id %s --status discovered --page 2 --per-page 25", serviceID),
232-
Client: &http.Client{
233-
Transport: &testutil.MockRoundTripper{
234-
Response: &http.Response{
235-
StatusCode: http.StatusOK,
236-
Status: http.StatusText(http.StatusOK),
237-
Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(listResponse))),
238-
},
239-
},
240-
},
241-
WantOutput: listDiscoveredOperationsOutput,
242-
},
243-
}
244-
245-
testutil.RunCLIScenarios(t, []string{apisecurity.CommandName, root.CommandName, "list"}, scenarios)
246-
}
247-
248199
func TestListCommandWithFilters(t *testing.T) {
249200
scenarios := []testutil.CLIScenario{
250201
{

pkg/commands/apisecurity/discoveredoperations/list.go

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,10 @@ type ListCommand struct {
2626
serviceName argparser.OptionalServiceNameID
2727

2828
// Optional.
29-
domain argparser.OptionalString
30-
method argparser.OptionalString
31-
path argparser.OptionalString
32-
status argparser.OptionalString
33-
page argparser.OptionalInt
34-
perPage argparser.OptionalInt
29+
domain argparser.OptionalString
30+
method argparser.OptionalString
31+
path argparser.OptionalString
32+
status argparser.OptionalString
3533
}
3634

3735
// NewListCommand returns a usable command registered under the parent.
@@ -63,8 +61,6 @@ func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand {
6361
c.CmdClause.Flag("domain", "The domain for the operation").Action(c.domain.Set).StringVar(&c.domain.Value)
6462
c.CmdClause.Flag("method", "Filters operations by HTTP method (e.g., GET, POST, PUT)").Action(c.method.Set).StringVar(&c.method.Value)
6563
c.CmdClause.Flag("path", "Filters operations by path (exact match)").Action(c.path.Set).StringVar(&c.path.Value)
66-
c.CmdClause.Flag("page", "Page number for pagination (0-indexed)").Action(c.page.Set).IntVar(&c.page.Value)
67-
c.CmdClause.Flag("per-page", "Number of items per page (default: 100)").Action(c.perPage.Set).IntVar(&c.perPage.Value)
6864
c.RegisterFlagBool(c.JSONFlag()) // --json
6965

7066
return &c
@@ -116,47 +112,57 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error {
116112
if c.path.WasSet {
117113
c.input.Path = &c.path.Value
118114
}
119-
if c.page.WasSet {
120-
c.input.Page = &c.page.Value
121-
}
122-
if c.perPage.WasSet {
123-
c.input.Limit = &c.perPage.Value
124-
}
125115

126116
fc, ok := c.Globals.APIClient.(*fastly.Client)
127117
if !ok {
128118
return errors.New("failed to convert interface to a fastly client")
129119
}
130120

131-
o, err := operations.ListDiscovered(context.TODO(), fc, &c.input)
132-
if err != nil {
133-
c.Globals.ErrLog.AddWithContext(err, map[string]any{
134-
"Service ID": serviceID,
135-
"Domain": c.domain.Value,
136-
"Method": c.method.Value,
137-
"Status": c.status.Value,
138-
"Path": c.path.Value,
139-
"Page": c.page.Value,
140-
"Per Page": c.perPage.Value,
141-
})
142-
return err
143-
}
121+
// Auto-paginate through all results
122+
var allOperations []operations.DiscoveredOperation
123+
page := 0
124+
limit := 100
125+
126+
for {
127+
c.input.Page = &page
128+
c.input.Limit = &limit
129+
130+
o, err := operations.ListDiscovered(context.TODO(), fc, &c.input)
131+
if err != nil {
132+
c.Globals.ErrLog.AddWithContext(err, map[string]any{
133+
"Service ID": serviceID,
134+
"Domain": c.domain.Value,
135+
"Method": c.method.Value,
136+
"Status": c.status.Value,
137+
"Path": c.path.Value,
138+
"Page": page,
139+
})
140+
return err
141+
}
144142

145-
if o == nil {
146-
o = &operations.DiscoveredOperations{
147-
Data: []operations.DiscoveredOperation{},
143+
if o == nil || len(o.Data) == 0 {
144+
break
148145
}
146+
147+
allOperations = append(allOperations, o.Data...)
148+
149+
// Check if we've fetched all results
150+
if len(allOperations) >= o.Meta.Total {
151+
break
152+
}
153+
154+
page++
149155
}
150156

151-
if ok, err := c.WriteJSON(out, o.Data); ok {
157+
if ok, err := c.WriteJSON(out, allOperations); ok {
152158
return err
153159
}
154160

155161
if !c.Globals.Verbose() {
156-
return c.printSummary(out, o.Data)
162+
return c.printSummary(out, allOperations)
157163
}
158164

159-
return c.printVerbose(out, o.Data)
165+
return c.printVerbose(out, allOperations)
160166
}
161167

162168
// printSummary displays the discovered operations in a table format.

pkg/commands/apisecurity/operations/list.go

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,10 @@ type ListCommand struct {
2626
serviceName argparser.OptionalServiceNameID
2727

2828
// Optional.
29-
domain argparser.OptionalString
30-
method argparser.OptionalString
31-
path argparser.OptionalString
32-
tagID argparser.OptionalString
33-
page argparser.OptionalInt
34-
perPage argparser.OptionalInt
29+
domain argparser.OptionalString
30+
method argparser.OptionalString
31+
path argparser.OptionalString
32+
tagID argparser.OptionalString
3533
}
3634

3735
// NewListCommand returns a usable command registered under the parent.
@@ -63,8 +61,6 @@ func NewListCommand(parent argparser.Registerer, g *global.Data) *ListCommand {
6361
c.CmdClause.Flag("method", "Filters operations by HTTP method (e.g., GET, POST, PUT)").Action(c.method.Set).StringVar(&c.method.Value)
6462
c.CmdClause.Flag("path", "Filters operations by path (exact match)").Action(c.path.Set).StringVar(&c.path.Value)
6563
c.CmdClause.Flag("tag-id", "Filters operations by tag ID").Action(c.tagID.Set).StringVar(&c.tagID.Value)
66-
c.CmdClause.Flag("page", "Page number for pagination (0-indexed)").Action(c.page.Set).IntVar(&c.page.Value)
67-
c.CmdClause.Flag("per-page", "Number of items per page (default: 100)").Action(c.perPage.Set).IntVar(&c.perPage.Value)
6864
c.RegisterFlagBool(c.JSONFlag()) // --json
6965

7066
return &c
@@ -99,49 +95,56 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error {
9995
c.input.TagID = &c.tagID.Value
10096
}
10197

102-
// Set pagination parameters
103-
if c.page.WasSet {
104-
c.input.Page = &c.page.Value
105-
}
106-
107-
if c.perPage.WasSet {
108-
c.input.Limit = &c.perPage.Value
109-
}
110-
11198
fc, ok := c.Globals.APIClient.(*fastly.Client)
11299
if !ok {
113100
return errors.New("failed to convert interface to a fastly client")
114101
}
115102

116-
o, err := operations.ListOperations(context.TODO(), fc, &c.input)
117-
if err != nil {
118-
c.Globals.ErrLog.AddWithContext(err, map[string]any{
119-
"Service ID": serviceID,
120-
"Domain": c.domain.Value,
121-
"Method": c.method.Value,
122-
"Path": c.path.Value,
123-
"Tag ID": c.tagID.Value,
124-
"Page": c.page.Value,
125-
"Per Page": c.perPage.Value,
126-
})
127-
return err
128-
}
103+
// Auto-paginate through all results
104+
var allOperations []operations.Operation
105+
page := 0
106+
limit := 100
107+
108+
for {
109+
c.input.Page = &page
110+
c.input.Limit = &limit
111+
112+
o, err := operations.ListOperations(context.TODO(), fc, &c.input)
113+
if err != nil {
114+
c.Globals.ErrLog.AddWithContext(err, map[string]any{
115+
"Service ID": serviceID,
116+
"Domain": c.domain.Value,
117+
"Method": c.method.Value,
118+
"Path": c.path.Value,
119+
"Tag ID": c.tagID.Value,
120+
"Page": page,
121+
})
122+
return err
123+
}
124+
125+
if o == nil || len(o.Data) == 0 {
126+
break
127+
}
128+
129+
allOperations = append(allOperations, o.Data...)
129130

130-
if o == nil {
131-
o = &operations.Operations{
132-
Data: []operations.Operation{},
131+
// Check if we've fetched all results
132+
if len(allOperations) >= o.Meta.Total {
133+
break
133134
}
135+
136+
page++
134137
}
135138

136-
if ok, err := c.WriteJSON(out, o.Data); ok {
139+
if ok, err := c.WriteJSON(out, allOperations); ok {
137140
return err
138141
}
139142

140143
if !c.Globals.Verbose() {
141-
return c.printSummary(out, o.Data)
144+
return c.printSummary(out, allOperations)
142145
}
143146

144-
return c.printVerbose(out, o.Data)
147+
return c.printVerbose(out, allOperations)
145148
}
146149

147150
// printSummary displays the operations in a table format.

pkg/commands/apisecurity/operations/operations_test.go

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -155,55 +155,6 @@ func TestListCommand(t *testing.T) {
155155
testutil.RunCLIScenarios(t, []string{apisecurity.CommandName, root.CommandName, "list"}, scenarios)
156156
}
157157

158-
func TestListCommandWithPagination(t *testing.T) {
159-
scenarios := []testutil.CLIScenario{
160-
{
161-
Name: "validate --page flag",
162-
Args: fmt.Sprintf("--service-id %s --page 1", serviceID),
163-
Client: &http.Client{
164-
Transport: &testutil.MockRoundTripper{
165-
Response: &http.Response{
166-
StatusCode: http.StatusOK,
167-
Status: http.StatusText(http.StatusOK),
168-
Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(listResponse))),
169-
},
170-
},
171-
},
172-
WantOutput: listOperationsOutput,
173-
},
174-
{
175-
Name: "validate --per-page flag",
176-
Args: fmt.Sprintf("--service-id %s --per-page 50", serviceID),
177-
Client: &http.Client{
178-
Transport: &testutil.MockRoundTripper{
179-
Response: &http.Response{
180-
StatusCode: http.StatusOK,
181-
Status: http.StatusText(http.StatusOK),
182-
Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(listResponse))),
183-
},
184-
},
185-
},
186-
WantOutput: listOperationsOutput,
187-
},
188-
{
189-
Name: "validate --page and --per-page together",
190-
Args: fmt.Sprintf("--service-id %s --page 2 --per-page 25", serviceID),
191-
Client: &http.Client{
192-
Transport: &testutil.MockRoundTripper{
193-
Response: &http.Response{
194-
StatusCode: http.StatusOK,
195-
Status: http.StatusText(http.StatusOK),
196-
Body: io.NopCloser(bytes.NewReader(testutil.GenJSON(listResponse))),
197-
},
198-
},
199-
},
200-
WantOutput: listOperationsOutput,
201-
},
202-
}
203-
204-
testutil.RunCLIScenarios(t, []string{apisecurity.CommandName, root.CommandName, "list"}, scenarios)
205-
}
206-
207158
func TestListCommandWithFilters(t *testing.T) {
208159
scenarios := []testutil.CLIScenario{
209160
{

0 commit comments

Comments
 (0)