Repository navigation
feat(lint): add atmos lint stacks command with 10 built-in quality rules - #2203
Open
RB (nitrocode) with Copilot wants to merge 50 commits into
Open
RB (nitrocode) with Copilot wants to merge 50 commits into
RB (nitrocode) with Copilot wants to merge 50 commits into
Conversation
Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Add Atmos Stack YAML Linter functionality
feat(lint): add Mar 15, 2026
atmos lint stacks command with 10 built-in quality rules
Dependency Review✅ No vulnerabilities or license issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
This comment was marked as outdated.
This comment was marked as outdated.
…dding lint command Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
…os lint stacks Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Item 1: Disambiguate stack name → file mapping - buildStackNameToFileIndex now returns map[string][]string (basename → []files) - Add buildStackStemToFileIndex returning map[string]string (full stem → file) - LintContext gains StackNameToFileIndex ([]string) and StackStemToFile (string) - L-08 uses new resolveFileForStack() that prefers StackStemToFile, then disambiguates basename collisions (prefers deploy/ dir), else omits File Item 2: Normalize --rule filter input - ExecuteLintStacksCmd now calls strings.ToUpper + TrimSpace on each rule ID - Empty tokens after trimming are dropped - Users can now pass "l-02" or "L-02" interchangeably Item 3: Drop unmatched globs from results - expandGlobImports no longer appends the literal pattern when a glob produces no file matches; it is silently dropped with a debug log - buildImportGraph skips adding an entry when the expanded result is empty - This prevents phantom references in L-07 and false depth inflation in L-03 Item 4: Standardize relative paths in L-03 findings - L-03 now converts File to a path relative to ctx.StacksBasePath (mirrors L-07's displayPath convention so all findings are consistently formatted) Item 5: Docs update in stacks.go - Long description now documents case-insensitive --rule, and the fail-closed behavior of --stack when no manifest stem matches Tests: - TestBuildStackNameToFileIndexCollision: assert collision → []string + stem index - TestLintRuleFilterNormalization: verify upper/lower/mixed/empty normalization - TestGlobNoMatchDroppedFromL03Depth: assert unmatched glob is dropped - TestL03RelativePathOutput: assert File field is relative to StacksBasePath - Update TestBuildImportGraph "no matches" to expect empty (not literal) - Update TestBuildStackNameToFileIndex for new []string type - Update TestL08FileAttributionWithIndex for new StackStemToFile + []string fields Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com> Agent-Logs-Url: https://github.com/cloudposse/atmos/sessions/ebe8551a-7679-4d09-9b9f-bf357998b8de
…attern doc comment Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com> Agent-Logs-Url: https://github.com/cloudposse/atmos/sessions/ebe8551a-7679-4d09-9b9f-bf357998b8de
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
…IDs, drop missing non-globs, parity test, empty L-08 File
Item 1: Scope L-07 when --stack has no imports
- Remove `len(importGraph) > 0` guard; always scope AllStackFiles when stackFilter != ""
- When importGraph is empty (root has no imports), set AllStackFiles = keys(rawStackConfigs)
- Test: TestScopeStackFilesNoImports
Item 2: Zero-pad single-digit rule IDs
- "l-7" → "L-07" via new isDigitOnly() helper + fmt.Sprintf("L-%02s", numPart)
- Update TestLintRuleFilterNormalization to test zero-padding
- New test: TestRuleIDZeroPadNormalization
- Update cmd/lint/stacks.go Long description
Item 3: Drop missing non-glob imports
- resolveNonGlobImport returns "" when no file on disk (was: best-effort fallback path)
- expandGlobImports skips "" returns
- Test: TestMissingNonGlobDroppedFromGraph
Item 4: Normalization parity test
- TestRulesRelNormParityWithL07: corpus test for exec's rulesRelNorm against golden values
- TestRelNormCorpusGolden: parity test in pkg/lint/rules using ExportedRelNorm
Item 5: L-08 empty File when unresolved
- stackNameToFile: return "" for bare stack name with empty basePath (was: returned stack name)
- Update TestStackNameToFile to match new behavior
- New test: TestL08EmptyFileWhenUnresolved
Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
Agent-Logs-Url: https://github.com/cloudposse/atmos/sessions/e3b42b29-53eb-476a-aa52-5f2f6a8e2c80
…DigitOnly comment, blank line style Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com> Agent-Logs-Url: https://github.com/cloudposse/atmos/sessions/e3b42b29-53eb-476a-aa52-5f2f6a8e2c80
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
…t, mergedLintConfig CohesionMaxGroups Item 4 (pathnorm package): - Create pkg/lint/pathnorm with NormalizeRelNoExt(path, base) as single canonical path normalization shared between exec and L-07 - Refactor internal/exec/lint_stacks.go to use pathnorm instead of local rulesRelNorm (eliminates duplication) - Refactor pkg/lint/rules/l07_orphaned_file.go: relNorm and normalizeForComparison now delegate to pathnorm.NormalizeRelNoExt - Add parity test TestPathnormParityWithRelNorm in rules_test.go - Add pathnorm_test.go with corpus golden tests Item 5a (concernGroup [-_/]): - Expand concernGroup in l05_cohesion.go to split on /, -, _ in priority order (path separator > first separator) - "network/vpc" → "network", "vpc_endpoints" → "vpc" - Add TestConcernGroupSeparators with 11 test cases Item 5b (mergedLintConfig CohesionMaxGroups): - Remove defaultCohesionThreshold const from l05_cohesion.go - Add CohesionMaxGroups default (3) to mergedLintConfig in exec - L-05 reads ctx.LintConfig.CohesionMaxGroups directly with safety guard - Update TestMergedLintConfig to assert CohesionMaxGroups=3 default - Add sub-test for CohesionMaxGroups not overridden when set Also: fix TestResolveNonGlobImport to expect "" (not fallback path) for missing non-glob imports (behavior change from phase 2) Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com> Agent-Logs-Url: https://github.com/cloudposse/atmos/sessions/57b2e063-b57d-444f-b355-db94975612a3
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
…roader patterns Item 1 (resolveNonGlobImport os.Stat for .yaml/.yml): - When importPath already has .yaml/.yml extension, probe disk via os.Stat before returning the path to drop phantom edges from mistyped/missing explicit-extension imports - Prevents L-03 depth inflation from e.g. "catalog/phantom.yaml" that doesn't exist - Update test "relative import with .yaml extension" to create file on disk - Add tests: missing .yaml → "", missing .yml → "" Item 2 (normalizeRuleID broader patterns): - Extract normalizeRuleID() helper from inline rule-parse logic - Handles all forms: "7", "L7", "l-7", "L-7", "L-07" → canonical "L-07" - Custom/unknown IDs pass through unchanged (upper-case) - Update ExecuteLintStacksCmd to use normalizeRuleID helper Item 3 (new tests): - TestL03DepthIgnoresMissingExtImport: explicit .yaml import that doesn't exist is dropped from import graph (no phantom edge, no L-03 inflation) - TestNormalizeRuleID: 16 cases covering all input forms - Extend TestLintRuleFilterNormalization: "7, L7, l-7" sub-test via normalizeRuleID Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com> Agent-Logs-Url: https://github.com/cloudposse/atmos/sessions/d1f7d81d-4e63-4060-9c9b-63940d355d4d
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Contributor
|
💥 This pull request now has conflicts. Could you fix it @Copilot? 🙏 |
1 similar comment
Contributor
|
💥 This pull request now has conflicts. Could you fix it @Copilot? 🙏 |
This branch was successfully deployed
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.
pkg/lint/pathnorm,concernGroup [-_/],mergedLintConfig CohesionMaxGroupsresolveNonGlobImport: addos.Statcheck for explicit.yaml/.ymlpaths (prevents phantom edges)normalizeRuleIDbroader patterns: handles7,L7,l-7→L-07; extracted as named helperTestL03DepthIgnoresMissingExtImport,TestNormalizeRuleID(16 cases), extendedTestLintRuleFilterNormalizationpkg/lint/...,internal/exec,cmd/lint💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.