You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ossie.apache.org by jb...@apache.org on 2026/09/24 15:40:19 UTC

(ossie) branch main updated: fix(cli): exit non-zero from unimplemented commands (#390)

This is an automated email from the ASF dual-hosted git repository.

jbonofre pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ossie.git


The following commit(s) were added to refs/heads/main by this push:
     new 3ccd9343 fix(cli): exit non-zero from unimplemented commands (#390)
3ccd9343 is described below

commit 3ccd9343be9a5a295b0a6088e5a43d296108a427
Author: Kyoungmin Kim <ka...@gmail.com>
AuthorDate: Fri Sep 25 00:40:12 2026 +0900

    fix(cli): exit non-zero from unimplemented commands (#390)
    
    * fix(cli): exit non-zero from unimplemented commands
    
    validate, convert, plugin install and plugin remove printed
    "not yet implemented" to stdout and returned nil, so they exited 0
    while doing nothing. In a pipeline such as
    `ossie validate model.yaml && deploy` that reads as a pass.
    
    Each stub now returns an error naming the command, which cobra
    reports on stderr and main turns into exit 1. Usage is silenced
    since the arguments were not the problem.
    
    Generated-by: Claude Code
    
    * test(cli): reset flags between stub test cases
    
    The convert case leaves --from and --input set on the shared rootCmd,
    so a later test running convert without flags would skip the required
    flag check.
    
    Generated-by: Claude Code
    
    * test(cli): expect errors from valid stub invocations
    
    ---------
    
    Co-authored-by: JB Onofré <jb...@apache.org>
---
 cli/cmd/args_test.go      |  8 +++---
 cli/cmd/convert.go        |  4 +--
 cli/cmd/plugin/install.go |  4 +--
 cli/cmd/plugin/remove.go  |  4 +--
 cli/cmd/stubs_test.go     | 70 +++++++++++++++++++++++++++++++++++++++++++++++
 cli/cmd/validate.go       |  4 +--
 6 files changed, 82 insertions(+), 12 deletions(-)

diff --git a/cli/cmd/args_test.go b/cli/cmd/args_test.go
index 4dd5fa9b..e12f22e6 100644
--- a/cli/cmd/args_test.go
+++ b/cli/cmd/args_test.go
@@ -65,11 +65,11 @@ func TestArgumentValidation(t *testing.T) {
 		{name: "convert trailing arg", args: []string{"convert", "--from", "x", "--input", "y", "extra"}, wantErr: true},
 		{name: "plugin bare", args: []string{"plugin"}, wantErr: true},
 		{name: "plugin install --all with name", args: []string{"plugin", "install", "--all", "foo"}, wantErr: true},
-		// Valid invocations keep working.
+		// The implemented command still works; the valid stub invocations fail.
 		{name: "plugin list", args: []string{"plugin", "list"}},
-		{name: "plugin install by name", args: []string{"plugin", "install", "foo"}},
-		{name: "plugin install --all", args: []string{"plugin", "install", "--all"}},
-		{name: "convert flags only", args: []string{"convert", "--from", "x", "--input", "y"}},
+		{name: "plugin install by name", args: []string{"plugin", "install", "foo"}, wantErr: true},
+		{name: "plugin install --all", args: []string{"plugin", "install", "--all"}, wantErr: true},
+		{name: "convert flags only", args: []string{"convert", "--from", "x", "--input", "y"}, wantErr: true},
 	}
 
 	for _, tt := range tests {
diff --git a/cli/cmd/convert.go b/cli/cmd/convert.go
index 1d20d78f..79c09681 100644
--- a/cli/cmd/convert.go
+++ b/cli/cmd/convert.go
@@ -44,6 +44,6 @@ func init() {
 }
 
 func runConvert(cmd *cobra.Command, args []string) error {
-	fmt.Fprintln(cmd.OutOrStdout(), "not yet implemented")
-	return nil
+	cmd.SilenceUsage = true
+	return fmt.Errorf("%s is not yet implemented", cmd.CommandPath())
 }
diff --git a/cli/cmd/plugin/install.go b/cli/cmd/plugin/install.go
index 38476898..641d81aa 100644
--- a/cli/cmd/plugin/install.go
+++ b/cli/cmd/plugin/install.go
@@ -46,6 +46,6 @@ func runPluginInstall(cmd *cobra.Command, args []string) error {
 	if !all && !hasName {
 		return errors.New("requires a plugin name or --all")
 	}
-	fmt.Fprintln(cmd.OutOrStdout(), "not yet implemented")
-	return nil
+	cmd.SilenceUsage = true
+	return fmt.Errorf("%s is not yet implemented", cmd.CommandPath())
 }
diff --git a/cli/cmd/plugin/remove.go b/cli/cmd/plugin/remove.go
index 38df2259..1f1cfd89 100644
--- a/cli/cmd/plugin/remove.go
+++ b/cli/cmd/plugin/remove.go
@@ -30,6 +30,6 @@ var removeCmd = &cobra.Command{
 }
 
 func runPluginRemove(cmd *cobra.Command, args []string) error {
-	fmt.Fprintln(cmd.OutOrStdout(), "not yet implemented")
-	return nil
+	cmd.SilenceUsage = true
+	return fmt.Errorf("%s is not yet implemented", cmd.CommandPath())
 }
diff --git a/cli/cmd/stubs_test.go b/cli/cmd/stubs_test.go
new file mode 100644
index 00000000..e405a22b
--- /dev/null
+++ b/cli/cmd/stubs_test.go
@@ -0,0 +1,70 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cmd
+
+import (
+	"bytes"
+	"strings"
+	"testing"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/pflag"
+)
+
+func TestUnimplementedCommandsFail(t *testing.T) {
+	t.Setenv("OSSIE_PLUGIN_DIR", t.TempDir())
+
+	tests := [][]string{
+		{"validate", "model.yaml"},
+		{"convert", "--from", "dbt", "--input", "model.yaml"},
+		{"plugin", "install", "dbt"},
+		{"plugin", "remove", "dbt"},
+	}
+
+	for _, args := range tests {
+		t.Run(strings.Join(args, " "), func(t *testing.T) {
+			t.Cleanup(func() { clearFlags(rootCmd) })
+
+			out := new(bytes.Buffer)
+			rootCmd.SetOut(out)
+			rootCmd.SetErr(out)
+			rootCmd.SetArgs(args)
+
+			err := rootCmd.Execute()
+			if err == nil {
+				t.Fatalf("Execute(%q) returned nil, want not-implemented error", args)
+			}
+			if !strings.Contains(err.Error(), "not yet implemented") {
+				t.Errorf("Execute(%q) error = %q, want it to mention not yet implemented", args, err)
+			}
+			if strings.Contains(out.String(), "Usage:") {
+				t.Errorf("Execute(%q) printed usage:\n%s", args, out.String())
+			}
+		})
+	}
+}
+
+// Flag values set by one Execute call stay on the shared rootCmd tree.
+func clearFlags(cmd *cobra.Command) {
+	cmd.Flags().Visit(func(f *pflag.Flag) {
+		_ = f.Value.Set(f.DefValue)
+		f.Changed = false
+	})
+	for _, sub := range cmd.Commands() {
+		clearFlags(sub)
+	}
+}
diff --git a/cli/cmd/validate.go b/cli/cmd/validate.go
index 08a3be55..0d096e60 100644
--- a/cli/cmd/validate.go
+++ b/cli/cmd/validate.go
@@ -35,6 +35,6 @@ func init() {
 }
 
 func runValidate(cmd *cobra.Command, args []string) error {
-	fmt.Fprintln(cmd.OutOrStdout(), "not yet implemented")
-	return nil
+	cmd.SilenceUsage = true
+	return fmt.Errorf("%s is not yet implemented", cmd.CommandPath())
 }