This commit is contained in:
Steve Yegge
2025-11-24 20:20:44 -08:00

View File

@@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"os"
"sort"
"strings"
"text/template"
"time"
@@ -26,16 +27,69 @@ func parseTimeFlag(s string) (time.Time, error) {
"2006-01-02T15:04:05",
"2006-01-02 15:04:05",
}
for _, format := range formats {
if t, err := time.Parse(format, s); err == nil {
return t, nil
}
}
return time.Time{}, fmt.Errorf("unable to parse time %q (try formats: 2006-01-02, 2006-01-02T15:04:05, or RFC3339)", s)
}
// sortIssues sorts a slice of issues by the specified field and direction
func sortIssues(issues []*types.Issue, sortBy string, reverse bool) {
if sortBy == "" {
return
}
sort.Slice(issues, func(i, j int) bool {
var less bool
switch sortBy {
case "priority":
// Lower priority numbers come first (P0 > P1 > P2 > P3 > P4)
less = issues[i].Priority < issues[j].Priority
case "created":
// Default: newest first (descending)
less = issues[i].CreatedAt.After(issues[j].CreatedAt)
case "updated":
// Default: newest first (descending)
less = issues[i].UpdatedAt.After(issues[j].UpdatedAt)
case "closed":
// Default: newest first (descending)
// Handle nil ClosedAt values
if issues[i].ClosedAt == nil && issues[j].ClosedAt == nil {
less = false
} else if issues[i].ClosedAt == nil {
less = false // nil sorts last
} else if issues[j].ClosedAt == nil {
less = true // non-nil sorts before nil
} else {
less = issues[i].ClosedAt.After(*issues[j].ClosedAt)
}
case "status":
less = issues[i].Status < issues[j].Status
case "id":
less = issues[i].ID < issues[j].ID
case "title":
less = strings.ToLower(issues[i].Title) < strings.ToLower(issues[j].Title)
case "type":
less = issues[i].IssueType < issues[j].IssueType
case "assignee":
less = issues[i].Assignee < issues[j].Assignee
default:
// Unknown sort field, no sorting
less = false
}
if reverse {
return !less
}
return less
})
}
var listCmd = &cobra.Command{
Use: "list",
Short: "List issues",
@@ -50,6 +104,8 @@ var listCmd = &cobra.Command{
titleSearch, _ := cmd.Flags().GetString("title")
idFilter, _ := cmd.Flags().GetString("id")
longFormat, _ := cmd.Flags().GetBool("long")
sortBy, _ := cmd.Flags().GetString("sort")
reverse, _ := cmd.Flags().GetBool("reverse")
// Pattern matching flags
titleContains, _ := cmd.Flags().GetString("title-contains")
@@ -310,6 +366,9 @@ var listCmd = &cobra.Command{
os.Exit(1)
}
// Apply sorting
sortIssues(issues, sortBy, reverse)
if longFormat {
// Long format: multi-line with details
fmt.Printf("\nFound %d issues:\n\n", len(issues))
@@ -363,6 +422,9 @@ var listCmd = &cobra.Command{
}
}
// Apply sorting
sortIssues(issues, sortBy, reverse)
// Handle format flag
if formatStr != "" {
if err := outputFormattedList(ctx, store, issues, formatStr); err != nil {
@@ -466,6 +528,8 @@ func init() {
listCmd.Flags().String("format", "", "Output format: 'digraph' (for golang.org/x/tools/cmd/digraph), 'dot' (Graphviz), or Go template")
listCmd.Flags().Bool("all", false, "Show all issues (default behavior; flag provided for CLI familiarity)")
listCmd.Flags().Bool("long", false, "Show detailed multi-line output for each issue")
listCmd.Flags().String("sort", "", "Sort by field: priority, created, updated, closed, status, id, title, type, assignee")
listCmd.Flags().BoolP("reverse", "r", false, "Reverse sort order")
// Pattern matching
listCmd.Flags().String("title-contains", "", "Filter by title substring (case-insensitive)")