1package bugcmd
2
3import (
4 "errors"
5 "fmt"
6 "strings"
7
8 "github.com/spf13/cobra"
9
10 "github.com/MichaelMure/git-bug/commands/cmdjson"
11 "github.com/MichaelMure/git-bug/commands/completion"
12 "github.com/MichaelMure/git-bug/commands/execenv"
13 "github.com/MichaelMure/git-bug/entities/bug"
14 "github.com/MichaelMure/git-bug/util/colors"
15)
16
17type bugShowOptions struct {
18 fields string
19 format string
20}
21
22func newBugShowCommand(env *execenv.Env) *cobra.Command {
23 options := bugShowOptions{}
24
25 cmd := &cobra.Command{
26 Use: "show [BUG_ID]",
27 Short: "Display the details of a bug",
28 PreRunE: execenv.LoadBackend(env),
29 RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
30 return runBugShow(env, options, args)
31 }),
32 ValidArgsFunction: BugCompletion(env),
33 }
34
35 flags := cmd.Flags()
36 flags.SortFlags = false
37
38 fields := []string{"author", "authorEmail", "createTime", "lastEdit", "humanId",
39 "id", "labels", "shortId", "status", "title", "actors", "participants"}
40 flags.StringVarP(&options.fields, "field", "", "",
41 "Select field to display. Valid values are ["+strings.Join(fields, ",")+"]")
42 cmd.RegisterFlagCompletionFunc("by", completion.From(fields))
43 flags.StringVarP(&options.format, "format", "f", "default",
44 "Select the output formatting style. Valid values are [default,json,org-mode]")
45
46 return cmd
47}
48
49func runBugShow(env *execenv.Env, opts bugShowOptions, args []string) error {
50 b, _, err := ResolveSelected(env.Backend, args)
51 if err != nil {
52 return err
53 }
54
55 snap := b.Compile()
56
57 if len(snap.Comments) == 0 {
58 return errors.New("invalid bug: no comment")
59 }
60
61 if opts.fields != "" {
62 switch opts.fields {
63 case "author":
64 env.Out.Printf("%s\n", snap.Author.DisplayName())
65 case "authorEmail":
66 env.Out.Printf("%s\n", snap.Author.Email())
67 case "createTime":
68 env.Out.Printf("%s\n", snap.CreateTime.String())
69 case "lastEdit":
70 env.Out.Printf("%s\n", snap.EditTime().String())
71 case "humanId":
72 env.Out.Printf("%s\n", snap.Id().Human())
73 case "id":
74 env.Out.Printf("%s\n", snap.Id())
75 case "labels":
76 for _, l := range snap.Labels {
77 env.Out.Printf("%s\n", l.String())
78 }
79 case "actors":
80 for _, a := range snap.Actors {
81 env.Out.Printf("%s\n", a.DisplayName())
82 }
83 case "participants":
84 for _, p := range snap.Participants {
85 env.Out.Printf("%s\n", p.DisplayName())
86 }
87 case "shortId":
88 env.Out.Printf("%s\n", snap.Id().Human())
89 case "status":
90 env.Out.Printf("%s\n", snap.Status)
91 case "title":
92 env.Out.Printf("%s\n", snap.Title)
93 default:
94 return fmt.Errorf("unsupported field: %s", opts.fields)
95 }
96
97 return nil
98 }
99
100 switch opts.format {
101 case "org-mode":
102 return showOrgModeFormatter(env, snap)
103 case "json":
104 return showJsonFormatter(env, snap)
105 case "default":
106 return showDefaultFormatter(env, snap)
107 default:
108 return fmt.Errorf("unknown format %s", opts.format)
109 }
110}
111
112func showDefaultFormatter(env *execenv.Env, snapshot *bug.Snapshot) error {
113 // Header
114 env.Out.Printf("%s [%s] %s\n\n",
115 colors.Cyan(snapshot.Id().Human()),
116 colors.Yellow(snapshot.Status),
117 snapshot.Title,
118 )
119
120 env.Out.Printf("%s opened this issue %s\n",
121 colors.Magenta(snapshot.Author.DisplayName()),
122 snapshot.CreateTime.String(),
123 )
124
125 env.Out.Printf("This was last edited at %s\n\n",
126 snapshot.EditTime().String(),
127 )
128
129 // Labels
130 var labels = make([]string, len(snapshot.Labels))
131 for i := range snapshot.Labels {
132 labels[i] = string(snapshot.Labels[i])
133 }
134
135 env.Out.Printf("labels: %s\n",
136 strings.Join(labels, ", "),
137 )
138
139 // Actors
140 var actors = make([]string, len(snapshot.Actors))
141 for i := range snapshot.Actors {
142 actors[i] = snapshot.Actors[i].DisplayName()
143 }
144
145 env.Out.Printf("actors: %s\n",
146 strings.Join(actors, ", "),
147 )
148
149 // Participants
150 var participants = make([]string, len(snapshot.Participants))
151 for i := range snapshot.Participants {
152 participants[i] = snapshot.Participants[i].DisplayName()
153 }
154
155 env.Out.Printf("participants: %s\n\n",
156 strings.Join(participants, ", "),
157 )
158
159 // Comments
160 indent := " "
161
162 for i, comment := range snapshot.Comments {
163 var message string
164 env.Out.Printf("%s%s #%d %s <%s>\n\n",
165 indent,
166 comment.CombinedId().Human(),
167 i,
168 comment.Author.DisplayName(),
169 comment.Author.Email(),
170 )
171
172 if comment.Message == "" {
173 message = colors.BlackBold(colors.WhiteBg("No description provided."))
174 } else {
175 message = comment.Message
176 }
177
178 env.Out.Printf("%s%s\n\n\n",
179 indent,
180 message,
181 )
182 }
183
184 return nil
185}
186
187func showJsonFormatter(env *execenv.Env, snap *bug.Snapshot) error {
188 jsonBug := cmdjson.NewBugSnapshot(snap)
189 return env.Out.PrintJSON(jsonBug)
190}
191
192func showOrgModeFormatter(env *execenv.Env, snapshot *bug.Snapshot) error {
193 // Header
194 env.Out.Printf("%s [%s] %s\n",
195 snapshot.Id().Human(),
196 snapshot.Status,
197 snapshot.Title,
198 )
199
200 env.Out.Printf("* Author: %s\n",
201 snapshot.Author.DisplayName(),
202 )
203
204 env.Out.Printf("* Creation Time: %s\n",
205 snapshot.CreateTime.String(),
206 )
207
208 env.Out.Printf("* Last Edit: %s\n",
209 snapshot.EditTime().String(),
210 )
211
212 // Labels
213 var labels = make([]string, len(snapshot.Labels))
214 for i, label := range snapshot.Labels {
215 labels[i] = string(label)
216 }
217
218 env.Out.Printf("* Labels:\n")
219 if len(labels) > 0 {
220 env.Out.Printf("** %s\n",
221 strings.Join(labels, "\n** "),
222 )
223 }
224
225 // Actors
226 var actors = make([]string, len(snapshot.Actors))
227 for i, actor := range snapshot.Actors {
228 actors[i] = fmt.Sprintf("%s %s",
229 actor.Id().Human(),
230 actor.DisplayName(),
231 )
232 }
233
234 env.Out.Printf("* Actors:\n** %s\n",
235 strings.Join(actors, "\n** "),
236 )
237
238 // Participants
239 var participants = make([]string, len(snapshot.Participants))
240 for i, participant := range snapshot.Participants {
241 participants[i] = fmt.Sprintf("%s %s",
242 participant.Id().Human(),
243 participant.DisplayName(),
244 )
245 }
246
247 env.Out.Printf("* Participants:\n** %s\n",
248 strings.Join(participants, "\n** "),
249 )
250
251 env.Out.Printf("* Comments:\n")
252
253 for i, comment := range snapshot.Comments {
254 var message string
255 env.Out.Printf("** #%d %s\n",
256 i, comment.Author.DisplayName())
257
258 if comment.Message == "" {
259 message = "No description provided."
260 } else {
261 message = strings.ReplaceAll(comment.Message, "\n", "\n: ")
262 }
263
264 env.Out.Printf(": %s\n", message)
265 }
266
267 return nil
268}