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