feat(linter): context-scoped needs:/dependencies: cross-checks
ci / vet, staticcheck, test, build (push) Failing after 1m54s
release / Build and publish release (push) Successful in 1m6s

When glint check runs in single-context mode (--branch, --tag, --source,
or --var), jobs that resolve to JobSkipped against that context are now
excluded from needs: and dependencies: cross-job checks (GL027-GL031).
This eliminates false-positive errors for jobs intentionally gated to
specific pipeline events (e.g. a deploy job with rules:if: CI_COMMIT_TAG
no longer triggers GL027 on branch pipelines).

linter.Lint now accepts a skipped map[string]bool (nil = check all jobs);
checkNeeds and checkDependencies skip jobs present in the map. Multi-context
mode (--context) passes nil, so all jobs are checked regardless of context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-25 00:25:09 +02:00
parent 3b0bcb72d3
commit 416659ffd8
12 changed files with 164 additions and 20 deletions
+26 -1
View File
@@ -6,6 +6,31 @@ import (
"git.k3nny.fr/glint/internal/model"
)
// TestCheckNeeds_SkippedJob verifies that a skipped job's needs: violations are suppressed.
func TestCheckNeeds_SkippedJob(t *testing.T) {
p := &model.Pipeline{
Stages: []string{"build", "deploy"},
Jobs: map[string]model.Job{
"skipped-job": {
Name: "skipped-job",
Stage: "build",
Script: []any{"echo"},
Needs: []any{"nonexistent-job"},
},
},
}
// Without skipping: should report unknown needs.
withoutSkip := checkNeeds(p, nil)
if len(withoutSkip) == 0 {
t.Fatal("expected GL027 without skipped set, got none")
}
// With job skipped: no findings.
withSkip := checkNeeds(p, map[string]bool{"skipped-job": true})
if len(withSkip) != 0 {
t.Errorf("expected no findings for skipped job, got %v", withSkip)
}
}
// TestCheckNeeds_StageOrder verifies that a job needing a job in a later stage
// produces RuleNeedsStageOrder (line 64-76 in needs.go).
func TestCheckNeeds_StageOrder(t *testing.T) {
@@ -25,7 +50,7 @@ func TestCheckNeeds_StageOrder(t *testing.T) {
},
},
}
findings := checkNeeds(p)
findings := checkNeeds(p, nil)
var gotStageOrder bool
for _, f := range findings {
if f.Rule == RuleNeedsStageOrder {