fix: make lint results independent of how the target is named#60
Merged
Conversation
Directory arguments were passed through almost verbatim, so whether a target was named relatively or absolutely leaked past the reported paths into rule verdicts and internal path resolution. - id-dir-mismatch derived the containing directory's name from the reported path, which has no directory component when the target is named "." — the default. Linting a Feature or Template from inside it therefore always reported the id as mismatched. The name now comes from the directory's own location, handed to rules as linter.Dir. - Compose resolution assumed the lint root was absolute, which only held when the target was named that way; a Dockerfile outside the configuration directory could otherwise be displayed as if inside it. - The github format emitted absolute paths, which GitHub cannot place on a diff. Paths inside the working directory are now reported relative to it, with "/" separators. - Arguments naming the same directory twice are linted once. - Errors name the path once, cleaned, and say what to pass when given a file rather than a directory. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KsXG8rvSVXzUGYMe4AR5mi
Paths were still kept in three representations — the spelling given on the command line, the absolute location, and the github format's own base directory — so each function had to know which space its path was in, and conversions like configDirName existed only to move between them. Opening the lint root on its absolute location makes every path derived from it absolute for free: os.Root.OpenRoot names a sub-root by joining onto its parent's name, so the .devcontainer sub-root and the paths built from it are absolute too. Only the rendering for the reader is left, which absPath.String does — relative to the working directory when the path is inside it, absolute otherwise. Being a Stringer, it renders in error messages without any call site having to ask for it. This drops lintRoot, configDirName, lintDir's filepath.Abs, and the github format's BaseDir. Findings now name a file the same way however the lint target was named, so an absolute target under the working directory is reported relative to it. The Dockerfile reference a Compose build resolves keeps its own base, the configuration directory: it identifies a contributor inside the merged configuration, so it must not depend on where decolint was run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KsXG8rvSVXzUGYMe4AR5mi
dedupePaths resolved every argument to decide whether it duplicated an earlier one, then threw the result away and returned the original spelling, leaving lintPath to resolve the same argument again. Options.Paths now holds the resolved directories, so lintPath takes them as they are. Deduplication compares the resolved values themselves, and the rule about which spelling to keep goes away with them: rendering no longer depends on how a directory was named, so there is nothing to choose between. Resolving in parseOptions means an argument that cannot be resolved fails there rather than mid-lint, which also makes -version and -rules fail when the working directory has been deleted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KsXG8rvSVXzUGYMe4AR5mi
…arsed Holding the resolved directories in Options gave parseOptions a dependency on the working directory and an error that has nothing to do with parsing a command line, which is all Options is meant to describe. It also let a deleted working directory fail -version and -rules, which name no directory at all. Options.Paths goes back to the arguments as named, and runLint resolves and deduplicates them before linting. Each target is still resolved once: lintPath keeps taking an absPath and does not resolve anything itself. resolvePaths moves next to absPath, so the whole of the CLI's path resolution now sits in one file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KsXG8rvSVXzUGYMe4AR5mi
resolvePaths walked the arguments to build a slice that runLint then walked again, so resolving, deduplicating and linting now happen in the one loop over the arguments. Folding them together also settles how a target that cannot be resolved is treated. It used to abort the run before anything was written, while every other per-target failure is recorded and the remaining targets are linted — the posture lintDir already takes for a broken file. Resolution failures now join the same way, so a bad target no longer discards the findings of the good ones. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KsXG8rvSVXzUGYMe4AR5mi
The directory name a rule is handed comes from the file's location on disk rather than the path findings report it at. That was checked through id-dir-mismatch's message and the JSON output, tying the test to the only rule that reads the name. Observe it with a stub rule at lintPath instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Directory arguments were passed through almost verbatim, so whether a
target was named relatively or absolutely leaked past the reported paths
into rule verdicts and internal path resolution.
reported path, which has no directory component when the target is
named "." — the default. Linting a Feature or Template from inside it
therefore always reported the id as mismatched. The name now comes
from the directory's own location, handed to rules as linter.Dir.
when the target was named that way; a Dockerfile outside the
configuration directory could otherwise be displayed as if inside it.
a diff. Paths inside the working directory are now reported relative
to it, with "/" separators.
file rather than a directory.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01KsXG8rvSVXzUGYMe4AR5mi