github.com/snyk/vervet/v5@v5.11.1-0.20240202085829-ad4dd7fb6101/config/linter.go (about) 1 package config 2 3 import "fmt" 4 5 const ( 6 defaultOpticCIImage = "snyk/sweater-comb:latest" 7 ) 8 9 var defaultSpectralExtraArgs = []string{"--format", "text"} 10 11 // Linters defines a named map of Linter instances. 12 // NOTE: Linters are deprecated and may be removed in v5. 13 type Linters map[string]*Linter 14 15 // Linter describes a set of standards and rules that an API should satisfy. 16 // NOTE: Linters are deprecated and may be removed in v5. 17 type Linter struct { 18 Name string `json:"-"` 19 Description string `json:"description,omitempty"` 20 Spectral *SpectralLinter `json:"spectral"` 21 SweaterComb *OpticCILinter `json:"sweater-comb"` 22 OpticCI *OpticCILinter `json:"optic-ci"` 23 } 24 25 func (l *Linter) validate() error { 26 nlinters := 0 27 if l.Spectral != nil { 28 nlinters++ 29 } 30 if l.SweaterComb != nil { 31 nlinters++ 32 } 33 if l.OpticCI != nil { 34 nlinters++ 35 } 36 switch nlinters { 37 case 0: 38 return fmt.Errorf("missing configuration (linters.%s)", l.Name) 39 case 1: 40 return nil 41 default: 42 return fmt.Errorf("a linter may only be of one type (linters.%s)", l.Name) 43 } 44 } 45 46 // SpectralLinter identifies a Linter as a collection of Spectral rulesets. 47 // NOTE: Linters are deprecated and may be removed in v5. 48 type SpectralLinter struct { 49 50 // Rules are a list of Spectral ruleset file locations 51 Rules []string `json:"rules"` 52 53 // Script identifies the path to the spectral script to use for linting. 54 // If not defined linting will look for spectral-cli on $PATH. 55 Script string `json:"script"` 56 57 // ExtraArgs may be used to pass extra arguments to `spectral lint`. If not 58 // specified, the default arguments `--format text` are used when running 59 // spectral. The `-r` flag must not be specified here, as this argument is 60 // automatically added from the Rules setting above. 61 // 62 // See https://meta.stoplight.io/docs/spectral/ZG9jOjI1MTg1-spectral-cli 63 // for the options supported. 64 ExtraArgs []string `json:"extraArgs"` 65 } 66 67 // OpticCILinter identifies an Optic CI Linter, which is distributed as 68 // a self-contained docker image. 69 // NOTE: Linters are deprecated and may be removed in v5. 70 type OpticCILinter struct { 71 // Image identifies the Optic CI docker image to use for linting. 72 Image string 73 74 // Script identifies the path to the Optic CI script to use for linting. 75 // Mutually exclusive with Image; if Script is specified Docker will not be 76 // used. 77 Script string 78 79 // Original is where to source the original version of an OpenAPI spec file 80 // when comparing. If empty, all changes are assumed to be new additions. 81 Original string `json:"original,omitempty"` 82 83 // Proposed is where to source the proposed changed version of an OpenAPI 84 // spec file when comparing. If empty, this is assumed to be the 85 // local working copy. 86 Proposed string `json:"proposed,omitempty"` 87 88 // Debug turns on debug logging. 89 Debug bool `json:"debug,omitempty"` 90 91 // Deprecated: CIContext is no longer used and should be removed in the 92 // next major release. 93 CIContext string `json:"-"` 94 95 // Deprecated: UploadResults is no longer used and should be removed in the 96 // next major release. Uploading optic-ci comparison results to Optic 97 // Cloud is determined by the presence of environment variables. 98 UploadResults bool `json:"-"` 99 100 // Exceptions are files that are excluded from CI checks. This is an escape 101 // hatch of last resort, if a file needs to land and can't pass CI yet. 102 // They are specified as a mapping from project relative path to sha256 103 // sums of that spec file that is exempt. This makes the exception very 104 // narrow -- only a specific version of a specific file is skipped, after 105 // outside review and approval. 106 Exceptions map[string][]string 107 108 // ExtraArgs may be used to pass extra arguments to `optic-ci`. 109 ExtraArgs []string `json:"extraArgs"` 110 } 111 112 func (l Linters) init() error { 113 for name, linter := range l { 114 if linter == nil { 115 return fmt.Errorf("missing linter definition (linters.%s)", name) 116 } 117 linter.Name = name 118 if err := linter.validate(); err != nil { 119 return err 120 } 121 if linter.Spectral != nil && len(linter.Spectral.ExtraArgs) == 0 { 122 linter.Spectral.ExtraArgs = defaultSpectralExtraArgs 123 } 124 if linter.SweaterComb != nil { 125 if linter.SweaterComb.Image == "" && linter.SweaterComb.Script == "" { 126 linter.SweaterComb.Image = defaultOpticCIImage 127 } 128 } 129 if linter.OpticCI != nil { 130 if linter.OpticCI.Image == "" && linter.OpticCI.Script == "" { 131 linter.OpticCI.Image = defaultOpticCIImage 132 } 133 } 134 } 135 return nil 136 }