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			message,
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	jsonBug.Author.Name = snapshot.Author.DisplayName()
284	jsonBug.Author.Login = snapshot.Author.Login()
285	jsonBug.Author.Id = snapshot.Author.Id().String()
286	jsonBug.Author.HumanId = snapshot.Author.Id().Human()
287
288	for _, element := range snapshot.Actors {
289		jsonBug.Actors = append(jsonBug.Actors, JSONIdentity{
290			element.Id().String(),
291			element.Id().Human(),
292			element.Name(),
293			element.Login(),
294		})
295	}
296
297	for _, element := range snapshot.Participants {
298		jsonBug.Actors = append(jsonBug.Actors, JSONIdentity{
299			element.Id().String(),
300			element.Id().Human(),
301			element.Name(),
302			element.Login(),
303		})
304	}
305
306	for i, comment := range snapshot.Comments {
307		var message string
308		if comment.Message == "" {
309			message = "No description provided."
310		} else {
311			message = comment.Message
312		}
313		jsonBug.Comments = append(jsonBug.Comments, JSONComment{
314			i,
315			comment.Author.Name(),
316			comment.Author.Login(),
317			message,
318		})
319	}
320
321	jsonObject, _ := json.MarshalIndent(jsonBug, "", "    ")
322	fmt.Printf("%s\n", jsonObject)
323
324	return nil
325}
326
327func showOrgmodeFormatter(snapshot *bug.Snapshot) error {
328	// Header
329	fmt.Printf("%s [%s] %s\n",
330		snapshot.Id().Human(),
331		snapshot.Status,
332		snapshot.Title,
333	)
334
335	fmt.Printf("* Author: %s\n",
336		snapshot.Author.DisplayName(),
337	)
338
339	fmt.Printf("* Creation Time: %s\n",
340		snapshot.CreatedAt.String(),
341	)
342
343	fmt.Printf("* Last Edit: %s\n",
344		snapshot.LastEditTime().String(),
345	)
346
347	// Labels
348	var labels = make([]string, len(snapshot.Labels))
349	for i, label := range snapshot.Labels {
350		labels[i] = string(label)
351	}
352
353	fmt.Printf("* Labels:\n")
354	if len(labels) > 0 {
355		fmt.Printf("** %s", strings.TrimSuffix(strings.Join(labels, "\n **"), "\n **"))
356	}
357
358	// Actors
359	var actors = make([]string, len(snapshot.Actors))
360	for i, actor := range snapshot.Actors {
361		actors[i] = fmt.Sprintf("%s %s",
362			actor.Id().Human(),
363			actor.DisplayName(),
364		)
365	}
366
367	fmt.Printf("* Actors: %s\n",
368		strings.TrimSuffix(strings.Join(actors, "\n **"), "\n **"),
369	)
370
371	// Participants
372	var participants = make([]string, len(snapshot.Participants))
373	for i, participant := range snapshot.Participants {
374		actors[i] = fmt.Sprintf("%s %s",
375			participant.Id().Human(),
376			participant.DisplayName(),
377		)
378	}
379
380	fmt.Printf("* Participants: %s\n",
381		strings.TrimSuffix(strings.Join(participants, "\n **"), "\n **"),
382	)
383
384	fmt.Printf("* Comments:\n")
385
386	for i, comment := range snapshot.Comments {
387		var message string
388		fmt.Printf("** #%d %s [%s]\n",
389			i,
390			comment.Author.DisplayName(),
391		)
392
393		if comment.Message == "" {
394			message = "No description provided."
395		} else {
396			message = strings.Replace(comment.Message, "\n", "\n: ", -1)
397		}
398
399		fmt.Printf(": %s\n",
400			message,
401		)
402	}
403
404	return nil
405}
406
407var showCmd = &cobra.Command{
408	Use:     "show [<id>]",
409	Short:   "Display the details of a bug.",
410	PreRunE: loadRepo,
411	RunE:    runShowBug,
412}
413
414func init() {
415	RootCmd.AddCommand(showCmd)
416	showCmd.Flags().StringVarP(&showFieldsQuery, "field", "", "",
417		"Select field to display. Valid values are [author,authorEmail,createTime,lastEdit,humanId,id,labels,shortId,status,title,actors,participants]")
418	showCmd.Flags().StringVarP(&showOutputFormat, "format", "f", "default",
419		"Select the output formatting style. Valid values are [default,plain,json,org-mode]")
420}