ls.go

  1package commands
  2
  3import (
  4	"fmt"
  5	"strings"
  6
  7	"github.com/MichaelMure/git-bug/cache"
  8	"github.com/MichaelMure/git-bug/util/colors"
  9	"github.com/MichaelMure/git-bug/util/interrupt"
 10	"github.com/MichaelMure/git-bug/util/text"
 11	"github.com/spf13/cobra"
 12)
 13
 14var (
 15	lsStatusQuery      []string
 16	lsAuthorQuery      []string
 17	lsParticipantQuery []string
 18	lsLabelQuery       []string
 19	lsTitleQuery       []string
 20	lsActorQuery       []string
 21	lsNoQuery          []string
 22	lsSortBy           string
 23	lsSortDirection    string
 24)
 25
 26func runLsBug(cmd *cobra.Command, args []string) error {
 27	backend, err := cache.NewRepoCache(repo)
 28	if err != nil {
 29		return err
 30	}
 31	defer backend.Close()
 32	interrupt.RegisterCleaner(backend.Close)
 33
 34	var query *cache.Query
 35	if len(args) >= 1 {
 36		query, err = cache.ParseQuery(strings.Join(args, " "))
 37
 38		if err != nil {
 39			return err
 40		}
 41	} else {
 42		query, err = lsQueryFromFlags()
 43		if err != nil {
 44			return err
 45		}
 46	}
 47
 48	allIds := backend.QueryBugs(query)
 49
 50	for _, id := range allIds {
 51		b, err := backend.ResolveBugExcerpt(id)
 52		if err != nil {
 53			return err
 54		}
 55
 56		var name string
 57		if b.AuthorId != "" {
 58			author, err := backend.ResolveIdentityExcerpt(b.AuthorId)
 59			if err != nil {
 60				name = "<missing author data>"
 61			} else {
 62				name = author.DisplayName()
 63			}
 64		} else {
 65			name = b.LegacyAuthor.DisplayName()
 66		}
 67
 68		labelsTxt := ""
 69		nbLabels := 0
 70		for _, l := range b.Labels {
 71			lc := l.Color()
 72			lc256 := lc.Term256()
 73			nbLabels++
 74			if nbLabels >= 5 && len(b.Labels) > 5 {
 75				labelsTxt += " …"
 76				break
 77			}
 78			labelsTxt += lc256.Escape() + " ◼" + lc256.Unescape()
 79		}
 80
 81		// truncate + pad if needed
 82		titleFmt := text.LeftPadMaxLine(b.Title, 50-(nbLabels*2), 0)
 83		authorFmt := text.LeftPadMaxLine(name, 15, 0)
 84
 85		comments := fmt.Sprintf("%4d 💬", b.LenComments)
 86		if b.LenComments > 9999 {
 87			comments = "    ∞ 💬"
 88		}
 89
 90		fmt.Printf("%s %s\t%s\t%s\t%s\n",
 91			colors.Cyan(b.Id.Human()),
 92			colors.Yellow(b.Status),
 93			titleFmt+labelsTxt,
 94			colors.Magenta(authorFmt),
 95			comments,
 96		)
 97	}
 98
 99	return nil
100}
101
102// Transform the command flags into a query
103func lsQueryFromFlags() (*cache.Query, error) {
104	query := cache.NewQuery()
105
106	for _, status := range lsStatusQuery {
107		f, err := cache.StatusFilter(status)
108		if err != nil {
109			return nil, err
110		}
111		query.Status = append(query.Status, f)
112	}
113
114	for _, title := range lsTitleQuery {
115		f := cache.TitleFilter(title)
116		query.Title = append(query.Title, f)
117	}
118
119	for _, author := range lsAuthorQuery {
120		f := cache.AuthorFilter(author)
121		query.Author = append(query.Author, f)
122	}
123
124	for _, actor := range lsActorQuery {
125		f := cache.ActorFilter(actor)
126		query.Actor = append(query.Actor, f)
127	}
128
129	for _, participant := range lsParticipantQuery {
130		f := cache.ParticipantFilter(participant)
131		query.Participant = append(query.Participant, f)
132	}
133
134	for _, label := range lsLabelQuery {
135		f := cache.LabelFilter(label)
136		query.Label = append(query.Label, f)
137	}
138
139	for _, no := range lsNoQuery {
140		switch no {
141		case "label":
142			query.NoFilters = append(query.NoFilters, cache.NoLabelFilter())
143		default:
144			return nil, fmt.Errorf("unknown \"no\" filter %s", no)
145		}
146	}
147
148	switch lsSortBy {
149	case "id":
150		query.OrderBy = cache.OrderById
151	case "creation":
152		query.OrderBy = cache.OrderByCreation
153	case "edit":
154		query.OrderBy = cache.OrderByEdit
155	default:
156		return nil, fmt.Errorf("unknown sort flag %s", lsSortBy)
157	}
158
159	switch lsSortDirection {
160	case "asc":
161		query.OrderDirection = cache.OrderAscending
162	case "desc":
163		query.OrderDirection = cache.OrderDescending
164	default:
165		return nil, fmt.Errorf("unknown sort direction %s", lsSortDirection)
166	}
167
168	return query, nil
169}
170
171var lsCmd = &cobra.Command{
172	Use:   "ls [<query>]",
173	Short: "List bugs.",
174	Long: `Display a summary of each bugs.
175
176You can pass an additional query to filter and order the list. This query can be expressed either with a simple query language or with flags.`,
177	Example: `List open bugs sorted by last edition with a query:
178git bug ls status:open sort:edit-desc
179
180List closed bugs sorted by creation with flags:
181git bug ls --status closed --by creation
182`,
183	PreRunE: loadRepo,
184	RunE:    runLsBug,
185}
186
187func init() {
188	RootCmd.AddCommand(lsCmd)
189
190	lsCmd.Flags().SortFlags = false
191
192	lsCmd.Flags().StringSliceVarP(&lsStatusQuery, "status", "s", nil,
193		"Filter by status. Valid values are [open,closed]")
194	lsCmd.Flags().StringSliceVarP(&lsAuthorQuery, "author", "a", nil,
195		"Filter by author")
196	lsCmd.Flags().StringSliceVarP(&lsParticipantQuery, "participant", "p", nil,
197		"Filter by participant")
198	lsCmd.Flags().StringSliceVarP(&lsActorQuery, "actor", "A", nil,
199		"Filter by actor")
200	lsCmd.Flags().StringSliceVarP(&lsLabelQuery, "label", "l", nil,
201		"Filter by label")
202	lsCmd.Flags().StringSliceVarP(&lsTitleQuery, "title", "t", nil,
203		"Filter by title")
204	lsCmd.Flags().StringSliceVarP(&lsNoQuery, "no", "n", nil,
205		"Filter by absence of something. Valid values are [label]")
206	lsCmd.Flags().StringVarP(&lsSortBy, "by", "b", "creation",
207		"Sort the results by a characteristic. Valid values are [id,creation,edit]")
208	lsCmd.Flags().StringVarP(&lsSortDirection, "direction", "d", "asc",
209		"Select the sorting direction. Valid values are [asc,desc]")
210}