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:
parent
a4b792e24d
commit
6ea331ce3b
|
@ -6,11 +6,28 @@ package repos
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/tea/modules/print"
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"github.com/urfave/cli/v2"
|
"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{
|
var typeFilterFlag = cli.StringFlag{
|
||||||
Name: "type",
|
Name: "type",
|
||||||
Aliases: []string{"T"},
|
Aliases: []string{"T"},
|
||||||
|
|
|
@ -27,6 +27,7 @@ var CmdReposListFlags = append([]cli.Flag{
|
||||||
Required: false,
|
Required: false,
|
||||||
Usage: "List your starred repos instead",
|
Usage: "List your starred repos instead",
|
||||||
},
|
},
|
||||||
|
&printFieldsFlag,
|
||||||
&typeFilterFlag,
|
&typeFilterFlag,
|
||||||
&flags.PaginationPageFlag,
|
&flags.PaginationPageFlag,
|
||||||
&flags.PaginationLimitFlag,
|
&flags.PaginationLimitFlag,
|
||||||
|
@ -79,7 +80,7 @@ func RunReposList(ctx *cli.Context) error {
|
||||||
reposFiltered = filterReposByType(rps, typeFilter)
|
reposFiltered = filterReposByType(rps, typeFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
print.ReposList(reposFiltered)
|
print.ReposList(reposFiltered, getFields(ctx))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ var CmdReposSearch = cli.Command{
|
||||||
Required: false,
|
Required: false,
|
||||||
Usage: "Filter archived repos (true|false)",
|
Usage: "Filter archived repos (true|false)",
|
||||||
},
|
},
|
||||||
|
&printFieldsFlag,
|
||||||
&flags.PaginationPageFlag,
|
&flags.PaginationPageFlag,
|
||||||
&flags.PaginationLimitFlag,
|
&flags.PaginationLimitFlag,
|
||||||
}, flags.LoginOutputFlags...),
|
}, flags.LoginOutputFlags...),
|
||||||
|
@ -122,6 +123,6 @@ func runReposSearch(ctx *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
print.ReposList(rps)
|
print.ReposList(rps, getFields(ctx))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,78 +6,158 @@ package print
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/sdk/gitea"
|
"code.gitea.io/sdk/gitea"
|
||||||
"code.gitea.io/tea/cmd/flags"
|
"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
|
// ReposList prints a listing of the repos
|
||||||
func ReposList(rps []*gitea.Repository) {
|
func ReposList(repos []*gitea.Repository, fields []string) {
|
||||||
if len(rps) == 0 {
|
if len(repos) == 0 {
|
||||||
fmt.Println("No repositories found")
|
fmt.Println("No repositories found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
headers := []string{
|
if len(fields) == 0 {
|
||||||
"Name",
|
fmt.Println("No fields to print")
|
||||||
"Type",
|
return
|
||||||
"SSH",
|
|
||||||
"Owner",
|
|
||||||
}
|
|
||||||
var values [][]string
|
|
||||||
|
|
||||||
for _, rp := range rps {
|
|
||||||
var mode = "source"
|
|
||||||
if rp.Fork {
|
|
||||||
mode = "fork"
|
|
||||||
}
|
|
||||||
if rp.Mirror {
|
|
||||||
mode = "mirror"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
values = append(
|
formatters := make([]fieldFormatter, len(fields))
|
||||||
values,
|
values := make([][]string, len(repos))
|
||||||
[]string{
|
|
||||||
rp.FullName,
|
// find field format functions by header name
|
||||||
mode,
|
for i, f := range fields {
|
||||||
rp.SSHURL,
|
if formatter, ok := fieldFormatters[strings.ToLower(f)]; ok {
|
||||||
rp.Owner.UserName,
|
formatters[i] = formatter
|
||||||
},
|
} else {
|
||||||
)
|
log.Fatalf("invalid field '%s'", f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputList(flags.GlobalOutputValue, headers, values)
|
// 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
|
// RepoDetails print an repo formatted to stdout
|
||||||
func RepoDetails(repo *gitea.Repository, topics []string) {
|
func RepoDetails(repo *gitea.Repository, topics []string) {
|
||||||
output := repo.FullName
|
title := "# " + repo.FullName
|
||||||
if repo.Mirror {
|
if repo.Mirror {
|
||||||
output += " (mirror)"
|
title += " (mirror)"
|
||||||
}
|
}
|
||||||
if repo.Fork {
|
if repo.Fork {
|
||||||
output += " (fork)"
|
title += " (fork)"
|
||||||
}
|
}
|
||||||
if repo.Archived {
|
if repo.Archived {
|
||||||
output += " (archived)"
|
title += " (archived)"
|
||||||
}
|
}
|
||||||
if repo.Empty {
|
if repo.Empty {
|
||||||
output += " (empty)"
|
title += " (empty)"
|
||||||
}
|
}
|
||||||
output += "\n"
|
title += "\n"
|
||||||
if len(topics) != 0 {
|
|
||||||
output += "Topics: " + strings.Join(topics, ", ") + "\n"
|
var desc string
|
||||||
|
if len(repo.Description) != 0 {
|
||||||
|
desc = fmt.Sprintf("*%s*\n\n", repo.Description)
|
||||||
}
|
}
|
||||||
output += "\n"
|
|
||||||
output += repo.Description + "\n\n"
|
stats := fmt.Sprintf(
|
||||||
output += fmt.Sprintf(
|
"Issues: %d, Stars: %d, Forks: %d, Size: %s\n",
|
||||||
"Open Issues: %d, Stars: %d, Forks: %d, Size: %s\n\n",
|
|
||||||
repo.OpenIssues,
|
repo.OpenIssues,
|
||||||
repo.Stars,
|
repo.Stars,
|
||||||
repo.Forks,
|
repo.Forks,
|
||||||
formatSize(int64(repo.Size)),
|
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,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue