From 2edfeebefc9f29058dd79002eb4b35b7c664fc9f Mon Sep 17 00:00:00 2001 From: Jon Gallant <2163001+jongio@users.noreply.github.com> Date: Sat, 25 Jul 2026 11:22:06 -0700 Subject: [PATCH] Allow report show to use short IDs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: e02217cd-ffed-496e-b8ea-848a781cda64 --- cmd/report.go | 36 ++++++++++++++++++++++++++++++++++-- cmd/report_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/cmd/report.go b/cmd/report.go index 73114e3b..b268ea40 100644 --- a/cmd/report.go +++ b/cmd/report.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net/url" + "strings" "time" "github.com/jongio/grut/internal/crashlog" @@ -140,9 +141,13 @@ func writeCrashReportListJSON(w io.Writer, reports []*crashlog.CrashReport) erro } func runReportShow(id string) error { - report, err := crashlog.Read(id) + reports, err := crashlog.List() + if err != nil { + return fmt.Errorf("listing crash reports: %w", err) + } + report, err := findCrashReport(id, reports) if err != nil { - return fmt.Errorf("reading crash report %q: %w", id, err) + return err } data, err := json.MarshalIndent(report, "", " ") @@ -153,6 +158,33 @@ func runReportShow(id string) error { return nil } +func findCrashReport(id string, reports []*crashlog.CrashReport) (*crashlog.CrashReport, error) { + id = strings.TrimSpace(id) + if id == "" { + return nil, fmt.Errorf("crash report ID is required") + } + for _, report := range reports { + if report.ID == id { + return report, nil + } + } + + var matches []*crashlog.CrashReport + for _, report := range reports { + if strings.HasPrefix(report.ID, id) { + matches = append(matches, report) + } + } + switch len(matches) { + case 1: + return matches[0], nil + case 0: + return nil, fmt.Errorf("crash report with id %q not found", id) + default: + return nil, fmt.Errorf("crash report id %q matches %d reports; use a longer ID", id, len(matches)) + } +} + func runReportLatest(noBrowser bool) error { reports, err := crashlog.List() if err != nil { diff --git a/cmd/report_test.go b/cmd/report_test.go index 5e46b41b..5b4b3979 100644 --- a/cmd/report_test.go +++ b/cmd/report_test.go @@ -196,6 +196,51 @@ func TestRunReport_ShowFlag_NonexistentID(t *testing.T) { assert.Error(t, err) } +func TestFindCrashReport_ExactID(t *testing.T) { + reports := []*crashlog.CrashReport{ + {ID: "123456789"}, + {ID: "123400000"}, + } + + report, err := findCrashReport("123456789", reports) + + require.NoError(t, err) + assert.Equal(t, "123456789", report.ID) +} + +func TestFindCrashReport_UnambiguousPrefix(t *testing.T) { + reports := []*crashlog.CrashReport{ + {ID: "123456789"}, + {ID: "987654321"}, + } + + report, err := findCrashReport("1234", reports) + + require.NoError(t, err) + assert.Equal(t, "123456789", report.ID) +} + +func TestFindCrashReport_AmbiguousPrefix(t *testing.T) { + reports := []*crashlog.CrashReport{ + {ID: "123456789"}, + {ID: "123400000"}, + } + + _, err := findCrashReport("1234", reports) + + require.Error(t, err) + assert.Contains(t, err.Error(), "matches 2 reports") +} + +func TestFindCrashReport_MissingPrefix(t *testing.T) { + reports := []*crashlog.CrashReport{{ID: "123456789"}} + + _, err := findCrashReport("999", reports) + + require.Error(t, err) + assert.Contains(t, err.Error(), "not found") +} + func TestRunReport_JSONWithoutListReturnsError(t *testing.T) { cmd := newReportCmd() cmd.SetArgs([]string{"--json"})