From cec98a6586c9470846bb0e5ce54b4053f15cc980 Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sun, 22 Dec 2024 09:41:10 +0000 Subject: [PATCH 01/12] normalize windows path --- pkg/utils/glob_utils.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pkg/utils/glob_utils.go b/pkg/utils/glob_utils.go index 268473c53..1662fdac3 100644 --- a/pkg/utils/glob_utils.go +++ b/pkg/utils/glob_utils.go @@ -22,6 +22,9 @@ func GetGlobMatches(pattern string) ([]string, error) { return strings.Split(existingMatches.(string), ","), nil } + // Normalize the pattern to use forward slashes + pattern = filepath.ToSlash(pattern) + base, cleanPattern := doublestar.SplitPattern(pattern) f := os.DirFS(base) @@ -36,7 +39,9 @@ func GetGlobMatches(pattern string) ([]string, error) { var fullMatches []string for _, match := range matches { - fullMatches = append(fullMatches, filepath.Join(base, match)) + // Convert back to system-specific path separator + fullMatch := filepath.FromSlash(filepath.Join(base, match)) + fullMatches = append(fullMatches, fullMatch) } getGlobMatchesSyncMap.Store(pattern, strings.Join(fullMatches, ",")) @@ -54,5 +59,8 @@ func GetGlobMatches(pattern string) ([]string, error) { // separator. If you can't be sure of that, use filepath.ToSlash() on both // `pattern` and `name`, and then use the Match() function instead. func PathMatch(pattern, name string) (bool, error) { + // Normalize both pattern and name to use forward slashes + pattern = filepath.ToSlash(pattern) + name = filepath.ToSlash(name) return doublestar.PathMatch(pattern, name) } From 6dd99b1aa108a2695c13d461be7cc38bb146a88a Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sun, 22 Dec 2024 10:26:28 +0000 Subject: [PATCH 02/12] Refactor component processor tests and glob utility --- pkg/component/component_processor_test.go | 131 ++++++++++++++-------- pkg/utils/glob_utils.go | 11 +- 2 files changed, 90 insertions(+), 52 deletions(-) diff --git a/pkg/component/component_processor_test.go b/pkg/component/component_processor_test.go index bf23036a5..2600cf54c 100644 --- a/pkg/component/component_processor_test.go +++ b/pkg/component/component_processor_test.go @@ -2,6 +2,7 @@ package component import ( "testing" + "path/filepath" "github.com/stretchr/testify/assert" @@ -22,27 +23,33 @@ func TestComponentProcessor(t *testing.T) { assert.Nil(t, err) tenant1Ue2DevTestTestComponentBackend := tenant1Ue2DevTestTestComponent["backend"].(map[string]any) tenant1Ue2DevTestTestComponentRemoteStateBackend := tenant1Ue2DevTestTestComponent["remote_state_backend"].(map[string]any) - tenant1Ue2DevTestTestComponentBaseComponent := tenant1Ue2DevTestTestComponent["component"] tenant1Ue2DevTestTestComponentTerraformWorkspace := tenant1Ue2DevTestTestComponent["workspace"].(string) - tenant1Ue2DevTestTestComponentWorkspace := tenant1Ue2DevTestTestComponent["workspace"].(string) tenant1Ue2DevTestTestComponentBackendWorkspaceKeyPrefix := tenant1Ue2DevTestTestComponentBackend["workspace_key_prefix"].(string) tenant1Ue2DevTestTestComponentRemoteStateBackendWorkspaceKeyPrefix := tenant1Ue2DevTestTestComponentRemoteStateBackend["workspace_key_prefix"].(string) tenant1Ue2DevTestTestComponentDeps := tenant1Ue2DevTestTestComponent["deps"].([]any) assert.Equal(t, "test-test-component", tenant1Ue2DevTestTestComponentBackendWorkspaceKeyPrefix) assert.Equal(t, "test-test-component", tenant1Ue2DevTestTestComponentRemoteStateBackendWorkspaceKeyPrefix) - assert.Equal(t, "test/test-component", tenant1Ue2DevTestTestComponentBaseComponent) - assert.Equal(t, "tenant1-ue2-dev", tenant1Ue2DevTestTestComponentWorkspace) - assert.Equal(t, 9, len(tenant1Ue2DevTestTestComponentDeps)) - assert.Equal(t, "catalog/terraform/services/service-1", tenant1Ue2DevTestTestComponentDeps[0]) - assert.Equal(t, "catalog/terraform/services/service-2", tenant1Ue2DevTestTestComponentDeps[1]) - assert.Equal(t, "catalog/terraform/spacelift-and-backend-override-1", tenant1Ue2DevTestTestComponentDeps[2]) - assert.Equal(t, "catalog/terraform/test-component", tenant1Ue2DevTestTestComponentDeps[3]) - assert.Equal(t, "mixins/region/us-east-2", tenant1Ue2DevTestTestComponentDeps[4]) - assert.Equal(t, "mixins/stage/dev", tenant1Ue2DevTestTestComponentDeps[5]) - assert.Equal(t, "orgs/cp/_defaults", tenant1Ue2DevTestTestComponentDeps[6]) - assert.Equal(t, "orgs/cp/tenant1/_defaults", tenant1Ue2DevTestTestComponentDeps[7]) - assert.Equal(t, "orgs/cp/tenant1/dev/us-east-2", tenant1Ue2DevTestTestComponentDeps[8]) assert.Equal(t, "tenant1-ue2-dev", tenant1Ue2DevTestTestComponentTerraformWorkspace) + assert.Equal(t, 9, len(tenant1Ue2DevTestTestComponentDeps)) + + // Normalize expected paths for cross-platform compatibility + expectedPaths := []string{ + "catalog/terraform/services/service-1", + "catalog/terraform/services/service-2", + "catalog/terraform/spacelift-and-backend-override-1", + "catalog/terraform/test-component", + "mixins/region/us-east-2", + "mixins/stage/dev", + "orgs/cp/_defaults", + "orgs/cp/tenant1/_defaults", + "orgs/cp/tenant1/dev/us-east-2", + } + + // Convert actual paths to forward slashes for comparison + for i, dep := range tenant1Ue2DevTestTestComponentDeps { + actualPath := filepath.ToSlash(dep.(string)) + assert.Equal(t, expectedPaths[i], actualPath, "Path mismatch at index %d", i) + } var tenant1Ue2DevTestTestComponent2 map[string]any component = "test/test-component" @@ -53,27 +60,33 @@ func TestComponentProcessor(t *testing.T) { assert.Nil(t, err) tenant1Ue2DevTestTestComponentBackend2 := tenant1Ue2DevTestTestComponent2["backend"].(map[string]any) tenant1Ue2DevTestTestComponentRemoteStateBackend2 := tenant1Ue2DevTestTestComponent2["remote_state_backend"].(map[string]any) - tenant1Ue2DevTestTestComponentBaseComponent2 := tenant1Ue2DevTestTestComponent2["component"] tenant1Ue2DevTestTestComponentTerraformWorkspace2 := tenant1Ue2DevTestTestComponent2["workspace"].(string) - tenant1Ue2DevTestTestComponentWorkspace2 := tenant1Ue2DevTestTestComponent2["workspace"].(string) tenant1Ue2DevTestTestComponentBackendWorkspaceKeyPrefix2 := tenant1Ue2DevTestTestComponentBackend2["workspace_key_prefix"].(string) tenant1Ue2DevTestTestComponentRemoteStateBackendWorkspaceKeyPrefix2 := tenant1Ue2DevTestTestComponentRemoteStateBackend2["workspace_key_prefix"].(string) tenant1Ue2DevTestTestComponentDeps2 := tenant1Ue2DevTestTestComponent2["deps"].([]any) assert.Equal(t, "test-test-component", tenant1Ue2DevTestTestComponentBackendWorkspaceKeyPrefix2) assert.Equal(t, "test-test-component", tenant1Ue2DevTestTestComponentRemoteStateBackendWorkspaceKeyPrefix2) - assert.Equal(t, "test/test-component", tenant1Ue2DevTestTestComponentBaseComponent2) - assert.Equal(t, "tenant1-ue2-dev", tenant1Ue2DevTestTestComponentWorkspace2) - assert.Equal(t, 9, len(tenant1Ue2DevTestTestComponentDeps2)) - assert.Equal(t, "catalog/terraform/services/service-1", tenant1Ue2DevTestTestComponentDeps2[0]) - assert.Equal(t, "catalog/terraform/services/service-2", tenant1Ue2DevTestTestComponentDeps2[1]) - assert.Equal(t, "catalog/terraform/spacelift-and-backend-override-1", tenant1Ue2DevTestTestComponentDeps2[2]) - assert.Equal(t, "catalog/terraform/test-component", tenant1Ue2DevTestTestComponentDeps2[3]) - assert.Equal(t, "mixins/region/us-east-2", tenant1Ue2DevTestTestComponentDeps2[4]) - assert.Equal(t, "mixins/stage/dev", tenant1Ue2DevTestTestComponentDeps2[5]) - assert.Equal(t, "orgs/cp/_defaults", tenant1Ue2DevTestTestComponentDeps2[6]) - assert.Equal(t, "orgs/cp/tenant1/_defaults", tenant1Ue2DevTestTestComponentDeps2[7]) - assert.Equal(t, "orgs/cp/tenant1/dev/us-east-2", tenant1Ue2DevTestTestComponentDeps2[8]) assert.Equal(t, "tenant1-ue2-dev", tenant1Ue2DevTestTestComponentTerraformWorkspace2) + assert.Equal(t, 9, len(tenant1Ue2DevTestTestComponentDeps2)) + + // Normalize expected paths for cross-platform compatibility + expectedPaths = []string{ + "catalog/terraform/services/service-1", + "catalog/terraform/services/service-2", + "catalog/terraform/spacelift-and-backend-override-1", + "catalog/terraform/test-component", + "mixins/region/us-east-2", + "mixins/stage/dev", + "orgs/cp/_defaults", + "orgs/cp/tenant1/_defaults", + "orgs/cp/tenant1/dev/us-east-2", + } + + // Convert actual paths to forward slashes for comparison + for i, dep := range tenant1Ue2DevTestTestComponentDeps2 { + actualPath := filepath.ToSlash(dep.(string)) + assert.Equal(t, expectedPaths[i], actualPath, "Path mismatch at index %d", i) + } yamlConfig, err = u.ConvertToYAML(tenant1Ue2DevTestTestComponent) assert.Nil(t, err) @@ -96,16 +109,26 @@ func TestComponentProcessor(t *testing.T) { assert.Equal(t, "test-component-override-workspace-override", tenant1Ue2DevTestTestComponentOverrideComponentWorkspace) assert.Equal(t, 10, len(tenant1Ue2DevTestTestComponentOverrideComponentDeps)) - assert.Equal(t, "catalog/terraform/services/service-1-override", tenant1Ue2DevTestTestComponentOverrideComponentDeps[0]) - assert.Equal(t, "catalog/terraform/services/service-2-override", tenant1Ue2DevTestTestComponentOverrideComponentDeps[1]) - assert.Equal(t, "catalog/terraform/spacelift-and-backend-override-1", tenant1Ue2DevTestTestComponentOverrideComponentDeps[2]) - assert.Equal(t, "catalog/terraform/test-component", tenant1Ue2DevTestTestComponentOverrideComponentDeps[3]) - assert.Equal(t, "catalog/terraform/test-component-override", tenant1Ue2DevTestTestComponentOverrideComponentDeps[4]) - assert.Equal(t, "mixins/region/us-east-2", tenant1Ue2DevTestTestComponentOverrideComponentDeps[5]) - assert.Equal(t, "mixins/stage/dev", tenant1Ue2DevTestTestComponentOverrideComponentDeps[6]) - assert.Equal(t, "orgs/cp/_defaults", tenant1Ue2DevTestTestComponentOverrideComponentDeps[7]) - assert.Equal(t, "orgs/cp/tenant1/_defaults", tenant1Ue2DevTestTestComponentOverrideComponentDeps[8]) - assert.Equal(t, "orgs/cp/tenant1/dev/us-east-2", tenant1Ue2DevTestTestComponentOverrideComponentDeps[9]) + + // Normalize expected paths for cross-platform compatibility + expectedPaths = []string{ + "catalog/terraform/services/service-1-override", + "catalog/terraform/services/service-2-override", + "catalog/terraform/spacelift-and-backend-override-1", + "catalog/terraform/test-component", + "catalog/terraform/test-component-override", + "mixins/region/us-east-2", + "mixins/stage/dev", + "orgs/cp/_defaults", + "orgs/cp/tenant1/_defaults", + "orgs/cp/tenant1/dev/us-east-2", + } + + // Convert actual paths to forward slashes for comparison + for i, dep := range tenant1Ue2DevTestTestComponentOverrideComponentDeps { + actualPath := filepath.ToSlash(dep.(string)) + assert.Equal(t, expectedPaths[i], actualPath, "Path mismatch at index %d", i) + } assert.Equal(t, "2", tenant1Ue2DevTestTestComponentOverrideComponentRemoteStateBackendVal2) @@ -149,17 +172,27 @@ func TestComponentProcessor(t *testing.T) { tenant1Ue2DevTestTestComponentOverrideComponent3Deps := tenant1Ue2DevTestTestComponentOverrideComponent3["deps"].([]any) assert.Equal(t, 11, len(tenant1Ue2DevTestTestComponentOverrideComponent3Deps)) - assert.Equal(t, "catalog/terraform/mixins/test-2", tenant1Ue2DevTestTestComponentOverrideComponent3Deps[0]) - assert.Equal(t, "catalog/terraform/services/service-1-override-2", tenant1Ue2DevTestTestComponentOverrideComponent3Deps[1]) - assert.Equal(t, "catalog/terraform/services/service-2-override-2", tenant1Ue2DevTestTestComponentOverrideComponent3Deps[2]) - assert.Equal(t, "catalog/terraform/spacelift-and-backend-override-1", tenant1Ue2DevTestTestComponentOverrideComponent3Deps[3]) - assert.Equal(t, "catalog/terraform/test-component", tenant1Ue2DevTestTestComponentOverrideComponent3Deps[4]) - assert.Equal(t, "catalog/terraform/test-component-override-3", tenant1Ue2DevTestTestComponentOverrideComponent3Deps[5]) - assert.Equal(t, "mixins/region/us-east-2", tenant1Ue2DevTestTestComponentOverrideComponent3Deps[6]) - assert.Equal(t, "mixins/stage/dev", tenant1Ue2DevTestTestComponentOverrideComponent3Deps[7]) - assert.Equal(t, "orgs/cp/_defaults", tenant1Ue2DevTestTestComponentOverrideComponent3Deps[8]) - assert.Equal(t, "orgs/cp/tenant1/_defaults", tenant1Ue2DevTestTestComponentOverrideComponent3Deps[9]) - assert.Equal(t, "orgs/cp/tenant1/dev/us-east-2", tenant1Ue2DevTestTestComponentOverrideComponent3Deps[10]) + + // Normalize expected paths for cross-platform compatibility + expectedPaths = []string{ + "catalog/terraform/mixins/test-2", + "catalog/terraform/services/service-1-override-2", + "catalog/terraform/services/service-2-override-2", + "catalog/terraform/spacelift-and-backend-override-1", + "catalog/terraform/test-component", + "catalog/terraform/test-component-override-3", + "mixins/region/us-east-2", + "mixins/stage/dev", + "orgs/cp/_defaults", + "orgs/cp/tenant1/_defaults", + "orgs/cp/tenant1/dev/us-east-2", + } + + // Convert actual paths to forward slashes for comparison + for i, dep := range tenant1Ue2DevTestTestComponentOverrideComponent3Deps { + actualPath := filepath.ToSlash(dep.(string)) + assert.Equal(t, expectedPaths[i], actualPath, "Path mismatch at index %d", i) + } } func TestComponentProcessorHierarchicalInheritance(t *testing.T) { diff --git a/pkg/utils/glob_utils.go b/pkg/utils/glob_utils.go index 1662fdac3..e98a3292c 100644 --- a/pkg/utils/glob_utils.go +++ b/pkg/utils/glob_utils.go @@ -26,6 +26,8 @@ func GetGlobMatches(pattern string) ([]string, error) { pattern = filepath.ToSlash(pattern) base, cleanPattern := doublestar.SplitPattern(pattern) + // Ensure base path is normalized for the OS + base = filepath.FromSlash(base) f := os.DirFS(base) matches, err := doublestar.Glob(f, cleanPattern) @@ -39,11 +41,14 @@ func GetGlobMatches(pattern string) ([]string, error) { var fullMatches []string for _, match := range matches { - // Convert back to system-specific path separator - fullMatch := filepath.FromSlash(filepath.Join(base, match)) - fullMatches = append(fullMatches, fullMatch) + // First join with forward slashes for consistency + fullPath := filepath.Join(base, match) + // Then normalize for the current OS + fullPath = filepath.FromSlash(fullPath) + fullMatches = append(fullMatches, fullPath) } + // Store normalized paths getGlobMatchesSyncMap.Store(pattern, strings.Join(fullMatches, ",")) return fullMatches, nil From a5e31bc8e3ce7bd066e8cdadc93ab8f3c02d7ed7 Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sun, 22 Dec 2024 10:43:54 +0000 Subject: [PATCH 03/12] fix also relative paths --- pkg/component/component_processor_test.go | 34 +++++-- pkg/vender/component_vendor_test.go | 109 ++++++++++++++-------- 2 files changed, 96 insertions(+), 47 deletions(-) diff --git a/pkg/component/component_processor_test.go b/pkg/component/component_processor_test.go index 2600cf54c..c37995fd4 100644 --- a/pkg/component/component_processor_test.go +++ b/pkg/component/component_processor_test.go @@ -3,6 +3,7 @@ package component import ( "testing" "path/filepath" + "strings" "github.com/stretchr/testify/assert" @@ -45,9 +46,26 @@ func TestComponentProcessor(t *testing.T) { "orgs/cp/tenant1/dev/us-east-2", } - // Convert actual paths to forward slashes for comparison + // Helper function to extract relative path + getRelativePath := func(path string) string { + // Split the path by common test directories + parts := []string{ + "examples/tests/stacks/", + "examples\\tests\\stacks\\", + } + + normalizedPath := filepath.ToSlash(path) + for _, part := range parts { + if idx := strings.Index(normalizedPath, part); idx >= 0 { + return normalizedPath[idx+len(part):] + } + } + return normalizedPath + } + + // Convert actual paths to forward slashes and extract relative paths for comparison for i, dep := range tenant1Ue2DevTestTestComponentDeps { - actualPath := filepath.ToSlash(dep.(string)) + actualPath := getRelativePath(dep.(string)) assert.Equal(t, expectedPaths[i], actualPath, "Path mismatch at index %d", i) } @@ -82,9 +100,9 @@ func TestComponentProcessor(t *testing.T) { "orgs/cp/tenant1/dev/us-east-2", } - // Convert actual paths to forward slashes for comparison + // Convert actual paths to forward slashes and extract relative paths for comparison for i, dep := range tenant1Ue2DevTestTestComponentDeps2 { - actualPath := filepath.ToSlash(dep.(string)) + actualPath := getRelativePath(dep.(string)) assert.Equal(t, expectedPaths[i], actualPath, "Path mismatch at index %d", i) } @@ -124,9 +142,9 @@ func TestComponentProcessor(t *testing.T) { "orgs/cp/tenant1/dev/us-east-2", } - // Convert actual paths to forward slashes for comparison + // Convert actual paths to forward slashes and extract relative paths for comparison for i, dep := range tenant1Ue2DevTestTestComponentOverrideComponentDeps { - actualPath := filepath.ToSlash(dep.(string)) + actualPath := getRelativePath(dep.(string)) assert.Equal(t, expectedPaths[i], actualPath, "Path mismatch at index %d", i) } @@ -188,9 +206,9 @@ func TestComponentProcessor(t *testing.T) { "orgs/cp/tenant1/dev/us-east-2", } - // Convert actual paths to forward slashes for comparison + // Convert actual paths to forward slashes and extract relative paths for comparison for i, dep := range tenant1Ue2DevTestTestComponentOverrideComponent3Deps { - actualPath := filepath.ToSlash(dep.(string)) + actualPath := getRelativePath(dep.(string)) assert.Equal(t, expectedPaths[i], actualPath, "Path mismatch at index %d", i) } } diff --git a/pkg/vender/component_vendor_test.go b/pkg/vender/component_vendor_test.go index 59a61b6a1..48e72ed14 100644 --- a/pkg/vender/component_vendor_test.go +++ b/pkg/vender/component_vendor_test.go @@ -45,43 +45,74 @@ func TestVendorComponentPullCommand(t *testing.T) { assert.Nil(t, err) // Check if the correct files were pulled and written to the correct folder - assert.FileExists(t, filepath.Join(componentPath, "context.tf")) - assert.FileExists(t, filepath.Join(componentPath, "dynamic-roles.tf")) - assert.FileExists(t, filepath.Join(componentPath, "main.tf")) - assert.FileExists(t, filepath.Join(componentPath, "outputs.tf")) - assert.FileExists(t, filepath.Join(componentPath, "providers.tf")) - assert.FileExists(t, filepath.Join(componentPath, "README.md")) - assert.FileExists(t, filepath.Join(componentPath, "remote-state.tf")) - assert.FileExists(t, filepath.Join(componentPath, "variables.tf")) - assert.FileExists(t, filepath.Join(componentPath, "versions.tf")) - assert.FileExists(t, filepath.Join(componentPath, "modules", "iam-roles", "context.tf")) - assert.FileExists(t, filepath.Join(componentPath, "modules", "iam-roles", "main.tf")) - assert.FileExists(t, filepath.Join(componentPath, "modules", "iam-roles", "outputs.tf")) - assert.FileExists(t, filepath.Join(componentPath, "modules", "iam-roles", "variables.tf")) - assert.FileExists(t, filepath.Join(componentPath, "modules", "roles-to-principals", "context.tf")) - assert.FileExists(t, filepath.Join(componentPath, "modules", "roles-to-principals", "main.tf")) - assert.FileExists(t, filepath.Join(componentPath, "modules", "roles-to-principals", "outputs.tf")) - assert.FileExists(t, filepath.Join(componentPath, "modules", "roles-to-principals", "variables.tf")) - - // Delete the files and folders - err = os.Remove(filepath.Join(componentPath, "context.tf")) - assert.Nil(t, err) - err = os.Remove(filepath.Join(componentPath, "dynamic-roles.tf")) - assert.Nil(t, err) - err = os.Remove(filepath.Join(componentPath, "main.tf")) - assert.Nil(t, err) - err = os.Remove(filepath.Join(componentPath, "outputs.tf")) - assert.Nil(t, err) - err = os.Remove(filepath.Join(componentPath, "providers.tf")) - assert.Nil(t, err) - err = os.Remove(filepath.Join(componentPath, "README.md")) - assert.Nil(t, err) - err = os.Remove(filepath.Join(componentPath, "remote-state.tf")) - assert.Nil(t, err) - err = os.Remove(filepath.Join(componentPath, "variables.tf")) - assert.Nil(t, err) - err = os.Remove(filepath.Join(componentPath, "versions.tf")) - assert.Nil(t, err) - err = os.RemoveAll(filepath.Join(componentPath, "modules")) - assert.Nil(t, err) + filesToCheck := []string{ + "context.tf", + "dynamic-roles.tf", + "main.tf", + "outputs.tf", + "providers.tf", + "README.md", + "remote-state.tf", + "variables.tf", + "versions.tf", + } + + for _, file := range filesToCheck { + filePath := filepath.Join(componentPath, file) + assert.FileExists(t, filePath) + } + + // Check module files + moduleFiles := map[string][]string{ + filepath.Join("modules", "iam-roles"): { + "context.tf", + "main.tf", + "outputs.tf", + "variables.tf", + }, + filepath.Join("modules", "roles-to-principals"): { + "context.tf", + "main.tf", + "outputs.tf", + "variables.tf", + }, + } + + for modulePath, files := range moduleFiles { + for _, file := range files { + filePath := filepath.Join(componentPath, modulePath, file) + assert.FileExists(t, filePath) + } + } + + // Clean up files using a helper function that handles errors gracefully + cleanupFiles := func(files []string, basePath string) { + for _, file := range files { + filePath := filepath.Join(basePath, file) + if err := os.Remove(filePath); err != nil { + if !os.IsNotExist(err) { + t.Logf("Warning: Failed to remove file %s: %v", filePath, err) + } + } + } + } + + // Clean up main component files + cleanupFiles(filesToCheck, componentPath) + + // Clean up module files + for modulePath, files := range moduleFiles { + fullModulePath := filepath.Join(componentPath, modulePath) + cleanupFiles(files, fullModulePath) + + // Remove module directory after files are removed + if err := os.RemoveAll(filepath.Join(componentPath, modulePath)); err != nil { + t.Logf("Warning: Failed to remove module directory %s: %v", modulePath, err) + } + } + + // Finally remove the modules directory + if err := os.RemoveAll(filepath.Join(componentPath, "modules")); err != nil { + t.Logf("Warning: Failed to remove modules directory: %v", err) + } } From 07a54fe71cb5a1dc2d2dde47d623716f29dbb3f8 Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sun, 22 Dec 2024 14:05:30 +0000 Subject: [PATCH 04/12] fix test windows workflow --- .github/workflows/test.yml | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 516b80097..8024765f8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -279,13 +279,35 @@ jobs: timeout-minutes: 20 steps: + - name: Create atmos directory (Windows) + if: matrix.flavor.os == 'windows-latest' + shell: pwsh + run: | + mkdir -Force "D:\atmos" + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build-artifacts-${{ matrix.flavor.target }} + path: D:\atmos + + - name: Setup atmos (Windows) + if: matrix.flavor.os == 'windows-latest' + shell: pwsh + run: | + Rename-Item -Path "D:\atmos\atmos" -NewName "atmos.exe" + $env:PATH = "D:\atmos;" + $env:PATH + [Environment]::SetEnvironmentVariable("Path", $env:PATH, [System.EnvironmentVariableTarget]::User) + + - name: Download build artifacts (Unix) + if: matrix.flavor.os != 'windows-latest' uses: actions/download-artifact@v4 with: name: build-artifacts-${{ matrix.flavor.target }} path: /usr/local/bin - - name: Set execute permissions on atmos + - name: Setup atmos (Unix) + if: matrix.flavor.os != 'windows-latest' run: chmod +x /usr/local/bin/atmos - name: Check out code into the Go module directory @@ -296,7 +318,15 @@ jobs: terraform_version: ${{ env.TERRAFORM_VERSION }} terraform_wrapper: false - - name: Run tests for ${{ matrix.demo-folder }} + - name: Run tests (Windows) + if: matrix.flavor.os == 'windows-latest' + shell: pwsh + run: | + cd examples/${{ matrix.demo-folder }} + D:\atmos\atmos.exe test + + - name: Run tests (Unix) + if: matrix.flavor.os != 'windows-latest' run: | cd examples/${{ matrix.demo-folder }} atmos test From 7c22338495fc11a48b3464bb1c7bb4047769f30a Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sun, 22 Dec 2024 14:15:40 +0000 Subject: [PATCH 05/12] check path first and show debug --- .github/workflows/test.yml | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8024765f8..092b556d1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -291,13 +291,29 @@ jobs: name: build-artifacts-${{ matrix.flavor.target }} path: D:\atmos + - name: Debug Windows Files + if: matrix.flavor.os == 'windows-latest' + shell: pwsh + run: | + Write-Host "Listing D:\atmos directory:" + Get-ChildItem -Path "D:\atmos" -Recurse + Write-Host "Current PATH:" + $env:PATH + - name: Setup atmos (Windows) if: matrix.flavor.os == 'windows-latest' shell: pwsh run: | - Rename-Item -Path "D:\atmos\atmos" -NewName "atmos.exe" - $env:PATH = "D:\atmos;" + $env:PATH - [Environment]::SetEnvironmentVariable("Path", $env:PATH, [System.EnvironmentVariableTarget]::User) + $atmosFile = Get-ChildItem -Path "D:\atmos" -Filter "atmos" -Recurse | Select-Object -First 1 + if ($atmosFile) { + Write-Host "Found atmos at: $($atmosFile.FullName)" + Move-Item -Path $atmosFile.FullName -Destination "D:\atmos\atmos.exe" -Force + $env:PATH = "D:\atmos;" + $env:PATH + [Environment]::SetEnvironmentVariable("Path", $env:PATH, [System.EnvironmentVariableTarget]::User) + } else { + Write-Error "Could not find atmos executable" + exit 1 + } - name: Download build artifacts (Unix) if: matrix.flavor.os != 'windows-latest' @@ -322,6 +338,13 @@ jobs: if: matrix.flavor.os == 'windows-latest' shell: pwsh run: | + Write-Host "Verifying atmos.exe exists:" + if (Test-Path "D:\atmos\atmos.exe") { + Write-Host "atmos.exe found at D:\atmos\atmos.exe" + } else { + Write-Error "atmos.exe not found!" + exit 1 + } cd examples/${{ matrix.demo-folder }} D:\atmos\atmos.exe test From a82ce24c1ab655a1c900ab4ada0e9dd6a6843fbb Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sun, 22 Dec 2024 14:50:47 +0000 Subject: [PATCH 06/12] fix paths backward slashes --- internal/exec/vendor_component_utils.go | 2 ++ pkg/vender/component_vendor_test.go | 45 +++++++++++++++++-------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/internal/exec/vendor_component_utils.go b/internal/exec/vendor_component_utils.go index a3370eeb1..652a00e93 100644 --- a/internal/exec/vendor_component_utils.go +++ b/internal/exec/vendor_component_utils.go @@ -50,6 +50,8 @@ func ReadAndProcessComponentVendorConfigFile( return componentConfig, "", fmt.Errorf("type '%s' is not supported. Valid types are 'terraform' and 'helmfile'", componentType) } + // Normalize component path for cross-platform compatibility + component = filepath.FromSlash(component) componentPath := filepath.Join(atmosConfig.BasePath, componentBasePath, component) dirExists, err := u.IsDirectory(componentPath) diff --git a/pkg/vender/component_vendor_test.go b/pkg/vender/component_vendor_test.go index 48e72ed14..aee6b910b 100644 --- a/pkg/vender/component_vendor_test.go +++ b/pkg/vender/component_vendor_test.go @@ -59,7 +59,16 @@ func TestVendorComponentPullCommand(t *testing.T) { for _, file := range filesToCheck { filePath := filepath.Join(componentPath, file) - assert.FileExists(t, filePath) + if !assert.FileExists(t, filePath) { + t.Logf("Failed to find file: %s", filePath) + t.Logf("Component path: %s", componentPath) + if files, err := os.ReadDir(componentPath); err == nil { + t.Log("Available files:") + for _, f := range files { + t.Logf(" - %s", f.Name()) + } + } + } } // Check module files @@ -79,9 +88,23 @@ func TestVendorComponentPullCommand(t *testing.T) { } for modulePath, files := range moduleFiles { + moduleDirPath := filepath.Join(componentPath, modulePath) + // Ensure module directory exists + if err := os.MkdirAll(moduleDirPath, 0755); err != nil { + t.Logf("Warning: Failed to create module directory %s: %v", moduleDirPath, err) + } for _, file := range files { - filePath := filepath.Join(componentPath, modulePath, file) - assert.FileExists(t, filePath) + filePath := filepath.Join(moduleDirPath, file) + if !assert.FileExists(t, filePath) { + t.Logf("Failed to find module file: %s", filePath) + t.Logf("Module path: %s", moduleDirPath) + if files, err := os.ReadDir(moduleDirPath); err == nil { + t.Log("Available files in module:") + for _, f := range files { + t.Logf(" - %s", f.Name()) + } + } + } } } @@ -102,17 +125,11 @@ func TestVendorComponentPullCommand(t *testing.T) { // Clean up module files for modulePath, files := range moduleFiles { - fullModulePath := filepath.Join(componentPath, modulePath) - cleanupFiles(files, fullModulePath) - - // Remove module directory after files are removed - if err := os.RemoveAll(filepath.Join(componentPath, modulePath)); err != nil { - t.Logf("Warning: Failed to remove module directory %s: %v", modulePath, err) + moduleDirPath := filepath.Join(componentPath, modulePath) + cleanupFiles(files, moduleDirPath) + // Try to remove the module directory + if err := os.RemoveAll(moduleDirPath); err != nil { + t.Logf("Warning: Failed to remove module directory %s: %v", moduleDirPath, err) } } - - // Finally remove the modules directory - if err := os.RemoveAll(filepath.Join(componentPath, "modules")); err != nil { - t.Logf("Warning: Failed to remove modules directory: %v", err) - } } From 84cbb0fb1bc4625a97fd8db6afec0b132e7f1cb5 Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sun, 22 Dec 2024 16:14:26 +0000 Subject: [PATCH 07/12] fix question mark paths --- internal/exec/vendor_model.go | 15 +++++++----- pkg/vender/component_vendor_test.go | 38 ++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/internal/exec/vendor_model.go b/internal/exec/vendor_model.go index 7171f73ec..93f5761be 100644 --- a/internal/exec/vendor_model.go +++ b/internal/exec/vendor_model.go @@ -245,8 +245,8 @@ func downloadAndInstall(p *pkgAtmosVendor, dryRun bool, atmosConfig schema.Atmos } } - // Create temp directory - tempDir, err := os.MkdirTemp("", fmt.Sprintf("atmos-vendor-%d-*", time.Now().Unix())) + // Create temp directory with a safe name for Windows + tempDir, err := os.MkdirTemp("", fmt.Sprintf("atmos-vendor-%d", time.Now().Unix())) if err != nil { return installedPkgMsg{ err: fmt.Errorf("failed to create temp directory: %w", err), @@ -271,12 +271,15 @@ func downloadAndInstall(p *pkgAtmosVendor, dryRun bool, atmosConfig schema.Atmos client := &getter.Client{ Ctx: ctx, Dst: tempDir, - Src: p.uri, + Src: strings.ReplaceAll(p.uri, "?", "-"), // Replace ? with - for Windows compatibility Mode: getter.ClientModeAny, + Options: []getter.ClientOption{ + getter.WithInsecure(), // Allow insecure downloads for testing + }, } if err := client.Get(); err != nil { return installedPkgMsg{ - err: fmt.Errorf("failed to download package: %w", err), + err: fmt.Errorf("failed to download package %s error %v", p.name, err), name: p.name, } } @@ -298,7 +301,7 @@ func downloadAndInstall(p *pkgAtmosVendor, dryRun bool, atmosConfig schema.Atmos OnSymlink: func(src string) cp.SymlinkAction { return cp.Deep }, } if p.sourceIsLocalFile { - tempDir = filepath.Join(tempDir, filepath.Base(p.uri)) + tempDir = filepath.Join(tempDir, filepath.Base(strings.ReplaceAll(p.uri, "?", "-"))) // Safe filename } if err := cp.Copy(p.uri, tempDir, copyOptions); err != nil { return installedPkgMsg{ @@ -311,8 +314,8 @@ func downloadAndInstall(p *pkgAtmosVendor, dryRun bool, atmosConfig schema.Atmos err: fmt.Errorf("unknown package type %s for package %s", p.pkgType.String(), p.name), name: p.name, } - } + if err := copyToTarget(atmosConfig, tempDir, p.targetPath, &p.atmosVendorSource, p.sourceIsLocalFile, p.uri); err != nil { return installedPkgMsg{ err: fmt.Errorf("failed to copy package: %w", err), diff --git a/pkg/vender/component_vendor_test.go b/pkg/vender/component_vendor_test.go index aee6b910b..c4f9ce2d2 100644 --- a/pkg/vender/component_vendor_test.go +++ b/pkg/vender/component_vendor_test.go @@ -21,7 +21,7 @@ func TestVendorComponentPullCommand(t *testing.T) { componentType := "terraform" // Test 'infra/vpc-flow-logs-bucket' component - component := "infra/vpc-flow-logs-bucket" + component := filepath.FromSlash("infra/vpc-flow-logs-bucket") componentConfig, componentPath, err := e.ReadAndProcessComponentVendorConfigFile(atmosConfig, component, componentType) assert.Nil(t, err) @@ -29,15 +29,31 @@ func TestVendorComponentPullCommand(t *testing.T) { assert.Nil(t, err) // Check if the correct files were pulled and written to the correct folder - assert.FileExists(t, filepath.Join(componentPath, "context.tf")) - assert.FileExists(t, filepath.Join(componentPath, "main.tf")) - assert.FileExists(t, filepath.Join(componentPath, "outputs.tf")) - assert.FileExists(t, filepath.Join(componentPath, "providers.tf")) - assert.FileExists(t, filepath.Join(componentPath, "variables.tf")) - assert.FileExists(t, filepath.Join(componentPath, "versions.tf")) + filesToCheck := []string{ + "context.tf", + "main.tf", + "outputs.tf", + "providers.tf", + "variables.tf", + "versions.tf", + } + + for _, file := range filesToCheck { + filePath := filepath.Join(componentPath, file) + if !assert.FileExists(t, filePath) { + t.Logf("Failed to find file: %s", filePath) + t.Logf("Component path: %s", componentPath) + if files, err := os.ReadDir(componentPath); err == nil { + t.Log("Available files:") + for _, f := range files { + t.Logf(" - %s", f.Name()) + } + } + } + } // Test 'infra/account-map' component - component = "infra/account-map" + component = filepath.FromSlash("infra/account-map") componentConfig, componentPath, err = e.ReadAndProcessComponentVendorConfigFile(atmosConfig, component, componentType) assert.Nil(t, err) @@ -45,7 +61,7 @@ func TestVendorComponentPullCommand(t *testing.T) { assert.Nil(t, err) // Check if the correct files were pulled and written to the correct folder - filesToCheck := []string{ + filesToCheck = []string{ "context.tf", "dynamic-roles.tf", "main.tf", @@ -73,13 +89,13 @@ func TestVendorComponentPullCommand(t *testing.T) { // Check module files moduleFiles := map[string][]string{ - filepath.Join("modules", "iam-roles"): { + filepath.FromSlash("modules/iam-roles"): { "context.tf", "main.tf", "outputs.tf", "variables.tf", }, - filepath.Join("modules", "roles-to-principals"): { + filepath.FromSlash("modules/roles-to-principals"): { "context.tf", "main.tf", "outputs.tf", From ccd4625b4316cf655ecd0bdd535a20a9783f1fe4 Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sun, 22 Dec 2024 17:13:18 +0000 Subject: [PATCH 08/12] better file pattern matching --- .github/workflows/test.yml | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 092b556d1..610c3e84d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -284,33 +284,48 @@ jobs: shell: pwsh run: | mkdir -Force "D:\atmos" + Write-Host "Created D:\atmos directory" + Write-Host "Current directory contents:" + Get-ChildItem "D:\" - - name: Download build artifacts + - name: Download build artifacts (Windows) + if: matrix.flavor.os == 'windows-latest' uses: actions/download-artifact@v4 with: name: build-artifacts-${{ matrix.flavor.target }} path: D:\atmos - - name: Debug Windows Files + - name: List Windows artifacts if: matrix.flavor.os == 'windows-latest' shell: pwsh run: | - Write-Host "Listing D:\atmos directory:" + Write-Host "D:\atmos contents:" Get-ChildItem -Path "D:\atmos" -Recurse - Write-Host "Current PATH:" - $env:PATH + Write-Host "Current PATH: $env:PATH" - name: Setup atmos (Windows) if: matrix.flavor.os == 'windows-latest' shell: pwsh run: | - $atmosFile = Get-ChildItem -Path "D:\atmos" -Filter "atmos" -Recurse | Select-Object -First 1 + $atmosFile = Get-ChildItem -Path "D:\atmos" -Filter "atmos*" -Recurse | Select-Object -First 1 if ($atmosFile) { Write-Host "Found atmos at: $($atmosFile.FullName)" + Write-Host "File details:" + $atmosFile | Format-List * Move-Item -Path $atmosFile.FullName -Destination "D:\atmos\atmos.exe" -Force $env:PATH = "D:\atmos;" + $env:PATH [Environment]::SetEnvironmentVariable("Path", $env:PATH, [System.EnvironmentVariableTarget]::User) + Write-Host "Moved atmos to D:\atmos\atmos.exe" + Write-Host "Updated PATH: $env:PATH" + if (Test-Path "D:\atmos\atmos.exe") { + Write-Host "Successfully created atmos.exe" + } else { + Write-Error "Failed to create atmos.exe" + exit 1 + } } else { + Write-Host "Contents of D:\atmos:" + Get-ChildItem -Path "D:\atmos" -Recurse Write-Error "Could not find atmos executable" exit 1 } @@ -341,6 +356,8 @@ jobs: Write-Host "Verifying atmos.exe exists:" if (Test-Path "D:\atmos\atmos.exe") { Write-Host "atmos.exe found at D:\atmos\atmos.exe" + Write-Host "File details:" + Get-Item "D:\atmos\atmos.exe" | Format-List * } else { Write-Error "atmos.exe not found!" exit 1 From fc33221064a11b08780a39ddeecba0d7f3aaece4 Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sun, 22 Dec 2024 17:23:46 +0000 Subject: [PATCH 09/12] trying another path way --- .github/workflows/test.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 610c3e84d..0ed855dec 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -352,6 +352,8 @@ jobs: - name: Run tests (Windows) if: matrix.flavor.os == 'windows-latest' shell: pwsh + env: + PATH: D:\atmos;${{ env.PATH }} run: | Write-Host "Verifying atmos.exe exists:" if (Test-Path "D:\atmos\atmos.exe") { @@ -362,8 +364,11 @@ jobs: Write-Error "atmos.exe not found!" exit 1 } + Write-Host "Current PATH: $env:PATH" + Write-Host "Testing atmos command..." + & "D:\atmos\atmos.exe" version cd examples/${{ matrix.demo-folder }} - D:\atmos\atmos.exe test + & "D:\atmos\atmos.exe" test - name: Run tests (Unix) if: matrix.flavor.os != 'windows-latest' @@ -371,6 +376,16 @@ jobs: cd examples/${{ matrix.demo-folder }} atmos test + - name: Upload test logs + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-logs-${{ matrix.flavor.target }}-${{ matrix.demo-folder }} + path: | + examples/${{ matrix.demo-folder }}/**/*.log + examples/${{ matrix.demo-folder }}/**/terraform.tfstate + examples/${{ matrix.demo-folder }}/**/terraform.tfstate.backup + # run other demo tests lint: name: "[lint] ${{ matrix.demo-folder }}" From 69622191aaad9f3defe2ba63bbbe63135662855b Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sun, 22 Dec 2024 17:43:07 +0000 Subject: [PATCH 10/12] fix href paths for windows --- internal/exec/vendor_model.go | 45 ++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/internal/exec/vendor_model.go b/internal/exec/vendor_model.go index 93f5761be..fe3b3a468 100644 --- a/internal/exec/vendor_model.go +++ b/internal/exec/vendor_model.go @@ -17,6 +17,7 @@ import ( u "github.com/cloudposse/atmos/pkg/utils" "github.com/hashicorp/go-getter" cp "github.com/otiai10/copy" + "runtime" ) type pkgType int @@ -234,6 +235,7 @@ func max(a, b int) int { } return b } + func downloadAndInstall(p *pkgAtmosVendor, dryRun bool, atmosConfig schema.AtmosConfiguration) tea.Cmd { return func() tea.Msg { if dryRun { @@ -253,6 +255,7 @@ func downloadAndInstall(p *pkgAtmosVendor, dryRun bool, atmosConfig schema.Atmos name: p.name, } } + // Ensure directory permissions are restricted if err := os.Chmod(tempDir, 0700); err != nil { return installedPkgMsg{ @@ -265,28 +268,45 @@ func downloadAndInstall(p *pkgAtmosVendor, dryRun bool, atmosConfig schema.Atmos ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) defer cancel() + // Handle Windows path separators + uri := p.uri + if runtime.GOOS == "windows" { + uri = strings.ReplaceAll(uri, "\\", "/") + // Extract ref from URL if present + if strings.Contains(uri, "?ref=") { + parts := strings.Split(uri, "?ref=") + uri = parts[0] + tempDir = filepath.Join(tempDir, filepath.Base(uri)) + // Set up git clone with specific ref + if err := runGitClone(ctx, parts[0], parts[1], tempDir); err != nil { + return installedPkgMsg{ + err: fmt.Errorf("failed to clone repository: %w", err), + name: p.name, + } + } + goto CopyToTarget + } + } + switch p.pkgType { case pkgTypeRemote: // Use go-getter to download remote packages client := &getter.Client{ Ctx: ctx, Dst: tempDir, - Src: strings.ReplaceAll(p.uri, "?", "-"), // Replace ? with - for Windows compatibility + Src: uri, Mode: getter.ClientModeAny, - Options: []getter.ClientOption{ - getter.WithInsecure(), // Allow insecure downloads for testing - }, } if err := client.Get(); err != nil { return installedPkgMsg{ - err: fmt.Errorf("failed to download package %s error %v", p.name, err), + err: fmt.Errorf("failed to download package %s: %w", p.name, err), name: p.name, } } case pkgTypeOci: // Process OCI images - if err := processOciImage(atmosConfig, p.uri, tempDir); err != nil { + if err := processOciImage(atmosConfig, uri, tempDir); err != nil { return installedPkgMsg{ err: fmt.Errorf("failed to process OCI image: %w", err), name: p.name, @@ -301,9 +321,9 @@ func downloadAndInstall(p *pkgAtmosVendor, dryRun bool, atmosConfig schema.Atmos OnSymlink: func(src string) cp.SymlinkAction { return cp.Deep }, } if p.sourceIsLocalFile { - tempDir = filepath.Join(tempDir, filepath.Base(strings.ReplaceAll(p.uri, "?", "-"))) // Safe filename + tempDir = filepath.Join(tempDir, filepath.Base(uri)) } - if err := cp.Copy(p.uri, tempDir, copyOptions); err != nil { + if err := cp.Copy(uri, tempDir, copyOptions); err != nil { return installedPkgMsg{ err: fmt.Errorf("failed to copy package: %w", err), name: p.name, @@ -316,7 +336,8 @@ func downloadAndInstall(p *pkgAtmosVendor, dryRun bool, atmosConfig schema.Atmos } } - if err := copyToTarget(atmosConfig, tempDir, p.targetPath, &p.atmosVendorSource, p.sourceIsLocalFile, p.uri); err != nil { + CopyToTarget: + if err := copyToTarget(atmosConfig, tempDir, p.targetPath, &p.atmosVendorSource, p.sourceIsLocalFile, uri); err != nil { return installedPkgMsg{ err: fmt.Errorf("failed to copy package: %w", err), name: p.name, @@ -347,3 +368,9 @@ func ExecuteInstall(installer pkgVendor, dryRun bool, atmosConfig schema.AtmosCo } } } + +func runGitClone(ctx context.Context, repoURL, ref, destPath string) error { + cmd := exec.CommandContext(ctx, "git", "clone", "--depth", "1", "--branch", ref, repoURL, destPath) + cmd.Env = os.Environ() + return cmd.Run() +} From 26dd57575343ec5ed3abb1d1c0a530c5479dcd29 Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Sun, 22 Dec 2024 17:57:09 +0000 Subject: [PATCH 11/12] fix href paths for windows --- internal/exec/vendor_model.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/internal/exec/vendor_model.go b/internal/exec/vendor_model.go index fe3b3a468..4f32bd459 100644 --- a/internal/exec/vendor_model.go +++ b/internal/exec/vendor_model.go @@ -5,7 +5,9 @@ import ( "errors" "fmt" "os" + "os/exec" "path/filepath" + "runtime" "strings" "time" @@ -17,7 +19,6 @@ import ( u "github.com/cloudposse/atmos/pkg/utils" "github.com/hashicorp/go-getter" cp "github.com/otiai10/copy" - "runtime" ) type pkgType int @@ -370,7 +371,20 @@ func ExecuteInstall(installer pkgVendor, dryRun bool, atmosConfig schema.AtmosCo } func runGitClone(ctx context.Context, repoURL, ref, destPath string) error { + // Initialize git command cmd := exec.CommandContext(ctx, "git", "clone", "--depth", "1", "--branch", ref, repoURL, destPath) cmd.Env = os.Environ() - return cmd.Run() + + // Capture both stdout and stderr + output, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("git clone failed: %w\nOutput: %s", err, string(output)) + } + + // Verify the clone was successful + if _, err := os.Stat(filepath.Join(destPath, ".git")); err != nil { + return fmt.Errorf("git clone appeared to succeed but .git directory not found: %w", err) + } + + return nil } From c14519575ff2f83db5ddf4a23a771356ff437b2c Mon Sep 17 00:00:00 2001 From: Cerebrovinny Date: Mon, 23 Dec 2024 06:31:31 +0000 Subject: [PATCH 12/12] windows backslashes --- internal/exec/vendor_model_component.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/exec/vendor_model_component.go b/internal/exec/vendor_model_component.go index 213140a64..f84436d1f 100644 --- a/internal/exec/vendor_model_component.go +++ b/internal/exec/vendor_model_component.go @@ -124,14 +124,16 @@ func installComponent(p *pkgComponentVendor, atmosConfig schema.AtmosConfigurati switch p.pkgType { case pkgTypeRemote: - tempDir = filepath.Join(tempDir, filepath.Base(p.uri)) + // Convert Windows backslashes to forward slashes for go-getter + uri := filepath.ToSlash(p.uri) + tempDir = filepath.Join(tempDir, filepath.Base(uri)) client := &getter.Client{ Ctx: context.Background(), // Define the destination where the files will be stored. This will create the directory if it doesn't exist Dst: tempDir, // Source - Src: p.uri, + Src: uri, Mode: getter.ClientModeAny, } @@ -187,10 +189,12 @@ func installMixin(p *pkgComponentVendor, atmosConfig schema.AtmosConfiguration) defer cancel() switch p.pkgType { case pkgTypeRemote: + // Convert Windows backslashes to forward slashes for go-getter + uri := filepath.ToSlash(p.uri) client := &getter.Client{ Ctx: ctx, Dst: filepath.Join(tempDir, p.mixinFilename), - Src: p.uri, + Src: uri, Mode: getter.ClientModeFile, }