Improved list output (#281)
remove unused debug var move outputList into a struct so we can add additional functionality for all list output rename list output to table.go make table sortable sort milestones sort milestones descending remove unnecessary if Co-authored-by: Norwin Roosen <git@nroo.de> Reviewed-on: https://gitea.com/gitea/tea/pulls/281 Reviewed-by: khmarbaise <khmarbaise@noreply.gitea.io> Reviewed-by: 6543 <6543@obermui.de> Co-Authored-By: Norwin <noerw@noreply.gitea.io> Co-Committed-By: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
parent
4a11cf455f
commit
a91168fd36
|
@ -26,20 +26,14 @@ func IssueDetails(issue *gitea.Issue) {
|
|||
|
||||
// IssuesList prints a listing of issues
|
||||
func IssuesList(issues []*gitea.Issue, output string) {
|
||||
var values [][]string
|
||||
headers := []string{
|
||||
t := tableWithHeader(
|
||||
"Index",
|
||||
"Title",
|
||||
"State",
|
||||
"Author",
|
||||
"Milestone",
|
||||
"Updated",
|
||||
}
|
||||
|
||||
if len(issues) == 0 {
|
||||
outputList(output, headers, values)
|
||||
return
|
||||
}
|
||||
)
|
||||
|
||||
for _, issue := range issues {
|
||||
author := issue.Poster.FullName
|
||||
|
@ -50,38 +44,29 @@ func IssuesList(issues []*gitea.Issue, output string) {
|
|||
if issue.Milestone != nil {
|
||||
mile = issue.Milestone.Title
|
||||
}
|
||||
values = append(
|
||||
values,
|
||||
[]string{
|
||||
strconv.FormatInt(issue.Index, 10),
|
||||
issue.Title,
|
||||
string(issue.State),
|
||||
author,
|
||||
mile,
|
||||
FormatTime(issue.Updated),
|
||||
},
|
||||
t.addRow(
|
||||
strconv.FormatInt(issue.Index, 10),
|
||||
issue.Title,
|
||||
string(issue.State),
|
||||
author,
|
||||
mile,
|
||||
FormatTime(issue.Updated),
|
||||
)
|
||||
}
|
||||
outputList(output, headers, values)
|
||||
t.print(output)
|
||||
}
|
||||
|
||||
// IssuesPullsList prints a listing of issues & pulls
|
||||
// TODO combine with IssuesList
|
||||
func IssuesPullsList(issues []*gitea.Issue, output string) {
|
||||
var values [][]string
|
||||
headers := []string{
|
||||
t := tableWithHeader(
|
||||
"Index",
|
||||
"State",
|
||||
"Kind",
|
||||
"Author",
|
||||
"Updated",
|
||||
"Title",
|
||||
}
|
||||
|
||||
if len(issues) == 0 {
|
||||
outputList(output, headers, values)
|
||||
return
|
||||
}
|
||||
)
|
||||
|
||||
for _, issue := range issues {
|
||||
name := issue.Poster.FullName
|
||||
|
@ -92,18 +77,15 @@ func IssuesPullsList(issues []*gitea.Issue, output string) {
|
|||
if issue.PullRequest != nil {
|
||||
kind = "Pull"
|
||||
}
|
||||
values = append(
|
||||
values,
|
||||
[]string{
|
||||
strconv.FormatInt(issue.Index, 10),
|
||||
string(issue.State),
|
||||
kind,
|
||||
name,
|
||||
FormatTime(issue.Updated),
|
||||
issue.Title,
|
||||
},
|
||||
t.addRow(
|
||||
strconv.FormatInt(issue.Index, 10),
|
||||
string(issue.State),
|
||||
kind,
|
||||
name,
|
||||
FormatTime(issue.Updated),
|
||||
issue.Title,
|
||||
)
|
||||
}
|
||||
|
||||
outputList(output, headers, values)
|
||||
t.print(output)
|
||||
}
|
||||
|
|
|
@ -14,33 +14,24 @@ import (
|
|||
|
||||
// LabelsList prints a listing of labels
|
||||
func LabelsList(labels []*gitea.Label, output string) {
|
||||
var values [][]string
|
||||
headers := []string{
|
||||
t := tableWithHeader(
|
||||
"Index",
|
||||
"Color",
|
||||
"Name",
|
||||
"Description",
|
||||
}
|
||||
|
||||
if len(labels) == 0 {
|
||||
outputList(output, headers, values)
|
||||
return
|
||||
}
|
||||
)
|
||||
|
||||
p := termenv.ColorProfile()
|
||||
|
||||
for _, label := range labels {
|
||||
color := termenv.String(label.Color)
|
||||
|
||||
values = append(
|
||||
values,
|
||||
[]string{
|
||||
strconv.FormatInt(label.ID, 10),
|
||||
fmt.Sprint(color.Background(p.Color("#" + label.Color))),
|
||||
label.Name,
|
||||
label.Description,
|
||||
},
|
||||
t.addRow(
|
||||
strconv.FormatInt(label.ID, 10),
|
||||
fmt.Sprint(color.Background(p.Color("#"+label.Color))),
|
||||
label.Name,
|
||||
label.Description,
|
||||
)
|
||||
}
|
||||
outputList(output, headers, values)
|
||||
t.print(output)
|
||||
}
|
||||
|
|
|
@ -33,24 +33,23 @@ func LoginDetails(login *config.Login, output string) {
|
|||
|
||||
// LoginsList prints a listing of logins
|
||||
func LoginsList(logins []config.Login, output string) {
|
||||
var values [][]string
|
||||
headers := []string{
|
||||
t := tableWithHeader(
|
||||
"Name",
|
||||
"URL",
|
||||
"SSHHost",
|
||||
"User",
|
||||
"Default",
|
||||
}
|
||||
)
|
||||
|
||||
for _, l := range logins {
|
||||
values = append(values, []string{
|
||||
t.addRow(
|
||||
l.Name,
|
||||
l.URL,
|
||||
l.GetSSHHost(),
|
||||
l.User,
|
||||
fmt.Sprint(l.Default),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
outputList(output, headers, values)
|
||||
t.print(output)
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ func MilestoneDetails(milestone *gitea.Milestone) {
|
|||
|
||||
// MilestonesList prints a listing of milestones
|
||||
func MilestonesList(miles []*gitea.Milestone, output string, state gitea.StateType) {
|
||||
|
||||
headers := []string{
|
||||
"Title",
|
||||
}
|
||||
|
@ -37,7 +36,7 @@ func MilestonesList(miles []*gitea.Milestone, output string, state gitea.StateTy
|
|||
"DueDate",
|
||||
)
|
||||
|
||||
var values [][]string
|
||||
t := table{headers: headers}
|
||||
|
||||
for _, m := range miles {
|
||||
var deadline = ""
|
||||
|
@ -56,8 +55,9 @@ func MilestonesList(miles []*gitea.Milestone, output string, state gitea.StateTy
|
|||
fmt.Sprintf("%d/%d", m.OpenIssues, m.ClosedIssues),
|
||||
deadline,
|
||||
)
|
||||
|
||||
values = append(values, item)
|
||||
t.addRowSlice(item)
|
||||
}
|
||||
outputList(output, headers, values)
|
||||
|
||||
t.sort(0, true)
|
||||
t.print(output)
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
// NotificationsList prints a listing of notification threads
|
||||
func NotificationsList(news []*gitea.NotificationThread, output string, showRepository bool) {
|
||||
var values [][]string
|
||||
headers := []string{
|
||||
"Type",
|
||||
"Index",
|
||||
|
@ -22,6 +21,8 @@ func NotificationsList(news []*gitea.NotificationThread, output string, showRepo
|
|||
headers = append(headers, "Repository")
|
||||
}
|
||||
|
||||
t := table{headers: headers}
|
||||
|
||||
for _, n := range news {
|
||||
if n.Subject == nil {
|
||||
continue
|
||||
|
@ -41,11 +42,10 @@ func NotificationsList(news []*gitea.NotificationThread, output string, showRepo
|
|||
if showRepository {
|
||||
item = append(item, n.Repository.FullName)
|
||||
}
|
||||
values = append(values, item)
|
||||
t.addRowSlice(item)
|
||||
}
|
||||
|
||||
if len(values) != 0 {
|
||||
outputList(output, headers, values)
|
||||
if t.Len() != 0 {
|
||||
t.print(output)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -17,28 +17,23 @@ func OrganizationsList(organizations []*gitea.Organization, output string) {
|
|||
return
|
||||
}
|
||||
|
||||
headers := []string{
|
||||
t := tableWithHeader(
|
||||
"Name",
|
||||
"FullName",
|
||||
"Website",
|
||||
"Location",
|
||||
"Description",
|
||||
}
|
||||
|
||||
var values [][]string
|
||||
)
|
||||
|
||||
for _, org := range organizations {
|
||||
values = append(
|
||||
values,
|
||||
[]string{
|
||||
org.UserName,
|
||||
org.FullName,
|
||||
org.Website,
|
||||
org.Location,
|
||||
org.Description,
|
||||
},
|
||||
t.addRow(
|
||||
org.UserName,
|
||||
org.FullName,
|
||||
org.Website,
|
||||
org.Location,
|
||||
org.Description,
|
||||
)
|
||||
}
|
||||
|
||||
outputList(output, headers, values)
|
||||
t.print(output)
|
||||
}
|
||||
|
|
|
@ -60,20 +60,14 @@ func PullDetails(pr *gitea.PullRequest, reviews []*gitea.PullReview) {
|
|||
|
||||
// PullsList prints a listing of pulls
|
||||
func PullsList(prs []*gitea.PullRequest, output string) {
|
||||
var values [][]string
|
||||
headers := []string{
|
||||
t := tableWithHeader(
|
||||
"Index",
|
||||
"Title",
|
||||
"State",
|
||||
"Author",
|
||||
"Milestone",
|
||||
"Updated",
|
||||
}
|
||||
|
||||
if len(prs) == 0 {
|
||||
outputList(output, headers, values)
|
||||
return
|
||||
}
|
||||
)
|
||||
|
||||
for _, pr := range prs {
|
||||
if pr == nil {
|
||||
|
@ -87,18 +81,15 @@ func PullsList(prs []*gitea.PullRequest, output string) {
|
|||
if pr.Milestone != nil {
|
||||
mile = pr.Milestone.Title
|
||||
}
|
||||
values = append(
|
||||
values,
|
||||
[]string{
|
||||
strconv.FormatInt(pr.Index, 10),
|
||||
pr.Title,
|
||||
string(pr.State),
|
||||
author,
|
||||
mile,
|
||||
FormatTime(*pr.Updated),
|
||||
},
|
||||
t.addRow(
|
||||
strconv.FormatInt(pr.Index, 10),
|
||||
pr.Title,
|
||||
string(pr.State),
|
||||
author,
|
||||
mile,
|
||||
FormatTime(*pr.Updated),
|
||||
)
|
||||
}
|
||||
|
||||
outputList(output, headers, values)
|
||||
t.print(output)
|
||||
}
|
||||
|
|
|
@ -10,19 +10,13 @@ import (
|
|||
|
||||
// ReleasesList prints a listing of releases
|
||||
func ReleasesList(releases []*gitea.Release, output string) {
|
||||
var values [][]string
|
||||
headers := []string{
|
||||
t := tableWithHeader(
|
||||
"Tag-Name",
|
||||
"Title",
|
||||
"Published At",
|
||||
"Status",
|
||||
"Tar URL",
|
||||
}
|
||||
|
||||
if len(releases) == 0 {
|
||||
outputList(output, headers, values)
|
||||
return
|
||||
}
|
||||
)
|
||||
|
||||
for _, release := range releases {
|
||||
status := "released"
|
||||
|
@ -31,17 +25,14 @@ func ReleasesList(releases []*gitea.Release, output string) {
|
|||
} else if release.IsPrerelease {
|
||||
status = "prerelease"
|
||||
}
|
||||
values = append(
|
||||
values,
|
||||
[]string{
|
||||
release.TagName,
|
||||
release.Title,
|
||||
FormatTime(release.PublishedAt),
|
||||
status,
|
||||
release.TarURL,
|
||||
},
|
||||
t.addRow(
|
||||
release.TagName,
|
||||
release.Title,
|
||||
FormatTime(release.PublishedAt),
|
||||
status,
|
||||
release.TarURL,
|
||||
)
|
||||
}
|
||||
|
||||
outputList(output, headers, values)
|
||||
t.print(output)
|
||||
}
|
||||
|
|
|
@ -90,7 +90,8 @@ func ReposList(repos []*gitea.Repository, output string, fields []string) {
|
|||
}
|
||||
}
|
||||
|
||||
outputList(output, fields, values)
|
||||
t := table{headers: fields, values: values}
|
||||
t.print(output)
|
||||
}
|
||||
|
||||
// RepoDetails print an repo formatted to stdout
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
@ -7,19 +7,67 @@ package print
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
var (
|
||||
showLog bool
|
||||
)
|
||||
// table provides infrastructure to easily print (sorted) lists in different formats
|
||||
type table struct {
|
||||
headers []string
|
||||
values [][]string
|
||||
sortDesc bool // used internally by sortable interface
|
||||
sortColumn uint // ↑
|
||||
}
|
||||
|
||||
// errorf printf content as an error information
|
||||
func errorf(format string, a ...interface{}) {
|
||||
fmt.Printf(format, a...)
|
||||
func tableWithHeader(header ...string) table {
|
||||
return table{headers: header}
|
||||
}
|
||||
|
||||
// it's the callers responsibility to ensure row length is equal to header length!
|
||||
func (t *table) addRow(row ...string) {
|
||||
t.addRowSlice(row)
|
||||
}
|
||||
|
||||
// it's the callers responsibility to ensure row length is equal to header length!
|
||||
func (t *table) addRowSlice(row []string) {
|
||||
t.values = append(t.values, row)
|
||||
}
|
||||
|
||||
func (t *table) sort(column uint, desc bool) {
|
||||
t.sortColumn = column
|
||||
t.sortDesc = desc
|
||||
sort.Stable(t) // stable to allow multiple calls to sort
|
||||
}
|
||||
|
||||
// sortable interface
|
||||
func (t table) Len() int { return len(t.values) }
|
||||
func (t table) Swap(i, j int) { t.values[i], t.values[j] = t.values[j], t.values[i] }
|
||||
func (t table) Less(i, j int) bool {
|
||||
const column = 0
|
||||
if t.sortDesc {
|
||||
i, j = j, i
|
||||
}
|
||||
return t.values[i][t.sortColumn] < t.values[j][t.sortColumn]
|
||||
}
|
||||
|
||||
func (t *table) print(output string) {
|
||||
switch {
|
||||
case output == "" || output == "table":
|
||||
outputtable(t.headers, t.values)
|
||||
case output == "csv":
|
||||
outputdsv(t.headers, t.values, ",")
|
||||
case output == "simple":
|
||||
outputsimple(t.headers, t.values)
|
||||
case output == "tsv":
|
||||
outputdsv(t.headers, t.values, "\t")
|
||||
case output == "yaml":
|
||||
outputyaml(t.headers, t.values)
|
||||
default:
|
||||
fmt.Printf("unknown output type '" + output + "', available types are:\n- csv: comma-separated values\n- simple: space-separated values\n- table: auto-aligned table format (default)\n- tsv: tab-separated values\n- yaml: YAML format\n")
|
||||
}
|
||||
}
|
||||
|
||||
// outputtable prints structured data as table
|
||||
|
@ -71,22 +119,3 @@ func outputyaml(headers []string, values [][]string) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// outputList provides general function to convert given list of items
|
||||
// into several outputs (table, csv, simple, tsv, yaml)
|
||||
func outputList(output string, headers []string, values [][]string) {
|
||||
switch {
|
||||
case output == "" || output == "table":
|
||||
outputtable(headers, values)
|
||||
case output == "csv":
|
||||
outputdsv(headers, values, ",")
|
||||
case output == "simple":
|
||||
outputsimple(headers, values)
|
||||
case output == "tsv":
|
||||
outputdsv(headers, values, "\t")
|
||||
case output == "yaml":
|
||||
outputyaml(headers, values)
|
||||
default:
|
||||
errorf("unknown output type '" + output + "', available types are:\n- csv: comma-separated values\n- simple: space-separated values\n- table: auto-aligned table format (default)\n- tsv: tab-separated values\n- yaml: YAML format\n")
|
||||
}
|
||||
}
|
|
@ -23,7 +23,12 @@ func formatDuration(seconds int64, outputType string) string {
|
|||
|
||||
// TrackedTimesList print list of tracked times to stdout
|
||||
func TrackedTimesList(times []*gitea.TrackedTime, outputType string, from, until time.Time, printTotal bool) {
|
||||
var outputValues [][]string
|
||||
tab := tableWithHeader(
|
||||
"Created",
|
||||
"Issue",
|
||||
"User",
|
||||
"Duration",
|
||||
)
|
||||
var totalDuration int64
|
||||
|
||||
for _, t := range times {
|
||||
|
@ -35,29 +40,16 @@ func TrackedTimesList(times []*gitea.TrackedTime, outputType string, from, until
|
|||
}
|
||||
|
||||
totalDuration += t.Time
|
||||
|
||||
outputValues = append(
|
||||
outputValues,
|
||||
[]string{
|
||||
FormatTime(t.Created),
|
||||
"#" + strconv.FormatInt(t.Issue.Index, 10),
|
||||
t.UserName,
|
||||
formatDuration(t.Time, outputType),
|
||||
},
|
||||
tab.addRow(
|
||||
FormatTime(t.Created),
|
||||
"#"+strconv.FormatInt(t.Issue.Index, 10),
|
||||
t.UserName,
|
||||
formatDuration(t.Time, outputType),
|
||||
)
|
||||
}
|
||||
|
||||
if printTotal {
|
||||
outputValues = append(outputValues, []string{
|
||||
"TOTAL", "", "", formatDuration(totalDuration, outputType),
|
||||
})
|
||||
tab.addRow("TOTAL", "", "", formatDuration(totalDuration, outputType))
|
||||
}
|
||||
|
||||
headers := []string{
|
||||
"Created",
|
||||
"Issue",
|
||||
"User",
|
||||
"Duration",
|
||||
}
|
||||
outputList(outputType, headers, outputValues)
|
||||
tab.print(outputType)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue