- Notifications
You must be signed in to change notification settings - Fork 20
fix: normalize template paths for Windows compatibility #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds NormalizeTemplatePath to standardize template paths to forward slashes, applies it throughout rendering and CLI modeline/path resolution, removes the generateModeline function, and updates error handling for modeline parsing and in-place file writes. Changes
Sequence Diagram(s)sequenceDiagram autonumber participant User participant CLI as Template Command participant Engine participant Normalize as NormalizeTemplatePath participant Helm as Helm Engine User->>CLI: talm template -t "templates\controlplane.yaml" CLI->>Engine: Render(templatePath, options) Engine->>Normalize: NormalizeTemplatePath(templatePath) Normalize-->>Engine: "templates/controlplane.yaml" Engine->>Helm: Render(chartName + "/" + normalizedPath) Helm-->>Engine: renderedOutput / renderError Engine-->>CLI: renderedOutput or wrapped error (includes normalized path) CLI-->>User: write output or error (in-place WriteFile error wrapped) Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello @lexfrei, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances cross-platform compatibility, particularly for Windows users, by resolving an inconsistency in how template paths are handled. The core problem stemmed from the Helm engine expecting forward slashes for template keys, while Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request effectively addresses an issue with template path normalization on Windows by introducing a NormalizeTemplatePath function and applying it across the codebase. The changes ensure that paths use forward slashes, which is compatible with the Helm engine. The addition of platform-specific tests is a great way to ensure this fix works as expected and prevents future regressions.
My review includes a couple of suggestions to further improve the code quality. One is to address a significant block of duplicated code for path resolution, which could be refactored for better maintainability. The other is to remove a redundant path normalization call, which would make the code slightly cleaner and more efficient. Overall, this is a solid contribution that improves cross-platform compatibility.
| for _, templateFile := range opts.TemplateFiles { | ||
| requestedTemplate := filepath.Join(chrt.Name(), templateFile) | ||
| // Use path.Join (not filepath.Join) because helm engine keys always use forward slashes | ||
| requestedTemplate := path.Join(chrt.Name(), NormalizeTemplatePath(templateFile)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The templateFile variable, which comes from opts.TemplateFiles, already contains paths that have been normalized in the generateOutput function in pkg/commands/template.go. Therefore, the call to NormalizeTemplatePath here is redundant. You can simplify the code by removing it.
| requestedTemplate := path.Join(chrt.Name(), NormalizeTemplatePath(templateFile)) | |
| requestedTemplate := path.Join(chrt.Name(), templateFile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keeping normalization as a defensive measure. filepath.ToSlash is idempotent (no-op on already-normalized paths), so the cost is negligible. This ensures the engine works correctly even if called from contexts that don't pre-normalize paths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
pkg/commands/template.go (2)
223-272: Consider extracting duplicated path resolution logic.The path resolution logic between lines 223-272 (for template rendering) and lines 298-383 (for modeline generation) is nearly identical. Both blocks handle the same edge cases: unresolvable root, absolute/relative path conversion, paths escaping root, and normalization.
Consider extracting this into a helper function like
resolveTemplatePaths(templateFiles []string, rootDir string) []stringto reduce duplication and maintenance burden.🔎 Sketch of potential helper function
// resolveTemplatePaths resolves template file paths relative to rootDir, // normalizing path separators for Helm engine compatibility. func resolveTemplatePaths(templateFiles []string, rootDir string) []string { resolved := make([]string, len(templateFiles)) absRootDir, rootErr := filepath.Abs(rootDir) if rootErr != nil { for i, p := range templateFiles { resolved[i] = engine.NormalizeTemplatePath(p) } return resolved } // ... rest of resolution logic return resolved }Also applies to: 298-383
313-321: Variableerris reused, shadowing the outer scope declaration.Line 313 assigns to
errwhich was declared at line 299. Then line 321 reassignserragain. While this works correctly, it can be confusing. Consider using distinct variable names (e.g.,absErr,relErr) for clarity, similar to what's done in the earlier block (lines 238-247).🔎 Suggested improvement
// Resolve relative path from current working directory -absTemplatePath, err = filepath.Abs(templatePath) -if err != nil { +var absErr error +absTemplatePath, absErr = filepath.Abs(templatePath) +if absErr != nil { // If we can't get absolute path, use original (normalized) templatePathsForModeline[i] = engine.NormalizeTemplatePath(templatePath) continue } } // Check if the resolved path is inside root project -relPath, err := filepath.Rel(absRootDirModeline, absTemplatePath) -if err != nil { +relPath, relErr := filepath.Rel(absRootDirModeline, absTemplatePath) +if relErr != nil { // If we can't get relative path, use original (normalized) templatePathsForModeline[i] = engine.NormalizeTemplatePath(templatePath) continue }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
pkg/commands/template.gopkg/engine/engine.gopkg/engine/engine_test.gopkg/engine/engine_windows_test.gopkg/engine/helm/engine_test.go
💤 Files with no reviewable changes (1)
- pkg/engine/helm/engine_test.go
🧰 Additional context used
🧬 Code graph analysis (3)
pkg/engine/engine_test.go (1)
pkg/engine/engine.go (1)
NormalizeTemplatePath(63-65)
pkg/engine/engine_windows_test.go (1)
pkg/engine/engine.go (1)
NormalizeTemplatePath(63-65)
pkg/commands/template.go (4)
pkg/commands/root_detection.go (1)
ResolveSecretsPath(226-234)pkg/commands/root.go (1)
Config(38-73)pkg/modeline/modeline.go (1)
Config(12-16)pkg/engine/engine.go (1)
NormalizeTemplatePath(63-65)
🔇 Additional comments (7)
pkg/engine/engine_test.go (1)
19-39: Well-structured table-driven tests for path normalization.The test cases appropriately verify that forward-slash paths pass through unchanged on Unix-like systems. This complements the Windows-specific tests in
engine_windows_test.gothat verify backslash conversion.pkg/engine/engine_windows_test.go (1)
1-40: Good Windows-specific test coverage with proper build constraint.The test cases effectively verify backslash-to-forward-slash conversion for Windows paths, including the important mixed-separator scenario. The
//go:build windowsconstraint ensures these tests only run on Windows wherefilepath.ToSlashactually performs conversion.pkg/engine/engine.go (2)
60-65: Clean implementation of path normalization.The use of
filepath.ToSlashis the correct approach for converting OS-specific path separators to forward slashes. The documentation clearly explains why this is needed for Helm engine compatibility.
244-245: Correct use ofpath.Joinfor Helm engine key construction.Using
path.Join(which always uses forward slashes) instead offilepath.Join(which uses OS-specific separators) is the right choice here since Helm engine map keys consistently use forward slashes. The inline comment helpfully documents this decision.pkg/commands/template.go (3)
144-144: Good error wrapping improvement.Using
%wfor error wrapping allows proper error unwrapping witherrors.Isanderrors.As.
176-178: Improved error handling for file write operations.The explicit error message with the filename provides better debugging context when write operations fail.
269-270: Path normalization correctly applied to resolved paths.The final normalization ensures forward-slash separators regardless of which resolution path was taken.
kvaps left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Use filepath.ToSlash to convert OS-specific path separators to forward slash for consistency with helm engine and embed.FS which always use forward slash internally. This fixes issue cozystack#10 where Windows users get "template not found" errors when using backslash in template paths. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
Remove TestRenderWithClientProvider and TestRenderWithClientProvider_error tests that reference non-existent ClientProvider interface and RenderWithClientProvider function. These tests were inherited from upstream Helm but never adapted for talm's LookupFunc implementation. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
- Export NormalizeTemplatePath and use in template.go - Add comment explaining path.Join vs filepath.Join choice - Update function documentation - Add edge case tests - Remove unused generateModeline function - Fix linter issues (error wrapping, unhandled error) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
When filepath.Abs() fails for either RootDir or individual template paths, the fallback code now properly normalizes paths using engine.NormalizeTemplatePath() instead of passing raw OS-specific paths to the helm engine. This fixes Windows path handling in edge cases where Abs() fails. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
Fix two bugs in the modeline path resolution loop: 1. Normalize paths in error fallback when filepath.Abs(RootDir) fails 2. Use correct variable absRootDirModeline instead of absRootDir Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
47555ff to f585274 Compare There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
pkg/commands/template.go (2)
223-272: Extract duplicated path resolution logic into a helper function.The path resolution logic (lines 223-272 and 298-384) is nearly identical, differing only in variable names to avoid shadowing. This duplication increases maintenance burden and the risk of inconsistency.
💡 Suggested refactor approach
Extract the common logic into a helper function:
// resolveAndNormalizeTemplatePaths converts template paths to normalized paths // relative to the project root, falling back to normalized originals on errors. func resolveAndNormalizeTemplatePaths(templatePaths []string, rootDir string) []string { resolved := make([]string, len(templatePaths)) absRootDir, rootErr := filepath.Abs(rootDir) if rootErr != nil { // If we can't get absolute root, normalize original paths for i, p := range templatePaths { resolved[i] = engine.NormalizeTemplatePath(p) } return resolved } // ... rest of the resolution logic ... return resolved }Then call it from both locations:
// For rendering resolvedTemplateFiles := resolveAndNormalizeTemplatePaths(templateCmdFlags.templateFiles, Config.RootDir) // For modeline templatePathsForModeline := resolveAndNormalizeTemplatePaths(templateCmdFlags.templateFiles, Config.RootDir)This eliminates ~100 lines of duplication and ensures consistent behavior.
Also applies to: 298-384
88-88: Typo in comment: "clinet" → "client".🔎 Proposed fix
-// Set dummy endpoint to avoid errors on building clinet +// Set dummy endpoint to avoid errors on building client
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
pkg/commands/template.gopkg/engine/engine.gopkg/engine/engine_test.gopkg/engine/engine_windows_test.gopkg/engine/helm/engine_test.go
💤 Files with no reviewable changes (1)
- pkg/engine/helm/engine_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
- pkg/engine/engine_windows_test.go
- pkg/engine/engine_test.go
- pkg/engine/engine.go
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/commands/template.go (4)
pkg/commands/root_detection.go (1)
ResolveSecretsPath(226-234)pkg/commands/root.go (1)
Config(38-73)pkg/modeline/modeline.go (1)
Config(12-16)pkg/engine/engine.go (1)
NormalizeTemplatePath(64-66)
🔇 Additional comments (3)
pkg/commands/template.go (3)
144-144: LGTM: Improved error wrapping.Using
%winstead of%venables proper error inspection witherrors.Isanderrors.As.
176-178: LGTM: Enhanced error context for file writes.Wrapping the write error with the specific filename improves debuggability.
370-378: os.SameFile behavior differs across platforms.On Unix, os.SameFile uses device and inode fields; on other systems the decision may be based on path names. If the canonical path optimization doesn't work as expected on Windows, the fallback behavior (skipping canonicalization) is acceptable and won't break functionality.
* fix: normalize template paths for Windows compatibility Use filepath.ToSlash to convert OS-specific path separators to forward slash for consistency with helm engine and embed.FS which always use forward slash internally. This fixes issue cozystack#10 where Windows users get "template not found" errors when using backslash in template paths. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> * fix(tests): remove broken lookup tests from helm engine Remove TestRenderWithClientProvider and TestRenderWithClientProvider_error tests that reference non-existent ClientProvider interface and RenderWithClientProvider function. These tests were inherited from upstream Helm but never adapted for talm's LookupFunc implementation. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> * refactor: address QA review findings - Export NormalizeTemplatePath and use in template.go - Add comment explaining path.Join vs filepath.Join choice - Update function documentation - Add edge case tests - Remove unused generateModeline function - Fix linter issues (error wrapping, unhandled error) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> * fix(template): normalize paths in error fallbacks When filepath.Abs() fails for either RootDir or individual template paths, the fallback code now properly normalizes paths using engine.NormalizeTemplatePath() instead of passing raw OS-specific paths to the helm engine. This fixes Windows path handling in edge cases where Abs() fails. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> * fix(template): fix modeline path handling Fix two bugs in the modeline path resolution loop: 1. Normalize paths in error fallback when filepath.Abs(RootDir) fails 2. Use correct variable absRootDirModeline instead of absRootDir Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> * style: fix gofmt formatting Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> --------- Signed-off-by: Aleksei Sviridkin <f@lex.la> Co-authored-by: Claude <noreply@anthropic.com>
Summary
Fixes #10 — template paths with Windows backslashes don't match helm engine map keys.
Changes:
NormalizeTemplatePath()function usingfilepath.ToSlash()to convert OS-specific separators to forward slashpkg/engine/helm/engine_test.gothat referenced non-existentClientProviderRoot Cause
filepath.Join()produces OS-specific paths (backslash on Windows), but helm engine'sRender()returns map keys with forward slashes regardless of OS. This mismatch causes "template not found" errors on Windows.Test Plan
go build ./...passesgo test ./pkg/engine/...passesgofmt -lcleanGOOS=windows go build ./pkg/engine/Summary by CodeRabbit
Bug Fixes
Refactor
Tests
✏️ Tip: You can customize this high-level summary in your review settings.