Merge pull request #403 from MichaelMure/ls-dump

Vincent Tiu created

[ls] add support for different output formats

Change summary

commands/ls.go                     | 128 ++++++++++++++++++++++++++++++-
doc/man/git-bug-ls.1               |   4 +
doc/md/git-bug_ls.md               |   1 
misc/bash_completion/git-bug       |   4 +
misc/powershell_completion/git-bug |   2 
misc/zsh_completion/git-bug        |   3 
6 files changed, 136 insertions(+), 6 deletions(-)

Detailed changes

commands/ls.go 🔗

@@ -1,8 +1,10 @@
 package commands
 
 import (
+	"encoding/json"
 	"fmt"
 	"strings"
+	"time"
 
 	text "github.com/MichaelMure/go-term-text"
 	"github.com/spf13/cobra"
@@ -21,9 +23,10 @@ var (
 	lsNoQuery       []string
 	lsSortBy        string
 	lsSortDirection string
+	lsOutputFormat  string
 )
 
-func runLsBug(cmd *cobra.Command, args []string) error {
+func runLsBug(_ *cobra.Command, args []string) error {
 	backend, err := cache.NewRepoCache(repo)
 	if err != nil {
 		return err
@@ -48,20 +51,127 @@ func runLsBug(cmd *cobra.Command, args []string) error {
 
 	allIds := backend.QueryBugs(q)
 
-	for _, id := range allIds {
+	bugExcerpt := make([]*cache.BugExcerpt, len(allIds))
+	for i, id := range allIds {
 		b, err := backend.ResolveBugExcerpt(id)
 		if err != nil {
 			return err
 		}
+		bugExcerpt[i] = b
+	}
+
+	switch lsOutputFormat {
+	case "plain":
+		return lsPlainFormatter(backend, bugExcerpt)
+	case "json":
+		return lsJsonFormatter(backend, bugExcerpt)
+	case "default":
+		return lsDefaultFormatter(backend, bugExcerpt)
+	default:
+		return fmt.Errorf("unknown format %s", lsOutputFormat)
+	}
+}
 
+type JSONBug struct {
+	Id           string    `json:"id"`
+	HumanId      string    `json:"human_id"`
+	CreationTime time.Time `json:"creation_time"`
+	LastEdited   time.Time `json:"last_edited"`
+
+	Status       string         `json:"status"`
+	Labels       []bug.Label    `json:"labels"`
+	Title        string         `json:"title"`
+	Actors       []JSONIdentity `json:"actors"`
+	Participants []JSONIdentity `json:"participants"`
+	Author       JSONIdentity   `json:"author"`
+
+	Comments int               `json:"comments"`
+	Metadata map[string]string `json:"metadata"`
+}
+
+type JSONIdentity struct {
+	Id      string `json:"id"`
+	HumanId string `json:"human_id"`
+	Name    string `json:"name"`
+	Login   string `json:"login"`
+}
+
+func lsJsonFormatter(backend *cache.RepoCache, bugExcerpts []*cache.BugExcerpt) error {
+	jsonBugs := make([]JSONBug, len(bugExcerpts))
+	for i, b := range bugExcerpts {
+		jsonBug := JSONBug{
+			b.Id.String(),
+			b.Id.Human(),
+			time.Unix(b.CreateUnixTime, 0),
+			time.Unix(b.EditUnixTime, 0),
+			b.Status.String(),
+			b.Labels,
+			b.Title,
+			[]JSONIdentity{},
+			[]JSONIdentity{},
+			JSONIdentity{},
+			b.LenComments,
+			b.CreateMetadata,
+		}
+
+		if b.AuthorId != "" {
+			author, err := backend.ResolveIdentityExcerpt(b.AuthorId)
+			if err != nil {
+				return err
+			}
+
+			jsonBug.Author.Name = author.DisplayName()
+			jsonBug.Author.Login = author.Login
+			jsonBug.Author.Id = author.Id.String()
+			jsonBug.Author.HumanId = author.Id.Human()
+		} else {
+			jsonBug.Author.Name = b.LegacyAuthor.DisplayName()
+			jsonBug.Author.Login = b.LegacyAuthor.Login
+		}
+
+		for _, element := range b.Actors {
+			actor, err := backend.ResolveIdentityExcerpt(element)
+			if err != nil {
+				return err
+			}
+
+			jsonBug.Actors = append(jsonBug.Actors, JSONIdentity{
+				actor.Id.String(),
+				actor.Id.Human(),
+				actor.Name,
+				actor.Login,
+			})
+		}
+
+		for _, element := range b.Participants {
+			participant, err := backend.ResolveIdentityExcerpt(element)
+			if err != nil {
+				return err
+			}
+			jsonBug.Participants = append(jsonBug.Participants, JSONIdentity{
+				participant.Id.String(),
+				participant.Id.Human(),
+				participant.DisplayName(),
+				participant.Login,
+			})
+		}
+
+		jsonBugs[i] = jsonBug
+	}
+	jsonObject, _ := json.MarshalIndent(jsonBugs, "", "    ")
+	fmt.Printf("%s\n", jsonObject)
+	return nil
+}
+
+func lsDefaultFormatter(backend *cache.RepoCache, bugExcerpts []*cache.BugExcerpt) error {
+	for _, b := range bugExcerpts {
 		var name string
 		if b.AuthorId != "" {
 			author, err := backend.ResolveIdentityExcerpt(b.AuthorId)
 			if err != nil {
-				name = "<missing author data>"
-			} else {
-				name = author.DisplayName()
+				return err
 			}
+			name = author.DisplayName()
 		} else {
 			name = b.LegacyAuthor.DisplayName()
 		}
@@ -92,7 +202,13 @@ func runLsBug(cmd *cobra.Command, args []string) error {
 			comments,
 		)
 	}
+	return nil
+}
 
+func lsPlainFormatter(_ *cache.RepoCache, bugExcerpts []*cache.BugExcerpt) error {
+	for _, b := range bugExcerpts {
+		fmt.Printf("[%s] %s\n", b.Status, b.Title)
+	}
 	return nil
 }
 
@@ -177,4 +293,6 @@ func init() {
 		"Sort the results by a characteristic. Valid values are [id,creation,edit]")
 	lsCmd.Flags().StringVarP(&lsSortDirection, "direction", "d", "asc",
 		"Select the sorting direction. Valid values are [asc,desc]")
+	lsCmd.Flags().StringVarP(&lsOutputFormat, "format", "f", "default",
+		"Select the output formatting style. Valid values are [default, plain(text), json]")
 }

doc/man/git-bug-ls.1 🔗

@@ -57,6 +57,10 @@ You can pass an additional query to filter and order the list. This query can be
 \fB\-d\fP, \fB\-\-direction\fP="asc"
 	Select the sorting direction. Valid values are [asc,desc]
 
+.PP
+\fB\-f\fP, \fB\-\-format\fP="default"
+	Select the output formatting style. Valid values are [default, plain(text), json]
+
 .PP
 \fB\-h\fP, \fB\-\-help\fP[=false]
 	help for ls

doc/md/git-bug_ls.md 🔗

@@ -35,6 +35,7 @@ git bug ls --status closed --by creation
   -n, --no strings            Filter by absence of something. Valid values are [label]
   -b, --by string             Sort the results by a characteristic. Valid values are [id,creation,edit] (default "creation")
   -d, --direction string      Select the sorting direction. Valid values are [asc,desc] (default "asc")
+  -f, --format string         Select the output formatting style. Valid values are [default, plain(text), json] (default "default")
   -h, --help                  help for ls
 ```
 

misc/bash_completion/git-bug 🔗

@@ -807,6 +807,10 @@ _git-bug_ls()
     two_word_flags+=("--direction")
     two_word_flags+=("-d")
     local_nonpersistent_flags+=("--direction=")
+    flags+=("--format=")
+    two_word_flags+=("--format")
+    two_word_flags+=("-f")
+    local_nonpersistent_flags+=("--format=")
 
     must_have_one_flag=()
     must_have_one_noun=()

misc/powershell_completion/git-bug 🔗

@@ -159,6 +159,8 @@ Register-ArgumentCompleter -Native -CommandName 'git-bug' -ScriptBlock {
             [CompletionResult]::new('--by', 'by', [CompletionResultType]::ParameterName, 'Sort the results by a characteristic. Valid values are [id,creation,edit]')
             [CompletionResult]::new('-d', 'd', [CompletionResultType]::ParameterName, 'Select the sorting direction. Valid values are [asc,desc]')
             [CompletionResult]::new('--direction', 'direction', [CompletionResultType]::ParameterName, 'Select the sorting direction. Valid values are [asc,desc]')
+            [CompletionResult]::new('-f', 'f', [CompletionResultType]::ParameterName, 'Select the output formatting style. Valid values are [default, plain(text), json]')
+            [CompletionResult]::new('--format', 'format', [CompletionResultType]::ParameterName, 'Select the output formatting style. Valid values are [default, plain(text), json]')
             break
         }
         'git-bug;ls-id' {

misc/zsh_completion/git-bug 🔗

@@ -303,7 +303,8 @@ function _git-bug_ls {
     '(*-t *--title)'{\*-t,\*--title}'[Filter by title]:' \
     '(*-n *--no)'{\*-n,\*--no}'[Filter by absence of something. Valid values are [label]]:' \
     '(-b --by)'{-b,--by}'[Sort the results by a characteristic. Valid values are [id,creation,edit]]:' \
-    '(-d --direction)'{-d,--direction}'[Select the sorting direction. Valid values are [asc,desc]]:'
+    '(-d --direction)'{-d,--direction}'[Select the sorting direction. Valid values are [asc,desc]]:' \
+    '(-f --format)'{-f,--format}'[Select the output formatting style. Valid values are [default, plain(text), json]]:'
 }
 
 function _git-bug_ls-id {