show.go

  1package commands
  2
  3import (
  4	"encoding/json"
  5	"errors"
  6	"fmt"
  7	"strings"
  8
  9	"github.com/spf13/cobra"
 10
 11	"github.com/MichaelMure/git-bug/bug"
 12	_select "github.com/MichaelMure/git-bug/commands/select"
 13	"github.com/MichaelMure/git-bug/util/colors"
 14)
 15
 16type showOptions struct {
 17	query  string
 18	format string
 19}
 20
 21func newShowCommand() *cobra.Command {
 22	env := newEnv()
 23	options := showOptions{}
 24
 25	cmd := &cobra.Command{
 26		Use:      "show [<id>]",
 27		Short:    "Display the details of a bug.",
 28		PreRunE:  loadBackend(env),
 29		PostRunE: closeBackend(env),
 30		RunE: func(cmd *cobra.Command, args []string) error {
 31			return runShow(env, options, args)
 32		},
 33	}
 34
 35	flags := cmd.Flags()
 36	flags.SortFlags = false
 37
 38	flags.StringVarP(&options.query, "field", "", "",
 39		"Select field to display. Valid values are [author,authorEmail,createTime,lastEdit,humanId,id,labels,shortId,status,title,actors,participants]")
 40	flags.StringVarP(&options.format, "format", "f", "default",
 41		"Select the output formatting style. Valid values are [default,json,org-mode]")
 42
 43	return cmd
 44}
 45
 46func runShow(env *Env, opts showOptions, args []string) error {
 47	b, args, err := _select.ResolveBug(env.backend, args)
 48	if err != nil {
 49		return err
 50	}
 51
 52	snap := b.Snapshot()
 53
 54	if len(snap.Comments) == 0 {
 55		return errors.New("invalid bug: no comment")
 56	}
 57
 58	if opts.query != "" {
 59		switch opts.query {
 60		case "author":
 61			env.out.Printf("%s\n", snap.Author.DisplayName())
 62		case "authorEmail":
 63			env.out.Printf("%s\n", snap.Author.Email())
 64		case "createTime":
 65			env.out.Printf("%s\n", snap.CreateTime.String())
 66		case "lastEdit":
 67			env.out.Printf("%s\n", snap.EditTime().String())
 68		case "humanId":
 69			env.out.Printf("%s\n", snap.Id().Human())
 70		case "id":
 71			env.out.Printf("%s\n", snap.Id())
 72		case "labels":
 73			for _, l := range snap.Labels {
 74				env.out.Printf("%s\n", l.String())
 75			}
 76		case "actors":
 77			for _, a := range snap.Actors {
 78				env.out.Printf("%s\n", a.DisplayName())
 79			}
 80		case "participants":
 81			for _, p := range snap.Participants {
 82				env.out.Printf("%s\n", p.DisplayName())
 83			}
 84		case "shortId":
 85			env.out.Printf("%s\n", snap.Id().Human())
 86		case "status":
 87			env.out.Printf("%s\n", snap.Status)
 88		case "title":
 89			env.out.Printf("%s\n", snap.Title)
 90		default:
 91			return fmt.Errorf("\nUnsupported field: %s\n", opts.query)
 92		}
 93
 94		return nil
 95	}
 96
 97	switch opts.format {
 98	case "org-mode":
 99		return showOrgModeFormatter(env, snap)
100	case "json":
101		return showJsonFormatter(env, snap)
102	case "default":
103		return showDefaultFormatter(env, snap)
104	default:
105		return fmt.Errorf("unknown format %s", opts.format)
106	}
107}
108
109func showDefaultFormatter(env *Env, snapshot *bug.Snapshot) error {
110	// Header
111	env.out.Printf("%s [%s] %s\n\n",
112		colors.Cyan(snapshot.Id().Human()),
113		colors.Yellow(snapshot.Status),
114		snapshot.Title,
115	)
116
117	env.out.Printf("%s opened this issue %s\n",
118		colors.Magenta(snapshot.Author.DisplayName()),
119		snapshot.CreateTime.String(),
120	)
121
122	env.out.Printf("This was last edited at %s\n\n",
123		snapshot.EditTime().String(),
124	)
125
126	// Labels
127	var labels = make([]string, len(snapshot.Labels))
128	for i := range snapshot.Labels {
129		labels[i] = string(snapshot.Labels[i])
130	}
131
132	env.out.Printf("labels: %s\n",
133		strings.Join(labels, ", "),
134	)
135
136	// Actors
137	var actors = make([]string, len(snapshot.Actors))
138	for i := range snapshot.Actors {
139		actors[i] = snapshot.Actors[i].DisplayName()
140	}
141
142	env.out.Printf("actors: %s\n",
143		strings.Join(actors, ", "),
144	)
145
146	// Participants
147	var participants = make([]string, len(snapshot.Participants))
148	for i := range snapshot.Participants {
149		participants[i] = snapshot.Participants[i].DisplayName()
150	}
151
152	env.out.Printf("participants: %s\n\n",
153		strings.Join(participants, ", "),
154	)
155
156	// Comments
157	indent := "  "
158
159	for i, comment := range snapshot.Comments {
160		var message string
161		env.out.Printf("%s%s #%d %s <%s>\n\n",
162			indent,
163			comment.Id().Human(),
164			i,
165			comment.Author.DisplayName(),
166			comment.Author.Email(),
167		)
168
169		if comment.Message == "" {
170			message = colors.GreyBold("No description provided.")
171		} else {
172			message = comment.Message
173		}
174
175		env.out.Printf("%s%s\n\n\n",
176			indent,
177			message,
178		)
179	}
180
181	return nil
182}
183
184type JSONBugSnapshot struct {
185	Id           string         `json:"id"`
186	HumanId      string         `json:"human_id"`
187	CreateTime   JSONTime       `json:"create_time"`
188	EditTime     JSONTime       `json:"edit_time"`
189	Status       string         `json:"status"`
190	Labels       []bug.Label    `json:"labels"`
191	Title        string         `json:"title"`
192	Author       JSONIdentity   `json:"author"`
193	Actors       []JSONIdentity `json:"actors"`
194	Participants []JSONIdentity `json:"participants"`
195	Comments     []JSONComment  `json:"comments"`
196}
197
198type JSONComment struct {
199	Id      string       `json:"id"`
200	HumanId string       `json:"human_id"`
201	Author  JSONIdentity `json:"author"`
202	Message string       `json:"message"`
203}
204
205func NewJSONComment(comment bug.Comment) JSONComment {
206	return JSONComment{
207		Id:      comment.Id().String(),
208		HumanId: comment.Id().Human(),
209		Author:  NewJSONIdentity(comment.Author),
210		Message: comment.Message,
211	}
212}
213
214func showJsonFormatter(env *Env, snapshot *bug.Snapshot) error {
215	jsonBug := JSONBugSnapshot{
216		Id:         snapshot.Id().String(),
217		HumanId:    snapshot.Id().Human(),
218		CreateTime: NewJSONTime(snapshot.CreateTime, 0),
219		EditTime:   NewJSONTime(snapshot.EditTime(), 0),
220		Status:     snapshot.Status.String(),
221		Labels:     snapshot.Labels,
222		Title:      snapshot.Title,
223		Author:     NewJSONIdentity(snapshot.Author),
224	}
225
226	jsonBug.Actors = make([]JSONIdentity, len(snapshot.Actors))
227	for i, element := range snapshot.Actors {
228		jsonBug.Actors[i] = NewJSONIdentity(element)
229	}
230
231	jsonBug.Participants = make([]JSONIdentity, len(snapshot.Participants))
232	for i, element := range snapshot.Participants {
233		jsonBug.Participants[i] = NewJSONIdentity(element)
234	}
235
236	jsonBug.Comments = make([]JSONComment, len(snapshot.Comments))
237	for i, comment := range snapshot.Comments {
238		jsonBug.Comments[i] = NewJSONComment(comment)
239	}
240
241	jsonObject, _ := json.MarshalIndent(jsonBug, "", "    ")
242	env.out.Printf("%s\n", jsonObject)
243
244	return nil
245}
246
247func showOrgModeFormatter(env *Env, snapshot *bug.Snapshot) error {
248	// Header
249	env.out.Printf("%s [%s] %s\n",
250		snapshot.Id().Human(),
251		snapshot.Status,
252		snapshot.Title,
253	)
254
255	env.out.Printf("* Author: %s\n",
256		snapshot.Author.DisplayName(),
257	)
258
259	env.out.Printf("* Creation Time: %s\n",
260		snapshot.CreateTime.String(),
261	)
262
263	env.out.Printf("* Last Edit: %s\n",
264		snapshot.EditTime().String(),
265	)
266
267	// Labels
268	var labels = make([]string, len(snapshot.Labels))
269	for i, label := range snapshot.Labels {
270		labels[i] = string(label)
271	}
272
273	env.out.Printf("* Labels:\n")
274	if len(labels) > 0 {
275		env.out.Printf("** %s\n",
276			strings.Join(labels, "\n** "),
277		)
278	}
279
280	// Actors
281	var actors = make([]string, len(snapshot.Actors))
282	for i, actor := range snapshot.Actors {
283		actors[i] = fmt.Sprintf("%s %s",
284			actor.Id().Human(),
285			actor.DisplayName(),
286		)
287	}
288
289	env.out.Printf("* Actors:\n** %s\n",
290		strings.Join(actors, "\n** "),
291	)
292
293	// Participants
294	var participants = make([]string, len(snapshot.Participants))
295	for i, participant := range snapshot.Participants {
296		participants[i] = fmt.Sprintf("%s %s",
297			participant.Id().Human(),
298			participant.DisplayName(),
299		)
300	}
301
302	env.out.Printf("* Participants:\n** %s\n",
303		strings.Join(participants, "\n** "),
304	)
305
306	env.out.Printf("* Comments:\n")
307
308	for i, comment := range snapshot.Comments {
309		var message string
310		env.out.Printf("** #%d %s\n",
311			i, comment.Author.DisplayName())
312
313		if comment.Message == "" {
314			message = "No description provided."
315		} else {
316			message = strings.ReplaceAll(comment.Message, "\n", "\n: ")
317		}
318
319		env.out.Printf(": %s\n", message)
320	}
321
322	return nil
323}