[object Object]

← back to Cli Printing Press

fix(cli): honor explicit --output flag in generate (#281)

6bbae936a0504dabab1febd4d00d3debeeaf50e6 · 2026-04-25 01:58:20 -0700 · Trevin Chow

The post-generate rename block at internal/cli/root.go:424 ran
unconditionally, comparing the output directory's basename against
the spec-derived API name and forcing them to match. The
explicitOutput flag was already computed nine lines earlier (and
correctly consulted by claimOrForce) but never gated the rename.

Skip the rename when --output is supplied so the caller's chosen
path is authoritative. Default-path runs still normalize to the
spec-derived slot for pipeline.DefaultOutputDir callers.

Reported in #275 (F-1).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 6bbae936a0504dabab1febd4d00d3debeeaf50e6
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Sat Apr 25 01:58:20 2026 -0700

    fix(cli): honor explicit --output flag in generate (#281)
    
    The post-generate rename block at internal/cli/root.go:424 ran
    unconditionally, comparing the output directory's basename against
    the spec-derived API name and forcing them to match. The
    explicitOutput flag was already computed nine lines earlier (and
    correctly consulted by claimOrForce) but never gated the rename.
    
    Skip the rename when --output is supplied so the caller's chosen
    path is authoritative. Default-path runs still normalize to the
    spec-derived slot for pipeline.DefaultOutputDir callers.
    
    Reported in #275 (F-1).
    
    Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 internal/cli/generate_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++
 internal/cli/root.go          | 26 ++++++++++++++------------
 2 files changed, 57 insertions(+), 12 deletions(-)

diff --git a/internal/cli/generate_test.go b/internal/cli/generate_test.go
index 3982989c..e35ed600 100644
--- a/internal/cli/generate_test.go
+++ b/internal/cli/generate_test.go
@@ -584,3 +584,46 @@ func TestGenerateCmdRejectsTrafficAnalysisWithPlan(t *testing.T) {
 	require.Error(t, err)
 	assert.Contains(t, err.Error(), "--traffic-analysis cannot be used with --plan")
 }
+
+func TestGenerateCmdHonorsExplicitOutput(t *testing.T) {
+	t.Parallel()
+
+	dir := t.TempDir()
+	specPath := filepath.Join(dir, "spec.yaml")
+	outputDir := filepath.Join(dir, "user-chosen-path")
+	derivedDir := filepath.Join(dir, "explicitoutput")
+
+	require.NoError(t, os.WriteFile(specPath, []byte(`name: explicitoutput
+description: Explicit output API
+version: 0.1.0
+base_url: https://api.example.com
+auth:
+  type: none
+config:
+  format: toml
+  path: ~/.config/explicitoutput-pp-cli/config.toml
+resources:
+  items:
+    description: Manage items
+    endpoints:
+      list:
+        method: GET
+        path: /items
+        description: List items
+`), 0o644))
+
+	cmd := newGenerateCmd()
+	cmd.SetArgs([]string{
+		"--spec", specPath,
+		"--output", outputDir,
+		"--validate=false",
+		"--force",
+	})
+
+	require.NoError(t, cmd.Execute())
+
+	assert.FileExists(t, filepath.Join(outputDir, "go.mod"),
+		"generated files should land at the user-supplied --output path")
+	assert.NoDirExists(t, derivedDir,
+		"the spec-derived directory must not be created when --output is explicit")
+}
diff --git a/internal/cli/root.go b/internal/cli/root.go
index df67b857..4a942e7b 100644
--- a/internal/cli/root.go
+++ b/internal/cli/root.go
@@ -421,18 +421,20 @@ func newGenerateCmd() *cobra.Command {
 				}
 			}
 
-			// Rename output directory to match the derived CLI name if they differ.
-			// This prevents mismatches when the caller passes a directory name
-			// that doesn't match what the generator derives from the spec title
-			// (e.g., --output .../calcom-pp-cli but spec title "Cal.com" derives "cal-com-pp-cli").
-			derivedDir := apiSpec.Name
-			currentBase := filepath.Base(absOut)
-			if currentBase != derivedDir {
-				finalPath := filepath.Join(filepath.Dir(absOut), derivedDir)
-				if err := os.Rename(absOut, finalPath); err != nil {
-					fmt.Fprintf(os.Stderr, "warning: could not rename output dir from %s to %s: %v\n", currentBase, derivedDir, err)
-				} else {
-					absOut = finalPath
+			// When --output was not explicitly supplied, normalize the output
+			// directory to the spec-derived name so default-path runs land in the
+			// expected slot (e.g., spec title "Cal.com" derives "cal-com-pp-cli").
+			// When --output is explicit, the caller's chosen path is authoritative.
+			if !explicitOutput {
+				derivedDir := apiSpec.Name
+				currentBase := filepath.Base(absOut)
+				if currentBase != derivedDir {
+					finalPath := filepath.Join(filepath.Dir(absOut), derivedDir)
+					if err := os.Rename(absOut, finalPath); err != nil {
+						fmt.Fprintf(os.Stderr, "warning: could not rename output dir from %s to %s: %v\n", currentBase, derivedDir, err)
+					} else {
+						absOut = finalPath
+					}
 				}
 			}
 

← 55114c4e fix(cli): treat access-denied sync errors as warnings (#274)  ·  back to Cli Printing Press  ·  fix(cli): dedup colliding flag identifiers in generated comm 72a84a88 →