Skip to content

Commit 3c6ce00

Browse files
authored
Merge pull request #5 from thedavidweng/feat/cobra-extras
2 parents 2c0a99d + 9ea2b84 commit 3c6ce00

42 files changed

Lines changed: 632 additions & 309 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

internal/cli/budgets.go

Lines changed: 80 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ import (
1414
)
1515

1616
func newBudgetsCommand(ctx context.Context, state *runtimeState, stdout io.Writer) *cobra.Command {
17-
cmd := &cobra.Command{Use: "budgets"}
17+
cmd := &cobra.Command{
18+
Use: "budgets",
19+
Short: "Manage budgets",
20+
Example: " money budgets list\n money budgets create --name Groceries --period monthly --start-date 2024-01-01 --end-date 2024-12-31 --confirm\n money budgets get <id>\n money budgets delete <id>",
21+
}
1822
cmd.AddCommand(newBudgetsListCommand(ctx, state, stdout))
1923
cmd.AddCommand(newBudgetsCreateCommand(ctx, state, stdout))
2024
cmd.AddCommand(newBudgetsGetCommand(ctx, state, stdout))
@@ -26,8 +30,9 @@ func newBudgetsCommand(ctx context.Context, state *runtimeState, stdout io.Write
2630
func newBudgetsListCommand(ctx context.Context, state *runtimeState, stdout io.Writer) *cobra.Command {
2731
var verbose bool
2832
cmd := &cobra.Command{
29-
Use: "list",
30-
Short: "List budgets",
33+
Use: "list",
34+
Short: "List budgets",
35+
Example: " money budgets list\n money budgets list --verbose --json",
3136
RunE: func(cmd *cobra.Command, args []string) error {
3237
activeStore, err := requireStore(state)
3338
if err != nil {
@@ -68,8 +73,9 @@ func newBudgetsCreateCommand(ctx context.Context, state *runtimeState, stdout io
6873
var name, currency, period, startDate, endDate string
6974
var dryRun, confirm bool
7075
cmd := &cobra.Command{
71-
Use: "create",
72-
Short: "Create a budget",
76+
Use: "create",
77+
Short: "Create a budget",
78+
Example: " money budgets create --name Groceries --period monthly --start-date 2024-01-01 --end-date 2024-12-31 --confirm\n money budgets create --name Rent --period yearly --start-date 2024-01-01 --end-date 2024-12-31 --dry-run",
7379
RunE: func(cmd *cobra.Command, args []string) error {
7480
if state.json && !dryRun && !confirm {
7581
return cliError{
@@ -100,7 +106,7 @@ func newBudgetsCreateCommand(ctx context.Context, state *runtimeState, stdout io
100106
env.Meta.Demo = state.demo
101107
return contracts.WriteJSON(stdout, env)
102108
}
103-
fmt.Fprintf(stdout, "Would create budget %q (%s, %s to %s)\n", budget.Name, budget.Period, budget.StartDate, budget.EndDate)
109+
_, _ = fmt.Fprintf(stdout, "Would create budget %q (%s, %s to %s)\n", budget.Name, budget.Period, budget.StartDate, budget.EndDate)
104110
return nil
105111
}
106112
activeStore, err := requireStore(state)
@@ -116,13 +122,16 @@ func newBudgetsCreateCommand(ctx context.Context, state *runtimeState, stdout io
116122
env.Meta.Demo = state.demo
117123
return contracts.WriteJSON(stdout, env)
118124
}
119-
fmt.Fprintf(stdout, "Created budget %s (%s)\n", created.Name, created.ID)
125+
_, _ = fmt.Fprintf(stdout, "Created budget %s (%s)\n", created.Name, created.ID)
120126
return nil
121127
},
122128
}
123129
cmd.Flags().StringVar(&name, "name", "", "budget name")
124130
cmd.Flags().StringVar(&currency, "currency", "USD", "budget currency")
125131
cmd.Flags().StringVar(&period, "period", "monthly", "budget period: monthly or yearly")
132+
_ = cmd.RegisterFlagCompletionFunc("period", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
133+
return []string{"monthly", "yearly"}, cobra.ShellCompDirectiveNoFileComp
134+
})
126135
cmd.Flags().StringVar(&startDate, "start-date", "", "budget start date (YYYY-MM-DD)")
127136
cmd.Flags().StringVar(&endDate, "end-date", "", "budget end date (YYYY-MM-DD)")
128137
cmd.Flags().BoolVar(&dryRun, "dry-run", false, "show write plan without saving")
@@ -135,6 +144,21 @@ func newBudgetsGetCommand(ctx context.Context, state *runtimeState, stdout io.Wr
135144
Use: "get <id>",
136145
Short: "Get a budget with its categories",
137146
Args: cobra.ExactArgs(1),
147+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
148+
activeStore, err := requireStore(state)
149+
if err != nil {
150+
return nil, cobra.ShellCompDirectiveNoFileComp
151+
}
152+
budgets, err := activeStore.ListBudgets(ctx)
153+
if err != nil {
154+
return nil, cobra.ShellCompDirectiveNoFileComp
155+
}
156+
var ids []string
157+
for _, b := range budgets {
158+
ids = append(ids, b.ID+"\t"+b.Name)
159+
}
160+
return ids, cobra.ShellCompDirectiveNoFileComp
161+
},
138162
RunE: func(cmd *cobra.Command, args []string) error {
139163
activeStore, err := requireStore(state)
140164
if err != nil {
@@ -145,12 +169,12 @@ func newBudgetsGetCommand(ctx context.Context, state *runtimeState, stdout io.Wr
145169
return err
146170
}
147171
if !state.json {
148-
fmt.Fprintf(stdout, "Budget: %s (%s)\n", budget.Name, budget.ID)
149-
fmt.Fprintf(stdout, "Period: %s\n", budget.Period)
150-
fmt.Fprintf(stdout, "Range: %s to %s\n", budget.StartDate, budget.EndDate)
151-
fmt.Fprintf(stdout, "Currency: %s\n", budget.Currency)
172+
_, _ = fmt.Fprintf(stdout, "Budget: %s (%s)\n", budget.Name, budget.ID)
173+
_, _ = fmt.Fprintf(stdout, "Period: %s\n", budget.Period)
174+
_, _ = fmt.Fprintf(stdout, "Range: %s to %s\n", budget.StartDate, budget.EndDate)
175+
_, _ = fmt.Fprintf(stdout, "Currency: %s\n", budget.Currency)
152176
if len(budget.Categories) > 0 {
153-
fmt.Fprintln(stdout, "Categories:")
177+
_, _ = fmt.Fprintln(stdout, "Categories:")
154178
table := tablewriter.NewWriter(stdout)
155179
table.SetHeader([]string{"NAME", "LIMIT", "CATEGORY ID"})
156180
table.SetBorder(false)
@@ -177,6 +201,21 @@ func newBudgetsDeleteCommand(ctx context.Context, state *runtimeState, stdout io
177201
Use: "delete <id>",
178202
Short: "Delete a budget",
179203
Args: cobra.ExactArgs(1),
204+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
205+
activeStore, err := requireStore(state)
206+
if err != nil {
207+
return nil, cobra.ShellCompDirectiveNoFileComp
208+
}
209+
budgets, err := activeStore.ListBudgets(ctx)
210+
if err != nil {
211+
return nil, cobra.ShellCompDirectiveNoFileComp
212+
}
213+
var ids []string
214+
for _, b := range budgets {
215+
ids = append(ids, b.ID+"\t"+b.Name)
216+
}
217+
return ids, cobra.ShellCompDirectiveNoFileComp
218+
},
180219
RunE: func(cmd *cobra.Command, args []string) error {
181220
activeStore, err := requireStore(state)
182221
if err != nil {
@@ -190,14 +229,18 @@ func newBudgetsDeleteCommand(ctx context.Context, state *runtimeState, stdout io
190229
env.Meta.Demo = state.demo
191230
return contracts.WriteJSON(stdout, env)
192231
}
193-
fmt.Fprintf(stdout, "Deleted budget %s\n", args[0])
232+
_, _ = fmt.Fprintf(stdout, "Deleted budget %s\n", args[0])
194233
return nil
195234
},
196235
}
197236
}
198237

199238
func newBudgetCategoriesCommand(ctx context.Context, state *runtimeState, stdout io.Writer) *cobra.Command {
200-
cmd := &cobra.Command{Use: "categories"}
239+
cmd := &cobra.Command{
240+
Use: "categories",
241+
Short: "Manage budget categories",
242+
Example: " money budgets categories create --budget-id <id> --name Groceries --limit 50000 --confirm\n money budgets categories delete <id>",
243+
}
201244
cmd.AddCommand(newBudgetCategoriesCreateCommand(ctx, state, stdout))
202245
cmd.AddCommand(newBudgetCategoriesDeleteCommand(ctx, state, stdout))
203246
return cmd
@@ -208,8 +251,9 @@ func newBudgetCategoriesCreateCommand(ctx context.Context, state *runtimeState,
208251
var limitMinor int64
209252
var dryRun, confirm bool
210253
cmd := &cobra.Command{
211-
Use: "create",
212-
Short: "Create a budget category",
254+
Use: "create",
255+
Short: "Create a budget category",
256+
Example: " money budgets categories create --budget-id <id> --name Groceries --limit 50000 --confirm\n money budgets categories create --budget-id <id> --name Dining --limit 30000 --currency USD --dry-run",
213257
RunE: func(cmd *cobra.Command, args []string) error {
214258
if state.json && !dryRun && !confirm {
215259
return cliError{
@@ -240,7 +284,7 @@ func newBudgetCategoriesCreateCommand(ctx context.Context, state *runtimeState,
240284
env.Meta.Demo = state.demo
241285
return contracts.WriteJSON(stdout, env)
242286
}
243-
fmt.Fprintf(stdout, "Would create budget category %q with limit %s %s\n", bc.Name, core.FormatMinorUnits(bc.LimitMinorUnits, bc.Currency), bc.Currency)
287+
_, _ = fmt.Fprintf(stdout, "Would create budget category %q with limit %s %s\n", bc.Name, core.FormatMinorUnits(bc.LimitMinorUnits, bc.Currency), bc.Currency)
244288
return nil
245289
}
246290
activeStore, err := requireStore(state)
@@ -256,7 +300,7 @@ func newBudgetCategoriesCreateCommand(ctx context.Context, state *runtimeState,
256300
env.Meta.Demo = state.demo
257301
return contracts.WriteJSON(stdout, env)
258302
}
259-
fmt.Fprintf(stdout, "Created budget category %s (%s)\n", created.Name, created.ID)
303+
_, _ = fmt.Fprintf(stdout, "Created budget category %s (%s)\n", created.Name, created.ID)
260304
return nil
261305
},
262306
}
@@ -275,6 +319,23 @@ func newBudgetCategoriesDeleteCommand(ctx context.Context, state *runtimeState,
275319
Use: "delete <id>",
276320
Short: "Delete a budget category",
277321
Args: cobra.ExactArgs(1),
322+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
323+
activeStore, err := requireStore(state)
324+
if err != nil {
325+
return nil, cobra.ShellCompDirectiveNoFileComp
326+
}
327+
budgets, err := activeStore.ListBudgets(ctx)
328+
if err != nil {
329+
return nil, cobra.ShellCompDirectiveNoFileComp
330+
}
331+
var ids []string
332+
for _, b := range budgets {
333+
for _, bc := range b.Categories {
334+
ids = append(ids, bc.ID+"\t"+bc.Name+" ("+b.Name+")")
335+
}
336+
}
337+
return ids, cobra.ShellCompDirectiveNoFileComp
338+
},
278339
RunE: func(cmd *cobra.Command, args []string) error {
279340
activeStore, err := requireStore(state)
280341
if err != nil {
@@ -288,7 +349,7 @@ func newBudgetCategoriesDeleteCommand(ctx context.Context, state *runtimeState,
288349
env.Meta.Demo = state.demo
289350
return contracts.WriteJSON(stdout, env)
290351
}
291-
fmt.Fprintf(stdout, "Deleted budget category %s\n", args[0])
352+
_, _ = fmt.Fprintf(stdout, "Deleted budget category %s\n", args[0])
292353
return nil
293354
},
294355
}

0 commit comments

Comments
 (0)