feat(linter): rules:needs: validation (GL044)
Add GL044 to validate jobs listed in rules:needs: overrides (GitLab CI 16.4+). rules:needs: lets a specific rule override the job's top-level needs: list; any referenced job must exist in the pipeline. Unknown jobs produce an error; optional: true entries produce a warning, matching the GL027 behaviour for top-level needs:. Cross-pipeline needs and skipped jobs (when a context is active) are excluded from checking. Implementation: - model.Rule gains a Needs []any field (yaml:"needs") - checkRulesNeeds(p, skipped) added to needs.go; wired into Lint - GL044 / RuleRulesNeedsUnknown added to rules.go and explain.go - 6 unit tests + 2 testdata fixtures; task validate updated Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -85,6 +85,44 @@ func checkNeeds(p *model.Pipeline, skipped map[string]bool) []Finding {
|
||||
return findings
|
||||
}
|
||||
|
||||
// checkRulesNeeds validates rules:needs: entries across all jobs. Each entry
|
||||
// in a rule's needs: list must reference a job that exists in the pipeline.
|
||||
// Cross-pipeline needs (maps with a "pipeline" key) are ignored. Skipped jobs
|
||||
// are excluded from checking (same semantics as top-level needs: via GL027).
|
||||
func checkRulesNeeds(p *model.Pipeline, skipped map[string]bool) []Finding {
|
||||
var findings []Finding
|
||||
for name, job := range p.Jobs {
|
||||
if skipped[name] {
|
||||
continue
|
||||
}
|
||||
for i, rule := range job.Rules {
|
||||
if len(rule.Needs) == 0 {
|
||||
continue
|
||||
}
|
||||
for _, entry := range parseNeedEntries(rule.Needs) {
|
||||
if _, exists := p.Jobs[entry.job]; !exists {
|
||||
sev := Error
|
||||
if entry.optional {
|
||||
sev = Warning
|
||||
}
|
||||
findings = append(findings, Finding{
|
||||
Severity: sev,
|
||||
Rule: RuleRulesNeedsUnknown,
|
||||
Job: name,
|
||||
File: job.File,
|
||||
Line: job.Line,
|
||||
Message: fmt.Sprintf(
|
||||
"rules[%d].needs: references unknown job %q",
|
||||
i, entry.job,
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return findings
|
||||
}
|
||||
|
||||
// parseNeedEntries extracts needs entries from a needs: list, preserving the
|
||||
// optional flag. Each element is a plain string (job name) or a map with a
|
||||
// "job" key. Cross-pipeline needs (maps with a "pipeline" key) are skipped.
|
||||
|
||||
Reference in New Issue
Block a user