diff --git a/.golangci.yml b/.golangci.yml index 99afdd0d4..ab889827f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -61,9 +61,11 @@ linters: text: do not define dynamic errors # dupword reports several errors in .proto test fixtures # gosec reports a few minor issues in tests + # prealloc is not important in tests - linters: - dupword - gosec + - prealloc path: _test\.go formatters: enable: diff --git a/Makefile b/Makefile index 3a7d0314e..4e7b0940d 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ DOCKER_BUILD_EXTRA_ARGS ?= DOCKER_BUILDER := bufbuild-plugins DOCKER_CACHE_DIR ?= $(TMP)/dockercache GO ?= go -GOLANGCI_LINT_VERSION ?= v2.7.2 +GOLANGCI_LINT_VERSION ?= v2.8.0 GOLANGCI_LINT := $(TMP)/golangci-lint-$(GOLANGCI_LINT_VERSION) GO_TEST_FLAGS ?= -race -count=1 diff --git a/internal/fetchclient/fetchclient.go b/internal/fetchclient/fetchclient.go index 90b443fd6..0c76a848a 100644 --- a/internal/fetchclient/fetchclient.go +++ b/internal/fetchclient/fetchclient.go @@ -81,19 +81,28 @@ func (c *Client) Fetch(ctx context.Context, config *source.Config) (string, erro func (c *Client) fetch(ctx context.Context, config *source.Config) (string, error) { ignoreVersions := xslices.ToStructMap(config.Source.IgnoreVersions) + maxVersion := config.Source.MaxVersion + if maxVersion != "" { + if !strings.HasPrefix(maxVersion, "v") { + maxVersion = "v" + maxVersion + } + if !semver.IsValid(maxVersion) { + return "", fmt.Errorf("%s: max_version is not a valid semver: %s", config.Filename, config.Source.MaxVersion) + } + } switch { case config.Source.GitHub != nil: - return c.fetchGithub(ctx, config.Source.GitHub.Owner, config.Source.GitHub.Repository, ignoreVersions) + return c.fetchGithub(ctx, config.Source.GitHub.Owner, config.Source.GitHub.Repository, ignoreVersions, maxVersion) case config.Source.DartFlutter != nil: - return c.fetchDartFlutter(ctx, config.Source.DartFlutter.Name, ignoreVersions) + return c.fetchDartFlutter(ctx, config.Source.DartFlutter.Name, ignoreVersions, maxVersion) case config.Source.GoProxy != nil: - return c.fetchGoProxy(ctx, config.Source.GoProxy.Name, ignoreVersions) + return c.fetchGoProxy(ctx, config.Source.GoProxy.Name, ignoreVersions, maxVersion) case config.Source.NPMRegistry != nil: - return c.fetchNPMRegistry(ctx, config.Source.NPMRegistry.Name, ignoreVersions) + return c.fetchNPMRegistry(ctx, config.Source.NPMRegistry.Name, ignoreVersions, maxVersion) case config.Source.Maven != nil: - return c.fetchMaven(ctx, config.Source.Maven.Group, config.Source.Maven.Name, ignoreVersions) + return c.fetchMaven(ctx, config.Source.Maven.Group, config.Source.Maven.Name, ignoreVersions, maxVersion) case config.Source.Crates != nil: - return c.fetchCrate(ctx, config.Source.Crates.CrateName, ignoreVersions) + return c.fetchCrate(ctx, config.Source.Crates.CrateName, ignoreVersions, maxVersion) } return "", errors.New("failed to match a source") } @@ -102,6 +111,7 @@ func (c *Client) fetchDartFlutter( ctx context.Context, name string, ignoreVersions map[string]struct{}, + maxVersion string, ) (string, error) { request, err := http.NewRequestWithContext( ctx, @@ -132,7 +142,7 @@ func (c *Client) fetchDartFlutter( if err := json.NewDecoder(response.Body).Decode(&data); err != nil { return "", err } - if len(ignoreVersions) == 0 { + if len(ignoreVersions) == 0 && maxVersion == "" { return data.Latest.Version, nil } var latestVersion string @@ -144,6 +154,9 @@ func (c *Client) fetchDartFlutter( if _, ok := ignoreVersions[version]; ok { continue } + if maxVersion != "" && semver.Compare(version, maxVersion) >= 0 { + continue + } if latestVersion == "" || semver.Compare(latestVersion, version) < 0 { latestVersion = version } @@ -155,7 +168,7 @@ func (c *Client) fetchDartFlutter( return latestVersion, nil } -func (c *Client) fetchCrate(ctx context.Context, name string, ignoreVersions map[string]struct{}) (string, error) { +func (c *Client) fetchCrate(ctx context.Context, name string, ignoreVersions map[string]struct{}, maxVersion string) (string, error) { request, err := http.NewRequestWithContext( ctx, http.MethodGet, @@ -186,7 +199,7 @@ func (c *Client) fetchCrate(ctx context.Context, name string, ignoreVersions map if err := json.NewDecoder(response.Body).Decode(&data); err != nil { return "", err } - var versions []string + versions := make([]string, 0, len(data.Versions)) for _, version := range data.Versions { if version.Yanked { // A yanked version a is a published crate's version that has been removed @@ -197,9 +210,13 @@ func (c *Client) fetchCrate(ctx context.Context, name string, ignoreVersions map if !ok { continue } - if _, ok := ignoreVersions[v]; !ok { - versions = append(versions, v) + if _, ok := ignoreVersions[v]; ok { + continue + } + if maxVersion != "" && semver.Compare(v, maxVersion) >= 0 { + continue } + versions = append(versions, v) } if len(versions) == 0 { return "", errors.New("no versions found") @@ -208,10 +225,13 @@ func (c *Client) fetchCrate(ctx context.Context, name string, ignoreVersions map return versions[len(versions)-1], nil } -func (c *Client) fetchGoProxy(ctx context.Context, name string, ignoreVersions map[string]struct{}) (string, error) { +func (c *Client) fetchGoProxy(ctx context.Context, name string, ignoreVersions map[string]struct{}, maxVersion string) (string, error) { if len(ignoreVersions) > 0 { return "", errors.New("ignore_versions not supported yet for go sources") } + if maxVersion != "" { + return "", errors.New("max_version not supported yet for go sources") + } request, err := http.NewRequestWithContext( ctx, http.MethodGet, @@ -239,7 +259,7 @@ func (c *Client) fetchGoProxy(ctx context.Context, name string, ignoreVersions m return data.Version, nil } -func (c *Client) fetchNPMRegistry(ctx context.Context, name string, ignoreVersions map[string]struct{}) (string, error) { +func (c *Client) fetchNPMRegistry(ctx context.Context, name string, ignoreVersions map[string]struct{}, maxVersion string) (string, error) { request, err := http.NewRequestWithContext( ctx, http.MethodGet, @@ -273,6 +293,9 @@ func (c *Client) fetchNPMRegistry(ctx context.Context, name string, ignoreVersio if _, ignored := ignoreVersions[semverVersion]; ignored { continue } + if maxVersion != "" && semver.Compare(semverVersion, maxVersion) >= 0 { + continue + } if latestVersion == "" || semver.Compare(latestVersion, semverVersion) < 0 { latestVersion = semverVersion } @@ -288,6 +311,7 @@ func (c *Client) fetchMaven( group string, name string, ignoreVersions map[string]struct{}, + maxVersion string, ) (string, error) { groupComponents := strings.Split(group, ".") targetURL, err := url.JoinPath(mavenURL, append(groupComponents, name, "maven-metadata.xml")...) @@ -329,6 +353,9 @@ func (c *Client) fetchMaven( if _, ok := ignoreVersions[v]; ok { continue } + if maxVersion != "" && semver.Compare(v, maxVersion) >= 0 { + continue + } if latestVersion == "" || semver.Compare(latestVersion, v) < 0 { latestVersion = v } @@ -344,6 +371,7 @@ func (c *Client) fetchGithub( owner string, repository string, ignoreVersions map[string]struct{}, + maxVersion string, ) (string, error) { // With the GitHub API we have a few options: // @@ -368,9 +396,13 @@ func (c *Client) fetchGithub( continue } if v, ok := ensureSemverPrefix(*tag.Name); ok { - if _, ok := ignoreVersions[v]; !ok { - versions = append(versions, v) + if _, ok := ignoreVersions[v]; ok { + continue + } + if maxVersion != "" && semver.Compare(v, maxVersion) >= 0 { + continue } + versions = append(versions, v) } } page = response.NextPage diff --git a/internal/source/config.go b/internal/source/config.go index 93f1a075a..1d75066ed 100644 --- a/internal/source/config.go +++ b/internal/source/config.go @@ -47,6 +47,9 @@ type Source struct { Crates *CratesConfig `yaml:"crates"` // IgnoreVersions is a list of versions to ignore when fetching. IgnoreVersions []string `yaml:"ignore_versions"` + // MaxVersion is an exclusive upper bound for versions. Versions >= this value will be ignored. + // Must be a valid semver version (e.g., "2.0.0"). + MaxVersion string `yaml:"max_version"` } var _ Cacheable = (*Source)(nil) diff --git a/plugins/grpc/swift/source.yaml b/plugins/grpc/swift/source.yaml index 28c12c371..708d08e67 100644 --- a/plugins/grpc/swift/source.yaml +++ b/plugins/grpc/swift/source.yaml @@ -2,3 +2,5 @@ source: github: owner: grpc repository: grpc-swift + # v2.x of the plugin is now packaged as grpc/swift-protobuf + max_version: 2.0.0