diff --git a/Makefile b/Makefile index 088ce90..eaa4b42 100644 --- a/Makefile +++ b/Makefile @@ -18,12 +18,12 @@ test-coverage: # Build the CLI build: - go build -o bin/edge-connect . + go build -o bin/edge-connect-cli ./cmd/cli # Clean generated files and build artifacts clean: rm -f sdk/client/types_generated.go - rm -f bin/edge-connect + rm -f bin/edge-connect-cli rm -f coverage.out coverage.html # Lint the code diff --git a/cmd/cli/main.go b/cmd/cli/main.go new file mode 100644 index 0000000..1ebdbf0 --- /dev/null +++ b/cmd/cli/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "os" + + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/driving/cli" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/driven/edgeconnect" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/services" +) + +func main() { + // Präsentationsschicht: Simple dependency wiring - no complex container needed + + // 1. Infrastructure Layer: Create EdgeConnect client (concrete implementation) + baseURL := getEnvOrDefault("EDGE_CONNECT_BASE_URL", "https://console.mobiledgex.net") + username := os.Getenv("EDGE_CONNECT_USERNAME") + password := os.Getenv("EDGE_CONNECT_PASSWORD") + + var client *edgeconnect.Client + if username != "" && password != "" { + client = edgeconnect.NewClientWithCredentials(baseURL, username, password) + } else { + client = edgeconnect.NewClient(baseURL) + } + + // 2. Application Layer: Create services with dependency injection (client implements repository interfaces) + appService := services.NewAppService(client) // client implements AppRepository + instanceService := services.NewAppInstanceService(client) // client implements AppInstanceRepository + cloudletService := services.NewCloudletService(client) // client implements CloudletRepository + + // 3. Presentation Layer: Execute CLI driven adapters with injected services (simple parameter passing) + cli.ExecuteWithServices(appService, instanceService, cloudletService) +} + +func getEnvOrDefault(key, defaultValue string) string { + if value := os.Getenv(key); value != "" { + return value + } + return defaultValue +} diff --git a/edge-connect-cli b/edge-connect-cli new file mode 100755 index 0000000..84f10a8 Binary files /dev/null and b/edge-connect-cli differ diff --git a/hexagonal-architecture-proposal.md b/hexagonal-architecture-proposal.md index b190b2d..84e0dab 100644 --- a/hexagonal-architecture-proposal.md +++ b/hexagonal-architecture-proposal.md @@ -52,12 +52,12 @@ Here is the proposed directory structure: ### Adapters -* `internal/adapters/cli`: The CLI adapter. It implements the user interface and calls the `driving` ports of the core. -* `internal/adapters/edgeconnect`: The EdgeXR API adapter. It implements the `driven` port interfaces and communicates with the EdgeXR API. +* `internal/adapters/driving/cli`: The CLI adapter. It implements the user interface and calls the `driving` ports of the core. +* `internal/adapters/driven/edgeconnect`: The EdgeXR API adapter. It implements the `driven` port interfaces and communicates with the EdgeXR API. ### `cmd` -* `cmd/main.go`: The main entry point of the application. It is responsible for wiring everything together: creating the adapters, injecting them into the core services, and starting the CLI. +* `cmd/cli/main.go`: The main entry point of the CLI application. It is responsible for wiring everything together: creating the adapters, injecting them into the core services, and starting the CLI. ## Refactoring Steps @@ -65,9 +65,9 @@ Here is the proposed directory structure: 2. **Define ports:** Define the `driving` and `driven` port interfaces in `internal/core/ports`. 3. **Implement core services:** Implement the core business logic in `internal/core/services`. 4. **Create adapters:** - * Move the existing CLI code from `cmd` to `internal/adapters/cli` and adapt it to call the core services. - * Move the existing `sdk` code to `internal/adapters/edgeconnect` and adapt it to implement the repository interfaces. -5. **Wire everything together:** Update `cmd/main.go` to create the adapters and inject them into the core services. + * Move the existing CLI code from `cmd` to `internal/adapters/driving/cli` and adapt it to call the core services. + * Move the existing `sdk` code to `internal/adapters/driven/edgeconnect` and adapt it to implement the repository interfaces. +5. **Wire everything together:** Update `cmd/cli/main.go` to create the adapters and inject them into the core services. ## Benefits diff --git a/internal/adapters/edgeconnect/appinstance.go b/internal/adapters/driven/edgeconnect/appinstance.go similarity index 100% rename from internal/adapters/edgeconnect/appinstance.go rename to internal/adapters/driven/edgeconnect/appinstance.go diff --git a/internal/adapters/edgeconnect/appinstance_test.go b/internal/adapters/driven/edgeconnect/appinstance_test.go similarity index 100% rename from internal/adapters/edgeconnect/appinstance_test.go rename to internal/adapters/driven/edgeconnect/appinstance_test.go diff --git a/internal/adapters/edgeconnect/apps.go b/internal/adapters/driven/edgeconnect/apps.go similarity index 100% rename from internal/adapters/edgeconnect/apps.go rename to internal/adapters/driven/edgeconnect/apps.go diff --git a/internal/adapters/edgeconnect/apps_test.go b/internal/adapters/driven/edgeconnect/apps_test.go similarity index 100% rename from internal/adapters/edgeconnect/apps_test.go rename to internal/adapters/driven/edgeconnect/apps_test.go diff --git a/internal/adapters/edgeconnect/auth.go b/internal/adapters/driven/edgeconnect/auth.go similarity index 100% rename from internal/adapters/edgeconnect/auth.go rename to internal/adapters/driven/edgeconnect/auth.go diff --git a/internal/adapters/edgeconnect/auth_test.go b/internal/adapters/driven/edgeconnect/auth_test.go similarity index 100% rename from internal/adapters/edgeconnect/auth_test.go rename to internal/adapters/driven/edgeconnect/auth_test.go diff --git a/internal/adapters/edgeconnect/client.go b/internal/adapters/driven/edgeconnect/client.go similarity index 100% rename from internal/adapters/edgeconnect/client.go rename to internal/adapters/driven/edgeconnect/client.go diff --git a/internal/adapters/edgeconnect/cloudlet.go b/internal/adapters/driven/edgeconnect/cloudlet.go similarity index 100% rename from internal/adapters/edgeconnect/cloudlet.go rename to internal/adapters/driven/edgeconnect/cloudlet.go diff --git a/internal/adapters/edgeconnect/cloudlet_test.go b/internal/adapters/driven/edgeconnect/cloudlet_test.go similarity index 100% rename from internal/adapters/edgeconnect/cloudlet_test.go rename to internal/adapters/driven/edgeconnect/cloudlet_test.go diff --git a/internal/adapters/edgeconnect/types.go b/internal/adapters/driven/edgeconnect/types.go similarity index 100% rename from internal/adapters/edgeconnect/types.go rename to internal/adapters/driven/edgeconnect/types.go diff --git a/internal/adapters/cli/app.go b/internal/adapters/driving/cli/app.go similarity index 92% rename from internal/adapters/cli/app.go rename to internal/adapters/driving/cli/app.go index 37758d3..b407b96 100644 --- a/internal/adapters/cli/app.go +++ b/internal/adapters/driving/cli/app.go @@ -66,7 +66,7 @@ var createAppCmd = &cobra.Command{ }, } - err := appService.CreateApp(context.Background(), region, app) + err := services.AppService.CreateApp(context.Background(), region, app) if err != nil { fmt.Printf("Error creating app: %v\n", err) os.Exit(1) @@ -85,7 +85,7 @@ var showAppCmd = &cobra.Command{ Version: appVersion, } - app, err := appService.ShowApp(context.Background(), region, appKey) + app, err := services.AppService.ShowApp(context.Background(), region, appKey) if err != nil { // Handle domain-specific errors with appropriate user feedback if domain.IsNotFoundError(err) { @@ -114,7 +114,7 @@ var listAppsCmd = &cobra.Command{ Version: appVersion, } - apps, err := appService.ShowApps(context.Background(), region, appKey) + apps, err := services.AppService.ShowApps(context.Background(), region, appKey) if err != nil { fmt.Printf("Error listing apps: %v\n", err) os.Exit(1) @@ -136,7 +136,7 @@ var deleteAppCmd = &cobra.Command{ Version: appVersion, } - err := appService.DeleteApp(context.Background(), region, appKey) + err := services.AppService.DeleteApp(context.Background(), region, appKey) if err != nil { fmt.Printf("Error deleting app: %v\n", err) os.Exit(1) diff --git a/internal/adapters/cli/app_test.go b/internal/adapters/driving/cli/app_test.go similarity index 100% rename from internal/adapters/cli/app_test.go rename to internal/adapters/driving/cli/app_test.go diff --git a/internal/adapters/cli/apply.go b/internal/adapters/driving/cli/apply.go similarity index 99% rename from internal/adapters/cli/apply.go rename to internal/adapters/driving/cli/apply.go index 5f18cea..a4be4a2 100644 --- a/internal/adapters/cli/apply.go +++ b/internal/adapters/driving/cli/apply.go @@ -12,7 +12,7 @@ import ( "strings" "time" - "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/edgeconnect" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/driven/edgeconnect" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/apply" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/config" "github.com/spf13/cobra" diff --git a/internal/adapters/cli/instance.go b/internal/adapters/driving/cli/instance.go similarity index 91% rename from internal/adapters/cli/instance.go rename to internal/adapters/driving/cli/instance.go index 7237bf9..b77e12d 100644 --- a/internal/adapters/cli/instance.go +++ b/internal/adapters/driving/cli/instance.go @@ -45,7 +45,7 @@ var createInstanceCmd = &cobra.Command{ }, } - err := instanceService.CreateAppInstance(context.Background(), region, appInst) + err := services.InstanceService.CreateAppInstance(context.Background(), region, appInst) if err != nil { fmt.Printf("Error creating app instance: %v\n", err) os.Exit(1) @@ -67,7 +67,7 @@ var showInstanceCmd = &cobra.Command{ }, } - instance, err := instanceService.ShowAppInstance(context.Background(), region, instanceKey) + instance, err := services.InstanceService.ShowAppInstance(context.Background(), region, instanceKey) if err != nil { fmt.Printf("Error showing app instance: %v\n", err) os.Exit(1) @@ -89,7 +89,7 @@ var listInstancesCmd = &cobra.Command{ }, } - instances, err := instanceService.ShowAppInstances(context.Background(), region, instanceKey) + instances, err := services.InstanceService.ShowAppInstances(context.Background(), region, instanceKey) if err != nil { fmt.Printf("Error listing app instances: %v\n", err) os.Exit(1) @@ -114,7 +114,7 @@ var deleteInstanceCmd = &cobra.Command{ }, } - err := instanceService.DeleteAppInstance(context.Background(), region, instanceKey) + err := services.InstanceService.DeleteAppInstance(context.Background(), region, instanceKey) if err != nil { fmt.Printf("Error deleting app instance: %v\n", err) os.Exit(1) diff --git a/internal/adapters/cli/root.go b/internal/adapters/driving/cli/root.go similarity index 73% rename from internal/adapters/cli/root.go rename to internal/adapters/driving/cli/root.go index 09f3728..12324e6 100644 --- a/internal/adapters/cli/root.go +++ b/internal/adapters/driving/cli/root.go @@ -15,24 +15,15 @@ var ( username string password string - appService driving.AppService - instanceService driving.AppInstanceService - cloudletService driving.CloudletService + // Services injected via constructor - no global state + services *ServiceContainer ) -// SetAppService injects the application service -func SetAppService(service driving.AppService) { - appService = service -} - -// SetInstanceService injects the instance service -func SetInstanceService(service driving.AppInstanceService) { - instanceService = service -} - -// SetCloudletService injects the cloudlet service -func SetCloudletService(service driving.CloudletService) { - cloudletService = service +// ServiceContainer holds injected services (simple struct - no complex container) +type ServiceContainer struct { + AppService driving.AppService + InstanceService driving.AppInstanceService + CloudletService driving.CloudletService } // rootCmd represents the base command when called without any subcommands @@ -52,6 +43,18 @@ func Execute() { } } +// ExecuteWithServices executes CLI with dependency-injected services (simple parameter passing) +func ExecuteWithServices(appSvc driving.AppService, instanceSvc driving.AppInstanceService, cloudletSvc driving.CloudletService) { + // Simple dependency injection - just store services in container + services = &ServiceContainer{ + AppService: appSvc, + InstanceService: instanceSvc, + CloudletService: cloudletSvc, + } + + Execute() +} + func init() { cobra.OnInitialize(initConfig) diff --git a/internal/core/apply/manager_test.go b/internal/core/apply/manager_test.go index a1f7b9a..4d0d7a5 100644 --- a/internal/core/apply/manager_test.go +++ b/internal/core/apply/manager_test.go @@ -12,7 +12,7 @@ import ( "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/config" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain" - "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/edgeconnect" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/driven/edgeconnect" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" diff --git a/main.go b/main.go deleted file mode 100644 index 14cfd1b..0000000 --- a/main.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/cli" - -func main() { - cli.Execute() -} diff --git a/sdk/examples/comprehensive/main.go b/sdk/examples/comprehensive/main.go index 23ee8a4..8dfe1c9 100644 --- a/sdk/examples/comprehensive/main.go +++ b/sdk/examples/comprehensive/main.go @@ -12,7 +12,7 @@ import ( "strings" "time" - "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/edgeconnect" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/driven/edgeconnect" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain" ) diff --git a/sdk/examples/deploy_app.go b/sdk/examples/deploy_app.go index e539ca8..ccb2c24 100644 --- a/sdk/examples/deploy_app.go +++ b/sdk/examples/deploy_app.go @@ -11,7 +11,7 @@ import ( "os" "time" - "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/edgeconnect" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/driven/edgeconnect" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain" )