Skip to content

Commit a8810f6

Browse files
committed
feat(repos): show pagination footer in list repos table output
Since the repos endpoint always paginates, surface the page context the way list controls/environments/flows do: append a "Showing page X of Y, total Z repos" footer from the response envelope's page/total_pages/total_count fields, and make the no-repos message page-aware. Covered by a server-free unit test plus an integration assertion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Kh9pJ2yQbnUPhytgtPSzv
1 parent a311fe7 commit a8810f6

2 files changed

Lines changed: 26 additions & 12 deletions

File tree

cmd/kosli/listRepos.go

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -118,29 +118,37 @@ func (o *listReposOptions) run(out io.Writer) error {
118118
})
119119
}
120120

121-
func printReposListAsTable(raw string, out io.Writer, page int) error {
122-
var repos []map[string]any
123-
var response struct {
124-
Repos []map[string]any `json:"repos"`
125-
}
121+
type listReposResponse struct {
122+
Repos []map[string]any `json:"repos"`
123+
Page int `json:"page"`
124+
TotalPages int `json:"total_pages"`
125+
TotalCount int `json:"total_count"`
126+
}
126127

127-
err := json.Unmarshal([]byte(raw), &response)
128-
if err != nil {
128+
func printReposListAsTable(raw string, out io.Writer, page int) error {
129+
response := &listReposResponse{}
130+
if err := json.Unmarshal([]byte(raw), response); err != nil {
129131
return err
130132
}
131-
repos = response.Repos
132133

133-
if len(repos) == 0 {
134-
logger.Info("No repos were found.")
134+
if len(response.Repos) == 0 {
135+
msg := "No repos were found"
136+
if page != 1 {
137+
msg = fmt.Sprintf("%s at page number %d", msg, page)
138+
}
139+
logger.Info(msg + ".")
135140
return nil
136141
}
137142

138143
header := []string{"NAME", "URL", "PROVIDER", "TAGS"}
139144
rows := []string{}
140-
for _, repo := range repos {
145+
for _, repo := range response.Repos {
141146
row := fmt.Sprintf("%v\t%v\t%v\t%s", repo["name"], repo["url"], repo["provider"], formatRepoTags(repo["tags"]))
142147
rows = append(rows, row)
143148
}
149+
150+
rows = append(rows, fmt.Sprintf("\nShowing page %d of %d, total %d repos", response.Page, response.TotalPages, response.TotalCount))
151+
144152
tabFormattedPrint(out, header, rows)
145153

146154
return nil

cmd/kosli/listRepos_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ func (suite *ListReposCommandTestSuite) TestListReposCmd() {
136136
cmd: fmt.Sprintf(`list repos %s`, suite.acmeOrgKosliArguments),
137137
goldenRegex: `(?m)^list-repos-suite-org/untagged-repo\s+https://github\.com/list-repos-suite-org/untagged-repo\s+github\s*$`,
138138
},
139+
{
140+
name: "15-table output shows the pagination footer",
141+
cmd: fmt.Sprintf(`list repos %s`, suite.acmeOrgKosliArguments),
142+
goldenRegex: `(?m)^Showing page 1 of \d+, total \d+ repos$`,
143+
},
139144
}
140145

141146
runTestCmd(suite.T(), tests)
@@ -151,11 +156,12 @@ func TestPrintReposListAsTableRendersBlankTagsCell(t *testing.T) {
151156
raw := `{"repos":[
152157
{"name":"o/tagged","url":"https://github.com/o/tagged","provider":"github","tags":{"team":"platform"}},
153158
{"name":"o/untagged","url":"https://github.com/o/untagged","provider":"github","tags":{}}
154-
]}`
159+
],"page":1,"total_pages":3,"total_count":45}`
155160
var buf bytes.Buffer
156161
require.NoError(t, printReposListAsTable(raw, &buf, 1))
157162
out := buf.String()
158163
require.Regexp(t, `(?m)^NAME\s+URL\s+PROVIDER\s+TAGS\s*$`, out)
159164
require.Regexp(t, `(?m)^o/tagged\s+https://github\.com/o/tagged\s+github\s+team=platform\s*$`, out)
160165
require.Regexp(t, `(?m)^o/untagged\s+https://github\.com/o/untagged\s+github\s*$`, out)
166+
require.Regexp(t, `(?m)^Showing page 1 of 3, total 45 repos$`, out)
161167
}

0 commit comments

Comments
 (0)