From 06f921963a0af4c6030ef032eeaf7f72a923bcba Mon Sep 17 00:00:00 2001 From: Patrick Sy Date: Tue, 7 Oct 2025 16:01:38 +0200 Subject: [PATCH] refactor(yaml): moved AppVersion into metadata --- internal/apply/manager_test.go | 4 +- internal/apply/planner.go | 7 +-- internal/apply/planner_test.go | 4 +- internal/apply/strategy_recreate.go | 2 +- internal/config/example_test.go | 5 +- internal/config/parser_test.go | 54 ++++++++++++------- internal/config/types.go | 43 ++++----------- .../comprehensive/EdgeConnectConfig.yaml | 2 +- 8 files changed, 57 insertions(+), 64 deletions(-) diff --git a/internal/apply/manager_test.go b/internal/apply/manager_test.go index 17fd027..539e7e0 100644 --- a/internal/apply/manager_test.go +++ b/internal/apply/manager_test.go @@ -137,11 +137,11 @@ func createTestManagerConfig(t *testing.T) *config.EdgeConnectConfig { return &config.EdgeConnectConfig{ Kind: "edgeconnect-deployment", Metadata: config.Metadata{ - Name: "test-app", + Name: "test-app", + AppVersion: "1.0.0", }, Spec: config.Spec{ K8sApp: &config.K8sApp{ - AppVersion: "1.0.0", ManifestFile: manifestFile, }, InfraTemplate: []config.InfraTemplate{ diff --git a/internal/apply/planner.go b/internal/apply/planner.go index 4e2a3e0..c0a9f70 100644 --- a/internal/apply/planner.go +++ b/internal/apply/planner.go @@ -134,7 +134,7 @@ func (p *EdgeConnectPlanner) planAppAction(ctx context.Context, config *config.E // Build desired app state desired := &AppState{ Name: config.Metadata.Name, - Version: config.Spec.GetAppVersion(), + Version: config.Metadata.AppVersion, Organization: config.Spec.InfraTemplate[0].Organization, // Use first infra template for org Region: config.Spec.InfraTemplate[0].Region, // Use first infra template for region Exists: false, // Will be set based on current state @@ -204,6 +204,7 @@ func (p *EdgeConnectPlanner) planAppAction(ctx context.Context, config *config.E action.Type = ActionUpdate action.Changes = changes action.Reason = "Application configuration has changed" + fmt.Printf("Changes: %v\n", changes) if manifestChanged { warnings = append(warnings, "Manifest file has changed - instances may need to be recreated") @@ -219,11 +220,11 @@ func (p *EdgeConnectPlanner) planInstanceActions(ctx context.Context, config *co var warnings []string for _, infra := range config.Spec.InfraTemplate { - instanceName := getInstanceName(config.Metadata.Name, config.Spec.GetAppVersion()) + instanceName := getInstanceName(config.Metadata.Name, config.Metadata.AppVersion) desired := &InstanceState{ Name: instanceName, - AppVersion: config.Spec.GetAppVersion(), + AppVersion: config.Metadata.AppVersion, Organization: infra.Organization, Region: infra.Region, CloudletOrg: infra.CloudletOrg, diff --git a/internal/apply/planner_test.go b/internal/apply/planner_test.go index 358ae41..5568dea 100644 --- a/internal/apply/planner_test.go +++ b/internal/apply/planner_test.go @@ -112,11 +112,11 @@ func createTestConfig(t *testing.T) *config.EdgeConnectConfig { return &config.EdgeConnectConfig{ Kind: "edgeconnect-deployment", Metadata: config.Metadata{ - Name: "test-app", + Name: "test-app", + AppVersion: "1.0.0", }, Spec: config.Spec{ K8sApp: &config.K8sApp{ - AppVersion: "1.0.0", ManifestFile: manifestFile, }, InfraTemplate: []config.InfraTemplate{ diff --git a/internal/apply/strategy_recreate.go b/internal/apply/strategy_recreate.go index da88664..3ac1502 100644 --- a/internal/apply/strategy_recreate.go +++ b/internal/apply/strategy_recreate.go @@ -440,7 +440,7 @@ func (r *RecreateStrategy) createInstance(ctx context.Context, action InstanceAc AppKey: edgeconnect.AppKey{ Organization: action.Target.Organization, Name: config.Metadata.Name, - Version: config.Spec.GetAppVersion(), + Version: config.Metadata.AppVersion, }, Flavor: edgeconnect.Flavor{ Name: action.Target.FlavorName, diff --git a/internal/config/example_test.go b/internal/config/example_test.go index 7219412..7316430 100644 --- a/internal/config/example_test.go +++ b/internal/config/example_test.go @@ -28,7 +28,7 @@ func TestParseExampleConfig(t *testing.T) { // Check k8s app configuration require.NotNil(t, config.Spec.K8sApp) - assert.Equal(t, "1.0.0", config.Spec.K8sApp.AppVersion) + assert.Equal(t, "1.0.0", config.Metadata.AppVersion) // Note: ManifestFile path should be resolved to absolute path assert.Contains(t, config.Spec.K8sApp.ManifestFile, "k8s-deployment.yaml") @@ -59,7 +59,6 @@ func TestParseExampleConfig(t *testing.T) { // Test utility methods assert.Equal(t, "edge-app-demo", config.Metadata.Name) - assert.Equal(t, "1.0.0", config.Spec.GetAppVersion()) assert.Contains(t, config.Spec.GetManifestFile(), "k8s-deployment.yaml") assert.True(t, config.Spec.IsK8sApp()) assert.False(t, config.Spec.IsDockerApp()) @@ -73,10 +72,10 @@ func TestValidateExampleStructure(t *testing.T) { Kind: "edgeconnect-deployment", Metadata: Metadata{ Name: "edge-app-demo", + AppVersion: "1.0.0", }, Spec: Spec{ DockerApp: &DockerApp{ // Use DockerApp to avoid manifest file validation - AppVersion: "1.0.0", Image: "nginx:latest", }, InfraTemplate: []InfraTemplate{ diff --git a/internal/config/parser_test.go b/internal/config/parser_test.go index d5e0865..c713ff5 100644 --- a/internal/config/parser_test.go +++ b/internal/config/parser_test.go @@ -32,9 +32,9 @@ func TestConfigParser_ParseBytes(t *testing.T) { kind: edgeconnect-deployment metadata: name: "test-app" + appVersion: "1.0.0" spec: k8sApp: - appVersion: "1.0.0" manifestFile: "./test-manifest.yaml" infraTemplate: - organization: "testorg" @@ -52,9 +52,9 @@ spec: kind: edgeconnect-deployment metadata: name: "test-app" + appVersion: "1.0.0" spec: dockerApp: - appVersion: "1.0.0" image: "nginx:latest" infraTemplate: - organization: "testorg" @@ -70,9 +70,9 @@ spec: yaml: ` metadata: name: "test-app" + appVersion: "1.0.0" spec: k8sApp: - appVersion: "1.0.0" manifestFile: "./test-manifest.yaml" infraTemplate: - organization: "testorg" @@ -90,9 +90,9 @@ spec: kind: invalid-kind metadata: name: "test-app" + appVersion: "1.0.0" spec: dockerApp: - appVersion: "1.0.0" image: "nginx:latest" infraTemplate: - organization: "testorg" @@ -110,6 +110,7 @@ spec: kind: edgeconnect-deployment metadata: name: "test-app" + appVersion: "1.0.0" spec: infraTemplate: - organization: "testorg" @@ -127,13 +128,12 @@ spec: kind: edgeconnect-deployment metadata: name: "test-app" + appVersion: "1.0.0" spec: k8sApp: - appVersion: "1.0.0" manifestFile: "./test-manifest.yaml" dockerApp: appName: "test-app" - appVersion: "1.0.0" image: "nginx:latest" infraTemplate: - organization: "testorg" @@ -151,9 +151,9 @@ spec: kind: edgeconnect-deployment metadata: name: "test-app" + appVersion: "1.0.0" spec: dockerApp: - appVersion: "1.0.0" image: "nginx:latest" infraTemplate: [] `, @@ -166,9 +166,9 @@ spec: kind: edgeconnect-deployment metadata: name: "test-app" + appVersion: "1.0.0" spec: dockerApp: - appVersion: "1.0.0" image: "nginx:latest" infraTemplate: - organization: "testorg" @@ -222,9 +222,9 @@ func TestConfigParser_ParseFile(t *testing.T) { kind: edgeconnect-deployment metadata: name: "test-app" + appVersion: "1.0.0" spec: dockerApp: - appVersion: "1.0.0" image: "nginx:latest" infraTemplate: - organization: "testorg" @@ -284,9 +284,9 @@ func TestConfigParser_RelativePathResolution(t *testing.T) { kind: edgeconnect-deployment metadata: name: "test-app" + appVersion: "1.0.0" spec: k8sApp: - appVersion: "1.0.0" manifestFile: "./manifest.yaml" infraTemplate: - organization: "testorg" @@ -322,10 +322,10 @@ func TestEdgeConnectConfig_Validate(t *testing.T) { Kind: "edgeconnect-deployment", Metadata: Metadata{ Name: "test-app", + AppVersion: "1.0.0", }, Spec: Spec{ DockerApp: &DockerApp{ - AppVersion: "1.0.0", Image: "nginx:latest", }, InfraTemplate: []InfraTemplate{ @@ -385,24 +385,42 @@ func TestMetadata_Validate(t *testing.T) { }{ { name: "valid metadata", - metadata: Metadata{Name: "test-app"}, + metadata: Metadata{Name: "test-app", AppVersion: "1.0.0"}, wantErr: false, }, { name: "empty name", - metadata: Metadata{Name: ""}, + metadata: Metadata{Name: "", AppVersion: "1.0.0"}, wantErr: true, errMsg: "metadata.name is required", }, { name: "name with leading whitespace", - metadata: Metadata{Name: " test-app"}, + metadata: Metadata{Name: " test-app", AppVersion: "1.0.0"}, wantErr: true, errMsg: "cannot have leading/trailing whitespace", }, { name: "name with trailing whitespace", - metadata: Metadata{Name: "test-app "}, + metadata: Metadata{Name: "test-app ", AppVersion: "1.0.0"}, + wantErr: true, + errMsg: "cannot have leading/trailing whitespace", + }, + { + name: "empty app version", + metadata: Metadata{Name: "test-app", AppVersion: ""}, + wantErr: true, + errMsg: "metadata.appVersion is required", + }, + { + name: "app version with leading whitespace", + metadata: Metadata{Name: "test-app", AppVersion: " 1.0.0"}, + wantErr: true, + errMsg: "cannot have leading/trailing whitespace", + }, + { + name: "app version with trailing whitespace", + metadata: Metadata{Name: "test-app", AppVersion: "1.0.0 "}, wantErr: true, errMsg: "cannot have leading/trailing whitespace", }, @@ -526,24 +544,20 @@ func TestOutboundConnection_Validate(t *testing.T) { func TestSpec_GetMethods(t *testing.T) { k8sSpec := &Spec{ K8sApp: &K8sApp{ - AppVersion: "1.0.0", ManifestFile: "k8s.yaml", }, } dockerSpec := &Spec{ DockerApp: &DockerApp{ - AppVersion: "2.0.0", ManifestFile: "docker.yaml", }, } - assert.Equal(t, "1.0.0", k8sSpec.GetAppVersion()) assert.Equal(t, "k8s.yaml", k8sSpec.GetManifestFile()) assert.True(t, k8sSpec.IsK8sApp()) assert.False(t, k8sSpec.IsDockerApp()) - assert.Equal(t, "2.0.0", dockerSpec.GetAppVersion()) assert.Equal(t, "docker.yaml", dockerSpec.GetManifestFile()) assert.False(t, dockerSpec.IsK8sApp()) assert.True(t, dockerSpec.IsDockerApp()) @@ -564,9 +578,9 @@ func TestReadManifestFile(t *testing.T) { kind: edgeconnect-deployment metadata: name: "test-app" + appVersion: "1.0.0" spec: k8sApp: - appVersion: "1.0.0" manifestFile: "./manifest.yaml" infraTemplate: - organization: "testorg" diff --git a/internal/config/types.go b/internal/config/types.go index 71388d0..88b52b7 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -18,7 +18,8 @@ type EdgeConnectConfig struct { // Metadata contains configuration metadata type Metadata struct { - Name string `yaml:"name"` + Name string `yaml:"name"` + AppVersion string `yaml:"appVersion"` } // Spec defines the application and infrastructure specification @@ -32,13 +33,11 @@ type Spec struct { // K8sApp defines Kubernetes application configuration type K8sApp struct { - AppVersion string `yaml:"appVersion"` ManifestFile string `yaml:"manifestFile"` } // DockerApp defines Docker application configuration type DockerApp struct { - AppVersion string `yaml:"appVersion"` ManifestFile string `yaml:"manifestFile"` Image string `yaml:"image"` } @@ -113,6 +112,15 @@ func (m *Metadata) Validate() error { return fmt.Errorf("metadata.name cannot have leading/trailing whitespace") } + if m.AppVersion == "" { + return fmt.Errorf("metadata.appVersion is required") + } + + // Validate version format + if strings.TrimSpace(m.AppVersion) != m.AppVersion { + return fmt.Errorf("metadata.appVersion cannot have leading/trailing whitespace") + } + return nil } @@ -171,10 +179,6 @@ func (s *Spec) Validate() error { // Validate validates k8s app configuration func (k *K8sApp) Validate() error { - if k.AppVersion == "" { - return fmt.Errorf("appVersion is required") - } - if k.ManifestFile == "" { return fmt.Errorf("manifestFile is required") } @@ -184,29 +188,15 @@ func (k *K8sApp) Validate() error { return fmt.Errorf("manifestFile does not exist: %s", k.ManifestFile) } - // Validate version format - if strings.TrimSpace(k.AppVersion) != k.AppVersion { - return fmt.Errorf("appVersion cannot have leading/trailing whitespace") - } - return nil } // Validate validates docker app configuration func (d *DockerApp) Validate() error { - if d.AppVersion == "" { - return fmt.Errorf("appVersion is required") - } - if d.Image == "" { return fmt.Errorf("image is required") } - // Validate version format - if strings.TrimSpace(d.AppVersion) != d.AppVersion { - return fmt.Errorf("appVersion cannot have leading/trailing whitespace") - } - // Check if manifest file exists if specified if d.ManifestFile != "" { if _, err := os.Stat(d.ManifestFile); os.IsNotExist(err) { @@ -326,17 +316,6 @@ func (d *DockerApp) GetManifestPath(configDir string) string { return filepath.Join(configDir, d.ManifestFile) } -// GetAppVersion returns the application version from the active app type -func (s *Spec) GetAppVersion() string { - if s.K8sApp != nil { - return s.K8sApp.AppVersion - } - if s.DockerApp != nil { - return s.DockerApp.AppVersion - } - return "" -} - // GetManifestFile returns the manifest file path from the active app type func (s *Spec) GetManifestFile() string { if s.K8sApp != nil { diff --git a/sdk/examples/comprehensive/EdgeConnectConfig.yaml b/sdk/examples/comprehensive/EdgeConnectConfig.yaml index 842494a..1430b33 100644 --- a/sdk/examples/comprehensive/EdgeConnectConfig.yaml +++ b/sdk/examples/comprehensive/EdgeConnectConfig.yaml @@ -3,13 +3,13 @@ kind: edgeconnect-deployment metadata: name: "edge-app-demo" # name could be used for appName + appVersion: "1.0.0" spec: # dockerApp: # Docker is OBSOLETE # appVersion: "1.0.0" # manifestFile: "./docker-compose.yaml" # image: "https://registry-1.docker.io/library/nginx:latest" k8sApp: - appVersion: "1.0.0" manifestFile: "./k8s-deployment.yaml" infraTemplate: - organization: "edp2"