From cc1cf689cd1e3e4e98f79df1ba9a866f2e83949f Mon Sep 17 00:00:00 2001 From: Andrei Lepikhov Date: Wed, 1 Jul 2026 13:12:15 +0200 Subject: [PATCH] Reveal consumed positional when cluster name is missing Author: Claude Opus 4.8 (1M context) --- internal/cli/cli.go | 10 ++++++++++ internal/cli/cli_test.go | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 05d8891..c9c5a4f 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -865,6 +865,16 @@ func resolveClusterArg(cmd, missingUsage, argsUsage string, required int, args [ if len(args) == required { cluster := config.DefaultCluster() if cluster == "" { + if required > 0 { + // The positional(s) supplied were consumed as the required + // entity (e.g. ), leaving the cluster unset. Spell that + // out so a lone argument isn't silently misread as the cluster + // and reported back as a bare "cluster name is required". + return "", nil, fmt.Errorf( + "cluster name is required: %q was read as the %s argument (usage: %s %s); "+ + "pass the cluster as the first argument or set default_cluster in ace.yaml", + strings.Join(args, " "), missingUsage, cmd, argsUsage) + } return "", nil, fmt.Errorf("cluster name is required: specify one explicitly or set default_cluster in ace.yaml") } return cluster, args, nil diff --git a/internal/cli/cli_test.go b/internal/cli/cli_test.go index 3eb0235..9a4d241 100644 --- a/internal/cli/cli_test.go +++ b/internal/cli/cli_test.go @@ -13,6 +13,7 @@ package cli import ( "context" + "strings" "testing" "github.com/pgedge/ace/pkg/config" @@ -61,6 +62,25 @@ func TestResolveClusterArgErrorsWithoutDefault(t *testing.T) { } } +// A lone positional is consumed as the required entity (repset), not the +// cluster. The error must name the consumed argument so the user sees why +// "cluster name is required" fired, instead of thinking their argument was +// ignored. +func TestResolveClusterArgSinglePositionalRevealsConsumedArg(t *testing.T) { + t.Cleanup(func() { config.Cfg = nil }) + config.Cfg = &config.Config{} + + _, _, err := resolveClusterArg("repset-diff", "", "[cluster] ", 1, []string{"demo"}) + if err == nil { + t.Fatalf("expected error for a lone positional with no default_cluster set") + } + for _, want := range []string{"demo", "", "repset-diff"} { + if !strings.Contains(err.Error(), want) { + t.Errorf("error %q missing expected substring %q", err.Error(), want) + } + } +} + func TestResolveClusterArgUnexpectedArgs(t *testing.T) { t.Cleanup(func() { config.Cfg = nil }) config.Cfg = &config.Config{DefaultCluster: "default"}