dev: validate test configurations (#4520)

This commit is contained in:
Ludovic Fernandez 2024-03-18 13:25:52 +01:00 committed by GitHub
parent a5e2fd817e
commit e6f90f69f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 217 additions and 112 deletions

1
go.mod
View File

@ -85,6 +85,7 @@ require (
github.com/ryancurrah/gomodguard v1.3.0 github.com/ryancurrah/gomodguard v1.3.0
github.com/ryanrolds/sqlclosecheck v0.5.1 github.com/ryanrolds/sqlclosecheck v0.5.1
github.com/sanposhiho/wastedassign/v2 v2.0.7 github.com/sanposhiho/wastedassign/v2 v2.0.7
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
github.com/sashamelentyev/interfacebloat v1.1.0 github.com/sashamelentyev/interfacebloat v1.1.0
github.com/sashamelentyev/usestdlibvars v1.25.0 github.com/sashamelentyev/usestdlibvars v1.25.0
github.com/securego/gosec/v2 v2.19.0 github.com/securego/gosec/v2 v2.19.0

2
go.sum generated
View File

@ -466,6 +466,8 @@ github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9f
github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ=
github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc=
github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI=
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw=
github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ=
github.com/sashamelentyev/usestdlibvars v1.25.0 h1:IK8SI2QyFzy/2OD2PYnhy84dpfNo9qADrRt6LH8vSzU= github.com/sashamelentyev/usestdlibvars v1.25.0 h1:IK8SI2QyFzy/2OD2PYnhy84dpfNo9qADrRt6LH8vSzU=

View File

@ -385,15 +385,18 @@
"additionalProperties": false "additionalProperties": false
} }
}, },
"type": "object",
"additionalProperties": false,
"properties": { "properties": {
"run": { "run": {
"description": "Options for analysis running,", "description": "Options for analysis running,",
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"concurrency": { "concurrency": {
"description": "Number of concurrent runners. Defaults to the number of available CPU cores.", "description": "Number of concurrent runners. Defaults to the number of available CPU cores.",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 0,
"examples": [4] "examples": [4]
}, },
"timeout": { "timeout": {
@ -441,12 +444,12 @@
"type": "string", "type": "string",
"default": "1.17" "default": "1.17"
} }
}, }
"additionalProperties": false
}, },
"output": { "output": {
"description": "Output configuration options.", "description": "Output configuration options.",
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"format": { "format": {
"description": "Output format to use.", "description": "Output format to use.",
@ -494,12 +497,12 @@
"type": "boolean", "type": "boolean",
"default": true "default": true
} }
}, }
"additionalProperties": false
}, },
"linters-settings": { "linters-settings": {
"description": "All available settings of specific linters.", "description": "All available settings of specific linters.",
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"dupword": { "dupword": {
"type": "object", "type": "object",
@ -683,8 +686,8 @@
"patternProperties": { "patternProperties": {
"^[^.]+$": { "^[^.]+$": {
"description": "Name of a rule.", "description": "Name of a rule.",
"additionalProperties": false,
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"list-mode": { "list-mode": {
"description": "Used to determine the package matching priority.", "description": "Used to determine the package matching priority.",
@ -709,11 +712,10 @@
}, },
"deny": { "deny": {
"description": "Packages that are not allowed where the value is a suggestion.", "description": "Packages that are not allowed where the value is a suggestion.",
"additionalProperties": false,
"type": "array", "type": "array",
"items": { "items": {
"additionalProperties": false,
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"desc": { "desc": {
"description": "Description", "description": "Description",
@ -936,6 +938,7 @@
}, },
{ {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"p": { "p": {
"description": "Pattern", "description": "Pattern",
@ -949,8 +952,7 @@
"description": "Message", "description": "Message",
"type": "string" "type": "string"
} }
}, }
"additionalProperties": false
} }
] ]
} }
@ -1236,6 +1238,7 @@
"type": "array", "type": "array",
"items": { "items": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"pattern": { "pattern": {
"type": "string" "type": "string"
@ -1243,8 +1246,7 @@
"replacement": { "replacement": {
"type": "string" "type": "string"
} }
}, }
"additionalProperties": false
} }
} }
} }
@ -1282,11 +1284,10 @@
"goheader": { "goheader": {
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"allOf": [
{
"properties": { "properties": {
"values": { "values": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"const": { "const": {
"description": "Constants to use in the template.", "description": "Constants to use in the template.",
@ -1308,12 +1309,12 @@
"regexp": { "regexp": {
"description": "Regular expressions to use in your template.", "description": "Regular expressions to use in your template.",
"type": "object", "type": "object",
"additionalProperties": false,
"patternProperties": { "patternProperties": {
"^.+$": { "^.+$": {
"type": "string" "type": "string"
} }
}, },
"additionalProperties": false,
"examples": [ "examples": [
{ {
"AUTHOR": ".*@mycompany\\.com" "AUTHOR": ".*@mycompany\\.com"
@ -1321,35 +1322,23 @@
] ]
} }
} }
}
}
}, },
{
"oneOf": [
{
"properties": {
"template": { "template": {
"description": "Template to put on top of every file.", "description": "Template to put on top of every file.",
"type": "string", "type": "string",
"examples": [ "examples": [
"{{ MY COMPANY }}\nSPDX-License-Identifier: Apache-2.0\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License." "{{ MY COMPANY }}\nSPDX-License-Identifier: Apache-2.0\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at:\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License."
] ]
}
}, },
"required": ["template"]
},
{
"properties": {
"template-path": { "template-path": {
"description": "Path to the file containing the template source.", "description": "Path to the file containing the template source.",
"type": "string", "type": "string",
"examples": ["my_header_template.txt"] "examples": ["my_header_template.txt"]
} }
}, },
"required": ["template-path"] "oneOf": [
} { "required": ["template"] },
] { "required": ["template-path"] }
}
] ]
}, },
"goimports": { "goimports": {
@ -1441,6 +1430,7 @@
"properties": { "properties": {
"allowed": { "allowed": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"modules": { "modules": {
"description": "List of allowed modules.", "description": "List of allowed modules.",
@ -1462,6 +1452,7 @@
}, },
"blocked": { "blocked": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"modules": { "modules": {
"description": "List of blocked modules.", "description": "List of blocked modules.",
@ -1471,6 +1462,7 @@
"patternProperties": { "patternProperties": {
"^.+$": { "^.+$": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"recommendations": { "recommendations": {
"description": "Recommended modules that should be used instead.", "description": "Recommended modules that should be used instead.",
@ -1497,6 +1489,7 @@
"patternProperties": { "patternProperties": {
"^.*$": { "^.*$": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"version": { "version": {
"description": "Version constraint.", "description": "Version constraint.",
@ -1727,6 +1720,7 @@
"type": "array", "type": "array",
"items": { "items": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"pkg": { "pkg": {
"description": "Package path e.g. knative.dev/serving/pkg/apis/autoscaling/v1alpha1", "description": "Package path e.g. knative.dev/serving/pkg/apis/autoscaling/v1alpha1",
@ -1931,6 +1925,7 @@
"type": "array", "type": "array",
"items": { "items": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"name": { "name": {
"type": "string" "type": "string"
@ -1941,8 +1936,7 @@
"arg-pos": { "arg-pos": {
"type": "integer" "type": "integer"
} }
}, }
"additionalProperties": false
} }
} }
} }
@ -2578,6 +2572,7 @@
"properties": { "properties": {
"case": { "case": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"use-field-name": { "use-field-name": {
"description": "Use the struct field name to check the name of the struct tag.", "description": "Use the struct field name to check the name of the struct tag.",
@ -2772,6 +2767,7 @@
}, },
"benchmark": { "benchmark": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"begin": { "begin": {
"description": "Check if `b.Helper()` begins helper function.", "description": "Check if `b.Helper()` begins helper function.",
@ -2792,6 +2788,7 @@
}, },
"tb": { "tb": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"begin": { "begin": {
"description": "Check if `tb.Helper()` begins helper function.", "description": "Check if `tb.Helper()` begins helper function.",
@ -2812,6 +2809,7 @@
}, },
"fuzz": { "fuzz": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"begin": { "begin": {
"description": "Check if `f.Helper()` begins helper function.", "description": "Check if `f.Helper()` begins helper function.",
@ -3210,15 +3208,24 @@
"type": "object" "type": "object"
} }
}, },
"required": ["path"] "oneOf": [
} {
} "properties": {
"type": {"enum": ["module"] }
} }
}, },
"additionalProperties": false {
"required": ["path"]
}
]
}
}
}
}
}, },
"linters": { "linters": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"enable": { "enable": {
"description": "List of enabled linters.", "description": "List of enabled linters.",
@ -3270,11 +3277,11 @@
"type": "boolean", "type": "boolean",
"default": false "default": false
} }
}, }
"additionalProperties": false
}, },
"issues": { "issues": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"exclude": { "exclude": {
"description": "List of regular expressions of issue texts to exclude.\nBut independently from this option we use default exclude patterns. Their usage can be controlled through `exclude-use-default`.", "description": "List of regular expressions of issue texts to exclude.\nBut independently from this option we use default exclude patterns. Their usage can be controlled through `exclude-use-default`.",
@ -3288,6 +3295,7 @@
"type": "array", "type": "array",
"items": { "items": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"path": { "path": {
"type": "string" "type": "string"
@ -3396,11 +3404,11 @@
"type": "boolean", "type": "boolean",
"default": false "default": false
} }
}, }
"additionalProperties": false
}, },
"severity": { "severity": {
"type": "object", "type": "object",
"additionalProperties": false,
"properties": { "properties": {
"default-severity": { "default-severity": {
"description": "Set the default severity for issues. If severity rules are defined and the issues do not match or no severity is provided to the rule this will be the default severity applied. Severities should match the supported severity names of the selected out format.", "description": "Set the default severity for issues. If severity rules are defined and the issues do not match or no severity is provided to the rule this will be the default severity applied. Severities should match the supported severity names of the selected out format.",
@ -3446,9 +3454,7 @@
"default": [] "default": []
} }
}, },
"required": ["default-severity"], "required": ["default-severity"]
"additionalProperties": false }
} }
},
"type": "object"
} }

View File

@ -0,0 +1,115 @@
package test
import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"testing"
"github.com/santhosh-tekuri/jsonschema/v5"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)
func Test_validateTestConfigurationFiles(t *testing.T) {
err := validateTestConfigurationFiles("../jsonschema/golangci.next.jsonschema.json", ".")
require.NoError(t, err)
}
func validateTestConfigurationFiles(schemaPath, targetDir string) error {
schema, err := loadSchema(filepath.FromSlash(schemaPath))
if err != nil {
return fmt.Errorf("load schema: %w", err)
}
yamlFiles, err := findConfigurationFiles(filepath.FromSlash(targetDir))
if err != nil {
return fmt.Errorf("find configuration files: %w", err)
}
var errAll error
for _, filename := range yamlFiles {
// internal tests
if filename == filepath.FromSlash("testdata/withconfig/.golangci.yml") {
continue
}
m, err := decodeYamlFile(filename)
if err != nil {
return err
}
err = schema.Validate(m)
if err != nil {
abs, _ := filepath.Abs(filename)
errAll = errors.Join(errAll, fmt.Errorf("%s: %w", abs, err))
}
}
return errAll
}
func loadSchema(schemaPath string) (*jsonschema.Schema, error) {
compiler := jsonschema.NewCompiler()
compiler.Draft = jsonschema.Draft7
schemaFile, err := os.Open(schemaPath)
if err != nil {
return nil, fmt.Errorf("open schema file: %w", err)
}
defer func() { _ = schemaFile.Close() }()
err = compiler.AddResource(filepath.Base(schemaPath), schemaFile)
if err != nil {
return nil, fmt.Errorf("add schema resource: %w", err)
}
schema, err := compiler.Compile(filepath.Base(schemaPath))
if err != nil {
return nil, fmt.Errorf("compile schema: %w", err)
}
return schema, nil
}
func findConfigurationFiles(targetDir string) ([]string, error) {
var yamlFiles []string
err := filepath.WalkDir(targetDir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if !d.IsDir() && (strings.EqualFold(filepath.Ext(d.Name()), ".yml") || strings.EqualFold(filepath.Ext(d.Name()), ".yaml")) {
yamlFiles = append(yamlFiles, path)
}
return nil
})
if err != nil {
return nil, fmt.Errorf("walk dir: %w", err)
}
return yamlFiles, nil
}
func decodeYamlFile(filename string) (any, error) {
yamlFile, err := os.Open(filename)
if err != nil {
return nil, fmt.Errorf("[%s] file open: %w", filename, err)
}
defer func() { _ = yamlFile.Close() }()
var m any
err = yaml.NewDecoder(yamlFile).Decode(&m)
if err != nil {
return nil, fmt.Errorf("[%s] yaml decode: %w", filename, err)
}
return m, nil
}

View File

@ -1,3 +1,4 @@
linters-settings: linters-settings:
govet: govet:
enable: fieldalignment enable:
- fieldalignment

View File

@ -1,3 +1,4 @@
linters-settings: linters-settings:
govet: govet:
enable: ifaceassert enable:
- ifaceassert

View File

@ -1,4 +0,0 @@
linters-settings:
importas:
fff: fmt
std_os: os

View File

@ -1,6 +1,7 @@
linters-settings: linters-settings:
testifylint: testifylint:
disable-all: true disable-all: true
enable: bool-compare enable:
- bool-compare
bool-compare: bool-compare:
ignore-custom-types: true ignore-custom-types: true

View File

@ -1,6 +1,7 @@
linters-settings: linters-settings:
testifylint: testifylint:
disable-all: true disable-all: true
enable: require-error enable:
- require-error
require-error: require-error:
fn-pattern: ^NoError$ fn-pattern: ^NoError$

View File

@ -1,16 +0,0 @@
//golangcitest:args -Eimportas
//golangcitest:config_path testdata/configs/importas_noalias.yml
//golangcitest:expected_exitcode 0
package testdata
import (
wrong_alias "fmt"
"os"
wrong_alias_again "os"
)
func ImportAsNoAlias() {
wrong_alias.Println("foo")
wrong_alias_again.Stdout.WriteString("bar")
os.Stdout.WriteString("test")
}

View File

@ -2,6 +2,3 @@ linters:
disable-all: true disable-all: true
enable: enable:
- unused - unused
linters-settings:
unused:
check-exported: true