Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .adder.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Adder configuration file
# See https://github.com/jrschumacher/adder for documentation

binary_name: otdfctl
input: docs/man
output: cmd/generated
package: generated
generated_file_suffix: _generated.go
index_format: _index
package_strategy: directory
30 changes: 30 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,33 @@ test-bats: build-test
.PHONY: clean
clean:
rm -rf $(TARGET_DIR)

# Target for generating CLI commands from documentation
# NOTE: Generated files require manual implementation of handler interfaces
# and should be committed to the repository after implementation
.PHONY: generate
generate:
go run github.com/jrschumacher/adder/cmd/adder@v0.1.1 generate -o cmd/generated

# Target for cleaning generated files
.PHONY: clean-generated
clean-generated:
rm -rf cmd/generated/

# Target for regenerating (clean + generate)
# WARNING: This will remove existing generated files - ensure handlers are implemented elsewhere
.PHONY: regenerate
regenerate: clean-generated generate

# Target for checking required tools are available
.PHONY: toolcheck
toolcheck:
@echo "Checking required tools..."
@command -v go >/dev/null 2>&1 || { echo >&2 "go is required but not installed. Visit https://golang.org/dl/"; exit 1; }
@echo "✓ go is available"
@go version 2>/dev/null | grep -q "go1\." || { echo >&2 "go version check failed"; exit 1; }
@echo "✓ go version is compatible"
@go run github.com/jrschumacher/adder/cmd/adder@v0.1.1 version >/dev/null 2>&1 || { echo >&2 "adder tool check failed. Run 'go mod download' to ensure dependencies are available."; exit 1; }
@echo "✓ adder is available"
@command -v bats >/dev/null 2>&1 || echo "⚠ bats is not installed (required for e2e tests). Install with: brew install bats-core"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The suggestion to install bats using brew is specific to macOS. To make this Makefile more portable for developers on other operating systems (like Linux), it would be better to provide a more generic installation instruction or link to the official bats-core installation guide.

For example, you could suggest installing via npm or from source, and link to https://github.com/bats-core/bats-core#installation.

@echo "All required tools are available!"
37 changes: 20 additions & 17 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,42 @@ package cmd
import (
"fmt"

configgenerated "github.com/opentdf/otdfctl/cmd/generated/config"
"github.com/opentdf/otdfctl/pkg/cli"
"github.com/opentdf/otdfctl/pkg/config"
"github.com/opentdf/otdfctl/pkg/man"
"github.com/spf13/cobra"
)

