[object Object]

← back to Cli Printing Press

fix(cli): route promoted-command file stem through safeResourceFileStem (#1489) (#1506)

bf7f346537502883bed2afede9db9d7bac06d915 · 2026-05-16 02:05:21 -0700 · Trevin Chow

PR #1021 fixed `safeResourceFileStem` to suffix `_cmd` on stems ending in
GOOS/GOARCH/test tokens, but only for the `<resource>_<verb>.go` emit
path. The promoted-command emitter at generator.go:2605 builds its path
as `"promoted_" + pc.PromotedName + ".go"` without the safe-stem wrapper,
so an OpenAPI resource named `test` produces `internal/cli/promoted_test.go`.
Go treats *_test.go as a test file and excludes it from the normal package
build, leaving root.go's `newTestPromotedCmd` reference undefined.

Wrap the stem in `safeResourceFileStem`. The function's `_test`/GOOS/GOARCH
trailing-token rules now cover both emit paths.

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>

Files touched

Diff

commit bf7f346537502883bed2afede9db9d7bac06d915
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Sat May 16 02:05:21 2026 -0700

    fix(cli): route promoted-command file stem through safeResourceFileStem (#1489) (#1506)
    
    PR #1021 fixed `safeResourceFileStem` to suffix `_cmd` on stems ending in
    GOOS/GOARCH/test tokens, but only for the `<resource>_<verb>.go` emit
    path. The promoted-command emitter at generator.go:2605 builds its path
    as `"promoted_" + pc.PromotedName + ".go"` without the safe-stem wrapper,
    so an OpenAPI resource named `test` produces `internal/cli/promoted_test.go`.
    Go treats *_test.go as a test file and excludes it from the normal package
    build, leaving root.go's `newTestPromotedCmd` reference undefined.
    
    Wrap the stem in `safeResourceFileStem`. The function's `_test`/GOOS/GOARCH
    trailing-token rules now cover both emit paths.
    
    Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
---
 internal/generator/generator.go      |  2 +-
 internal/generator/generator_test.go | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/internal/generator/generator.go b/internal/generator/generator.go
index 396aa39a..e86c6f65 100644
--- a/internal/generator/generator.go
+++ b/internal/generator/generator.go
@@ -2602,7 +2602,7 @@ func (g *Generator) renderPromotedCommandFiles(promotedCommands []PromotedComman
 			IsReadOnly:      endpointIsReadCommand(pc.Endpoint, pc.EndpointName),
 			APISpec:         g.Spec,
 		}
-		promotedPath := filepath.Join("internal", "cli", "promoted_"+pc.PromotedName+".go")
+		promotedPath := filepath.Join("internal", "cli", safeResourceFileStem("promoted_"+pc.PromotedName)+".go")
 		if err := g.renderTemplate("command_promoted.go.tmpl", promotedPath, promotedData); err != nil {
 			return fmt.Errorf("rendering promoted command %s: %w", pc.PromotedName, err)
 		}
diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go
index fd4fd4d2..da908f17 100644
--- a/internal/generator/generator_test.go
+++ b/internal/generator/generator_test.go
@@ -5509,6 +5509,41 @@ func TestGeneratedOutput_PromotedCommandCompiles(t *testing.T) {
 	runGoCommand(t, outputDir, "build", "./...")
 }
 
+// A resource named `test` produces `promoted_test.go`; Go treats *_test.go as a
+// test file and excludes it from the normal package build, so root.go's
+// reference to newTestPromotedCmd fails to compile. Mirrors the safe-stem fix
+// that #1021 applied to `<resource>_<verb>.go`.
+func TestGeneratedOutput_PromotedCommand_TestResourceCompiles(t *testing.T) {
+	t.Parallel()
+
+	apiSpec := &spec.APISpec{
+		Name:    "promotedtest",
+		Version: "0.1.0",
+		BaseURL: "https://api.example.com",
+		Auth:    spec.AuthConfig{Type: "api_key", Header: "X-Api-Key", EnvVars: []string{"PT_API_KEY"}},
+		Config:  spec.ConfigSpec{Format: "toml", Path: "~/.config/promotedtest-pp-cli/config.toml"},
+		Resources: map[string]spec.Resource{
+			"test": {
+				Description: "Single-endpoint resource whose name collides with Go's *_test.go convention",
+				Endpoints: map[string]spec.Endpoint{
+					"generate": {Method: "POST", Path: "/test/generate", Description: "Generate a test"},
+				},
+			},
+		},
+	}
+
+	outputDir := filepath.Join(t.TempDir(), "promotedtest-pp-cli")
+	gen := New(apiSpec, outputDir)
+	require.NoError(t, gen.Generate())
+
+	assert.NoFileExists(t, filepath.Join(outputDir, "internal", "cli", "promoted_test.go"),
+		"promoted_test.go is excluded from go build; safeResourceFileStem must rewrite to promoted_test_cmd.go")
+	assert.FileExists(t, filepath.Join(outputDir, "internal", "cli", "promoted_test_cmd.go"))
+
+	runGoCommand(t, outputDir, "mod", "tidy")
+	runGoCommand(t, outputDir, "build", "./...")
+}
+
 func TestGeneratedOutput_ResourceParentsHiddenWhenAPIBrowserGenerated(t *testing.T) {
 	t.Parallel()
 

← f64e9913 fix(skills): drop cli-skills mirror regen from publish flow  ·  back to Cli Printing Press  ·  feat(cli): catalog auth_env_vars declares canonical credenti fe4a5ec3 →