mirror of
				https://gitea.com/gitea/tea.git
				synced 2025-10-30 16:55:25 +01:00 
			
		
		
		
	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:
		| @@ -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, | ||||||
|  | 	)) | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Norwin
					Norwin