From 0842bb7e92679302e672b5f680a5d1871c7c1ace Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Thu, 12 Nov 2026 15:31:27 +0000 Subject: [PATCH] chore(ci): update golangci-lint to v2.15.0 v2.11.3 cannot type check the Go 1.27 standard library, so lint fails as soon as the module moves to Go 1.27. Fix the new findings and disable exhaustruct_v5 like exhaustruct before it. --- .github/workflows/lint.yml | 2 +- .golangci.yaml | 2 ++ marshallers.go | 2 +- parser.go | 12 ++++-------- publiccode-parser/publiccode_parser.go | 6 ++---- v0.go | 10 +++++----- v1.go | 6 +++--- validations.go | 2 +- validators/common.go | 4 ++-- validators/validator.go | 2 +- 10 files changed, 22 insertions(+), 26 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7d28067..85e2b85 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,5 +16,5 @@ jobs: go-version-file: go.mod - uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0 with: - version: v2.11.3 + version: v2.15.0 args: --timeout 3m diff --git a/.golangci.yaml b/.golangci.yaml index ab1234f..489f633 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -27,12 +27,14 @@ linters: - godox # Not terribly useful and ends up in too much boilerplate - exhaustruct + - exhaustruct_v5 # https://github.com/italia/developers-italia-api/issues/190) # Don't feel about chasing this one down - musttag # Meh - noinlineerr # Deprecated + - gomodguard - wsl # More false positive than actual issues diff --git a/marshallers.go b/marshallers.go index 7dad7c0..e68b7ca 100644 --- a/marshallers.go +++ b/marshallers.go @@ -20,7 +20,7 @@ func (u *URL) UnmarshalYAML(unmarshal func(any) error) error { return fmt.Errorf("parsing URL %q: %w", s, err) } - *u = (URL)(*urlp) + *u = URL(*urlp) return nil } diff --git a/parser.go b/parser.go index 31ac101..f470ef8 100644 --- a/parser.go +++ b/parser.go @@ -213,8 +213,7 @@ func (p *Parser) Parse(uri string) (PublicCode, error) { func (p *Parser) parseStream(in io.Reader, fileURL *url.URL) (PublicCode, error) { publiccode, err := p.parseAndValidate(in, fileURL) - var results ValidationResults - if errors.As(err, &results) { + if results, ok := errors.AsType[ValidationResults](err); ok { setFileName(results, fileNameFromURL(fileURL)) } @@ -284,8 +283,7 @@ func (p *Parser) parseAndValidate(in io.Reader, fileURL *url.URL) (PublicCode, e // detect structural issues (multi-document, empty file, syntax errors). file, err := parser.ParseBytes(b, 0) if err != nil { - var se *yaml.SyntaxError - if errors.As(err, &se) { + if se, ok := errors.AsType[*yaml.SyntaxError](err); ok { line := 0 if tok := se.GetToken(); tok != nil { line = tok.Position.Line @@ -401,8 +399,7 @@ func (p *Parser) parseAndValidate(in io.Reader, fileURL *url.URL) (PublicCode, e err = sharedValidate.Struct(publiccode) if err != nil { - var validationErrs validator.ValidationErrors - if errors.As(err, &validationErrs) { + if validationErrs, ok := errors.AsType[validator.ValidationErrors](err); ok { for _, err := range validationErrs { key := strings.SplitN(err.Namespace(), ".", 2)[1] key = reMapKey.ReplaceAllString(key, ".$1") @@ -472,8 +469,7 @@ func (p *Parser) parseAndValidate(in io.Reader, fileURL *url.URL) (PublicCode, e } if err = validateFields(publiccode, p, !p.disableNetwork, currentBaseURL); err != nil { - var vr ValidationResults - if errors.As(err, &vr) { + if vr, ok := errors.AsType[ValidationResults](err); ok { for _, result := range vr { var valErr ValidationError diff --git a/publiccode-parser/publiccode_parser.go b/publiccode-parser/publiccode_parser.go index 9768bdf..5293c40 100644 --- a/publiccode-parser/publiccode_parser.go +++ b/publiccode-parser/publiccode_parser.go @@ -159,11 +159,9 @@ func hasValidationErrors(results error) bool { return false } - var vr publiccode.ValidationResults - if errors.As(results, &vr) { + if vr, ok := errors.AsType[publiccode.ValidationResults](results); ok { for _, res := range vr { - var ve publiccode.ValidationError - if errors.As(res, &ve) { + if _, ok := errors.AsType[publiccode.ValidationError](res); ok { return true } } diff --git a/v0.go b/v0.go index 7faa958..efc5f58 100644 --- a/v0.go +++ b/v0.go @@ -56,18 +56,18 @@ type PublicCodeV0 struct { MainCopyrightOwner *string `json:"mainCopyrightOwner,omitempty" yaml:"mainCopyrightOwner,omitempty"` RepoOwner *string `json:"repoOwner,omitempty" yaml:"repoOwner,omitempty"` AuthorsFile *string `json:"authorsFile,omitempty" yaml:"authorsFile,omitempty"` - } `yaml:"legal" json:"legal"` + } `json:"legal" yaml:"legal"` Maintenance struct { Type string `json:"type" validate:"required,oneof=internal contract community none" yaml:"type"` Contractors *[]ContractorV0 `json:"contractors,omitempty" validate:"required_if=Type contract,excluded_unless=Type contract,omitempty,dive" yaml:"contractors,omitempty"` Contacts *[]ContactV0 `json:"contacts,omitempty" validate:"required_if=Type community,required_if=Type internal,omitempty,dive" yaml:"contacts,omitempty"` - } `yaml:"maintenance" json:"maintenance"` + } `json:"maintenance" yaml:"maintenance"` Localisation struct { LocalisationReady *bool `json:"localisationReady" validate:"required" yaml:"localisationReady"` AvailableLanguages []string `json:"availableLanguages" validate:"required,gt=0,dive,bcp47_strict_language_tag" yaml:"availableLanguages"` - } `yaml:"localisation" json:"localisation"` + } `json:"localisation" yaml:"localisation"` DependsOn *struct { Open *[]DependencyV0 `json:"open,omitempty" validate:"omitempty,dive" yaml:"open,omitempty"` @@ -151,7 +151,7 @@ type ITSectionV0 struct { Riuso struct { CodiceIPA string `json:"codiceIPA,omitempty" validate:"omitempty,is_italian_ipa_code" yaml:"codiceIPA,omitempty"` - } `yaml:"riuso,omitempty" json:"riuso,omitzero"` + } `json:"riuso,omitzero" yaml:"riuso,omitempty"` Piattaforme struct { SPID bool `json:"spid" yaml:"spid"` @@ -159,7 +159,7 @@ type ITSectionV0 struct { CIE bool `json:"cie" yaml:"cie"` ANPR bool `json:"anpr" yaml:"anpr"` Io bool `json:"io" yaml:"io"` - } `yaml:"piattaforme" json:"piattaforme"` + } `json:"piattaforme" yaml:"piattaforme"` } func (p PublicCodeV0) Version() uint { diff --git a/v1.go b/v1.go index af6b58f..ec8cd05 100644 --- a/v1.go +++ b/v1.go @@ -48,18 +48,18 @@ type PublicCodeV1 struct { Legal struct { License string `json:"license" validate:"required,is_spdx_expression" yaml:"license"` MainCopyrightOwner *string `json:"mainCopyrightOwner,omitempty" yaml:"mainCopyrightOwner,omitempty"` - } `yaml:"legal" json:"legal"` + } `json:"legal" yaml:"legal"` Maintenance struct { Type string `json:"type" validate:"required,oneof=internal contract community none" yaml:"type"` Contractors *[]ContractorV1 `json:"contractors,omitempty" validate:"required_if=Type contract,excluded_unless=Type contract,omitempty,dive" yaml:"contractors,omitempty"` Contacts *[]ContactV1 `json:"contacts,omitempty" validate:"required_if=Type community,required_if=Type internal,omitempty,dive" yaml:"contacts,omitempty"` - } `yaml:"maintenance" json:"maintenance"` + } `json:"maintenance" yaml:"maintenance"` Localisation struct { LocalisationReady *bool `json:"localisationReady" validate:"required" yaml:"localisationReady"` AvailableLanguages []string `json:"availableLanguages" validate:"required,gt=0,dive,bcp47_strict_language_tag" yaml:"availableLanguages"` - } `yaml:"localisation" json:"localisation"` + } `json:"localisation" yaml:"localisation"` DependsOn *struct { Open *[]DependencyV1 `json:"open,omitempty" validate:"omitempty,dive" yaml:"open,omitempty"` diff --git a/validations.go b/validations.go index fd2b3d0..0ceb024 100644 --- a/validations.go +++ b/validations.go @@ -140,7 +140,7 @@ func (p *Parser) fileExists(u url.URL, network bool) (bool, error) { // If we have an absolute local path, perform validation on it, otherwise do it // on the remote URL if any. If none are available, validation is skipped. if u.Scheme == "file" { - _, err := os.Stat(u.Path) //nolint:gosec // G703: path is from a validated file:// URL + _, err := os.Stat(u.Path) if err != nil { err = fmt.Errorf("no such file: %s", netutil.DisplayURL(&u)) //nolint:err113 // dynamic message with path context } diff --git a/validators/common.go b/validators/common.go index 3af7284..a383644 100644 --- a/validators/common.go +++ b/validators/common.go @@ -55,7 +55,7 @@ func uMin(fl validator.FieldLevel) bool { func isHTTPURL(fl validator.FieldLevel) bool { validate := sharedValidator - if stringer, ok := fl.Field().Interface().(fmt.Stringer); ok { + if stringer, ok := reflect.TypeAssert[fmt.Stringer](fl.Field()); ok { err := validate.Var(stringer.String(), "http_url") return err == nil @@ -70,7 +70,7 @@ func isHTTPURL(fl validator.FieldLevel) bool { func isURL(fl validator.FieldLevel) bool { validate := sharedValidator - if stringer, ok := fl.Field().Interface().(fmt.Stringer); ok { + if stringer, ok := reflect.TypeAssert[fmt.Stringer](fl.Field()); ok { err := validate.Var(stringer.String(), "url") return err == nil diff --git a/validators/validator.go b/validators/validator.go index 80d04ed..8009c19 100644 --- a/validators/validator.go +++ b/validators/validator.go @@ -32,7 +32,7 @@ func New() *validator.Validate { validate.RegisterAlias("date", "datetime=2006-01-02") validate.RegisterTagNameFunc(func(fld reflect.StructField) string { - name := strings.SplitN(fld.Tag.Get("yaml"), ",", 2)[0] + name, _, _ := strings.Cut(fld.Tag.Get("yaml"), ",") if name == "-" { return "" }