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