Skip to content

Commit 230d356

Browse files
committed
feat: add flag shortcuts
1 parent af43d77 commit 230d356

27 files changed

Lines changed: 206 additions & 137 deletions

.task/checksum/docs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
8cdc8a0d92ea52364fe347f5b64a72e6
1+
f998a0f05834950ec6719dfc2c4a6c95

README.md

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,10 @@ hourgit init [--project <name>] [--force] [--merge] [--yes]
119119

120120
| Flag | Default | Description |
121121
|------|---------|-------------|
122-
| `--project` | auto-detect | Assign repository to a project by name or ID (creates if needed) |
123-
| `--force` | `false` | Overwrite existing post-checkout hook |
124-
| `--merge` | `false` | Append to existing post-checkout hook |
125-
| `--yes` | `false` | Skip confirmation prompt |
122+
| `-p`, `--project` | auto-detect | Assign repository to a project by name or ID (creates if needed) |
123+
| `-f`, `--force` | `false` | Overwrite existing post-checkout hook |
124+
| `-m`, `--merge` | `false` | Append to existing post-checkout hook |
125+
| `-y`, `--yes` | `false` | Skip confirmation prompt |
126126

127127
#### `hourgit log`
128128

@@ -134,12 +134,12 @@ hourgit log [MESSAGE] [--duration <dur>] [--from <time>] [--to <time>] [--date <
134134

135135
| Flag | Default | Description |
136136
|------|---------|-------------|
137-
| `--project` | auto-detect | Project name or ID |
138-
| `--duration` || Duration to log (e.g. `30m`, `3h`, `1d3h30m`) |
139-
| `--from` || Start time (e.g. `9am`, `14:00`) |
140-
| `--to` || End time (e.g. `5pm`, `17:00`) |
141-
| `--date` | today | Date to log for (`YYYY-MM-DD`) |
142-
| `--task` || Task label for this entry |
137+
| `-p`, `--project` | auto-detect | Project name or ID |
138+
| `-d`, `--duration` || Duration to log (e.g. `30m`, `3h`, `1d3h30m`) |
139+
| `-F`, `--from` || Start time (e.g. `9am`, `14:00`) |
140+
| `-T`, `--to` || End time (e.g. `5pm`, `17:00`) |
141+
| `-D`, `--date` | today | Date to log for (`YYYY-MM-DD`) |
142+
| `-t`, `--task` || Task label for this entry |
143143

144144
> `--duration` and `--from`/`--to` are mutually exclusive. A message is always required (prompted if not provided).
145145
@@ -170,13 +170,14 @@ hourgit edit <hash> [--duration <dur>] [--from <time>] [--to <time>] [--date <da
170170

171171
| Flag | Default | Description |
172172
|------|---------|-------------|
173-
| `--project` | auto-detect | Project name or ID |
174-
| `--duration` || New duration (e.g. `30m`, `3h`, `3h30m`) |
175-
| `--from` || New start time (e.g. `9am`, `14:00`) |
176-
| `--to` || New end time (e.g. `5pm`, `17:00`) |
177-
| `--date` || New date (`YYYY-MM-DD`) |
178-
| `--task` || New task label (empty string clears it) |
173+
| `-p`, `--project` | auto-detect | Project name or ID |
174+
| `-d`, `--duration` || New duration (e.g. `30m`, `3h`, `3h30m`) |
175+
| `-F`, `--from` || New start time (e.g. `9am`, `14:00`) |
176+
| `-T`, `--to` || New end time (e.g. `5pm`, `17:00`) |
177+
| `-D`, `--date` || New date (`YYYY-MM-DD`) |
178+
| `-t`, `--task` || New task label (empty string clears it) |
179179
| `-m`, `--message` || New message |
180+
| `-y`, `--yes` | `false` | Skip confirmation prompt |
180181

181182
> `--duration` and `--from`/`--to` are mutually exclusive. `--from` only: keeps existing end time, recalculates duration. `--to` only: keeps existing start time, recalculates duration. Entry ID and creation timestamp are preserved. If the entry is not found in the current repo's project, all projects are searched.
182183
@@ -200,8 +201,8 @@ hourgit remove <hash> [--project <name>] [--yes]
200201

201202
| Flag | Default | Description |
202203
|------|---------|-------------|
203-
| `--project` | auto-detect | Project name or ID |
204-
| `--yes` | `false` | Skip confirmation prompt |
204+
| `-p`, `--project` | auto-detect | Project name or ID |
205+
| `-y`, `--yes` | `false` | Skip confirmation prompt |
205206

206207
> Works with both log and checkout entries (unlike `edit`, which only supports log entries). Shows entry details and asks for confirmation before deleting. If the entry is not found in the current repo's project, all projects are searched.
207208
@@ -215,7 +216,7 @@ hourgit sync [--project <name>]
215216

216217
| Flag | Default | Description |
217218
|------|---------|-------------|
218-
| `--project` | auto-detect | Project name or ID |
219+
| `-p`, `--project` | auto-detect | Project name or ID |
219220

220221
#### `hourgit report`
221222

@@ -227,11 +228,11 @@ hourgit report [--month <1-12>] [--week <1-53>] [--year <YYYY>] [--project <name
227228

228229
| Flag | Default | Description |
229230
|------|---------|-------------|
230-
| `--month` | current month | Month number 1-12 |
231-
| `--week` || ISO week number 1-53 |
232-
| `--year` | current year | Year (complementary to `--month` or `--week`) |
233-
| `--project` | auto-detect | Project name or ID |
234-
| `--export` || Export format (`pdf`); auto-generates filename based on period |
231+
| `-m`, `--month` | current month | Month number 1-12 |
232+
| `-w`, `--week` || ISO week number 1-53 |
233+
| `-y`, `--year` | current year | Year (complementary to `--month` or `--week`) |
234+
| `-p`, `--project` | auto-detect | Project name or ID |
235+
| `-e`, `--export` || Export format (`pdf`); auto-generates filename based on period |
235236

236237
> `--month` and `--week` cannot be used together. `--year` alone is not valid — it must be paired with `--month` or `--week`. Neither flag defaults to the current month.
237238
@@ -270,8 +271,8 @@ hourgit history [--project <name>] [--limit <N>]
270271

271272
| Flag | Default | Description |
272273
|------|---------|-------------|
273-
| `--project` | all projects | Filter by project name or ID |
274-
| `--limit` | `50` | Maximum number of entries to show (use `0` for all) |
274+
| `-p`, `--project` | all projects | Filter by project name or ID |
275+
| `-l`, `--limit` | `50` | Maximum number of entries to show (use `0` for all) |
275276

276277
> Each line shows the entry hash, timestamp, type (log or checkout), project name, and details. Log entries display duration + task label (if set) + message. Checkout entries display previous branch → next branch.
277278
@@ -285,7 +286,7 @@ hourgit status [--project <name>]
285286

286287
| Flag | Default | Description |
287288
|------|---------|-------------|
288-
| `--project` | auto-detect | Project name or ID |
289+
| `-p`, `--project` | auto-detect | Project name or ID |
289290

290291
**Output includes:**
291292

@@ -321,8 +322,8 @@ hourgit project assign <name> [--force] [--yes]
321322

322323
| Flag | Default | Description |
323324
|------|---------|-------------|
324-
| `--force` | `false` | Reassign repository to a different project |
325-
| `--yes` | `false` | Skip confirmation prompt |
325+
| `-f`, `--force` | `false` | Reassign repository to a different project |
326+
| `-y`, `--yes` | `false` | Skip confirmation prompt |
326327

327328
#### `hourgit project list`
328329

@@ -344,7 +345,7 @@ hourgit project remove <name> [--yes]
344345

345346
| Flag | Default | Description |
346347
|------|---------|-------------|
347-
| `--yes` | `false` | Skip confirmation prompt |
348+
| `-y`, `--yes` | `false` | Skip confirmation prompt |
348349

349350
### Schedule Configuration
350351

@@ -362,7 +363,7 @@ hourgit config get [--project <name>]
362363

363364
| Flag | Default | Description |
364365
|------|---------|-------------|
365-
| `--project` | auto-detect | Project name or ID |
366+
| `-p`, `--project` | auto-detect | Project name or ID |
366367

367368
#### `hourgit config set`
368369

@@ -374,7 +375,7 @@ hourgit config set [--project <name>]
374375

375376
| Flag | Default | Description |
376377
|------|---------|-------------|
377-
| `--project` | auto-detect | Project name or ID |
378+
| `-p`, `--project` | auto-detect | Project name or ID |
378379

379380
#### `hourgit config reset`
380381

@@ -386,8 +387,8 @@ hourgit config reset [--project <name>] [--yes]
386387

387388
| Flag | Default | Description |
388389
|------|---------|-------------|
389-
| `--project` | auto-detect | Project name or ID |
390-
| `--yes` | `false` | Skip confirmation prompt |
390+
| `-p`, `--project` | auto-detect | Project name or ID |
391+
| `-y`, `--yes` | `false` | Skip confirmation prompt |
391392

392393
#### `hourgit config report`
393394

@@ -399,9 +400,9 @@ hourgit config report [--project <name>] [--month <1-12>] [--year <YYYY>]
399400

400401
| Flag | Default | Description |
401402
|------|---------|-------------|
402-
| `--project` | auto-detect | Project name or ID |
403-
| `--month` | current month | Month number 1-12 |
404-
| `--year` | current year | Year |
403+
| `-p`, `--project` | auto-detect | Project name or ID |
404+
| `-m`, `--month` | current month | Month number 1-12 |
405+
| `-y`, `--year` | current year | Year |
405406

406407
### Default Schedule
407408

@@ -439,7 +440,7 @@ hourgit defaults reset [--yes]
439440

440441
| Flag | Default | Description |
441442
|------|---------|-------------|
442-
| `--yes` | `false` | Skip confirmation prompt |
443+
| `-y`, `--yes` | `false` | Skip confirmation prompt |
443444

444445
#### `hourgit defaults report`
445446

@@ -451,8 +452,8 @@ hourgit defaults report [--month <1-12>] [--year <YYYY>]
451452

452453
| Flag | Default | Description |
453454
|------|---------|-------------|
454-
| `--month` | current month | Month number 1-12 |
455-
| `--year` | current year | Year |
455+
| `-m`, `--month` | current month | Month number 1-12 |
456+
| `-y`, `--year` | current year | Year |
456457

457458
### Shell Completions
458459

@@ -470,7 +471,7 @@ hourgit completion install [SHELL] [--yes]
470471

471472
| Flag | Default | Description |
472473
|------|---------|-------------|
473-
| `--yes` | `false` | Skip confirmation prompt |
474+
| `-y`, `--yes` | `false` | Skip confirmation prompt |
474475

475476
#### `hourgit completion generate`
476477

internal/cli/command.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import "github.com/spf13/cobra"
44

55
// BoolFlag defines a boolean flag for a command.
66
type BoolFlag struct {
7-
Name string
8-
Usage string
9-
Default bool
7+
Name string
8+
Shorthand string
9+
Usage string
10+
Default bool
1011
}
1112

1213
// StringFlag defines a string flag for a command.
@@ -37,7 +38,11 @@ func (lc LeafCommand) Build() *cobra.Command {
3738
RunE: lc.RunE,
3839
}
3940
for _, f := range lc.BoolFlags {
40-
cmd.Flags().Bool(f.Name, f.Default, f.Usage)
41+
if f.Shorthand != "" {
42+
cmd.Flags().BoolP(f.Name, f.Shorthand, f.Default, f.Usage)
43+
} else {
44+
cmd.Flags().Bool(f.Name, f.Default, f.Usage)
45+
}
4146
}
4247
for _, f := range lc.StrFlags {
4348
if f.Shorthand != "" {

internal/cli/command_test.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ func TestLeafCommandBuild(t *testing.T) {
1414
Short: "A test command",
1515
Args: cobra.ExactArgs(1),
1616
BoolFlags: []BoolFlag{
17-
{Name: "verbose", Usage: "enable verbose output", Default: false},
17+
{Name: "verbose", Shorthand: "v", Usage: "enable verbose output", Default: false},
1818
{Name: "dry-run", Usage: "simulate execution", Default: true},
1919
},
2020
StrFlags: []StringFlag{
21-
{Name: "output", Usage: "output file", Default: "out.txt"},
21+
{Name: "output", Shorthand: "o", Usage: "output file", Default: "out.txt"},
2222
},
2323
RunE: func(cmd *cobra.Command, args []string) error { return nil },
2424
}.Build()
@@ -31,6 +31,7 @@ func TestLeafCommandBuild(t *testing.T) {
3131
verbose := cmd.Flags().Lookup("verbose")
3232
require.NotNil(t, verbose)
3333
assert.Equal(t, "false", verbose.DefValue)
34+
assert.Equal(t, "v", verbose.Shorthand)
3435

3536
dryRun := cmd.Flags().Lookup("dry-run")
3637
require.NotNil(t, dryRun)
@@ -39,6 +40,34 @@ func TestLeafCommandBuild(t *testing.T) {
3940
output := cmd.Flags().Lookup("output")
4041
require.NotNil(t, output)
4142
assert.Equal(t, "out.txt", output.DefValue)
43+
assert.Equal(t, "o", output.Shorthand)
44+
}
45+
46+
func TestLeafCommandShortFlags(t *testing.T) {
47+
var gotVerbose bool
48+
var gotOutput string
49+
50+
cmd := LeafCommand{
51+
Use: "test",
52+
Short: "A test command",
53+
BoolFlags: []BoolFlag{
54+
{Name: "verbose", Shorthand: "v", Usage: "enable verbose output"},
55+
},
56+
StrFlags: []StringFlag{
57+
{Name: "output", Shorthand: "o", Usage: "output file"},
58+
},
59+
RunE: func(cmd *cobra.Command, args []string) error {
60+
gotVerbose, _ = cmd.Flags().GetBool("verbose")
61+
gotOutput, _ = cmd.Flags().GetString("output")
62+
return nil
63+
},
64+
}.Build()
65+
66+
cmd.SetArgs([]string{"-v", "-o", "result.txt"})
67+
require.NoError(t, cmd.Execute())
68+
69+
assert.True(t, gotVerbose)
70+
assert.Equal(t, "result.txt", gotOutput)
4271
}
4372

4473
func TestLeafCommandBuildNoFlags(t *testing.T) {

internal/cli/completion_install_cmd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ var completionInstallCmd = LeafCommand{
1313
Short: "Install shell completions into your shell config",
1414
Args: cobra.RangeArgs(0, 1),
1515
BoolFlags: []BoolFlag{
16-
{Name: "yes", Usage: "Skip confirmation prompt"},
16+
{Name: "yes", Shorthand: "y", Usage: "Skip confirmation prompt"},
1717
},
1818
RunE: func(cmd *cobra.Command, args []string) error {
1919
shell := ""

internal/cli/config_get.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ var configGetCmd = LeafCommand{
1111
Use: "get",
1212
Short: "Show the schedule configuration for a project",
1313
StrFlags: []StringFlag{
14-
{Name: "project", Usage: "project name or ID (auto-detected from repo if omitted)"},
14+
{Name: "project", Shorthand: "p", Usage: "project name or ID (auto-detected from repo if omitted)"},
1515
},
1616
RunE: func(cmd *cobra.Command, args []string) error {
1717
homeDir, repoDir, err := getContextPaths()

internal/cli/config_report.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ var configReportCmd = LeafCommand{
1212
Use: "report",
1313
Short: "Show expanded working hours for a given month",
1414
StrFlags: []StringFlag{
15-
{Name: "project", Usage: "project name or ID (auto-detected from repo if omitted)"},
16-
{Name: "month", Usage: "month number 1-12 (default: current)"},
17-
{Name: "year", Usage: "year (default: current)"},
15+
{Name: "project", Shorthand: "p", Usage: "project name or ID (auto-detected from repo if omitted)"},
16+
{Name: "month", Shorthand: "m", Usage: "month number 1-12 (default: current)"},
17+
{Name: "year", Shorthand: "y", Usage: "year (default: current)"},
1818
},
1919
RunE: func(cmd *cobra.Command, args []string) error {
2020
homeDir, repoDir, err := getContextPaths()

internal/cli/config_reset.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ var configResetCmd = LeafCommand{
1111
Use: "reset",
1212
Short: "Reset a project's schedule to the defaults",
1313
StrFlags: []StringFlag{
14-
{Name: "project", Usage: "project name or ID (auto-detected from repo if omitted)"},
14+
{Name: "project", Shorthand: "p", Usage: "project name or ID (auto-detected from repo if omitted)"},
1515
},
1616
BoolFlags: []BoolFlag{
17-
{Name: "yes", Usage: "skip confirmation prompt"},
17+
{Name: "yes", Shorthand: "y", Usage: "skip confirmation prompt"},
1818
},
1919
RunE: func(cmd *cobra.Command, args []string) error {
2020
homeDir, repoDir, err := getContextPaths()

internal/cli/config_set.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ var configSetCmd = LeafCommand{
1010
Use: "set",
1111
Short: "Interactively edit a project's schedule",
1212
StrFlags: []StringFlag{
13-
{Name: "project", Usage: "project name or ID (auto-detected from repo if omitted)"},
13+
{Name: "project", Shorthand: "p", Usage: "project name or ID (auto-detected from repo if omitted)"},
1414
},
1515
RunE: func(cmd *cobra.Command, args []string) error {
1616
homeDir, repoDir, err := getContextPaths()

internal/cli/defaults_report.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ var defaultsReportCmd = LeafCommand{
1212
Use: "report",
1313
Short: "Show expanded default working hours for a given month",
1414
StrFlags: []StringFlag{
15-
{Name: "month", Usage: "month number 1-12 (default: current)"},
16-
{Name: "year", Usage: "year (default: current)"},
15+
{Name: "month", Shorthand: "m", Usage: "month number 1-12 (default: current)"},
16+
{Name: "year", Shorthand: "y", Usage: "year (default: current)"},
1717
},
1818
RunE: func(cmd *cobra.Command, args []string) error {
1919
homeDir, err := os.UserHomeDir()

0 commit comments

Comments
 (0)