Allow composition within command internal helpers
This commit is contained in:
@@ -358,6 +358,8 @@ fetch endpoint reports absence. Focused publication/wrapper tests pass.
|
||||
|
||||
### R10 — Medium: The boundary checker bans valid command-internal composition
|
||||
|
||||
Status: Resolved.
|
||||
|
||||
Category: Inadvertently strengthened architectural prohibition.
|
||||
|
||||
**Evidence:** [checkImportDirections](../../internal/apicheck/main.go), around
|
||||
@@ -381,6 +383,12 @@ turning current package inventory into a fixed future architecture.
|
||||
internal imports of command code and internal-helper imports of public facades
|
||||
remain rejected.
|
||||
|
||||
**Resolution:** The import checker identifies each executable’s internal helper
|
||||
subtree and permits collaboration inside it. Library-to-command imports,
|
||||
helper-to-controller imports, and internal-to-facade imports remain rejected.
|
||||
Positive and negative dependency fixtures and the actual compiled repository
|
||||
boundary checks pass.
|
||||
|
||||
## Remediation boundaries
|
||||
|
||||
Address these findings before treating the initial implementation as complete
|
||||
|
||||
@@ -112,7 +112,10 @@ func checkImportDirections(packages []listedPackage) error {
|
||||
continue
|
||||
}
|
||||
for _, imported := range pkg.Imports {
|
||||
if imported == modulePath || imported == modulePath+"/buildinfo" || strings.HasPrefix(imported, modulePath+"/cmd/") {
|
||||
commandDependency := strings.HasPrefix(imported, modulePath+"/cmd/")
|
||||
owner := commandInternalRoot(pkg.ImportPath)
|
||||
ownHelper := owner != "" && strings.HasPrefix(imported+"/", owner)
|
||||
if imported == modulePath || imported == modulePath+"/buildinfo" || commandDependency && !ownHelper {
|
||||
violations = append(violations, fmt.Sprintf("internal package %s imports public or command package %s", pkg.ImportPath, imported))
|
||||
}
|
||||
}
|
||||
@@ -150,8 +153,21 @@ func checkImportDirections(packages []listedPackage) error {
|
||||
}
|
||||
|
||||
func isInternalPackage(path string) bool {
|
||||
return strings.HasPrefix(path, modulePath+"/internal/") ||
|
||||
strings.HasPrefix(path, modulePath+"/") && strings.Contains(strings.TrimPrefix(path, modulePath), "/internal/")
|
||||
return strings.HasPrefix(path, modulePath+"/") &&
|
||||
(strings.Contains(strings.TrimPrefix(path, modulePath), "/internal/") || strings.HasSuffix(path, "/internal"))
|
||||
}
|
||||
|
||||
// commandInternalRoot identifies the helper subtree owned by one executable.
|
||||
func commandInternalRoot(path string) string {
|
||||
if !strings.HasPrefix(path, modulePath+"/cmd/") {
|
||||
return ""
|
||||
}
|
||||
relative := strings.TrimPrefix(path, modulePath+"/cmd/")
|
||||
owner, _, ok := strings.Cut(relative+"/", "/internal/")
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return modulePath + "/cmd/" + owner + "/internal/"
|
||||
}
|
||||
|
||||
func forbiddenRuntimeDependency(path string) bool {
|
||||
|
||||
@@ -182,3 +182,27 @@ func typecheckWithImporter(t *testing.T, fset *token.FileSet, path, source strin
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
|
||||
func TestCommandInternalCompositionPreservesLibraryBoundaries(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name, from, to string
|
||||
reject bool
|
||||
}{
|
||||
{"command helpers", "/cmd/releasekit/internal/cli/parser", "/cmd/releasekit/internal/cli/settings", false},
|
||||
{"other executable helpers", "/cmd/future/internal/parser", "/cmd/future/internal/settings", false},
|
||||
{"helper root", "/cmd/releasekit/internal", "/cmd/releasekit/internal/cli", false},
|
||||
{"controller uses facade", "/cmd/releasekit", "", false},
|
||||
{"library imports controller", "/internal/build", "/cmd/releasekit", true},
|
||||
{"library imports helper", "/internal/build", "/cmd/releasekit/internal/cli", true},
|
||||
{"helper imports facade", "/cmd/releasekit/internal/cli", "", true},
|
||||
{"helper imports runtime facade", "/cmd/releasekit/internal/cli", "/buildinfo", true},
|
||||
{"helper imports controller", "/cmd/releasekit/internal/cli", "/cmd/releasekit", true},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
err := checkImportDirections([]listedPackage{{ImportPath: modulePath + test.from, Imports: []string{modulePath + test.to}}})
|
||||
if (err != nil) != test.reject {
|
||||
t.Fatalf("dependency %s -> %s: %v", test.from, test.to, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user