Skip to content
Draft
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
28 changes: 28 additions & 0 deletions cmd/adapter/dev.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

import (
"github.com/spf13/cobra"
)

// devCmd is the parent command for development tools
var devCmd = &cobra.Command{
Use: "dev",
Short: "Development tools for adapter testing and debugging",
Long: `Development tools for testing and debugging adapters locally.

These commands help adapter developers:
- Validate configuration files offline
- Test event processing without a message broker
- Preview what would happen without connecting to Kubernetes

Examples:
# Validate an adapter configuration
adapter dev validate --config ./adapter-config.yaml

# Dry-run an event through the adapter
adapter dev run --config ./adapter-config.yaml --event ./test-event.json`,
}

func init() {
// Subcommands are added in their respective files
}
137 changes: 137 additions & 0 deletions cmd/adapter/dev_run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package main

import (
"context"
"fmt"
"os"

"github.com/openshift-hyperfleet/hyperfleet-adapter/internal/dev"
"github.com/spf13/cobra"
)

var (
runConfigPath string
runEventPath string
runMockAPIResponses string
runEnvFile string
runVerbose bool
runOutput string
runShowManifests bool
runShowPayloads bool
runShowParams bool
)

var runCmd = &cobra.Command{
Use: "run",
Short: "Dry-run an event through the adapter",
Long: `Process an event through the adapter in dry-run mode.

This command executes the full adapter pipeline without:
- Connecting to a real message broker
- Making actual Kubernetes API calls
- Making actual HyperFleet API calls

It shows what WOULD happen if the event were processed.

Examples:
# Basic dry-run
adapter dev run --config ./adapter-config.yaml --event ./test-event.json

# With mock API responses
adapter dev run --config ./adapter-config.yaml --event ./test-event.json \
--mock-api-responses ./mock-responses.yaml

# Show rendered manifests
adapter dev run --config ./adapter-config.yaml --event ./test-event.json \
--show-manifests --verbose

# Load environment from .env file
adapter dev run --config ./adapter-config.yaml --event ./test-event.json \
--env-file .env.local`,
RunE: runDryRun,
}

func init() {
runCmd.Flags().StringVarP(&runConfigPath, "config", "c", "",
"Path to adapter configuration file (required)")
runCmd.Flags().StringVarP(&runEventPath, "event", "e", "",
"Path to event file in JSON or YAML format (required)")
runCmd.Flags().StringVar(&runMockAPIResponses, "mock-api-responses", "",
"Path to YAML file with mock API responses")
runCmd.Flags().StringVar(&runEnvFile, "env-file", "",
"Path to .env file for environment variables")
runCmd.Flags().BoolVarP(&runVerbose, "verbose", "v", false,
"Show detailed execution trace")
runCmd.Flags().StringVarP(&runOutput, "output", "o", "text",
"Output format: text or json")
runCmd.Flags().BoolVar(&runShowManifests, "show-manifests", false,
"Display rendered Kubernetes manifests")
runCmd.Flags().BoolVar(&runShowPayloads, "show-payloads", false,
"Display built payloads")
runCmd.Flags().BoolVar(&runShowParams, "show-params", false,
"Display extracted parameters")

_ = runCmd.MarkFlagRequired("config")
_ = runCmd.MarkFlagRequired("event")

devCmd.AddCommand(runCmd)
}

