From 9f09b0d25c7beaab179250cdbe19689ca1f60d62 Mon Sep 17 00:00:00 2001 From: Thales Maciel Date: Fri, 20 Mar 2026 17:40:52 -0300 Subject: [PATCH] Show vm create defaults in CLI help Expose the static vm create CPU, memory, system overlay, and work disk defaults at the Cobra flag declaration layer so banger vm create --help shows the values users get by default. Keep the daemon as the fallback source of truth by only sending those fields in VMCreateParams when the user actually changes the flags. This preserves existing RPC behavior for omitted values while improving the CLI UX. Add CLI coverage for displayed defaults and for unchanged versus changed flag propagation. Verified with GOCACHE=/tmp/banger-gocache go test ./... and go run ./cmd/banger vm create --help. --- internal/cli/banger.go | 32 +++++++++++-------- internal/cli/cli_test.go | 69 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 83 insertions(+), 18 deletions(-) diff --git a/internal/cli/banger.go b/internal/cli/banger.go index b7f3361..9de83e5 100644 --- a/internal/cli/banger.go +++ b/internal/cli/banger.go @@ -300,10 +300,10 @@ func newVMCreateCommand() *cobra.Command { var ( name string imageName string - vcpu int - memory int - systemOverlaySize string - workDiskSize string + vcpu = model.DefaultVCPUCount + memory = model.DefaultMemoryMiB + systemOverlaySize = model.FormatSizeBytes(model.DefaultSystemOverlaySize) + workDiskSize = model.FormatSizeBytes(model.DefaultWorkDiskSize) natEnabled bool noStart bool ) @@ -332,10 +332,10 @@ func newVMCreateCommand() *cobra.Command { } cmd.Flags().StringVar(&name, "name", "", "vm name") cmd.Flags().StringVar(&imageName, "image", "", "image name or id") - cmd.Flags().IntVar(&vcpu, "vcpu", 0, "vcpu count") - cmd.Flags().IntVar(&memory, "memory", 0, "memory in MiB") - cmd.Flags().StringVar(&systemOverlaySize, "system-overlay-size", "", "system overlay size") - cmd.Flags().StringVar(&workDiskSize, "disk-size", "", "work disk size") + cmd.Flags().IntVar(&vcpu, "vcpu", model.DefaultVCPUCount, "vcpu count") + cmd.Flags().IntVar(&memory, "memory", model.DefaultMemoryMiB, "memory in MiB") + cmd.Flags().StringVar(&systemOverlaySize, "system-overlay-size", model.FormatSizeBytes(model.DefaultSystemOverlaySize), "system overlay size") + cmd.Flags().StringVar(&workDiskSize, "disk-size", model.FormatSizeBytes(model.DefaultWorkDiskSize), "work disk size") cmd.Flags().BoolVar(&natEnabled, "nat", false, "enable NAT") cmd.Flags().BoolVar(&noStart, "no-start", false, "create without starting") return cmd @@ -1019,12 +1019,10 @@ func vmSetParamsFromFlags(idOrName string, vcpu, memory int, diskSize string, na func vmCreateParamsFromFlags(cmd *cobra.Command, name, imageName string, vcpu, memory int, systemOverlaySize, workDiskSize string, natEnabled, noStart bool) (api.VMCreateParams, error) { params := api.VMCreateParams{ - Name: name, - ImageName: imageName, - SystemOverlaySize: systemOverlaySize, - WorkDiskSize: workDiskSize, - NATEnabled: natEnabled, - NoStart: noStart, + Name: name, + ImageName: imageName, + NATEnabled: natEnabled, + NoStart: noStart, } if cmd.Flags().Changed("vcpu") { if err := validatePositiveSetting("vcpu", vcpu); err != nil { @@ -1038,6 +1036,12 @@ func vmCreateParamsFromFlags(cmd *cobra.Command, name, imageName string, vcpu, m } params.MemoryMiB = &memory } + if cmd.Flags().Changed("system-overlay-size") { + params.SystemOverlaySize = systemOverlaySize + } + if cmd.Flags().Changed("disk-size") { + params.WorkDiskSize = workDiskSize + } return params, nil } diff --git a/internal/cli/cli_test.go b/internal/cli/cli_test.go index 54af725..da0869d 100644 --- a/internal/cli/cli_test.go +++ b/internal/cli/cli_test.go @@ -128,6 +128,31 @@ func TestVMCreateFlagsExist(t *testing.T) { } } +func TestVMCreateFlagsShowStaticDefaults(t *testing.T) { + root := NewBangerCommand() + vm, _, err := root.Find([]string{"vm"}) + if err != nil { + t.Fatalf("find vm: %v", err) + } + create, _, err := vm.Find([]string{"create"}) + if err != nil { + t.Fatalf("find create: %v", err) + } + + if got := create.Flags().Lookup("vcpu").DefValue; got != fmt.Sprintf("%d", model.DefaultVCPUCount) { + t.Fatalf("vcpu default = %q, want %d", got, model.DefaultVCPUCount) + } + if got := create.Flags().Lookup("memory").DefValue; got != fmt.Sprintf("%d", model.DefaultMemoryMiB) { + t.Fatalf("memory default = %q, want %d", got, model.DefaultMemoryMiB) + } + if got := create.Flags().Lookup("system-overlay-size").DefValue; got != model.FormatSizeBytes(model.DefaultSystemOverlaySize) { + t.Fatalf("system-overlay-size default = %q, want %q", got, model.FormatSizeBytes(model.DefaultSystemOverlaySize)) + } + if got := create.Flags().Lookup("disk-size").DefValue; got != model.FormatSizeBytes(model.DefaultWorkDiskSize) { + t.Fatalf("disk-size default = %q, want %q", got, model.FormatSizeBytes(model.DefaultWorkDiskSize)) + } +} + func TestImageRegisterFlagsExist(t *testing.T) { root := NewBangerCommand() image, _, err := root.Find([]string{"image"}) @@ -199,7 +224,7 @@ func TestVMSetParamsFromFlags(t *testing.T) { } } -func TestVMCreateParamsFromFlagsUsesNilForOmittedCPUAndMemory(t *testing.T) { +func TestVMCreateParamsFromFlagsOmitsStaticDefaultsWhenFlagsAreUnchanged(t *testing.T) { cmd := NewBangerCommand() vm, _, err := cmd.Find([]string{"vm"}) if err != nil { @@ -210,12 +235,48 @@ func TestVMCreateParamsFromFlagsUsesNilForOmittedCPUAndMemory(t *testing.T) { t.Fatalf("find create: %v", err) } - params, err := vmCreateParamsFromFlags(create, "devbox", "default", 0, 0, "8G", "16G", false, false) + params, err := vmCreateParamsFromFlags( + create, + "devbox", + "default", + model.DefaultVCPUCount, + model.DefaultMemoryMiB, + model.FormatSizeBytes(model.DefaultSystemOverlaySize), + model.FormatSizeBytes(model.DefaultWorkDiskSize), + false, + false, + ) if err != nil { t.Fatalf("vmCreateParamsFromFlags: %v", err) } - if params.VCPUCount != nil || params.MemoryMiB != nil { - t.Fatalf("expected omitted cpu/memory to stay nil: %+v", params) + if params.VCPUCount != nil || params.MemoryMiB != nil || params.SystemOverlaySize != "" || params.WorkDiskSize != "" { + t.Fatalf("expected unchanged defaults to stay omitted: %+v", params) + } +} + +func TestVMCreateParamsFromFlagsIncludesChangedDiskFlags(t *testing.T) { + cmd := NewBangerCommand() + vm, _, err := cmd.Find([]string{"vm"}) + if err != nil { + t.Fatalf("find vm: %v", err) + } + create, _, err := vm.Find([]string{"create"}) + if err != nil { + t.Fatalf("find create: %v", err) + } + if err := create.Flags().Set("system-overlay-size", "16G"); err != nil { + t.Fatalf("set system-overlay-size flag: %v", err) + } + if err := create.Flags().Set("disk-size", "32G"); err != nil { + t.Fatalf("set disk-size flag: %v", err) + } + + params, err := vmCreateParamsFromFlags(create, "devbox", "default", model.DefaultVCPUCount, model.DefaultMemoryMiB, "16G", "32G", false, false) + if err != nil { + t.Fatalf("vmCreateParamsFromFlags: %v", err) + } + if params.SystemOverlaySize != "16G" || params.WorkDiskSize != "32G" { + t.Fatalf("expected changed disk flags to be included: %+v", params) } }