fizzy-cli 0.8.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/.golangci.yml +56 -0
  2. package/IMPLEMENTATION_PLAN.md +58 -0
  3. package/docs/API.md +89 -0
  4. package/package.json +2 -1
  5. package/.env +0 -1
  6. package/.github/workflows/release.yml +0 -29
  7. package/.github/workflows/tests.yml +0 -24
  8. package/AGENTS.md +0 -33
  9. package/CHANGELOG.md +0 -194
  10. package/Makefile +0 -43
  11. package/bin/fizzy +0 -0
  12. package/cmd/account.go +0 -14
  13. package/cmd/account_list.go +0 -44
  14. package/cmd/account_list_test.go +0 -118
  15. package/cmd/board.go +0 -49
  16. package/cmd/board_create.go +0 -59
  17. package/cmd/board_create_test.go +0 -141
  18. package/cmd/board_delete.go +0 -40
  19. package/cmd/board_delete_test.go +0 -121
  20. package/cmd/board_list.go +0 -44
  21. package/cmd/board_list_test.go +0 -115
  22. package/cmd/board_show.go +0 -40
  23. package/cmd/board_show_test.go +0 -113
  24. package/cmd/board_test.go +0 -92
  25. package/cmd/board_update.go +0 -72
  26. package/cmd/board_update_test.go +0 -233
  27. package/cmd/card.go +0 -24
  28. package/cmd/card_assign.go +0 -55
  29. package/cmd/card_assign_test.go +0 -130
  30. package/cmd/card_close.go +0 -46
  31. package/cmd/card_close_test.go +0 -92
  32. package/cmd/card_create.go +0 -72
  33. package/cmd/card_create_test.go +0 -186
  34. package/cmd/card_delete.go +0 -46
  35. package/cmd/card_delete_test.go +0 -92
  36. package/cmd/card_golden.go +0 -46
  37. package/cmd/card_golden_test.go +0 -92
  38. package/cmd/card_list.go +0 -114
  39. package/cmd/card_list_test.go +0 -373
  40. package/cmd/card_not_now.go +0 -46
  41. package/cmd/card_not_now_test.go +0 -92
  42. package/cmd/card_reaction.go +0 -13
  43. package/cmd/card_reaction_create.go +0 -46
  44. package/cmd/card_reaction_create_test.go +0 -148
  45. package/cmd/card_reaction_delete.go +0 -46
  46. package/cmd/card_reaction_delete_test.go +0 -112
  47. package/cmd/card_reaction_list.go +0 -51
  48. package/cmd/card_reaction_list_test.go +0 -127
  49. package/cmd/card_reopen.go +0 -46
  50. package/cmd/card_reopen_test.go +0 -92
  51. package/cmd/card_show.go +0 -46
  52. package/cmd/card_show_test.go +0 -92
  53. package/cmd/card_tag.go +0 -51
  54. package/cmd/card_tag_test.go +0 -112
  55. package/cmd/card_triage.go +0 -46
  56. package/cmd/card_ungolden.go +0 -46
  57. package/cmd/card_ungolden_test.go +0 -92
  58. package/cmd/card_untriage.go +0 -46
  59. package/cmd/card_untriage_test.go +0 -92
  60. package/cmd/card_unwatch.go +0 -46
  61. package/cmd/card_unwatch_test.go +0 -92
  62. package/cmd/card_update.go +0 -82
  63. package/cmd/card_update_test.go +0 -149
  64. package/cmd/card_watch.go +0 -46
  65. package/cmd/card_watch_test.go +0 -92
  66. package/cmd/column.go +0 -14
  67. package/cmd/column_create.go +0 -79
  68. package/cmd/column_create_test.go +0 -178
  69. package/cmd/column_delete.go +0 -40
  70. package/cmd/column_delete_test.go +0 -121
  71. package/cmd/column_list.go +0 -44
  72. package/cmd/column_list_test.go +0 -138
  73. package/cmd/column_show.go +0 -40
  74. package/cmd/column_show_test.go +0 -111
  75. package/cmd/column_update.go +0 -67
  76. package/cmd/column_update_test.go +0 -198
  77. package/cmd/comment.go +0 -14
  78. package/cmd/comment_create.go +0 -51
  79. package/cmd/comment_create_test.go +0 -129
  80. package/cmd/comment_delete.go +0 -46
  81. package/cmd/comment_delete_test.go +0 -92
  82. package/cmd/comment_list.go +0 -51
  83. package/cmd/comment_list_test.go +0 -132
  84. package/cmd/comment_show.go +0 -46
  85. package/cmd/comment_show_test.go +0 -104
  86. package/cmd/comment_update.go +0 -51
  87. package/cmd/comment_update_test.go +0 -130
  88. package/cmd/login.go +0 -81
  89. package/cmd/login_test.go +0 -98
  90. package/cmd/notification.go +0 -14
  91. package/cmd/notification_list.go +0 -69
  92. package/cmd/notification_list_test.go +0 -288
  93. package/cmd/notification_read.go +0 -51
  94. package/cmd/notification_read_all.go +0 -38
  95. package/cmd/notification_read_all_test.go +0 -75
  96. package/cmd/notification_read_test.go +0 -138
  97. package/cmd/notification_unread.go +0 -44
  98. package/cmd/notification_unread_test.go +0 -99
  99. package/cmd/reaction.go +0 -13
  100. package/cmd/reaction_create.go +0 -46
  101. package/cmd/reaction_create_test.go +0 -113
  102. package/cmd/reaction_delete.go +0 -46
  103. package/cmd/reaction_delete_test.go +0 -92
  104. package/cmd/reaction_list.go +0 -51
  105. package/cmd/reaction_list_test.go +0 -125
  106. package/cmd/root.go +0 -38
  107. package/cmd/step.go +0 -14
  108. package/cmd/step_create.go +0 -53
  109. package/cmd/step_create_test.go +0 -171
  110. package/cmd/step_delete.go +0 -46
  111. package/cmd/step_delete_test.go +0 -92
  112. package/cmd/step_update.go +0 -66
  113. package/cmd/step_update_test.go +0 -190
  114. package/cmd/tag.go +0 -15
  115. package/cmd/tag_list.go +0 -47
  116. package/cmd/tag_list_test.go +0 -109
  117. package/cmd/use.go +0 -85
  118. package/cmd/use_test.go +0 -186
  119. package/cmd/user.go +0 -22
  120. package/cmd/user_deactivate.go +0 -40
  121. package/cmd/user_deactivate_test.go +0 -121
  122. package/cmd/user_list.go +0 -44
  123. package/cmd/user_list_test.go +0 -126
  124. package/cmd/user_show.go +0 -40
  125. package/cmd/user_show_test.go +0 -110
  126. package/cmd/user_update.go +0 -71
  127. package/cmd/user_update_test.go +0 -177
  128. package/go.mod +0 -31
  129. package/go.sum +0 -53
  130. package/internal/api/boards.go +0 -93
  131. package/internal/api/cards.go +0 -322
  132. package/internal/api/client.go +0 -99
  133. package/internal/api/columns.go +0 -113
  134. package/internal/api/comments.go +0 -108
  135. package/internal/api/identity.go +0 -24
  136. package/internal/api/notifications.go +0 -89
  137. package/internal/api/reactions.go +0 -130
  138. package/internal/api/steps.go +0 -101
  139. package/internal/api/tags.go +0 -24
  140. package/internal/api/types.go +0 -195
  141. package/internal/api/users.go +0 -75
  142. package/internal/app/app.go +0 -49
  143. package/internal/colors/colors.go +0 -32
  144. package/internal/config/config.go +0 -70
  145. package/internal/testutil/client.go +0 -26
  146. package/internal/ui/account_list.go +0 -14
  147. package/internal/ui/account_selector.go +0 -63
  148. package/internal/ui/board_list.go +0 -14
  149. package/internal/ui/board_show.go +0 -17
  150. package/internal/ui/card_list.go +0 -14
  151. package/internal/ui/card_show.go +0 -23
  152. package/internal/ui/column_list.go +0 -28
  153. package/internal/ui/column_show.go +0 -16
  154. package/internal/ui/comment_list.go +0 -25
  155. package/internal/ui/format.go +0 -27
  156. package/internal/ui/notification_list.go +0 -27
  157. package/internal/ui/reaction_list.go +0 -14
  158. package/internal/ui/user_list.go +0 -19
  159. package/internal/ui/user_show.go +0 -23