func runDryRun(cmd *cobra.Command, args []string) error {
// Load environment variables from .env file if provided
if runEnvFile != "" {
envVars, err := dev.LoadEnvFile(runEnvFile)
if err != nil {
return fmt.Errorf("failed to load env file: %w", err)
}
if err := dev.ApplyEnvVars(envVars); err != nil {
return fmt.Errorf("failed to apply env vars: %w", err)
}
}

// Load the event
eventSource := dev.NewFileEventSource(runEventPath)
eventData, err := eventSource.LoadEvent()
if err != nil {
return fmt.Errorf("failed to load event: %w", err)
}

// Configure run options
opts := &dev.RunOptions{
MockAPIResponsesPath: runMockAPIResponses,
ShowManifests: runShowManifests,
ShowPayloads: runShowPayloads,
ShowParams: runShowParams,
EnvFilePath: runEnvFile,
}

// Execute with trace
ctx := context.Background()
result, err := dev.ExecuteWithTrace(ctx, runConfigPath, eventData, opts)
if err != nil {
return fmt.Errorf("execution failed: %w", err)
}

// Determine output format
format := dev.OutputFormatText
if runOutput == "json" {
format = dev.OutputFormatJSON
}

// Enable verbose if show flags are set
verbose := runVerbose || runShowManifests || runShowPayloads || runShowParams

writer := dev.NewOutputWriter(os.Stdout, format, verbose)

// Write the results
if err := writer.WriteTraceResult(result); err != nil {
return fmt.Errorf("failed to write results: %w", err)
}

// Exit with error code if execution failed
if !result.Success {
os.Exit(1)
}

return nil
}
106 changes: 106 additions & 0 deletions cmd/adapter/dev_validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package main

import (
"fmt"
"os"

"github.com/openshift-hyperfleet/hyperfleet-adapter/internal/dev"
"github.com/spf13/cobra"
)

var (
validateConfigPath string
validateVerbose bool
validateOutput string
validateStrict bool
validateEnvFile string
)

var validateCmd = &cobra.Command{
Use: "validate",
Short: "Validate adapter configuration file",
Long: `Validate an adapter configuration file offline.

This command checks:
- YAML syntax and schema structure
- Parameter definitions and references
- CEL expression syntax
- Go template variable references
- Kubernetes manifest structure

Examples:
# Basic validation
adapter dev validate --config ./adapter-config.yaml

# Verbose output with details
adapter dev validate --config ./adapter-config.yaml --verbose

# JSON output for CI pipelines
adapter dev validate --config ./adapter-config.yaml --output json

# Strict mode (treat warnings as errors)
adapter dev validate --config ./adapter-config.yaml --strict

# With environment variables from .env file
adapter dev validate --config ./adapter-config.yaml --env-file .env.local`,
RunE: runValidate,
}

func init() {
validateCmd.Flags().StringVarP(&validateConfigPath, "config", "c", "",
"Path to adapter configuration file (required)")
validateCmd.Flags().BoolVarP(&validateVerbose, "verbose", "v", false,
"Show detailed validation results")
validateCmd.Flags().StringVarP(&validateOutput, "output", "o", "text",
"Output format: text or json")
validateCmd.Flags().BoolVar(&validateStrict, "strict", false,
"Treat warnings as errors")
validateCmd.Flags().StringVar(&validateEnvFile, "env-file", "",
"Path to .env file for required environment variables")

_ = validateCmd.MarkFlagRequired("config")

devCmd.AddCommand(validateCmd)
}

func runValidate(cmd *cobra.Command, args []string) error {
// Load environment variables from .env file if provided
if validateEnvFile != "" {
envVars, err := dev.LoadEnvFile(validateEnvFile)
if err != nil {
return fmt.Errorf("failed to load env file: %w", err)
}
if err := dev.ApplyEnvVars(envVars); err != nil {
return fmt.Errorf("failed to apply env vars: %w", err)
}
}

// Determine output format
format := dev.OutputFormatText
if validateOutput == "json" {
format = dev.OutputFormatJSON
}

writer := dev.NewOutputWriter(os.Stdout, format, validateVerbose)

// Validate the configuration
result, err := dev.ValidateConfigWithOpts(validateConfigPath, dev.ValidateOptions{
Strict: validateStrict,
Verbose: validateVerbose,
})
if err != nil {
return fmt.Errorf("validation error: %w", err)
}

// Write the results
if err := writer.WriteValidationResult(result); err != nil {
return fmt.Errorf("failed to write results: %w", err)
}

// Exit with error code if validation failed
if !result.Valid {
os.Exit(1)
}

return nil
}
1 change: 1 addition & 0 deletions cmd/adapter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ and HyperFleet API calls.`,
// Add subcommands
rootCmd.AddCommand(serveCmd)
rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(devCmd)

// Execute
if err := rootCmd.Execute(); err != nil {
Expand Down
Loading