improve formatting of `tea repos` (#223)

make fmt

code review

use OutputMarkdown

use FormatTime()

improved repo printing

- ReposList() now allows selection of fields
- RepoDetail() uses glamour and provides more details

Co-authored-by: Norwin Roosen <git@nroo.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/223
Reviewed-by: 6543 <6543@noreply.gitea.io>
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-Authored-By: Norwin <noerw@noreply.gitea.io>
Co-Committed-By: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
Norwin 2020-10-10 01:17:31 +00:00 committed by Lunny Xiao
parent a4b792e24d
commit 6ea331ce3b
4 changed files with 143 additions and 44 deletions

View File

@ -6,11 +6,28 @@ package repos
import (
"fmt"
"strings"
"code.gitea.io/tea/modules/print"
"code.gitea.io/sdk/gitea"
"github.com/urfave/cli/v2"
)
// printFieldsFlag provides a selection of fields to print
var printFieldsFlag = cli.StringFlag{
Name: "fields",
Aliases: []string{"f"},
Usage: fmt.Sprintf(`Comma-separated list of fields to print. Available values:
%s
`, strings.Join(print.RepoFields, ",")),
Value: "owner,name,type,ssh",
}
func getFields(ctx *cli.Context) []string {
return strings.Split(ctx.String("fields"), ",")
}
var typeFilterFlag = cli.StringFlag{
Name: "type",
Aliases: []string{"T"},

View File

@ -27,6 +27,7 @@ var CmdReposListFlags = append([]cli.Flag{
Required: false,
Usage: "List your starred repos instead",
},
&printFieldsFlag,
&typeFilterFlag,
&flags.PaginationPageFlag,
&flags.PaginationLimitFlag,
@ -79,7 +80,7 @@ func RunReposList(ctx *cli.Context) error {
reposFiltered = filterReposByType(rps, typeFilter)
}
print.ReposList(reposFiltered)
print.ReposList(reposFiltered, getFields(ctx))
return nil
}

View File

@ -50,6 +50,7 @@ var CmdReposSearch = cli.Command{
Required: false,
Usage: "Filter archived repos (true|false)",
},
&printFieldsFlag,
&flags.PaginationPageFlag,
&flags.PaginationLimitFlag,
}, flags.LoginOutputFlags...),
@ -122,6 +123,6 @@ func runReposSearch(ctx *cli.Context) error {
return err
}
print.ReposList(rps)
print.ReposList(rps, getFields(ctx))
return nil
}

View File

@ -6,78 +6,158 @@ package print
import (
"fmt"
"log"
"strings"
"time"
"code.gitea.io/sdk/gitea"
"code.gitea.io/tea/cmd/flags"
)
type rp = *gitea.Repository
type fieldFormatter = func(*gitea.Repository) string
var (
fieldFormatters map[string]fieldFormatter
// RepoFields are the available fields to print with ReposList()
RepoFields []string
)
func init() {
fieldFormatters = map[string]fieldFormatter{
"description": func(r rp) string { return r.Description },
"forks": func(r rp) string { return fmt.Sprintf("%d", r.Forks) },
"id": func(r rp) string { return r.FullName },
"name": func(r rp) string { return r.Name },
"owner": func(r rp) string { return r.Owner.UserName },
"stars": func(r rp) string { return fmt.Sprintf("%d", r.Stars) },
"ssh": func(r rp) string { return r.SSHURL },
"updated": func(r rp) string { return FormatTime(r.Updated) },
"url": func(r rp) string { return r.HTMLURL },
"permission": func(r rp) string {
if r.Permissions.Admin {
return "admin"
} else if r.Permissions.Push {
return "write"
}
return "read"
},
"type": func(r rp) string {
if r.Fork {
return "fork"
}
if r.Mirror {
return "mirror"
}
return "source"
},
}
for f := range fieldFormatters {
RepoFields = append(RepoFields, f)
}
}
// ReposList prints a listing of the repos
func ReposList(rps []*gitea.Repository) {
if len(rps) == 0 {
func ReposList(repos []*gitea.Repository, fields []string) {
if len(repos) == 0 {
fmt.Println("No repositories found")
return
}
headers := []string{
"Name",
"Type",
"SSH",
"Owner",
}
var values [][]string
for _, rp := range rps {
var mode = "source"
if rp.Fork {
mode = "fork"
}
if rp.Mirror {
mode = "mirror"
}
values = append(
values,
[]string{
rp.FullName,
mode,
rp.SSHURL,
rp.Owner.UserName,
},
)
if len(fields) == 0 {
fmt.Println("No fields to print")
return
}
OutputList(flags.GlobalOutputValue, headers, values)
formatters := make([]fieldFormatter, len(fields))
values := make([][]string, len(repos))
// find field format functions by header name
for i, f := range fields {
if formatter, ok := fieldFormatters[strings.ToLower(f)]; ok {
formatters[i] = formatter
} else {
log.Fatalf("invalid field '%s'", f)
}
}
// extract values from each repo and store them in 2D table
for i, repo := range repos {
values[i] = make([]string, len(formatters))
for j, format := range formatters {
values[i][j] = format(repo)
}
}
OutputList(flags.GlobalOutputValue, fields, values)
}
// RepoDetails print an repo formatted to stdout
func RepoDetails(repo *gitea.Repository, topics []string) {
output := repo.FullName
title := "# " + repo.FullName
if repo.Mirror {
output += " (mirror)"
title += " (mirror)"
}
if repo.Fork {
output += " (fork)"
title += " (fork)"
}
if repo.Archived {
output += " (archived)"
title += " (archived)"
}
if repo.Empty {
output += " (empty)"
title += " (empty)"
}
output += "\n"
if len(topics) != 0 {
output += "Topics: " + strings.Join(topics, ", ") + "\n"
title += "\n"
var desc string
if len(repo.Description) != 0 {
desc = fmt.Sprintf("*%s*\n\n", repo.Description)
}
output += "\n"
output += repo.Description + "\n\n"
output += fmt.Sprintf(
"Open Issues: %d, Stars: %d, Forks: %d, Size: %s\n\n",
stats := fmt.Sprintf(
"Issues: %d, Stars: %d, Forks: %d, Size: %s\n",
repo.OpenIssues,
repo.Stars,
repo.Forks,
formatSize(int64(repo.Size)),
)
fmt.Print(output)
// NOTE: for mirrors, this is the time the mirror was last fetched..
updated := fmt.Sprintf(
"Updated: %s (%s ago)\n",
repo.Updated.Format("2006-01-02 15:04"),
time.Now().Sub(repo.Updated).Truncate(time.Minute),
)
urls := fmt.Sprintf(
"- Browse:\t%s\n- Clone:\t%s\n",
repo.HTMLURL,
repo.SSHURL,
)
if len(repo.Website) != 0 {
urls += fmt.Sprintf("- Web:\t%s\n", repo.Website)
}
perm := fmt.Sprintf(
"- Permission:\t%s\n",
fieldFormatters["permission"](repo),
)
var tops string
if len(topics) != 0 {
tops = fmt.Sprintf("- Topics:\t%s\n", strings.Join(topics, ", "))
}
OutputMarkdown(fmt.Sprintf(
"%s%s\n%s\n%s%s%s%s",
title,
desc,
stats,
updated,
urls,
perm,
tops,
))
}