show.go

  1package commands
  2
  3import (
  4	"encoding/json"
  5	"errors"
  6	"fmt"
  7	"github.com/MichaelMure/git-bug/bug"
  8	"github.com/MichaelMure/git-bug/cache"
  9	_select "github.com/MichaelMure/git-bug/commands/select"
 10	"github.com/MichaelMure/git-bug/util/colors"
 11	"github.com/MichaelMure/git-bug/util/interrupt"
 12	"github.com/spf13/cobra"
 13	"strings"
 14	"time"
 15)
 16
 17var (
 18	showFieldsQuery  string
 19	showOutputFormat string
 20)
 21
 22func runShowBug(_ *cobra.Command, args []string) error {
 23	backend, err := cache.NewRepoCache(repo)
 24	if err != nil {
 25		return err
 26	}
 27	defer backend.Close()
 28	interrupt.RegisterCleaner(backend.Close)
 29
 30	b, args, err := _select.ResolveBug(backend, args)
 31	if err != nil {
 32		return err
 33	}
 34
 35	snapshot := b.Snapshot()
 36
 37	if len(snapshot.Comments) == 0 {
 38		return errors.New("invalid bug: no comment")
 39	}
 40
 41	if showFieldsQuery != "" {
 42		switch showFieldsQuery {
 43		case "author":
 44			fmt.Printf("%s\n", snapshot.Author.DisplayName())
 45		case "authorEmail":
 46			fmt.Printf("%s\n", snapshot.Author.Email())
 47		case "createTime":
 48			fmt.Printf("%s\n", snapshot.CreatedAt.String())
 49		case "lastEdit":
 50			fmt.Printf("%s\n", snapshot.LastEditTime().String())
 51		case "humanId":
 52			fmt.Printf("%s\n", snapshot.Id().Human())
 53		case "id":
 54			fmt.Printf("%s\n", snapshot.Id())
 55		case "labels":
 56			for _, l := range snapshot.Labels {
 57				fmt.Printf("%s\n", l.String())
 58			}
 59		case "actors":
 60			for _, a := range snapshot.Actors {
 61				fmt.Printf("%s\n", a.DisplayName())
 62			}
 63		case "participants":
 64			for _, p := range snapshot.Participants {
 65				fmt.Printf("%s\n", p.DisplayName())
 66			}
 67		case "shortId":
 68			fmt.Printf("%s\n", snapshot.Id().Human())
 69		case "status":
 70			fmt.Printf("%s\n", snapshot.Status)
 71		case "title":
 72			fmt.Printf("%s\n", snapshot.Title)
 73		default:
 74			return fmt.Errorf("\nUnsupported field: %s\n", showFieldsQuery)
 75		}
 76
 77		return nil
 78	}
 79
 80	switch showOutputFormat {
 81	case "org-mode":
 82		return showOrgmodeFormatter(snapshot)
 83	case "json":
 84		return showJsonFormatter(snapshot)
 85	case "plain":
 86		return showPlainFormatter(snapshot)
 87	case "default":
 88		return showDefaultFormatter(snapshot)
 89	default:
 90		return fmt.Errorf("unknown format %s", showOutputFormat)
 91	}
 92}
 93
 94func showDefaultFormatter(snapshot *bug.Snapshot) error {
 95	// Header
 96	fmt.Printf("%s [%s] %s\n\n",
 97		colors.Cyan(snapshot.Id().Human()),
 98		colors.Yellow(snapshot.Status),
 99		snapshot.Title,
100	)
101
102	fmt.Printf("%s opened this issue %s\n",
103		colors.Magenta(snapshot.Author.DisplayName()),
104		snapshot.CreatedAt.String(),
105	)
106
107	fmt.Printf("This was last edited at %s\n\n",
108		snapshot.LastEditTime().String(),
109	)
110
111	// Labels
112	var labels = make([]string, len(snapshot.Labels))
113	for i := range snapshot.Labels {
114		labels[i] = string(snapshot.Labels[i])
115	}
116
117	fmt.Printf("labels: %s\n",
118		strings.Join(labels, ", "),
119	)
120
121	// Actors
122	var actors = make([]string, len(snapshot.Actors))
123	for i := range snapshot.Actors {
124		actors[i] = snapshot.Actors[i].DisplayName()
125	}
126
127	fmt.Printf("actors: %s\n",
128		strings.Join(actors, ", "),
129	)
130
131	// Participants
132	var participants = make([]string, len(snapshot.Participants))
133	for i := range snapshot.Participants {
134		participants[i] = snapshot.Participants[i].DisplayName()
135	}
136
137	fmt.Printf("participants: %s\n\n",
138		strings.Join(participants, ", "),
139	)
140
141	// Comments
142	indent := "  "
143
144	for i, comment := range snapshot.Comments {
145		var message string
146		fmt.Printf("%s#%d %s <%s>\n\n",
147			indent,
148			i,
149			comment.Author.DisplayName(),
150			comment.Author.Email(),
151		)
152
153		if comment.Message == "" {
154			message = colors.GreyBold("No description provided.")
155		} else {
156			message = comment.Message
157		}
158
159		fmt.Printf("%s%s\n\n\n",
160			indent,
161			message,
162		)
163	}
164
165	return nil
166}
167
168func showPlainFormatter(snapshot *bug.Snapshot) error {
169	// Header
170	fmt.Printf("%s [%s] %s\n",
171		snapshot.Id().Human(),
172		snapshot.Status,
173		snapshot.Title,
174	)
175
176	fmt.Printf("author: %s\n",
177		snapshot.Author.DisplayName(),
178	)
179
180	fmt.Printf("creation time: %s\n",
181		snapshot.CreatedAt.String(),
182	)
183
184	fmt.Printf("last edit: %s\n",
185		snapshot.LastEditTime().String(),
186	)
187
188	// Labels
189	var labels = make([]string, len(snapshot.Labels))
190	for i := range snapshot.Labels {
191		labels[i] = string(snapshot.Labels[i])
192	}
193
194	fmt.Printf("labels: %s\n",
195		strings.Join(labels, ", "),
196	)
197
198	// Actors
199	var actors = make([]string, len(snapshot.Actors))
200	for i := range snapshot.Actors {
201		actors[i] = snapshot.Actors[i].DisplayName()
202	}
203
204	fmt.Printf("actors: %s\n",
205		strings.Join(actors, ", "),
206	)
207
208	// Participants
209	var participants = make([]string, len(snapshot.Participants))
210	for i := range snapshot.Participants {
211		participants[i] = snapshot.Participants[i].DisplayName()
212	}
213
214	fmt.Printf("participants: %s\n",
215		strings.Join(participants, ", "),
216	)
217
218	// Comments
219	indent := "  "
220
221	for i, comment := range snapshot.Comments {
222		var message string
223		fmt.Printf("%s#%d %s <%s>\n",
224			indent,
225			i,
226			comment.Author.DisplayName(),
227			comment.Author.Email(),
228		)
229
230		if comment.Message == "" {
231			message = "No description provided."
232		} else {
233			message = comment.Message
234		}
235
236		fmt.Printf("%s%s\n",
237			indent,
238			strings.ReplaceAll(message, "\n", fmt.Sprintf("\n%s", indent)),
239		)
240	}
241
242	return nil
243}
244
245type JSONBugSnapshot struct {
246	Id           string    `json:"id"`
247	HumanId      string    `json:"human_id"`
248	CreationTime time.Time `json:"creation_time"`
249	LastEdited   time.Time `json:"last_edited"`
250
251	Status       string         `json:"status"`
252	Labels       []bug.Label    `json:"labels"`
253	Title        string         `json:"title"`
254	Author       JSONIdentity   `json:"author"`
255	Actors       []JSONIdentity `json:"actors"`
256	Participants []JSONIdentity `json:"participants"`
257
258	Comments []JSONComment `json:"comments"`
259}
260
261type JSONComment struct {
262	Id          int    `json:"id"`
263	AuthorName  string `json:"author_name"`
264	AuthorLogin string `json:"author_login"`
265	Message     string `json:"message"`
266}
267
268func showJsonFormatter(snapshot *bug.Snapshot) error {
269	jsonBug := JSONBugSnapshot{
270		snapshot.Id().String(),
271		snapshot.Id().Human(),
272		snapshot.CreatedAt,
273		snapshot.LastEditTime(),
274		snapshot.Status.String(),
275		snapshot.Labels,
276		snapshot.Title,
277		JSONIdentity{},
278		[]JSONIdentity{},
279		[]JSONIdentity{},
280		[]JSONComment{},
281	}
282
283	author, err := NewJSONIdentity(snapshot.Author)
284	if err != nil {
285		return err
286	}
287	jsonBug.Author = author
288
289	for _, element := range snapshot.Actors {
290		actor, err := NewJSONIdentity(element)
291		if err != nil {
292			return err
293		}
294		jsonBug.Actors = append(jsonBug.Actors, actor)
295	}
296
297	for _, element := range snapshot.Participants {
298		participant, err := NewJSONIdentity(element)
299		if err != nil {
300			return err
301		}
302		jsonBug.Participants = append(jsonBug.Participants, participant)
303	}
304
305	for i, comment := range snapshot.Comments {
306		var message string
307		if comment.Message == "" {
308			message = "No description provided."
309		} else {
310			message = comment.Message
311		}
312		jsonBug.Comments = append(jsonBug.Comments, JSONComment{
313			i,
314			comment.Author.Name(),
315			comment.Author.Login(),
316			message,
317		})
318	}
319
320	jsonObject, _ := json.MarshalIndent(jsonBug, "", "    ")
321	fmt.Printf("%s\n", jsonObject)
322
323	return nil
324}
325
326func showOrgmodeFormatter(snapshot *bug.Snapshot) error {
327	// Header
328	fmt.Printf("%s [%s] %s\n",
329		snapshot.Id().Human(),
330		snapshot.Status,
331		snapshot.Title,
332	)
333
334	fmt.Printf("* Author: %s\n",
335		snapshot.Author.DisplayName(),
336	)
337
338	fmt.Printf("* Creation Time: %s\n",
339		snapshot.CreatedAt.String(),
340	)
341
342	fmt.Printf("* Last Edit: %s\n",
343		snapshot.LastEditTime().String(),
344	)
345
346	// Labels
347	var labels = make([]string, len(snapshot.Labels))
348	for i, label := range snapshot.Labels {
349		labels[i] = string(label)
350	}
351
352	fmt.Printf("* Labels:\n")
353	if len(labels) > 0 {
354		fmt.Printf("** %s\n",
355			strings.Join(labels, "\n** "),
356		)
357	}
358
359	// Actors
360	var actors = make([]string, len(snapshot.Actors))
361	for i, actor := range snapshot.Actors {
362		actors[i] = fmt.Sprintf("%s %s",
363			actor.Id().Human(),
364			actor.DisplayName(),
365		)
366	}
367
368	fmt.Printf("* Actors:\n** %s\n",
369		strings.Join(actors, "\n** "),
370	)
371
372	// Participants
373	var participants = make([]string, len(snapshot.Participants))
374	for i, participant := range snapshot.Participants {
375		participants[i] = fmt.Sprintf("%s %s",
376			participant.Id().Human(),
377			participant.DisplayName(),
378		)
379	}
380
381	fmt.Printf("* Participants:\n** %s\n",
382		strings.Join(participants, "\n** "),
383	)
384
385	fmt.Printf("* Comments:\n")
386
387	for i, comment := range snapshot.Comments {
388		var message string
389		fmt.Printf("** #%d %s\n",
390			i,
391			comment.Author.DisplayName(),
392		)
393
394		if comment.Message == "" {
395			message = "No description provided."
396		} else {
397			message = strings.ReplaceAll(comment.Message, "\n", "\n: ")
398		}
399
400		fmt.Printf(": %s\n",
401			message,
402		)
403	}
404
405	return nil
406}
407
408var showCmd = &cobra.Command{
409	Use:     "show [<id>]",
410	Short:   "Display the details of a bug.",
411	PreRunE: loadRepo,
412	RunE:    runShowBug,
413}
414
415func init() {
416	RootCmd.AddCommand(showCmd)
417	showCmd.Flags().StringVarP(&showFieldsQuery, "field", "", "",
418		"Select field to display. Valid values are [author,authorEmail,createTime,lastEdit,humanId,id,labels,shortId,status,title,actors,participants]")
419	showCmd.Flags().StringVarP(&showOutputFormat, "format", "f", "default",
420		"Select the output formatting style. Valid values are [default,plain,json,org-mode]")
421}