@@ -1,92 +0,0 @@
1
- package cmd
2
-
3
- import (
4
- "context"
5
- "net/http"
6
- "net/http/httptest"
7
- "testing"
8
-
9
- "github.com/rogeriopvl/fizzy/internal/app"
10
- "github.com/rogeriopvl/fizzy/internal/testutil"
11
- )
12
-
13
- func TestCardReopenCommandSuccess(t *testing.T) {
14
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
15
- if r.URL.Path != "/cards/123/closure" {
16
- t.Errorf("expected /cards/123/closure, got %s", r.URL.Path)
17
- }
18
- if r.Method != http.MethodDelete {
19
- t.Errorf("expected DELETE, got %s", r.Method)
20
- }
21
-
22
- auth := r.Header.Get("Authorization")
23
- if auth != "Bearer test-token" {
24
- t.Errorf("expected Bearer test-token, got %s", auth)
25
- }
26
-
27
- w.WriteHeader(http.StatusNoContent)
28
- }))
29
- defer server.Close()
30
-
31
- client := testutil.NewTestClient(server.URL, "", "", "test-token")
32
- testApp := &app.App{Client: client}
33
-
34
- cmd := cardReopenCmd
35
- cmd.SetContext(testApp.ToContext(context.Background()))
36
-
37
- if err := handleReopenCard(cmd, "123"); err != nil {
38
- t.Fatalf("handleReopenCard failed: %v", err)
39
- }
40
- }
41
-
42
- func TestCardReopenCommandInvalidCardNumber(t *testing.T) {
43
- testApp := &app.App{}
44
-
45
- cmd := cardReopenCmd
46
- cmd.SetContext(testApp.ToContext(context.Background()))
47
-
48
- err := handleReopenCard(cmd, "not-a-number")
49
- if err == nil {
50
- t.Errorf("expected error for invalid card number")
51
- }
52
- if err.Error() != "invalid card number: strconv.Atoi: parsing \"not-a-number\": invalid syntax" {
53
- t.Errorf("expected invalid card number error, got %v", err)
54
- }
55
- }
56
-
57
- func TestCardReopenCommandNoClient(t *testing.T) {
58
- testApp := &app.App{}
59
-
60
- cmd := cardReopenCmd
61
- cmd.SetContext(testApp.ToContext(context.Background()))
62
-
63
- err := handleReopenCard(cmd, "123")
64
- if err == nil {
65
- t.Errorf("expected error when client not available")
66
- }
67
- if err.Error() != "API client not available" {
68
- t.Errorf("expected 'client not available' error, got %v", err)
69
- }
70
- }
71
-
72
- func TestCardReopenCommandAPIError(t *testing.T) {
73
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
74
- w.WriteHeader(http.StatusInternalServerError)
75
- w.Write([]byte("Internal Server Error"))
76
- }))
77
- defer server.Close()
78
-
79
- client := testutil.NewTestClient(server.URL, "", "", "test-token")
80
- testApp := &app.App{Client: client}
81
-
82
- cmd := cardReopenCmd
83
- cmd.SetContext(testApp.ToContext(context.Background()))
84
-
85
- err := handleReopenCard(cmd, "123")
86
- if err == nil {
87
- t.Errorf("expected error for API failure")
88
- }
89
- if err.Error() != "reopening card: unexpected status code 500: Internal Server Error" {
90
- t.Errorf("expected API error, got %v", err)
91
- }
92
- }
package/cmd/card_show.go DELETED
@@ -1,46 +0,0 @@
1
- package cmd
2
-
3
- import (
4
- "context"
5
- "fmt"
6
- "strconv"
7
-
8
- "github.com/rogeriopvl/fizzy/internal/app"
9
- "github.com/rogeriopvl/fizzy/internal/ui"
10
- "github.com/spf13/cobra"
11
- )
12
-
13
- var cardShowCmd = &cobra.Command{
14
- Use: "show <card_id>",
15
- Short: "Show card details",
16
- Long: `Retrieve and display details for a specific card`,
17
- Args: cobra.ExactArgs(1),
18
- Run: func(cmd *cobra.Command, args []string) {
19
- if err := handleShowCard(cmd, args[0]); err != nil {
20
- fmt.Fprintf(cmd.OutOrStderr(), "Error: %v\n", err)
21
- }
22
- },
23
- }
24
-
25
- func handleShowCard(cmd *cobra.Command, cardID string) error {
26
- a := app.FromContext(cmd.Context())
27
- if a == nil || a.Client == nil {
28
- return fmt.Errorf("API client not available")
29
- }
30
-
31
- cardNumber, err := strconv.Atoi(cardID)
32
- if err != nil {
33
- return fmt.Errorf("card ID must be a number: %w", err)
34
- }
35
-
36
- card, err := a.Client.GetCard(context.Background(), cardNumber)
37
- if err != nil {
38
- return fmt.Errorf("fetching card: %w", err)
39
- }
40
-
41
- return ui.DisplayCard(card)
42
- }
43
-
44
- func init() {
45
- cardCmd.AddCommand(cardShowCmd)
46
- }
@@ -1,92 +0,0 @@
1
- package cmd
2
-
3
- import (
4
- "context"
5
- "encoding/json"
6
- "net/http"
7
- "net/http/httptest"
8
- "testing"
9
-
10
- "github.com/rogeriopvl/fizzy/internal/api"
11
- "github.com/rogeriopvl/fizzy/internal/app"
12
- "github.com/rogeriopvl/fizzy/internal/testutil"
13
- )
14
-
15
- func TestCardShowCommand(t *testing.T) {
16
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
17
- if r.URL.Path != "/cards/1" {
18
- t.Errorf("expected /cards/1, got %s", r.URL.Path)
19
- }
20
- if r.Method != http.MethodGet {
21
- t.Errorf("expected GET, got %s", r.Method)
22
- }
23
-
24
- auth := r.Header.Get("Authorization")
25
- if auth != "Bearer test-token" {
26
- t.Errorf("expected Bearer test-token, got %s", auth)
27
- }
28
-
29
- w.Header().Set("Content-Type", "application/json")
30
- response := api.Card{
31
- ID: "card-123",
32
- Number: 1,
33
- Title: "Implement feature",
34
- Status: "in_progress",
35
- Description: "This is a test card",
36
- Tags: []string{"feature", "backend"},
37
- Golden: false,
38
- CreatedAt: "2025-01-01T00:00:00Z",
39
- LastActiveAt: "2025-01-15T10:30:00Z",
40
- URL: "https://example.com/card/1",
41
- }
42
- json.NewEncoder(w).Encode(response)
43
- }))
44
- defer server.Close()
45
-
46
- client := testutil.NewTestClient(server.URL, "", "", "test-token")
47
- testApp := &app.App{Client: client}
48
-
49
- cmd := cardShowCmd
50
- cmd.SetContext(testApp.ToContext(context.Background()))
51
-
52
- if err := handleShowCard(cmd, "1"); err != nil {
53
- t.Fatalf("handleShowCard failed: %v", err)
54
- }
55
- }
56
-
57
- func TestCardShowCommandAPIError(t *testing.T) {
58
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
59
- w.WriteHeader(http.StatusNotFound)
60
- w.Write([]byte("Card not found"))
61
- }))
62
- defer server.Close()
63
-
64
- client := testutil.NewTestClient(server.URL, "", "", "test-token")
65
- testApp := &app.App{Client: client}
66
-
67
- cmd := cardShowCmd
68
- cmd.SetContext(testApp.ToContext(context.Background()))
69
-
70
- err := handleShowCard(cmd, "999")
71
- if err == nil {
72
- t.Errorf("expected error for API failure")
73
- }
74
- if err.Error() != "fetching card: unexpected status code 404: Card not found" {
75
- t.Errorf("expected API error, got %v", err)
76
- }
77
- }
78
-
79
- func TestCardShowCommandNoClient(t *testing.T) {
80
- testApp := &app.App{}
81
-
82
- cmd := cardShowCmd
83
- cmd.SetContext(testApp.ToContext(context.Background()))
84
-
85
- err := handleShowCard(cmd, "1")
86
- if err == nil {
87
- t.Errorf("expected error when client not available")
88
- }
89
- if err.Error() != "API client not available" {
90
- t.Errorf("expected 'client not available' error, got %v", err)
91
- }
92
- }
package/cmd/card_tag.go DELETED
@@ -1,51 +0,0 @@
1
- package cmd
2
-
3
- import (
4
- "context"
5
- "fmt"
6
- "strconv"
7
- "strings"
8
-
9
- "github.com/rogeriopvl/fizzy/internal/app"
10
- "github.com/spf13/cobra"
11
- )
12
-
13
- var cardTagCmd = &cobra.Command{
14
- Use: "tag <card_number> <tag_title>",
15
- Short: "Toggle a tag on or off for a card",
16
- Long: `Toggle a tag on or off for a card. If the tag doesn't exist, it will be created.
17
-
18
- The tag title can be specified with or without a leading # symbol.`,
19
- Args: cobra.ExactArgs(2),
20
- Run: func(cmd *cobra.Command, args []string) {
21
- if err := handleTagCard(cmd, args[0], args[1]); err != nil {
22
- fmt.Fprintf(cmd.OutOrStderr(), "Error: %v\n", err)
23
- }
24
- },
25
- }
26
-
27
- func handleTagCard(cmd *cobra.Command, cardNumber, tagTitle string) error {
28
- cardNum, err := strconv.Atoi(cardNumber)
29
- if err != nil {
30
- return fmt.Errorf("invalid card number: %w", err)
31
- }
32
-
33
- a := app.FromContext(cmd.Context())
34
- if a == nil || a.Client == nil {
35
- return fmt.Errorf("API client not available")
36
- }
37
-
38
- tagTitle = strings.TrimPrefix(tagTitle, "#")
39
-
40
- _, err = a.Client.PostCardTagging(context.Background(), cardNum, tagTitle)
41
- if err != nil {
42
- return fmt.Errorf("toggling tag on card: %w", err)
43
- }
44
-
45
- fmt.Fprintf(cmd.OutOrStdout(), "✓ Tag '%s' toggled on card #%d\n", tagTitle, cardNum)
46
- return nil
47
- }
48
-
49
- func init() {
50
- cardCmd.AddCommand(cardTagCmd)
51
- }
@@ -1,112 +0,0 @@
1
- package cmd
2
-
3
- import (
4
- "context"
5
- "net/http"
6
- "net/http/httptest"
7
- "testing"
8
-
9
- "github.com/rogeriopvl/fizzy/internal/app"
10
- "github.com/rogeriopvl/fizzy/internal/testutil"
11
- )
12
-
13
- func TestCardTagCommandSuccess(t *testing.T) {
14
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
15
- if r.URL.Path != "/cards/123/taggings" {
16
- t.Errorf("expected /cards/123/taggings, got %s", r.URL.Path)
17
- }
18
- if r.Method != http.MethodPost {
19
- t.Errorf("expected POST, got %s", r.Method)
20
- }
21
-
22
- auth := r.Header.Get("Authorization")
23
- if auth != "Bearer test-token" {
24
- t.Errorf("expected Bearer test-token, got %s", auth)
25
- }
26
-
27
- w.WriteHeader(http.StatusNoContent)
28
- }))
29
- defer server.Close()
30
-
31
- client := testutil.NewTestClient(server.URL, "", "", "test-token")
32
- testApp := &app.App{Client: client}
33
-
34
- cmd := cardTagCmd
35
- cmd.SetContext(testApp.ToContext(context.Background()))
36
-
37
- if err := handleTagCard(cmd, "123", "bug"); err != nil {
38
- t.Fatalf("handleTagCard failed: %v", err)
39
- }
40
- }
41
-
42
- func TestCardTagCommandWithHashPrefix(t *testing.T) {
43
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
44
- if r.URL.Path != "/cards/456/taggings" {
45
- t.Errorf("expected /cards/456/taggings, got %s", r.URL.Path)
46
- }
47
- w.WriteHeader(http.StatusNoContent)
48
- }))
49
- defer server.Close()
50
-
51
- client := testutil.NewTestClient(server.URL, "", "", "test-token")
52
- testApp := &app.App{Client: client}
53
-
54
- cmd := cardTagCmd
55
- cmd.SetContext(testApp.ToContext(context.Background()))
56
-
57
- if err := handleTagCard(cmd, "456", "#feature"); err != nil {
58
- t.Fatalf("handleTagCard with # prefix failed: %v", err)
59
- }
60
- }
61
-
62
- func TestCardTagCommandAPIError(t *testing.T) {
63
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
64
- w.WriteHeader(http.StatusNotFound)
65
- w.Write([]byte("Card not found"))
66
- }))
67
- defer server.Close()
68
-
69
- client := testutil.NewTestClient(server.URL, "", "", "test-token")
70
- testApp := &app.App{Client: client}
71
-
72
- cmd := cardTagCmd
73
- cmd.SetContext(testApp.ToContext(context.Background()))
74
-
75
- err := handleTagCard(cmd, "999", "bug")
76
- if err == nil {
77
- t.Errorf("expected error for API failure")
78
- }
79
- if err.Error() != "toggling tag on card: unexpected status code 404: Card not found" {
80
- t.Errorf("expected API error, got %v", err)
81
- }
82
- }
83
-
84
- func TestCardTagCommandInvalidCardNumber(t *testing.T) {
85
- testApp := &app.App{}
86
-
87
- cmd := cardTagCmd
88
- cmd.SetContext(testApp.ToContext(context.Background()))
89
-
90
- err := handleTagCard(cmd, "not-a-number", "bug")
91
- if err == nil {
92
- t.Errorf("expected error for invalid card number")
93
- }
94
- if err.Error() != "invalid card number: strconv.Atoi: parsing \"not-a-number\": invalid syntax" {
95
- t.Errorf("expected invalid card number error, got %v", err)
96
- }
97
- }
98
-
99
- func TestCardTagCommandNoClient(t *testing.T) {
100
- testApp := &app.App{}
101
-
102
- cmd := cardTagCmd
103
- cmd.SetContext(testApp.ToContext(context.Background()))
104
-
105
- err := handleTagCard(cmd, "123", "bug")
106
- if err == nil {
107
- t.Errorf("expected error when client not available")
108
- }
109
- if err.Error() != "API client not available" {
110
- t.Errorf("expected 'client not available' error, got %v", err)
111
- }
112
- }
@@ -1,46 +0,0 @@
1
- package cmd
2
-
3
- import (
4
- "context"
5
- "fmt"
6
- "strconv"
7
-
8
- "github.com/rogeriopvl/fizzy/internal/app"
9
- "github.com/spf13/cobra"
10
- )
11
-
12
- var cardTriageCmd = &cobra.Command{
13
- Use: "triage <card_number> <column_id>",
14
- Short: "Move a card from triage into a column",
15
- Long: `Move a card from triage into a specified column`,
16
- Args: cobra.ExactArgs(2),
17
- Run: func(cmd *cobra.Command, args []string) {
18
- if err := handleTriageCard(cmd, args[0], args[1]); err != nil {
19
- fmt.Fprintf(cmd.OutOrStderr(), "Error: %v\n", err)
20
- }
21
- },
22
- }
23
-
24
- func handleTriageCard(cmd *cobra.Command, cardNumber string, columnID string) error {
25
- cardNum, err := strconv.Atoi(cardNumber)
26
- if err != nil {
27
- return fmt.Errorf("invalid card number: %w", err)
28
- }
29
-
30
- a := app.FromContext(cmd.Context())
31
- if a == nil || a.Client == nil {
32
- return fmt.Errorf("API client not available")
33
- }
34
-
35
- _, err = a.Client.PostCardTriage(context.Background(), cardNum, columnID)
36
- if err != nil {
37
- return fmt.Errorf("triaging card: %w", err)
38
- }
39
-
40
- fmt.Fprintf(cmd.OutOrStdout(), "✓ Card #%d moved to column successfully\n", cardNum)
41
- return nil
42
- }
43
-
44
- func init() {
45
- cardCmd.AddCommand(cardTriageCmd)
46
- }
@@ -1,46 +0,0 @@
1
- package cmd
2
-
3
- import (
4
- "context"
5
- "fmt"
6
- "strconv"
7
-
8
- "github.com/rogeriopvl/fizzy/internal/app"
9
- "github.com/spf13/cobra"
10
- )
11
-
12
- var cardUngoldenCmd = &cobra.Command{
13
- Use: "ungolden <card_number>",
14
- Short: "Remove golden status from a card",
15
- Long: `Remove golden status from an existing card`,
16
- Args: cobra.ExactArgs(1),
17
- Run: func(cmd *cobra.Command, args []string) {
18
- if err := handleUngoldenCard(cmd, args[0]); err != nil {
19
- fmt.Fprintf(cmd.OutOrStderr(), "Error: %v\n", err)
20
- }
21
- },
22
- }
23
-
24
- func handleUngoldenCard(cmd *cobra.Command, cardNumber string) error {
25
- cardNum, err := strconv.Atoi(cardNumber)
26
- if err != nil {
27
- return fmt.Errorf("invalid card number: %w", err)
28
- }
29
-
30
- a := app.FromContext(cmd.Context())
31
- if a == nil || a.Client == nil {
32
- return fmt.Errorf("API client not available")
33
- }
34
-
35
- _, err = a.Client.DeleteCardGoldenness(context.Background(), cardNum)
36
- if err != nil {
37
- return fmt.Errorf("removing golden status: %w", err)
38
- }
39
-
40
- fmt.Fprintf(cmd.OutOrStdout(), "✓ Card #%d golden status removed\n", cardNum)
41
- return nil
42
- }
43
-
44
- func init() {
45
- cardCmd.AddCommand(cardUngoldenCmd)
46
- }
@@ -1,92 +0,0 @@
1
- package cmd
2
-
3
- import (
4
- "context"
5
- "net/http"
6
- "net/http/httptest"
7
- "testing"
8
-
9
- "github.com/rogeriopvl/fizzy/internal/app"
10
- "github.com/rogeriopvl/fizzy/internal/testutil"
11
- )
12
-
13
- func TestCardUngoldenCommandSuccess(t *testing.T) {
14
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
15
- if r.URL.Path != "/cards/123/goldness" {
16
- t.Errorf("expected /cards/123/goldness, got %s", r.URL.Path)
17
- }
18
- if r.Method != http.MethodDelete {
19
- t.Errorf("expected DELETE, got %s", r.Method)
20
- }
21
-
22
- auth := r.Header.Get("Authorization")
23
- if auth != "Bearer test-token" {
24
- t.Errorf("expected Bearer test-token, got %s", auth)
25
- }
26
-
27
- w.WriteHeader(http.StatusNoContent)
28
- }))
29
- defer server.Close()
30
-
31
- client := testutil.NewTestClient(server.URL, "", "", "test-token")
32
- testApp := &app.App{Client: client}
33
-
34
- cmd := cardUngoldenCmd
35
- cmd.SetContext(testApp.ToContext(context.Background()))
36
-
37
- if err := handleUngoldenCard(cmd, "123"); err != nil {
38
- t.Fatalf("handleUngoldenCard failed: %v", err)
39
- }
40
- }
41
-
42
- func TestCardUngoldenCommandInvalidCardNumber(t *testing.T) {
43
- testApp := &app.App{}
44
-
45
- cmd := cardUngoldenCmd
46
- cmd.SetContext(testApp.ToContext(context.Background()))
47
-
48
- err := handleUngoldenCard(cmd, "not-a-number")
49
- if err == nil {
50
- t.Errorf("expected error for invalid card number")
51
- }
52
- if err.Error() != "invalid card number: strconv.Atoi: parsing \"not-a-number\": invalid syntax" {
53
- t.Errorf("expected invalid card number error, got %v", err)
54
- }
55
- }
56
-
57
- func TestCardUngoldenCommandNoClient(t *testing.T) {
58
- testApp := &app.App{}
59
-
60
- cmd := cardUngoldenCmd
61
- cmd.SetContext(testApp.ToContext(context.Background()))
62
-
63
- err := handleUngoldenCard(cmd, "123")
64
- if err == nil {
65
- t.Errorf("expected error when client not available")
66
- }
67
- if err.Error() != "API client not available" {
68
- t.Errorf("expected 'client not available' error, got %v", err)
69
- }
70
- }
71
-
72
- func TestCardUngoldenCommandAPIError(t *testing.T) {
73
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
74
- w.WriteHeader(http.StatusInternalServerError)
75
- w.Write([]byte("Internal Server Error"))
76
- }))
77
- defer server.Close()
78
-
79
- client := testutil.NewTestClient(server.URL, "", "", "test-token")
80
- testApp := &app.App{Client: client}
81
-
82
- cmd := cardUngoldenCmd
83
- cmd.SetContext(testApp.ToContext(context.Background()))
84
-
85
- err := handleUngoldenCard(cmd, "123")
86
- if err == nil {
87
- t.Errorf("expected error for API failure")
88
- }
89
- if err.Error() != "removing golden status: unexpected status code 500: Internal Server Error" {
90
- t.Errorf("expected API error, got %v", err)
91
- }
92
- }
@@ -1,46 +0,0 @@
1
- package cmd
2
-
3
- import (
4
- "context"
5
- "fmt"
6
- "strconv"
7
-
8
- "github.com/rogeriopvl/fizzy/internal/app"
9
- "github.com/spf13/cobra"
10
- )
11
-
12
- var cardUntriagedCmd = &cobra.Command{
13
- Use: "untriage <card_number>",
14
- Short: "Send a card back to triage",
15
- Long: `Send an existing card back to the triage column`,
16
- Args: cobra.ExactArgs(1),
17
- Run: func(cmd *cobra.Command, args []string) {
18
- if err := handleUntriagedCard(cmd, args[0]); err != nil {
19
- fmt.Fprintf(cmd.OutOrStderr(), "Error: %v\n", err)
20
- }
21
- },
22
- }
23
-
24
- func handleUntriagedCard(cmd *cobra.Command, cardNumber string) error {
25
- cardNum, err := strconv.Atoi(cardNumber)
26
- if err != nil {
27
- return fmt.Errorf("invalid card number: %w", err)
28
- }
29
-
30
- a := app.FromContext(cmd.Context())
31
- if a == nil || a.Client == nil {
32
- return fmt.Errorf("API client not available")
33
- }
34
-
35
- _, err = a.Client.DeleteCardTriage(context.Background(), cardNum)
36
- if err != nil {
37
- return fmt.Errorf("sending card back to triage: %w", err)
38
- }
39
-
40
- fmt.Fprintf(cmd.OutOrStdout(), "✓ Card #%d sent back to triage successfully\n", cardNum)
41
- return nil
42
- }
43
-
44
- func init() {
45
- cardCmd.AddCommand(cardUntriagedCmd)
46
- }