Files
glint/internal/model/pipeline.go
T
k3nny 8dc30d9207
ci / vet, staticcheck, test, build (push) Failing after 2m4s
release / Build and publish release (push) Successful in 1m12s
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>
2026-06-25 00:33:52 +02:00

104 lines
4.1 KiB
Go

package model
// Pipeline represents the top-level structure of a .gitlab-ci.yml file.
// Unknown top-level keys are collected into Jobs.
type Pipeline struct {
SourceFile string // path of the root pipeline file; set by Parse
Stages []string `yaml:"stages"`
Variables map[string]any `yaml:"variables"` // string or {value,description,options} map
Default *DefaultConfig `yaml:"default"`
Include []any `yaml:"include"`
Workflow *Workflow `yaml:"workflow"`
// Jobs holds every non-reserved top-level key (i.e. job definitions).
Jobs map[string]Job `yaml:"-"`
RawJobs map[string]map[string]any `yaml:"-"` // pre-resolution raw maps, used by the resolver
// Suppressions maps job names to lists of suppressed rule IDs parsed from
// "# glint: ignore RULE" comments in the pipeline YAML. Only populated for
// the root pipeline file (not for included templates).
Suppressions map[string][]string `yaml:"-"`
}
// SetJobOrigin sets the File field on all jobs that don't already have one.
// Called after ParseBytes to record which file each job came from.
func (p *Pipeline) SetJobOrigin(file string) {
for name, j := range p.Jobs {
if j.File == "" {
j.File = file
}
p.Jobs[name] = j
}
}
type DefaultConfig struct {
Image any `yaml:"image"` // string or {name,pull_policy,...} map
BeforeScript any `yaml:"before_script"` // []string or string (block scalar)
AfterScript any `yaml:"after_script"` // []string or string
Cache any `yaml:"cache"`
Artifacts any `yaml:"artifacts"`
Retry any `yaml:"retry"`
Timeout string `yaml:"timeout"`
Tags []string `yaml:"tags"`
}
type Workflow struct {
Rules []Rule `yaml:"rules"`
}
type Job struct {
Name string // set by parser, not from YAML
File string // source file; set by Parse / resolver
Line int // line of the job key in its source file; set by parser
Stage string `yaml:"stage"`
Script any `yaml:"script"` // []string or string (block scalar)
Run any `yaml:"run"` // alternative to script (CI steps)
BeforeScript any `yaml:"before_script"` // []string or string
AfterScript any `yaml:"after_script"` // []string or string
Image any `yaml:"image"`
Services []any `yaml:"services"`
Variables map[string]any `yaml:"variables"` // string or {value,description,options} map
Rules []Rule `yaml:"rules"`
Only any `yaml:"only"`
Except any `yaml:"except"`
Needs []any `yaml:"needs"`
Dependencies []string `yaml:"dependencies"`
Artifacts any `yaml:"artifacts"`
Cache any `yaml:"cache"`
Tags []string `yaml:"tags"`
Allow any `yaml:"allow_failure"`
When string `yaml:"when"`
StartIn string `yaml:"start_in"`
Timeout string `yaml:"timeout"`
Retry any `yaml:"retry"`
Parallel any `yaml:"parallel"`
Extends any `yaml:"extends"`
Trigger any `yaml:"trigger"`
Inherit any `yaml:"inherit"`
Environment any `yaml:"environment"`
Release any `yaml:"release"`
Coverage string `yaml:"coverage"`
Secrets any `yaml:"secrets"`
IDTokens any `yaml:"id_tokens"`
Pages any `yaml:"pages"`
Interruptible any `yaml:"interruptible"`
ResourceGroup string `yaml:"resource_group"`
}
type Rule struct {
If string `yaml:"if"`
When string `yaml:"when"`
Changes any `yaml:"changes"` // []string or {paths,compare_to} map
Exists any `yaml:"exists"` // []string or map form
Variables map[string]any `yaml:"variables"` // set/override variables when rule matches (GitLab CI 15.0+)
Needs []any `yaml:"needs"` // override needs: when this rule matches (GitLab CI 16.4+)
}
// ReservedKeys are top-level GitLab CI keys that are NOT job definitions.
var ReservedKeys = map[string]bool{
"stages": true,
"variables": true,
"default": true,
"include": true,
"workflow": true,
"spec": true, // CI component spec header
}