Skip to content

Commit 4693787

Browse files
grokifyclaude
andcommitted
feat(cli): add stdout default and multi-format output for search-prs
Change search-prs behavior to output ASCII table to stdout by default when no -o/--outfile flag is specified. When writing to file, auto-detect format from extension (.xlsx, .md, .csv). This follows Unix conventions where CLI tools write to stdout by default, enabling piping and quick lookups without creating files. - Default: ASCII table to stdout (pipeable) - Status messages go to stderr - Supported formats: .xlsx (Excel), .md (Markdown), .csv (CSV) Applies to both gogithub search-prs subcommand and standalone searchuserpr. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 22e2067 commit 4693787

2 files changed

Lines changed: 113 additions & 34 deletions

File tree

cmd/gogithub/cmd_search_prs.go

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"os"
7+
"path/filepath"
78
"strings"
89

910
"github.com/google/go-github/v88/github"
@@ -20,16 +21,25 @@ var searchPRsCmd = &cobra.Command{
2021
Use: "search-prs",
2122
Short: "Search for open pull requests by user",
2223
Long: `Search for open pull requests across GitHub for specified users.
23-
Results are exported to an Excel file.
2424
25-
Example:
26-
gogithub search-prs --accounts grokify,octocat --outfile prs.xlsx`,
25+
By default, results are displayed as an ASCII table to stdout.
26+
Use -o/--outfile to write to a file (format auto-detected from extension).
27+
28+
Supported formats:
29+
.xlsx Excel spreadsheet
30+
.md Markdown table
31+
.csv CSV file
32+
33+
Examples:
34+
gogithub search-prs -a grokify # ASCII table to stdout
35+
gogithub search-prs -a grokify -o prs.xlsx # Excel file
36+
gogithub search-prs -a grokify,octocat -o prs.md # Markdown file`,
2737
RunE: runSearchPRs,
2838
}
2939

3040
func init() {
3141
searchPRsCmd.Flags().StringSliceVarP(&searchAccounts, "accounts", "a", nil, "GitHub accounts to search (required)")
32-
searchPRsCmd.Flags().StringVarP(&searchOutfile, "outfile", "o", "githubissues.xlsx", "Output Excel file")
42+
searchPRsCmd.Flags().StringVarP(&searchOutfile, "outfile", "o", "", "Output file (format from extension: .xlsx, .md, .csv)")
3343
_ = searchPRsCmd.MarkFlagRequired("accounts")
3444
}
3545

@@ -39,11 +49,11 @@ func runSearchPRs(cmd *cobra.Command, args []string) error {
3949
return nil
4050
}
4151

