Skip to content

Commit 8c0148c

Browse files
committed
fix(engine): thread CommandName through Options for multi-node errors
helpers.FailIfMultiNodes(ctx, name) embeds the name in its error message. The call site in engine.Render hardcoded "talm template", which was accurate when Render was only called from the template subcommand. PR #119 made apply call Render too, so users running `talm apply` with a multi-node modeline saw an error talking about `talm template` — confusing. Add Options.CommandName, default to "talm" when empty, set "talm apply" in apply's buildApplyRenderOptions and "talm template" in template's option-build. TestRenderFailIfMultiNodes_UsesCommandName covers both subcommands plus the empty-string fallback and explicitly asserts the historical "talm template" no longer leaks into the apply case. Closes #121 Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
1 parent 84dcf99 commit 8c0148c

4 files changed

Lines changed: 56 additions & 1 deletion

File tree

pkg/commands/apply.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ func buildApplyRenderOptions(modelineTemplates []string, withSecretsPath string)
221221
Full: true,
222222
Root: Config.RootDir,
223223
TemplateFiles: resolvedTemplates,
224+
CommandName: "talm apply",
224225
}
225226
}
226227

pkg/commands/template.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ func generateOutput(ctx context.Context, c *client.Client, args []string) (strin
288288
Offline: templateCmdFlags.offline,
289289
KubernetesVersion: templateCmdFlags.kubernetesVersion,
290290
TemplateFiles: resolvedTemplateFiles,
291+
CommandName: "talm template",
291292
}
292293

293294
result, err := engine.Render(ctx, c, opts)

pkg/engine/engine.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ type Options struct {
5656
TemplateFiles []string
5757
ClusterName string
5858
Endpoint string
59+
// CommandName names the caller subcommand for error messages such as
60+
// the one produced by FailIfMultiNodes. Empty value falls back to "talm".
61+
CommandName string
5962
}
6063

6164
// NormalizeTemplatePath converts OS-specific path separators to forward slash.
@@ -215,7 +218,11 @@ func Render(ctx context.Context, c *client.Client, opts Options) ([]byte, error)
215218

216219
// Gather facts and enable lookup options
217220
if !opts.Offline {
218-
if err := helpers.FailIfMultiNodes(ctx, "talm template"); err != nil {
221+
cmdName := opts.CommandName
222+
if cmdName == "" {
223+
cmdName = "talm"
224+
}
225+
if err := helpers.FailIfMultiNodes(ctx, cmdName); err != nil {
219226
return nil, err
220227
}
221228
helmEngine.LookupFunc = newLookupFunction(ctx, c)

pkg/engine/render_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"testing"
2525

2626
helmEngine "github.com/cozystack/talm/pkg/engine/helm"
27+
"github.com/siderolabs/talos/pkg/machinery/client"
2728
"helm.sh/helm/v3/pkg/chart/loader"
2829
"helm.sh/helm/v3/pkg/chartutil"
2930
)
@@ -930,6 +931,51 @@ func TestMultiDocGeneric_VlanOnBondTopology(t *testing.T) {
930931
assertNotContains(t, result, "kind: LinkConfig")
931932
}
932933

934+
// TestRenderFailIfMultiNodes_UsesCommandName covers #121: the multi-node
935+
// rejection error must reference the calling subcommand passed via
936+
// Options.CommandName, not the historical hardcoded "talm template" that
937+
// confused users running `talm apply`.
938+
func TestRenderFailIfMultiNodes_UsesCommandName(t *testing.T) {
939+
tests := []struct {
940+
name string
941+
commandName string
942+
wantInError string
943+
}{
944+
{"talm apply", "talm apply", "talm apply"},
945+
{"talm template", "talm template", "talm template"},
946+
{"empty falls back to talm", "", "talm"},
947+
}
948+
949+
for _, tt := range tests {
950+
t.Run(tt.name, func(t *testing.T) {
951+
ctx := client.WithNodes(context.Background(), "10.0.0.1", "10.0.0.2")
952+
opts := Options{
953+
Offline: false,
954+
CommandName: tt.commandName,
955+
}
956+
_, err := Render(ctx, nil, opts)
957+
if err == nil {
958+
t.Fatalf("Render expected an error, got nil")
959+
}
960+
if !strings.Contains(err.Error(), tt.wantInError) {
961+
t.Errorf("error = %q, expected to contain %q", err.Error(), tt.wantInError)
962+
}
963+
})
964+
}
965+
966+
t.Run("non-empty CommandName must not leak the historical default", func(t *testing.T) {
967+
ctx := client.WithNodes(context.Background(), "10.0.0.1", "10.0.0.2")
968+
opts := Options{Offline: false, CommandName: "talm apply"}
969+
_, err := Render(ctx, nil, opts)
970+
if err == nil {
971+
t.Fatal("Render expected an error, got nil")
972+
}
973+
if strings.Contains(err.Error(), "talm template") {
974+
t.Errorf("error must not mention 'talm template' when CommandName is 'talm apply'; got %q", err.Error())
975+
}
976+
})
977+
}
978+
933979
// TestRenderInvalidTalosVersion verifies that malformed TalosVersion values
934980
// surface a user-friendly error before template rendering, instead of the
935981
// opaque "error calling semverCompare: invalid semantic version" that escapes

0 commit comments

Comments
 (0)