-
Notifications
You must be signed in to change notification settings - Fork 0
fix: service path detection #24
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
|
Warning Rate limit exceeded@pilat has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 8 minutes and 59 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (3)
WalkthroughThis PR centralizes project logic into a new Manager type, adds filesystem and git service interfaces (with OS implementations and mocks), and updates CLI commands to use an instantiated manager with context-aware APIs and structured autodetection/source-result types. Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as CLI Command
participant Manager as Manager
participant FS as FileSystem
participant Git as Git Service
participant Project as Project Repo
CLI->>Manager: AutodetectProject(ctx, name)
Manager->>FS: ReadDir / Stat (cwd, mounts)
alt matched local mount
FS-->>Manager: local mount path
Manager->>Project: Load(project by mount)
Project-->>Manager: Project
else check git remotes
Manager->>Git: New(path).GetRemote(ctx)
Git-->>Manager: remote URL
Manager->>Project: match remote → map to project
Project-->>Manager: Project
else check manifest repos
Manager->>Project: enumerate manifests
Project-->>Manager: Project
end
Manager-->>CLI: *Project (autodetected) or error
Notes:
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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 |
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: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
internal/git/git.go (1)
28-33: Consider returning the interface type for better abstraction.
New()returns*svc(concrete type). For consistency with dependency injection patterns, consider returningServiceinstead. This makes it explicit that callers should program to the interface.-func New(targetFolder string) *svc { +func New(targetFolder string) Service {This is optional since callers can still assign to a
Servicevariable.cmd/devbox/ps.go (1)
56-63: Missing return after sending to error channel causes goroutine leak.After sending to
errChon lines 58 and 62, the goroutine continues its infinite loop. This causes:
- Potential deadlock on second send to unbuffered channel
- Goroutine leak since loop never terminates on error/empty case
🔎 Proposed fix
containers, err := apiService.Ps(ctx, p.Name, opts) if err != nil { errCh <- fmt.Errorf("failed to list services: %w", err) + return } if len(containers) == 0 { errCh <- nil + return }cmd/devbox/devbox.go (1)
69-83: Minor: Project loaded but discarded in wrapper.The
AutodetectProjectresult is discarded on line 73. The wrapper validates detectability while commands reload the project inRunE. This is acceptable but causes duplicate work.If this becomes a performance concern, consider passing the detected project through context or a closure.
cmd/devbox/umount.go (1)
79-84: Same copy-paste error in runUmount.func runUmount(ctx context.Context, p *project.Project, sources []string) error { err := p.Umount(ctx, sources) if err != nil { - return fmt.Errorf("failed to mount source code: %w", err) + return fmt.Errorf("failed to unmount source code: %w", err) } return nil }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (2)
internal/git/git_test.gois excluded by!**/*_test.gointernal/manager/manager_test.gois excluded by!**/*_test.go
📒 Files selected for processing (27)
.mockery.yamlcmd/devbox/destroy.gocmd/devbox/devbox.gocmd/devbox/down.gocmd/devbox/env.gocmd/devbox/info.gocmd/devbox/init.gocmd/devbox/install_ca.gocmd/devbox/list.gocmd/devbox/logs.gocmd/devbox/mount.gocmd/devbox/ps.gocmd/devbox/restart.gocmd/devbox/run.gocmd/devbox/shell.gocmd/devbox/umount.gocmd/devbox/up.gocmd/devbox/update.gocmd/devbox/update_hosts.gointernal/git/git.gointernal/git/mock_CommandRunner.gointernal/git/mock_Service.gointernal/manager/manager.gointernal/pkg/fs/fs.gointernal/pkg/fs/mock_DirEntry.gointernal/pkg/fs/mock_FileInfo.gointernal/pkg/fs/mock_FileSystem.go
🧰 Additional context used
📓 Path-based instructions (3)
internal/**/*.go
⚙️ CodeRabbit configuration file
internal/**/*.go: Core packages providing project functionality:
- project/: Project configuration, Docker Compose extensions (x-devbox-*)
- manager/: Project/service autodetection from current directory
- git/: Git operations (clone, sparse checkout, sync)
- cert/: SSL certificate generation
- hosts/: /etc/hosts management with project-scoped markers
- table/: CLI table output formatting
Review for:
- Clean interfaces and proper encapsulation
- Error wrapping with context
- No interface{} - use 'any' instead (enforced by linter)
- YAGNI principle - no speculative features or premature abstractions
- Security considerations for host file and certificate operations
Files:
internal/pkg/fs/mock_FileInfo.gointernal/git/mock_CommandRunner.gointernal/git/git.gointernal/git/mock_Service.gointernal/pkg/fs/mock_DirEntry.gointernal/manager/manager.gointernal/pkg/fs/fs.gointernal/pkg/fs/mock_FileSystem.go
cmd/devbox/**/*.go
⚙️ CodeRabbit configuration file
cmd/devbox/**/*.go: This directory contains CLI commands using Cobra framework.
Each command is in a separate file with an init() function that registers via root.AddCommand().Review for:
- Proper error handling with context wrapping (fmt.Errorf with %w)
- Consistent command structure following existing patterns
- Appropriate use of runWrapper for context handling
- Clear, concise command descriptions
- No over-engineering - only implement what's needed
Files:
cmd/devbox/update_hosts.gocmd/devbox/destroy.gocmd/devbox/down.gocmd/devbox/restart.gocmd/devbox/list.gocmd/devbox/up.gocmd/devbox/info.gocmd/devbox/init.gocmd/devbox/umount.gocmd/devbox/env.gocmd/devbox/install_ca.gocmd/devbox/logs.gocmd/devbox/update.gocmd/devbox/devbox.gocmd/devbox/run.gocmd/devbox/ps.gocmd/devbox/mount.gocmd/devbox/shell.go
internal/manager/**/*.go
⚙️ CodeRabbit configuration file
internal/manager/**/*.go: Project autodetection with three-step process:
- Check if directory is a local mount of any project
- Match Git remote URL + path against project source definitions
- Check if directory is the project's manifest repository
Review for edge cases in path matching and Git remote detection.
Files:
internal/manager/manager.go
🧬 Code graph analysis (10)
cmd/devbox/destroy.go (1)
internal/project/project.go (2)
p(108-118)Project(24-35)
cmd/devbox/list.go (3)
internal/git/git.go (1)
New(28-33)internal/manager/manager.go (1)
New(43-53)internal/project/project.go (4)
New(50-107)p(108-118)Project(24-35)p(139-148)
internal/git/git.go (2)
internal/git/structs.go (1)
CommitInfo(3-8)internal/project/config.go (1)
Service(12-21)
internal/git/mock_Service.go (1)
internal/git/structs.go (1)
CommitInfo(3-8)
cmd/devbox/devbox.go (1)
internal/manager/manager.go (2)
Manager(35-40)New(43-53)
internal/pkg/fs/mock_DirEntry.go (1)
internal/pkg/fs/fs.go (1)
FileInfo(18-25)
internal/manager/manager.go (5)
internal/git/git.go (2)
Service(11-19)New(28-33)internal/pkg/fs/fs.go (2)
FileSystem(9-15)New(51-53)internal/project/project.go (2)
Project(24-35)New(50-107)internal/git/normalizer.go (1)
NormalizeURL(21-60)internal/app/const.go (4)
SourcesDir(13-13)AppDir(9-9)EnvFile(15-15)StateFile(14-14)
internal/pkg/fs/fs.go (1)
internal/manager/manager.go (1)
New(43-53)
cmd/devbox/mount.go (1)
internal/manager/manager.go (1)
AutodetectSourceForMount(22-22)
internal/pkg/fs/mock_FileSystem.go (1)
internal/pkg/fs/fs.go (2)
DirEntry(28-33)FileInfo(18-25)
🔇 Additional comments (34)
internal/git/mock_CommandRunner.go (1)
1-1: Auto-generated mock file updated with new mockery version.No issues here—this is a standard regeneration after updating the mockery tool to v2.53.5.
cmd/devbox/run.go (2)
21-24: Context-aware autodetection in ValidArgsFunction.Good—context propagation now covers the shell completion path as well, allowing cancellation during tab completion scenarios.
34-37: Consistent context propagation in RunE.Same pattern applied correctly to the command execution path.
cmd/devbox/info.go (1)
26-29: LGTM.Clean migration to the context-aware
AutodetectProjectAPI.cmd/devbox/env.go (1)
29-32: LGTM.Context is properly passed. The error wrapping with
"failed to detect project"provides good diagnostic context..mockery.yaml (1)
14-19: Mock generation config expanded for new abstractions.Good additions for testability. The
Serviceinterface in git and the filesystem abstractions (FileSystem,FileInfo,DirEntry) enable proper unit testing with dependency injection.cmd/devbox/update_hosts.go (1)
21-24: LGTM.Context-aware autodetection applied consistently to this hidden command.
cmd/devbox/down.go (1)
20-23: LGTM.Context propagation enables proper cancellation through the down operation chain.
cmd/devbox/logs.go (1)
21-24: LGTM!Context propagation to
AutodetectProjectis correctly implemented. The error handling remains proper with early returns.Also applies to: 34-37
internal/git/git.go (1)
11-21: Well-structured interface for testability.The
Serviceinterface correctly abstracts git operations. The compile-time assertion (var _ Service = (*svc)(nil)) is idiomatic Go for ensuring interface compliance.cmd/devbox/restart.go (1)
23-26: LGTM!Context propagation is correctly applied. Using
context.Background()in the flag completion callback (line 59) is appropriate since there's no parent context available in that callback signature.Also applies to: 59-62, 71-74
cmd/devbox/ps.go (1)
22-25: LGTM!Context propagation is correct.
cmd/devbox/destroy.go (1)
20-23: LGTM!Context propagation to both
AutodetectProjectandDestroyis correctly implemented. Error wrapping follows proper Go patterns.Also applies to: 44-46
cmd/devbox/devbox.go (1)
23-23: LGTM!The
mgrpackage-level variable is properly initialized ininitDocker()beforeinitCobra()callsroot.Execute(), ensuring it's available for flag completions and command execution.Also applies to: 64-65
cmd/devbox/shell.go (1)
32-35: LGTM!Context propagation is correctly implemented.
cmd/devbox/up.go (1)
25-28: LGTM!Context propagation is correctly applied across all
AutodetectProjectcall sites. Usingcontext.Background()in the flag completion callback (line 80) is appropriate given the callback signature limitations.Also applies to: 38-41, 80-83
cmd/devbox/init.go (1)
47-51: Context propagation looks good.The signature change to accept
context.Contextand its propagation tomgr.Initaligns with the broader refactor for context-aware operations.cmd/devbox/list.go (1)
36-52: Clean migration to mgr-based API.The refactor to use
mgr.List()andmgr.Load()is consistent with the new Manager abstraction. Usinggit.New()directly for read-only git info retrieval is acceptable here.cmd/devbox/install_ca.go (1)
18-22: Context propagation is correct.The migration to
mgr.AutodetectProject(ctx, projectName)is consistent with the refactored API.internal/pkg/fs/fs.go (2)
9-15: Clean FileSystem abstraction.The interface is minimal and covers the essential operations needed for the manager package. The compile-time assertion on line 47 is a good practice.
63-73: ReadDir wrapper correctly adapts os.DirEntry to the custom interface.The conversion loop properly wraps each
os.DirEntryintoosDirEntryto satisfy the[]DirEntryreturn type.internal/pkg/fs/mock_FileInfo.go (1)
1-310: Autogenerated mock - no manual changes needed.This is mockery-generated code following standard testify/mock patterns. Ensure this file is regenerated if the
FileInfointerface changes.cmd/devbox/umount.go (1)
21-30: Context-aware API migration looks correct.The switch to
mgr.AutodetectProject(ctx, ...)andmgr.AutodetectSource(ctx, ...)with result struct unpacking is consistent. Usingcontext.Background()in the flag completion callback (line 68) is reasonable since completions don't benefit from cancellation.Also applies to: 39-47, 68-73
cmd/devbox/mount.go (2)
50-55: Clear mount path resolution logic.The fallback from explicit
targetPathtoresult.LocalPathis straightforward and the intent is clear.
22-31: Context-aware API migration is consistent.The migration to
mgr.AutodetectProjectandmgr.AutodetectSourcewith result struct unpacking follows the established pattern. Shell completion usescontext.Background()appropriately.Also applies to: 40-48, 75-80
internal/git/mock_Service.go (1)
1-395: Autogenerated mock - no manual changes needed.This is mockery-generated code for the
Serviceinterface. Ensure regeneration if the interface changes.internal/pkg/fs/mock_FileSystem.go (1)
1-301: Autogenerated mock — looks good.Standard mockery-generated mock implementing the
FileSysteminterface. The generated code correctly handles all interface methods with proper type assertions and panic guards for missing return values.internal/pkg/fs/mock_DirEntry.go (1)
1-228: Autogenerated mock — looks good.Standard mockery-generated mock for
DirEntryinterface. Correctly usesiofsalias forio/fsto avoid package name collision with the localfspackage.internal/manager/manager.go (6)
35-53: Clean dependency injection pattern.The Manager struct with injectable
gitFactory,fs,listFn, andloadFnfields enables unit testing without mocking global state. The self-referential function fields (m.listFn = m.list) is a reasonable pattern for swapping implementations in tests.
482-525: Good defensive coding in Init.Proper input validation with
validNameRegexprevents path traversal. The cleanup function ensures partial state is removed on failure. The_ = m.fs.RemoveAll()pattern is appropriate for best-effort cleanup where failure shouldn't mask the original error.
428-445: Correct path prefix matching.Using component-based comparison (
strings.Spliton separator) rather than string prefix is the right approach — prevents false positives like./sources/foomatching./sources/foobar. Edge cases handled properly.
55-112: Well-structured three-step autodetection.The detection follows the documented process (local mount → git remote → manifest repo) with proper ambiguity handling. Error messages are descriptive and help users understand why detection failed.
270-301: Potential issue:localPathtakes last match value.When multiple services use the same source,
localPathis reassigned in each iteration (lines 286, 296). The final value depends on map iteration order, which is non-deterministic. If all matching services should yield the samelocalPath, this is fine. Otherwise, consider verifying consistency or documenting the expected behavior.
598-605: Clean utility function with sorted output.
mapKeyscorrectly provides deterministic ordering. Consider reusing this inGetLocalMountCandidatesandGetLocalMountsfor consistency.
- Fix misleading error messages in init.go and umount.go - Add missing returns after error channel send in ps.go (goroutine leak) - Wrap error with context in update.go for consistency - Use app.SourcesDir constant instead of hardcoded string - Add sorting for deterministic output in GetLocalMountCandidates/GetLocalMounts - Return interface type from git.New() for better abstraction - Add comment about structural typing in fs.go 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
internal/git/git.go (2)
128-132: Error chain lost - missing%wverb.
GetInforeturns an error without wrapping the originalerr. This breaks error unwrapping for callers.Suggested fix
func (s *svc) GetInfo(ctx context.Context) (*CommitInfo, error) { out, err := s.runner.Run(ctx, "git", "-C", s.targetPath, "log", "-1", "--pretty=format:%H%n%aN%n%ad%n%s") if err != nil { - return nil, fmt.Errorf("failed to get commit info: %s", out) + return nil, fmt.Errorf("failed to get commit info: %s: %w", out, err) }
91-109: Inconsistent error format string style.These errors use
%s %w(space before%w) while others like line 43, 80, 86 use%s\n%wor proper colon separation. Pick one style for consistency. Typically": %w"is idiomatic.Example normalization
- return fmt.Errorf("failed to init sparse-checkout: %s %w", out, err) + return fmt.Errorf("failed to init sparse-checkout: %s: %w", out, err)
♻️ Duplicate comments (1)
internal/manager/manager.go (1)
455-459: Silent error swallowing persists - consider propagating or logging.
ReadDirerrors are still silently ignored, returning an empty slice. This hides potential issues (permission denied, missing directory). If changing the signature is difficult, at minimum log the error for debugging.Suggested fix - return error
-func (m *Manager) list(filter string) []string { +func (m *Manager) list(filter string) ([]string, error) { folders, err := m.fs.ReadDir(app.AppDir) if err != nil { - return []string{} + return nil, fmt.Errorf("failed to read app directory: %w", err) }This would require updating
listFntype and callers, but provides better error visibility.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (7)
cmd/devbox/init.gocmd/devbox/ps.gocmd/devbox/umount.gocmd/devbox/update.gointernal/git/git.gointernal/manager/manager.gointernal/pkg/fs/fs.go
🧰 Additional context used
📓 Path-based instructions (3)
internal/**/*.go
⚙️ CodeRabbit configuration file
internal/**/*.go: Core packages providing project functionality:
- project/: Project configuration, Docker Compose extensions (x-devbox-*)
- manager/: Project/service autodetection from current directory
- git/: Git operations (clone, sparse checkout, sync)
- cert/: SSL certificate generation
- hosts/: /etc/hosts management with project-scoped markers
- table/: CLI table output formatting
Review for:
- Clean interfaces and proper encapsulation
- Error wrapping with context
- No interface{} - use 'any' instead (enforced by linter)
- YAGNI principle - no speculative features or premature abstractions
- Security considerations for host file and certificate operations
Files:
internal/git/git.gointernal/pkg/fs/fs.gointernal/manager/manager.go
cmd/devbox/**/*.go
⚙️ CodeRabbit configuration file
cmd/devbox/**/*.go: This directory contains CLI commands using Cobra framework.
Each command is in a separate file with an init() function that registers via root.AddCommand().Review for:
- Proper error handling with context wrapping (fmt.Errorf with %w)
- Consistent command structure following existing patterns
- Appropriate use of runWrapper for context handling
- Clear, concise command descriptions
- No over-engineering - only implement what's needed
Files:
cmd/devbox/init.gocmd/devbox/ps.gocmd/devbox/umount.gocmd/devbox/update.go
internal/manager/**/*.go
⚙️ CodeRabbit configuration file
internal/manager/**/*.go: Project autodetection with three-step process:
- Check if directory is a local mount of any project
- Match Git remote URL + path against project source definitions
- Check if directory is the project's manifest repository
Review for edge cases in path matching and Git remote detection.
Files:
internal/manager/manager.go
🧬 Code graph analysis (4)
internal/git/git.go (3)
internal/git/structs.go (1)
CommitInfo(3-8)internal/git/exec.go (1)
CommandRunner(10-13)internal/manager/manager.go (1)
New(43-53)
internal/pkg/fs/fs.go (2)
internal/git/git.go (1)
New(28-33)internal/manager/manager.go (1)
New(43-53)
cmd/devbox/umount.go (1)
internal/manager/manager.go (1)
AutodetectSourceForUmount(23-23)
internal/manager/manager.go (5)
internal/git/git.go (2)
Service(11-19)New(28-33)internal/pkg/fs/fs.go (2)
FileSystem(9-15)New(52-54)internal/project/project.go (2)
Project(24-35)New(50-107)internal/git/normalizer.go (1)
NormalizeURL(21-60)internal/app/const.go (4)
SourcesDir(13-13)AppDir(9-9)EnvFile(15-15)StateFile(14-14)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: E2E Tests
🔇 Additional comments (21)
internal/git/git.go (2)
11-22: Interface and compile-time check look good.Clean interface definition with appropriate method signatures. The
var _ Service = (*svc)(nil)compile-time assertion is idiomatic Go for ensuring interface compliance.
28-33: Returning interface from constructor is correct for this use case.Returning
ServicefromNew()enables the dependency injection pattern used byManager. This aligns with thegitFactoryfield ininternal/manager/manager.go(lines 42-52).cmd/devbox/ps.go (2)
22-25: Context propagation to AutodetectProject is correct.The call now properly passes
ctxto enable cancellation and timeout propagation through the autodetection flow.
56-65: Good fix - early returns prevent goroutine leaks.The added
returnstatements after sending toerrChensure the goroutine exits instead of continuing the infinite loop after an error or empty result. This prevents resource leaks.cmd/devbox/umount.go (3)
21-30: Context-aware autodetection in completion handler looks good.Properly propagates context to
AutodetectProjectand uses the newAutodetectSourcereturning*SourceDetectionResult.
44-55: Error message correctly updated and result struct usage is proper.The error message now says "unmount" (previously flagged). Using
result.Sourcesandresult.AffectedServicesfrom the newSourceDetectionResultstruct is correct.
68-73: Completion function usescontext.Background()- acceptable for shell completions.Shell completion functions often can't access a request-scoped context, so
context.Background()is a reasonable fallback here.cmd/devbox/update.go (1)
33-36: Error wrapping now consistent with the rest of the function.The autodetect error is properly wrapped with context, matching the pattern used elsewhere in this handler (lines 39-54).
cmd/devbox/init.go (2)
33-35: Error message corrected.Changed from "failed to list projects" to "failed to initialize project" - now accurately describes the operation.
47-51: Context propagation through runInit is correct.The function signature properly accepts
context.Contextand passes it tomgr.Init. Error wrapping is appropriate.internal/pkg/fs/fs.go (3)
9-15: Clean FileSystem interface for dependency injection.The interface surface is minimal and appropriate for the manager's needs. Good adherence to interface segregation.
43-46: Structural typing comment added as previously suggested.The comment clarifies the implicit interface satisfaction between
os.FileInfoand the customFileInfointerface.
48-54: Compile-time check and constructor are idiomatic.
var _ FileSystem = (*OSFileSystem)(nil)ensures interface compliance at compile time. Constructor returns concrete type, allowing flexibility for callers.internal/manager/manager.go (8)
26-31: SourceDetectionResult struct is well-documented.Clear field names with comments explaining each field's purpose. Good practice for exported types.
42-53: Manager constructor properly initializes dependencies.Default implementations are injected for
gitFactoryandfs, with internal function pointers (listFn,loadFn) enabling test overrides. This is a clean pattern for testability.
55-112: AutodetectProject implements a clear three-step detection strategy.The detection order (local mount → source remote → project repo) is logical. Each step checks for ambiguity and returns appropriate errors. Context is properly propagated.
206-209: Hardcoded path replaced with app.SourcesDir constant.Now uses
"./"+app.SourcesDir+"/"instead of hardcoded"./sources/", addressing the previous review feedback.
582-583: Sorting added for deterministic output - good fix.Both
GetLocalMountCandidatesandGetLocalMountsnow callsort.Strings()before returning, ensuring consistent CLI output and stable test results.Also applies to: 596-597
600-607: mapKeys helper includes sorting - deterministic output.The helper properly sorts results before returning, which ensures all callers get consistent ordering.
420-425: cwdMatchesServiceSubpath handles edge cases correctly.Properly handles empty
serviceSubpath(root case) by checking for""or"."incwdRelPath. ThepathStartsWithdelegation for non-empty subpaths is appropriate.
428-445: pathStartsWith uses proper path component matching.Uses
filepath.Cleanand splits by separator to avoid false positives from string prefix matching (e.g.,foo/barwouldn't incorrectly matchfoo/barbaz).
Changed list() to return ([]string, error) to properly propagate ReadDir errors instead of silently returning an empty slice. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
9e146af to
00705c9
Compare
Summary
Managertype for better testability and dependency injectionServiceinterface to git package andFileSystemabstraction ininternal/pkg/fsfor improved testabilitySummary by CodeRabbit
Refactoring
Tests
✏️ Tip: You can customize this high-level summary in your review settings.