02d8e63a98
Adds project-level configuration and per-job suppression directives:
.glint.yml (searched from pipeline dir up to the git root):
- ignore: [GL007, GL032] — suppress rules globally for the project
- severity: {GL004: warning} — override rule severity (error/warning/ignore)
- stages: [quality] — extra stages beyond the pipeline's stages: block
- token: / url: / cache_dir: — defaults for flags; lower priority than
CLI flags and environment variables
Inline suppression (# glint: ignore):
- Place "# glint: ignore GL007" immediately before a job definition to
suppress that rule for the specific job only
- Multiple rules: "# glint: ignore GL007, GL032" (comma or space separated)
- Wildcard: "# glint: ignore all" suppresses every finding for the job
- Suppressions are scoped to the annotated job; pipeline-level findings
are unaffected
- Parsed from yaml.Node head/line comments in the first parse pass;
stored in Pipeline.Suppressions (root file only, not includes)
New packages: internal/config (Load, walk-up search, .git boundary stop)
New files: cmd/glint/filter.go (applyConfig, isSuppressed helpers)
Tests: config_test.go, parser_suppress_test.go, filter_test.go
Validate fixtures: testdata/config_ignored/, config_severity/, config_suppress/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
103 lines
4.0 KiB
Go
103 lines
4.0 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+)
|
|
}
|
|
|
|
// 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
|
|
}
|