show.go

  1package commands
  2
  3import (
  4	"encoding/json"
  5	"errors"
  6	"fmt"
  7	"strings"
  8
  9	"github.com/spf13/cobra"
 10
 11	_select "github.com/MichaelMure/git-bug/commands/select"
 12	"github.com/MichaelMure/git-bug/entities/bug"
 13	"github.com/MichaelMure/git-bug/util/colors"
 14)
 15
 16type showOptions struct {
 17	fields 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		RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
 30			return runShow(env, options, args)
 31		}),
 32		ValidArgsFunction: completeBug(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", completeFrom(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 runShow(env *Env, opts showOptions, args []string) error {
 50	b, args, err := _select.ResolveBug(env.backend, args)
 51	if err != nil {
 52		return err
 53	}
 54
 55	snap := b.Snapshot()
 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("\nUnsupported field: %s\n", 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 *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.Id().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
187type JSONBugSnapshot struct {
188	Id           string         `json:"id"`
189	HumanId      string         `json:"human_id"`
190	CreateTime   JSONTime       `json:"create_time"`
191	EditTime     JSONTime       `json:"edit_time"`
192	Status       string         `json:"status"`
193	Labels       []bug.Label    `json:"labels"`
194	Title        string         `json:"title"`
195	Author       JSONIdentity   `json:"author"`
196	Actors       []JSONIdentity `json:"actors"`
197	Participants []JSONIdentity `json:"participants"`
198	Comments     []JSONComment  `json:"comments"`
199}
200
201type JSONComment struct {
202	Id      string       `json:"id"`
203	HumanId string       `json:"human_id"`
204	Author  JSONIdentity `json:"author"`
205	Message string       `json:"message"`
206}
207
208func NewJSONComment(comment bug.Comment) JSONComment {
209	return JSONComment{
210		Id:      comment.Id().String(),
211		HumanId: comment.Id().Human(),
212		Author:  NewJSONIdentity(comment.Author),
213		Message: comment.Message,
214	}
215}
216
217func showJsonFormatter(env *Env, snapshot *bug.Snapshot) error {
218	jsonBug := JSONBugSnapshot{
219		Id:         snapshot.Id().String(),
220		HumanId:    snapshot.Id().Human(),
221		CreateTime: NewJSONTime(snapshot.CreateTime, 0),
222		EditTime:   NewJSONTime(snapshot.EditTime(), 0),
223		Status:     snapshot.Status.String(),
224		Labels:     snapshot.Labels,
225		Title:      snapshot.Title,
226		Author:     NewJSONIdentity(snapshot.Author),
227	}
228
229	jsonBug.Actors = make([]JSONIdentity, len(snapshot.Actors))
230	for i, element := range snapshot.Actors {
231		jsonBug.Actors[i] = NewJSONIdentity(element)
232	}
233
234	jsonBug.Participants = make([]JSONIdentity, len(snapshot.Participants))
235	for i, element := range snapshot.Participants {
236		jsonBug.Participants[i] = NewJSONIdentity(element)
237	}
238
239	jsonBug.Comments = make([]JSONComment, len(snapshot.Comments))
240	for i, comment := range snapshot.Comments {
241		jsonBug.Comments[i] = NewJSONComment(comment)
242	}
243
244	jsonObject, _ := json.MarshalIndent(jsonBug, "", "    ")
245	env.out.Printf("%s\n", jsonObject)
246
247	return nil
248}
249
250func showOrgModeFormatter(env *Env, snapshot *bug.Snapshot) error {
251	// Header
252	env.out.Printf("%s [%s] %s\n",
253		snapshot.Id().Human(),
254		snapshot.Status,
255		snapshot.Title,
256	)
257
258	env.out.Printf("* Author: %s\n",
259		snapshot.Author.DisplayName(),
260	)
261
262	env.out.Printf("* Creation Time: %s\n",
263		snapshot.CreateTime.String(),
264	)
265
266	env.out.Printf("* Last Edit: %s\n",
267		snapshot.EditTime().String(),
268	)
269
270	// Labels
271	var labels = make([]string, len(snapshot.Labels))
272	for i, label := range snapshot.Labels {
273		labels[i] = string(label)
274	}
275
276	env.out.Printf("* Labels:\n")
277	if len(labels) > 0 {
278		env.out.Printf("** %s\n",
279			strings.Join(labels, "\n** "),
280		)
281	}
282
283	// Actors
284	var actors = make([]string, len(snapshot.Actors))
285	for i, actor := range snapshot.Actors {
286		actors[i] = fmt.Sprintf("%s %s",
287			actor.Id().Human(),
288			actor.DisplayName(),
289		)
290	}
291
292	env.out.Printf("* Actors:\n** %s\n",
293		strings.Join(actors, "\n** "),
294	)
295
296	// Participants
297	var participants = make([]string, len(snapshot.Participants))
298	for i, participant := range snapshot.Participants {
299		participants[i] = fmt.Sprintf("%s %s",
300			participant.Id().Human(),
301			participant.DisplayName(),
302		)
303	}
304
305	env.out.Printf("* Participants:\n** %s\n",
306		strings.Join(participants, "\n** "),
307	)
308
309	env.out.Printf("* Comments:\n")
310
311	for i, comment := range snapshot.Comments {
312		var message string
313		env.out.Printf("** #%d %s\n",
314			i, comment.Author.DisplayName())
315
316		if comment.Message == "" {
317			message = "No description provided."
318		} else {
319			message = strings.ReplaceAll(comment.Message, "\n", "\n: ")
320		}
321
322		env.out.Printf(": %s\n", message)
323	}
324
325	return nil
326}