Skip to content

Commit 2683fd4

Browse files
authored
Refactor commands (#98)
* wip * wip
1 parent 14867a2 commit 2683fd4

11 files changed

Lines changed: 2036 additions & 1919 deletions

File tree

cli/cmd/yapi/history.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
"time"
10+
11+
"github.com/spf13/cobra"
12+
"github.com/spf13/pflag"
13+
"yapi.run/cli/internal/cli/color"
14+
"yapi.run/cli/internal/observability"
15+
)
16+
17+
type historyEntry struct {
18+
Timestamp string `json:"timestamp"`
19+
Event string `json:"event,omitempty"` // legacy single event
20+
Events []string `json:"events,omitempty"` // new merged events
21+
Command string `json:"command,omitempty"`
22+
FromTUI bool `json:"from_tui,omitempty"`
23+
// Fields from request tracking
24+
OS string `json:"os,omitempty"`
25+
Arch string `json:"arch,omitempty"`
26+
Version string `json:"version,omitempty"`
27+
Commit string `json:"commit,omitempty"`
28+
Props map[string]any `json:"-"` // For parsing additional fields
29+
}
30+
31+
func historyE(cmd *cobra.Command, args []string) error {
32+
jsonOutput, _ := cmd.Flags().GetBool("json")
33+
34+
count := 10
35+
if len(args) == 1 {
36+
n, err := fmt.Sscanf(args[0], "%d", &count)
37+
if err != nil || n != 1 || count < 1 {
38+
return fmt.Errorf("invalid count: %s", args[0])
39+
}
40+
}
41+
42+
data, err := os.ReadFile(observability.HistoryFilePath)
43+
if err != nil {
44+
if os.IsNotExist(err) {
45+
fmt.Println("No history yet")
46+
return nil
47+
}
48+
return fmt.Errorf("failed to read history: %w", err)
49+
}
50+
51+
lines := strings.Split(strings.TrimSpace(string(data)), "\n")
52+
if len(lines) == 0 || (len(lines) == 1 && lines[0] == "") {
53+
fmt.Println("No history yet")
54+
return nil
55+
}
56+
57+
start := len(lines) - count
58+
if start < 0 {
59+
start = 0
60+
}
61+
62+
entries := lines[start:]
63+
64+
if jsonOutput {
65+
fmt.Println("[")
66+
for i, line := range entries {
67+
fmt.Print(" " + line)
68+
if i < len(entries)-1 {
69+
fmt.Println(",")
70+
} else {
71+
fmt.Println()
72+
}
73+
}
74+
fmt.Println("]")
75+
return nil
76+
}
77+
78+
// Pretty print for humans
79+
for _, line := range entries {
80+
var entry historyEntry
81+
if err := json.Unmarshal([]byte(line), &entry); err != nil {
82+
continue
83+
}
84+
t, _ := time.Parse(time.RFC3339, entry.Timestamp)
85+
timeStr := color.Dim(t.Format("2006-01-02 15:04:05"))
86+
87+
// New merged format has Command field directly
88+
if entry.Command != "" {
89+
fmt.Printf("%s %s\n", timeStr, entry.Command)
90+
continue
91+
}
92+
93+
// Legacy: request_executed entries had method/url
94+
if entry.Event == "request_executed" {
95+
var raw map[string]any
96+
if err := json.Unmarshal([]byte(line), &raw); err == nil {
97+
method, _ := raw["method"].(string)
98+
url, _ := raw["url"].(string)
99+
status, _ := raw["status_code"].(float64)
100+
if method != "" && url != "" {
101+
fmt.Printf("%s %s %s %s\n", timeStr, color.Cyan(method), url, color.Dim(fmt.Sprintf("[%d]", int(status))))
102+
continue
103+
}
104+
}
105+
}
106+
}
107+
return nil
108+
}
109+
110+
// logHistoryCmd writes a command to history as JSON
111+
func logHistoryCmd(cmdStr string) {
112+
logHistoryEntry(cmdStr, false)
113+
}
114+
115+
// logHistoryFromTUI writes a TUI-selected command to history
116+
func logHistoryFromTUI(cmdStr string) {
117+
logHistoryEntry(cmdStr, true)
118+
}
119+
120+
func logHistoryEntry(cmdStr string, fromTUI bool) {
121+
props := map[string]any{
122+
"command": cmdStr,
123+
}
124+
if fromTUI {
125+
props["from_tui"] = true
126+
}
127+
observability.Track("command", props)
128+
}
129+
130+
// reconstructCommand builds the full command string from cobra command and args
131+
func reconstructCommand(cmd *cobra.Command, args []string) string {
132+
parts := []string{"yapi", cmd.Name()}
133+
134+
// Add flags that were set
135+
cmd.Flags().Visit(func(f *pflag.Flag) {
136+
if f.Value.Type() == "bool" {
137+
parts = append(parts, "--"+f.Name)
138+
} else {
139+
parts = append(parts, fmt.Sprintf("--%s=%q", f.Name, f.Value.String()))
140+
}
141+
})
142+
143+
// Add args (quote paths)
144+
for _, arg := range args {
145+
absPath, err := filepath.Abs(arg)
146+
if err == nil && fileExists(absPath) {
147+
parts = append(parts, fmt.Sprintf("%q", absPath))
148+
} else {
149+
parts = append(parts, arg)
150+
}
151+
}
152+
153+
return strings.Join(parts, " ")
154+
}

0 commit comments

Comments
 (0)