tangled
alpha
login
or
join now
desertthunder.dev
/
noteleaf
cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists ๐
charm
leaflet
readability
golang
29
fork
atom
overview
issues
2
pulls
pipelines
build: test command execution
desertthunder.dev
4 months ago
3711edfb
46de6b15
+116
-15
5 changed files
expand all
collapse all
unified
split
cmd
commands.go
commands_test.go
go.mod
go.sum
internal
handlers
notes.go
+7
-3
cmd/commands.go
···
308
Aliases: []string{"new"},
309
RunE: func(cmd *cobra.Command, args []string) error {
310
interactive, _ := cmd.Flags().GetBool("interactive")
0
311
filePath, _ := cmd.Flags().GetString("file")
312
313
var title, content string
···
319
}
320
321
defer c.handler.Close()
322
-
return c.handler.Create(cmd.Context(), title, content, filePath, interactive)
323
},
324
}
325
createCmd.Flags().BoolP("interactive", "i", false, "Open interactive editor")
0
326
createCmd.Flags().StringP("file", "f", "", "Create note from markdown file")
327
root.AddCommand(createCmd)
328
329
listCmd := &cobra.Command{
330
-
Use: "list [--archived] [--tags=tag1,tag2]",
331
Short: "Opens interactive TUI browser for navigating and viewing notes",
332
Aliases: []string{"ls"},
333
RunE: func(cmd *cobra.Command, args []string) error {
334
archived, _ := cmd.Flags().GetBool("archived")
0
335
tagsStr, _ := cmd.Flags().GetString("tags")
336
337
var tags []string
···
343
}
344
345
defer c.handler.Close()
346
-
return c.handler.List(cmd.Context(), false, archived, tags)
347
},
348
}
349
listCmd.Flags().BoolP("archived", "a", false, "Show archived notes")
0
350
listCmd.Flags().String("tags", "", "Filter by tags (comma-separated)")
351
root.AddCommand(listCmd)
352
···
308
Aliases: []string{"new"},
309
RunE: func(cmd *cobra.Command, args []string) error {
310
interactive, _ := cmd.Flags().GetBool("interactive")
311
+
editor, _ := cmd.Flags().GetBool("editor")
312
filePath, _ := cmd.Flags().GetString("file")
313
314
var title, content string
···
320
}
321
322
defer c.handler.Close()
323
+
return c.handler.CreateWithOptions(cmd.Context(), title, content, filePath, interactive, editor)
324
},
325
}
326
createCmd.Flags().BoolP("interactive", "i", false, "Open interactive editor")
327
+
createCmd.Flags().BoolP("editor", "e", false, "Prompt to open note in editor after creation")
328
createCmd.Flags().StringP("file", "f", "", "Create note from markdown file")
329
root.AddCommand(createCmd)
330
331
listCmd := &cobra.Command{
332
+
Use: "list [--archived] [--static] [--tags=tag1,tag2]",
333
Short: "Opens interactive TUI browser for navigating and viewing notes",
334
Aliases: []string{"ls"},
335
RunE: func(cmd *cobra.Command, args []string) error {
336
archived, _ := cmd.Flags().GetBool("archived")
337
+
static, _ := cmd.Flags().GetBool("static")
338
tagsStr, _ := cmd.Flags().GetString("tags")
339
340
var tags []string
···
346
}
347
348
defer c.handler.Close()
349
+
return c.handler.List(cmd.Context(), static, archived, tags)
350
},
351
}
352
listCmd.Flags().BoolP("archived", "a", false, "Show archived notes")
353
+
listCmd.Flags().BoolP("static", "s", false, "Show static list instead of interactive TUI")
354
listCmd.Flags().String("tags", "", "Filter by tags (comma-separated)")
355
root.AddCommand(listCmd)
356
+90
-1
cmd/commands_test.go
···
260
261
expectedSubcommands := []string{
262
"create [title] [content...]",
263
-
"list [--archived] [--tags=tag1,tag2]",
264
"read [note-id]",
265
"edit [note-id]",
266
"remove [note-id]",
···
354
})
355
356
}
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
260
261
expectedSubcommands := []string{
262
"create [title] [content...]",
263
+
"list [--archived] [--static] [--tags=tag1,tag2]",
264
"read [note-id]",
265
"edit [note-id]",
266
"remove [note-id]",
···
354
})
355
356
}
357
+
358
+
func TestCommandExecution(t *testing.T) {
359
+
t.Run("Movie Commands", func(t *testing.T) {
360
+
handler, cleanup := createTestMovieHandler(t)
361
+
defer cleanup()
362
+
363
+
t.Run("list command - default", func(t *testing.T) {
364
+
cmd := NewMovieCommand(handler).Create()
365
+
cmd.SetArgs([]string{"list"})
366
+
err := cmd.Execute()
367
+
if err != nil {
368
+
t.Errorf("movie list command failed: %v", err)
369
+
}
370
+
})
371
+
372
+
t.Run("add command with empty args", func(t *testing.T) {
373
+
cmd := NewMovieCommand(handler).Create()
374
+
cmd.SetArgs([]string{"add"})
375
+
err := cmd.Execute()
376
+
if err == nil {
377
+
t.Error("expected movie add command to fail with empty args")
378
+
}
379
+
})
380
+
})
381
+
382
+
t.Run("TV Commands", func(t *testing.T) {
383
+
handler, cleanup := createTestTVHandler(t)
384
+
defer cleanup()
385
+
386
+
t.Run("list command - default", func(t *testing.T) {
387
+
cmd := NewTVCommand(handler).Create()
388
+
cmd.SetArgs([]string{"list"})
389
+
err := cmd.Execute()
390
+
if err != nil {
391
+
t.Errorf("tv list command failed: %v", err)
392
+
}
393
+
})
394
+
395
+
t.Run("add command with empty args", func(t *testing.T) {
396
+
cmd := NewTVCommand(handler).Create()
397
+
cmd.SetArgs([]string{"add"})
398
+
err := cmd.Execute()
399
+
if err == nil {
400
+
t.Error("expected tv add command to fail with empty args")
401
+
}
402
+
})
403
+
})
404
+
405
+
t.Run("Book Commands", func(t *testing.T) {
406
+
handler, cleanup := createTestBookHandler(t)
407
+
defer cleanup()
408
+
409
+
t.Run("list command - default", func(t *testing.T) {
410
+
cmd := NewBookCommand(handler).Create()
411
+
cmd.SetArgs([]string{"list"})
412
+
err := cmd.Execute()
413
+
if err != nil {
414
+
t.Errorf("book list command failed: %v", err)
415
+
}
416
+
})
417
+
})
418
+
419
+
t.Run("Note Commands", func(t *testing.T) {
420
+
421
+
t.Run("create command - non-interactive", func(t *testing.T) {
422
+
handler, cleanup := createTestNoteHandler(t)
423
+
defer cleanup()
424
+
425
+
cmd := NewNoteCommand(handler).Create()
426
+
cmd.SetArgs([]string{"create", "test title", "test content"})
427
+
err := cmd.Execute()
428
+
if err != nil {
429
+
t.Errorf("note create command failed: %v", err)
430
+
}
431
+
})
432
+
433
+
t.Run("list command - static mode", func(t *testing.T) {
434
+
handler, cleanup := createTestNoteHandler(t)
435
+
defer cleanup()
436
+
437
+
cmd := NewNoteCommand(handler).Create()
438
+
cmd.SetArgs([]string{"list", "--static"})
439
+
err := cmd.Execute()
440
+
if err != nil {
441
+
t.Errorf("note list command failed: %v", err)
442
+
}
443
+
})
444
+
})
445
+
}
-1
go.mod
···
82
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
83
golang.org/x/sys v0.36.0 // indirect
84
golang.org/x/text v0.29.0
85
-
golang.org/x/tools v0.37.0
86
)
···
82
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
83
golang.org/x/sys v0.36.0 // indirect
84
golang.org/x/text v0.29.0
0
85
)
-2
go.sum
···
230
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
231
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
232
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
233
-
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
234
-
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
235
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
236
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
237
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
···
230
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
231
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
232
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
0
0
233
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
234
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
235
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
+19
-8
internal/handlers/notes.go
···
57
58
// Create handles note creation with optional title, content, and file path
59
func (h *NoteHandler) Create(ctx context.Context, title string, content string, filePath string, interactive bool) error {
0
0
0
0
0
60
if interactive || (title == "" && content == "" && filePath == "") {
61
return h.createInteractive(ctx)
62
}
···
65
return h.createFromFile(ctx, filePath)
66
}
67
68
-
return h.createFromArgs(ctx, title, content)
69
}
70
71
func (h *NoteHandler) createInteractive(ctx context.Context) error {
···
175
}
176
177
func (h *NoteHandler) createFromArgs(ctx context.Context, title, content string) error {
0
0
0
0
178
note := &models.Note{
179
Title: title,
180
Content: content,
···
187
188
fmt.Printf("Created note: %s (ID: %d)\n", title, id)
189
190
-
editor := h.getEditor()
191
-
if editor != "" {
192
-
fmt.Print("Open in editor? [y/N]: ")
193
-
var response string
194
-
fmt.Scanln(&response)
195
-
if strings.ToLower(response) == "y" || strings.ToLower(response) == "yes" {
196
-
return h.Edit(ctx, id)
0
0
197
}
198
}
199
···
57
58
// Create handles note creation with optional title, content, and file path
59
func (h *NoteHandler) Create(ctx context.Context, title string, content string, filePath string, interactive bool) error {
60
+
return h.CreateWithOptions(ctx, title, content, filePath, interactive, false)
61
+
}
62
+
63
+
// CreateWithOptions handles note creation with additional options
64
+
func (h *NoteHandler) CreateWithOptions(ctx context.Context, title string, content string, filePath string, interactive bool, promptEditor bool) error {
65
if interactive || (title == "" && content == "" && filePath == "") {
66
return h.createInteractive(ctx)
67
}
···
70
return h.createFromFile(ctx, filePath)
71
}
72
73
+
return h.createFromArgsWithOptions(ctx, title, content, promptEditor)
74
}
75
76
func (h *NoteHandler) createInteractive(ctx context.Context) error {
···
180
}
181
182
func (h *NoteHandler) createFromArgs(ctx context.Context, title, content string) error {
183
+
return h.createFromArgsWithOptions(ctx, title, content, false)
184
+
}
185
+
186
+
func (h *NoteHandler) createFromArgsWithOptions(ctx context.Context, title, content string, promptEditor bool) error {
187
note := &models.Note{
188
Title: title,
189
Content: content,
···
196
197
fmt.Printf("Created note: %s (ID: %d)\n", title, id)
198
199
+
if promptEditor {
200
+
editor := h.getEditor()
201
+
if editor != "" {
202
+
fmt.Print("Open in editor? [y/N]: ")
203
+
var response string
204
+
fmt.Scanln(&response)
205
+
if strings.ToLower(response) == "y" || strings.ToLower(response) == "yes" {
206
+
return h.Edit(ctx, id)
207
+
}
208
}
209
}
210