Add machine-readable output formats

- Default table output (when stdout is attached to a terminal) stays the same;
- When stdout is redirected, output tab-separated values and no header line;
- With `--json` flag, output structured JSON data.

Example:

    $ ghcs list --json
    [
      {
        "Branch": "main",
        "Created At": "2021-06-10T15:04:46+02:00",
        "Name": "mislav-playground-jvqj",
        "Repository": "mislav/playground",
        "State": "Shutdown"
      },
      {
        "Branch": "master",
        "Created At": "2021-07-15T15:51:08+02:00",
        "Name": "mislav-github-github-pwgg365xv",
        "Repository": "github/github",
        "State": "Shutdown"
      }
    ]
This commit is contained in:
Mislav Marohnić 2021-08-04 15:56:10 +02:00
parent ebc8ce5adb
commit 140a54a009
5 changed files with 101 additions and 8 deletions

View file

@ -73,7 +73,7 @@ func Delete(codespaceName string) error {
fmt.Println("Codespace deleted.")
return List()
return List(&ListOptions{})
}
func DeleteAll() error {
@ -103,7 +103,7 @@ func DeleteAll() error {
fmt.Printf("Codespace deleted: %s\n", c.Name)
}
return List()
return List(&ListOptions{})
}
func DeleteByRepo(repo string) error {
@ -143,5 +143,5 @@ func DeleteByRepo(repo string) error {
fmt.Printf("No codespace was found for repository: %s\n", repo)
}
return List()
return List(&ListOptions{})
}

View file

@ -5,21 +5,28 @@ import (
"fmt"
"os"
"github.com/olekukonko/tablewriter"
"github.com/github/ghcs/api"
"github.com/github/ghcs/cmd/ghcs/output"
"github.com/spf13/cobra"
)
type ListOptions struct {
AsJSON bool
}
func NewListCmd() *cobra.Command {
opts := &ListOptions{}
listCmd := &cobra.Command{
Use: "list",
Short: "List GitHub Codespaces you have on your account.",
RunE: func(cmd *cobra.Command, args []string) error {
return List()
return List(opts)
},
}
listCmd.Flags().BoolVar(&opts.AsJSON, "json", false, "Output as JSON")
return listCmd
}
@ -27,7 +34,7 @@ func init() {
rootCmd.AddCommand(NewListCmd())
}
func List() error {
func List(opts *ListOptions) error {
apiClient := api.New(os.Getenv("GITHUB_TOKEN"))
ctx := context.Background()
@ -46,7 +53,7 @@ func List() error {
return nil
}
table := tablewriter.NewWriter(os.Stdout)
table := output.NewTable(os.Stdout, opts.AsJSON)
table.SetHeader([]string{"Name", "Repository", "Branch", "State", "Created At"})
for _, codespace := range codespaces {
table.Append([]string{

View file

@ -0,0 +1,33 @@
package output
import (
"encoding/json"
"io"
)
type jsonwriter struct {
w io.Writer
pretty bool
cols []string
data []interface{}
}
func (j *jsonwriter) SetHeader(cols []string) {
j.cols = cols
}
func (j *jsonwriter) Append(values []string) {
row := make(map[string]string)
for i, v := range values {
row[j.cols[i]] = v
}
j.data = append(j.data, row)
}
func (j *jsonwriter) Render() {
enc := json.NewEncoder(j.w)
if j.pretty {
enc.SetIndent("", " ")
}
_ = enc.Encode(j.data)
}

View file

@ -0,0 +1,28 @@
package output
import (
"io"
"os"
"github.com/olekukonko/tablewriter"
"golang.org/x/term"
)
type Table interface {
SetHeader([]string)
Append([]string)
Render()
}
func NewTable(w io.Writer, asJSON bool) Table {
f, ok := w.(*os.File)
isTTY := ok && term.IsTerminal(int(f.Fd()))
if asJSON {
return &jsonwriter{w: w, pretty: isTTY}
}
if isTTY {
return tablewriter.NewWriter(w)
}
return &tabwriter{w: w}
}

View file

@ -0,0 +1,25 @@
package output
import (
"fmt"
"io"
)
type tabwriter struct {
w io.Writer
}
func (j *tabwriter) SetHeader([]string) {}
func (j *tabwriter) Append(values []string) {
var sep string
for i, v := range values {
if i == 1 {
sep = "\t"
}
fmt.Fprintf(j.w, "%s%s", sep, v)
}
fmt.Fprint(j.w, "\n")
}
func (j *tabwriter) Render() {}