42-
fmt.Printf("Loading public pull requests for (%s)\n", strings.Join(searchAccounts, ", "))
43-
4452
searchOutfile = strings.TrimSpace(searchOutfile)
45-
if searchOutfile == "" {
46-
searchOutfile = "githubissues.xlsx"
53+
54+
// Only print status messages when writing to file (not stdout)
55+
if searchOutfile != "" {
56+
fmt.Fprintf(os.Stderr, "Loading public pull requests for (%s)\n", strings.Join(searchAccounts, ", "))
4757
}
4858

4959
// Create unauthenticated client for public data
@@ -64,18 +74,47 @@ func runSearchPRs(cmd *cobra.Command, args []string) error {
6474
ii = append(ii, iss...)
6575
}
6676

67-
ts, err := ii.TableSet()
68-
if err != nil {
69-
return fmt.Errorf("create table: %w", err)
77+
// Output to stdout if no outfile specified
78+
if searchOutfile == "" {
79+
tbl, err := ii.Table("Pull Requests")
80+
if err != nil {
81+
return fmt.Errorf("create table: %w", err)
82+
}
83+
return tbl.Text(os.Stdout)
7084
}
7185

72-
if err := ts.WriteXLSX(searchOutfile); err != nil {
73-
return fmt.Errorf("write xlsx: %w", err)
86+
// Write to file based on extension
87+
ext := strings.ToLower(filepath.Ext(searchOutfile))
88+
switch ext {
89+
case ".xlsx":
90+
ts, err := ii.TableSet()
91+
if err != nil {
92+
return fmt.Errorf("create table: %w", err)
93+
}
94+
if err := ts.WriteXLSX(searchOutfile); err != nil {
95+
return fmt.Errorf("write xlsx: %w", err)
96+
}
97+
case ".md":
98+
tbl, err := ii.Table("Pull Requests")
99+
if err != nil {
100+
return fmt.Errorf("create table: %w", err)
101+
}
102+
if err := tbl.WriteMarkdown(searchOutfile, 0644, "\n", true); err != nil {
103+
return fmt.Errorf("write markdown: %w", err)
104+
}
105+
case ".csv":
106+
tbl, err := ii.Table("Pull Requests")
107+
if err != nil {
108+
return fmt.Errorf("create table: %w", err)
109+
}
110+
if err := tbl.WriteCSV(searchOutfile); err != nil {
111+
return fmt.Errorf("write csv: %w", err)
112+
}
113+
default:
114+
return fmt.Errorf("unsupported file extension %q (use .xlsx, .md, or .csv)", ext)
74115
}
75116

76-
fmt.Printf("Wrote %s\n", searchOutfile)
77-
fmt.Println("Done")
78-
117+
fmt.Fprintf(os.Stderr, "Wrote %s\n", searchOutfile)
79118
return nil
80119
}
81120

cmd/searchuserpr/main.go

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ import (
55
"fmt"
66
"log"
77
"os"
8+
"path/filepath"
89
"strings"
910

1011
"github.com/google/go-github/v88/github"
1112
"github.com/grokify/gogithub/search"
12-
"github.com/grokify/mogo/log/logutil"
1313
flags "github.com/jessevdk/go-flags"
1414
)
1515

1616
type Options struct {
17-
Accounts []string `short:"a" long:"accounts" description:"Accounts" required:"true"`
18-
Outfile string `short:"o" long:"outfile" description:"Output File" required:"false"`
17+
Accounts []string `short:"a" long:"accounts" description:"GitHub accounts to search" required:"true"`
18+
Outfile string `short:"o" long:"outfile" description:"Output file (format from extension: .xlsx, .md, .csv)" required:"false"`
1919
}
2020

2121
func main() {
@@ -24,17 +24,19 @@ func main() {
2424
if err != nil {
2525
log.Fatal(err)
2626
}
27-
fmt.Printf("loading public pull requests for (%s)\n", strings.Join(opts.Accounts, ", "))
28-
opts.Outfile = strings.TrimSpace(opts.Outfile)
29-
if opts.Outfile == "" {
30-
opts.Outfile = "githubissues.xlsx"
31-
}
3227

3328
if len(opts.Accounts) == 0 {
34-
fmt.Println("DONE")
29+
fmt.Println("No accounts specified")
3530
os.Exit(0)
3631
}
3732

33+
opts.Outfile = strings.TrimSpace(opts.Outfile)
34+
35+
// Only print status messages when writing to file (not stdout)
36+
if opts.Outfile != "" {
37+
fmt.Fprintf(os.Stderr, "Loading public pull requests for (%s)\n", strings.Join(opts.Accounts, ", "))
38+
}
39+
3840
ghClient, err := github.NewClient()
3941
if err != nil {
4042
log.Fatal(err)
@@ -45,17 +47,55 @@ func main() {
4547

4648
for _, acct := range opts.Accounts {
4749
qry := search.NewQuery().User(acct).StateOpen().IsPR().Build()
48-
iss2, err := c.SearchIssuesAll(context.Background(), qry, nil)
49-
logutil.FatalErr(err)
50-
ii = append(ii, iss2...)
50+
iss, err := c.SearchIssuesAll(context.Background(), qry, nil)
51+
if err != nil {
52+
log.Fatalf("search issues for %s: %v", acct, err)
53+
}
54+
ii = append(ii, iss...)
5155
}
5256

53-
ts, err := ii.TableSet()
54-
logutil.FatalErr(err)
57+
// Output to stdout if no outfile specified
58+
if opts.Outfile == "" {
59+
tbl, err := ii.Table("Pull Requests")
60+
if err != nil {
61+
log.Fatalf("create table: %v", err)
62+
}
63+
if err := tbl.Text(os.Stdout); err != nil {
64+
log.Fatalf("write table: %v", err)
65+
}
66+
return
67+
}
5568

56-
err = ts.WriteXLSX(opts.Outfile)
57-
logutil.FatalErr(err)
58-
fmt.Printf("WROTE (%s)\n", opts.Outfile)
69+
// Write to file based on extension
70+
ext := strings.ToLower(filepath.Ext(opts.Outfile))
71+
switch ext {
72+
case ".xlsx":
73+
ts, err := ii.TableSet()
74+
if err != nil {
75+
log.Fatalf("create table: %v", err)
76+
}
77+
if err := ts.WriteXLSX(opts.Outfile); err != nil {
78+
log.Fatalf("write xlsx: %v", err)
79+
}
80+
case ".md":
81+
tbl, err := ii.Table("Pull Requests")
82+
if err != nil {
83+
log.Fatalf("create table: %v", err)
84+
}
85+
if err := tbl.WriteMarkdown(opts.Outfile, 0644, "\n", true); err != nil {
86+
log.Fatalf("write markdown: %v", err)
87+
}
88+
case ".csv":
89+
tbl, err := ii.Table("Pull Requests")
90+
if err != nil {
91+
log.Fatalf("create table: %v", err)
92+
}
93+
if err := tbl.WriteCSV(opts.Outfile); err != nil {
94+
log.Fatalf("write csv: %v", err)
95+
}
96+
default:
97+
log.Fatalf("unsupported file extension %q (use .xlsx, .md, or .csv)", ext)
98+
}
5999

60-
fmt.Println("DONE")
100+
fmt.Fprintf(os.Stderr, "Wrote %s\n", opts.Outfile)
61101
}

0 commit comments

Comments
 (0)