bug_show.go

  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}