func config_updateOutput(cmd *cobra.Command, args []string) {
c := cli.New(cmd, args)
// handleConfigOutput implements the business logic for the config output command
func handleConfigOutput(cmd *cobra.Command, req *configgenerated.OutputRequest) error {
c := cli.New(cmd, []string{})
h := NewHandler(c)
defer h.Close()

format := c.Flags.GetRequiredString("format")
format := req.Flags.Format

err := config.UpdateOutputFormat(cfgKey, format)
if err != nil {
c.ExitWithError("Failed to update output format", err)
}
Comment on lines 21 to 23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The handler function handleConfigOutput has a signature that returns an error, which is the standard for cobra's RunE functions. However, on error, c.ExitWithError is called, which terminates the program immediately. This bypasses cobra's error handling mechanism.

Instead of calling c.ExitWithError, you should return a descriptive error. The generated command wrapper will then handle printing the error and exiting. This pattern should be applied to all new command handlers in this PR for consistency and proper error flow.

	return fmt.Errorf("Failed to update output format: %w", err)


c.Println(cli.SuccessMessage(fmt.Sprintf("Output format updated to %s", format)))
return nil
}

// handleConfig implements the parent config command (shows help if called without subcommands)
func handleConfig(cmd *cobra.Command, req *configgenerated.ConfigRequest) error {
return cmd.Help()
}

func init() {
outputCmd := man.Docs.GetCommand("config/output",
man.WithRun(config_updateOutput),
)
outputCmd.Flags().String(
outputCmd.GetDocFlag("format").Name,
outputCmd.GetDocFlag("format").Default,
outputCmd.GetDocFlag("format").Description,
)

cmd := man.Docs.GetCommand("config",
man.WithSubcommands(outputCmd),
)
RootCmd.AddCommand(&cmd.Command)
// Create commands using generated constructors with handler functions
configCmd := configgenerated.NewConfigCommand(handleConfig)
outputCmd := configgenerated.NewOutputCommand(handleConfigOutput)

// Add subcommand to parent
configCmd.AddCommand(outputCmd)

// Add to root command
RootCmd.AddCommand(configCmd)
}
93 changes: 49 additions & 44 deletions cmd/dev-selectors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ package cmd

import (
"fmt"
"strings"

selectorsgenerated "github.com/opentdf/otdfctl/cmd/generated/dev/selectors"
"github.com/opentdf/otdfctl/pkg/cli"
"github.com/opentdf/otdfctl/pkg/handlers"
"github.com/opentdf/otdfctl/pkg/man"
"github.com/spf13/cobra"
)

var selectors []string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The global variable selectors appears to be a leftover from the previous implementation and is no longer used. It can be safely removed to improve code clarity.


func dev_selectorsGen(cmd *cobra.Command, args []string) {
c := cli.New(cmd, args)
h := NewHandler(c)
defer h.Close()
// handleDevSelectorsGenerate implements the business logic for the generate command
func handleDevSelectorsGenerate(cmd *cobra.Command, req *selectorsgenerated.GenerateRequest) error {
c := cli.New(cmd, []string{})
handler := NewHandler(c)
defer handler.Close()

subject := c.Flags.GetRequiredString("subject")

Expand All @@ -30,15 +32,26 @@ func dev_selectorsGen(cmd *cobra.Command, args []string) {

t := cli.NewTabular(rows...)
cli.PrintSuccessTable(cmd, "", t)
return nil
}

func dev_selectorsTest(cmd *cobra.Command, args []string) {
c := cli.New(cmd, args)
h := NewHandler(c)
defer h.Close()
// handleDevSelectorsTest implements the business logic for the test command
func handleDevSelectorsTest(cmd *cobra.Command, req *selectorsgenerated.TestRequest) error {
c := cli.New(cmd, []string{})
handler := NewHandler(c)
defer handler.Close()

subject := c.Flags.GetRequiredString("subject")
selectors = c.Flags.GetStringSlice("selector", selectors, cli.FlagsStringSliceOptions{Min: 1})

// Convert single selector string to slice for compatibility with existing logic
var selectorsList []string
if req.Flags.Selector != "" {
selectorsList = strings.Split(req.Flags.Selector, ",")
}

if len(selectorsList) == 0 {
cli.ExitWithError("Must provide at least one selector", nil)
}
Comment on lines +52 to +54
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This function calls cli.ExitWithError instead of returning an error, which is inconsistent with the RunE pattern used by cobra. Please refactor this to return an error, allowing the caller to handle program termination and error reporting.

		return fmt.Errorf("Must provide at least one selector")


flattened, err := handlers.FlattenSubjectContext(subject)
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This function calls cli.PrintSuccessTable and then does not return an error. To align with cobra's RunE error handling pattern, this should return nil.

Expand All @@ -47,7 +60,8 @@ func dev_selectorsTest(cmd *cobra.Command, args []string) {

rows := [][]string{}
for _, item := range flattened {
for _, selector := range selectors {
for _, selector := range selectorsList {
selector = strings.TrimSpace(selector)
if selector == item.Key {
rows = append(rows, []string{item.Key, fmt.Sprintf("%v", item.Value)})
}
Expand All @@ -56,40 +70,31 @@ func dev_selectorsTest(cmd *cobra.Command, args []string) {

t := cli.NewTabular(rows...)
cli.PrintSuccessTable(cmd, "", t)
return nil
}

func init() {
genCmd := man.Docs.GetCommand("dev/selectors/generate",
man.WithRun(dev_selectorsGen),
)
genCmd.Flags().StringP(
genCmd.GetDocFlag("subject").Name,
genCmd.GetDocFlag("subject").Shorthand,
genCmd.GetDocFlag("subject").Default,
genCmd.GetDocFlag("subject").Description,
)

testCmd := man.Docs.GetCommand("dev/selectors/test",
man.WithRun(dev_selectorsTest),
)
testCmd.Flags().StringP(
testCmd.GetDocFlag("subject").Name,
testCmd.GetDocFlag("subject").Shorthand,
testCmd.GetDocFlag("subject").Default,
testCmd.GetDocFlag("subject").Description,
)
testCmd.Flags().StringSliceVarP(
&selectors,
testCmd.GetDocFlag("selector").Name,
testCmd.GetDocFlag("selector").Shorthand,
[]string{},
testCmd.GetDocFlag("selector").Description,
)

doc := man.Docs.GetCommand("dev/selectors",
man.WithSubcommands(genCmd, testCmd),
)

dev_selectorsCmd := &doc.Command
devCmd.AddCommand(dev_selectorsCmd)
// Create commands using generated code with handler functions
genCmd := selectorsgenerated.NewGenerateCommand(handleDevSelectorsGenerate)
testCmd := selectorsgenerated.NewTestCommand(handleDevSelectorsTest)

// Create selectors parent command
selectorsCmd := &cobra.Command{
Use: "selectors",
Aliases: []string{"sel"},
Short: "Selectors",
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}

// Add subcommands
selectorsCmd.AddCommand(genCmd)
selectorsCmd.AddCommand(testCmd)

// Export for use by dev.go
DevSelectorsCmd = selectorsCmd
}

// DevSelectorsCmd exports the selectors command for use by dev.go
var DevSelectorsCmd *cobra.Command
20 changes: 16 additions & 4 deletions cmd/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ import (
"github.com/spf13/cobra"
)

// devCmd is the command for playground-style development
var devCmd = man.Docs.GetCommand("dev")

var (
metadataLabels []string
defaultListFlagLimit int32 = 300
Expand Down Expand Up @@ -153,9 +150,24 @@ func readPipedStdin() []byte {
}

func init() {
// Create dev command
devCmd := &cobra.Command{
Use: "dev",
Short: "Development Tools",
Hidden: true,
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}

// Create design-system subcommand using manual approach (complex UI logic)
designCmd := man.Docs.GetCommand("dev/design-system",
man.WithRun(dev_designSystem),
)
devCmd.AddCommand(&designCmd.Command)
RootCmd.AddCommand(&devCmd.Command)

// Add selectors subcommand (from dev-selectors.go)
devCmd.AddCommand(DevSelectorsCmd)

RootCmd.AddCommand(devCmd)
}
109 changes: 109 additions & 0 deletions cmd/generated/_index_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading