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}