From 4f16a29cb5e8bf4978763581602caa6012865091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa=20Montoro?= Date: Wed, 25 Mar 2026 14:41:33 +0100 Subject: [PATCH] MM-67793: Remove dependency on blang/semver/v4 (#35742) * Remove dependency on blang/semver/v4 Instead, consolidate on the usage of Masterminds/semver/v3 * Remove empty line * make modules-tidy --- server/channels/api4/user.go | 4 ++-- server/channels/app/agents.go | 8 ++++---- server/channels/app/plugin.go | 14 +++++++------- server/channels/app/plugin_install.go | 26 ++++++++++++-------------- server/channels/web/web.go | 8 ++++---- server/go.mod | 4 ++-- server/go.sum | 2 -- server/public/go.mod | 2 +- server/public/go.sum | 4 ++-- server/public/model/config.go | 4 ++-- server/public/model/manifest.go | 10 +++++----- server/public/model/metrics.go | 6 +++--- server/public/model/packet_metadata.go | 4 ++-- server/public/pluginapi/client.go | 4 ++-- server/public/pluginapi/system.go | 4 ++-- 15 files changed, 50 insertions(+), 54 deletions(-) diff --git a/server/channels/api4/user.go b/server/channels/api4/user.go index e98f701e767..7a3725d3ec9 100644 --- a/server/channels/api4/user.go +++ b/server/channels/api4/user.go @@ -16,7 +16,7 @@ import ( "strings" "time" - "github.com/blang/semver/v4" + "github.com/Masterminds/semver/v3" "github.com/mattermost/mattermost/server/public/model" "github.com/mattermost/mattermost/server/public/shared/mlog" @@ -2538,7 +2538,7 @@ func handleDeviceProps(c *Context, w http.ResponseWriter, r *http.Request) { mobileVersion := receivedProps[model.SessionPropMobileVersion] if mobileVersion != "" { - if _, err := semver.Parse(mobileVersion); err != nil { + if _, err := semver.StrictNewVersion(mobileVersion); err != nil { c.SetInvalidParam(model.SessionPropMobileVersion) return } diff --git a/server/channels/app/agents.go b/server/channels/app/agents.go index 7e665cc8110..e435b853589 100644 --- a/server/channels/app/agents.go +++ b/server/channels/app/agents.go @@ -6,7 +6,7 @@ package app import ( "net/http" - "github.com/blang/semver/v4" + "github.com/Masterminds/semver/v3" agentclient "github.com/mattermost/mattermost-plugin-ai/public/bridgeclient" "github.com/mattermost/mattermost/server/public/model" @@ -45,7 +45,7 @@ func (a *App) GetAIPluginBridgeStatus(rctx request.CTX) (bool, string) { plugins := pluginsEnvironment.Active() for _, plugin := range plugins { if plugin.Manifest != nil && plugin.Manifest.Id == aiPluginID { - pluginVersion, err := semver.Parse(plugin.Manifest.Version) + pluginVersion, err := semver.StrictNewVersion(plugin.Manifest.Version) if err != nil { rctx.Logger().Debug("AI plugin bridge not available - failed to parse plugin version", mlog.String("plugin_id", aiPluginID), @@ -55,12 +55,12 @@ func (a *App) GetAIPluginBridgeStatus(rctx request.CTX) (bool, string) { return false, "app.agents.bridge.not_available.plugin_version_parse_failed" } - minVersion, err := semver.Parse(minAIPluginVersionForBridge) + minVersion, err := semver.StrictNewVersion(minAIPluginVersionForBridge) if err != nil { return false, "app.agents.bridge.not_available.min_version_parse_failed" } - if pluginVersion.LT(minVersion) { + if pluginVersion.LessThan(minVersion) { rctx.Logger().Debug("AI plugin bridge not available - plugin version is too old", mlog.String("plugin_id", aiPluginID), mlog.String("current_version", plugin.Manifest.Version), diff --git a/server/channels/app/plugin.go b/server/channels/app/plugin.go index dc1ced66af0..c491bfadcf5 100644 --- a/server/channels/app/plugin.go +++ b/server/channels/app/plugin.go @@ -16,7 +16,7 @@ import ( "strings" "sync" - "github.com/blang/semver/v4" + "github.com/Masterminds/semver/v3" svg "github.com/h2non/go-is-svg" "github.com/pkg/errors" @@ -687,18 +687,18 @@ func (a *App) mergePrepackagedPlugins(remoteMarketplacePlugins map[string]*model } // If available in the marketplace, only overwrite if newer. - prepackagedVersion, err := semver.Parse(prepackaged.Manifest.Version) + prepackagedVersion, err := semver.StrictNewVersion(prepackaged.Manifest.Version) if err != nil { return model.NewAppError("mergePrepackagedPlugins", "app.plugin.invalid_version.app_error", nil, "", http.StatusBadRequest).Wrap(err) } marketplacePlugin := remoteMarketplacePlugins[prepackaged.Manifest.Id] - marketplaceVersion, err := semver.Parse(marketplacePlugin.Manifest.Version) + marketplaceVersion, err := semver.StrictNewVersion(marketplacePlugin.Manifest.Version) if err != nil { return model.NewAppError("mergePrepackagedPlugins", "app.plugin.invalid_version.app_error", nil, "", http.StatusBadRequest).Wrap(err) } - if prepackagedVersion.GT(marketplaceVersion) { + if prepackagedVersion.GreaterThan(marketplaceVersion) { remoteMarketplacePlugins[prepackaged.Manifest.Id] = prepackagedMarketplace } } @@ -1075,7 +1075,7 @@ func (ch *Channels) shouldPersistTransitionallyPrepackagedPlugin(availablePlugin return true } - prepackagedVersion, err := semver.Parse(p.Manifest.Version) + prepackagedVersion, err := semver.StrictNewVersion(p.Manifest.Version) if err != nil { logger.Error("Should not persist transitionally prepackged plugin: invalid prepackaged version", mlog.Err(err)) return false @@ -1083,14 +1083,14 @@ func (ch *Channels) shouldPersistTransitionallyPrepackagedPlugin(availablePlugin logger = logger.With(mlog.String("existing_version", existing.Manifest.Version)) - existingVersion, err := semver.Parse(existing.Manifest.Version) + existingVersion, err := semver.StrictNewVersion(existing.Manifest.Version) if err != nil { // Consider this an old version and replace with the prepackaged version instead. logger.Warn("Should persist transitionally prepackged plugin: invalid existing version", mlog.Err(err)) return true } - if prepackagedVersion.GT(existingVersion) { + if prepackagedVersion.GreaterThan(existingVersion) { logger.Info("Should persist transitionally prepackged plugin: newer version") return true } diff --git a/server/channels/app/plugin_install.go b/server/channels/app/plugin_install.go index b00ee339d13..1edc881e9b7 100644 --- a/server/channels/app/plugin_install.go +++ b/server/channels/app/plugin_install.go @@ -81,7 +81,7 @@ import ( "os" "path/filepath" - "github.com/blang/semver/v4" + "github.com/Masterminds/semver/v3" "github.com/mattermost/mattermost/server/public/model" "github.com/mattermost/mattermost/server/public/shared/mlog" @@ -301,21 +301,21 @@ func (ch *Channels) InstallMarketplacePlugin(request *model.InstallMarketplacePl } if plugin != nil { - var prepackagedVersion semver.Version + prepackagedVersion, _ := semver.StrictNewVersion("0.0.0") if prepackagedPlugin != nil { var err error - prepackagedVersion, err = semver.Parse(prepackagedPlugin.Manifest.Version) + prepackagedVersion, err = semver.StrictNewVersion(prepackagedPlugin.Manifest.Version) if err != nil { return nil, model.NewAppError("InstallMarketplacePlugin", "app.plugin.invalid_version.app_error", nil, "", http.StatusBadRequest).Wrap(err) } } - marketplaceVersion, err := semver.Parse(plugin.Manifest.Version) + marketplaceVersion, err := semver.StrictNewVersion(plugin.Manifest.Version) if err != nil { return nil, model.NewAppError("InstallMarketplacePlugin", "app.prepackged-plugin.invalid_version.app_error", nil, "", http.StatusBadRequest).Wrap(err) } - if prepackagedVersion.LT(marketplaceVersion) { // Always true if no prepackaged plugin was found + if prepackagedVersion.LessThan(marketplaceVersion) { // Always true if no prepackaged plugin was found logger.Debug("Found upgraded plugin from remote marketplace", mlog.String("version", plugin.Manifest.Version), mlog.String("download_url", plugin.DownloadURL)) downloadedPluginBytes, err := ch.srv.downloadFromURL(plugin.DownloadURL) @@ -462,19 +462,17 @@ func (ch *Channels) installExtractedPlugin(manifest *model.Manifest, fromPluginD // Skip installation if already installed and newer. if installationStrategy == installPluginLocallyOnlyIfNewOrUpgrade { - var version, existingVersion semver.Version - - version, err = semver.Parse(manifest.Version) - if err != nil { - return nil, model.NewAppError("installExtractedPlugin", "app.plugin.invalid_version.app_error", nil, "", http.StatusBadRequest).Wrap(err) + version, vErr := semver.StrictNewVersion(manifest.Version) + if vErr != nil { + return nil, model.NewAppError("installExtractedPlugin", "app.plugin.invalid_version.app_error", nil, "", http.StatusBadRequest).Wrap(vErr) } - existingVersion, err = semver.Parse(existingManifest.Version) - if err != nil { - return nil, model.NewAppError("installExtractedPlugin", "app.plugin.invalid_version.app_error", nil, "", http.StatusInternalServerError).Wrap(err) + existingVersion, vErr := semver.StrictNewVersion(existingManifest.Version) + if vErr != nil { + return nil, model.NewAppError("installExtractedPlugin", "app.plugin.invalid_version.app_error", nil, "", http.StatusInternalServerError).Wrap(vErr) } - if version.LTE(existingVersion) { + if version.LessThanEqual(existingVersion) { logger.Warn("Skipping local installation of plugin since not a newer version", mlog.String("version", version.String()), mlog.String("existing_version", existingVersion.String())) return nil, model.NewAppError("installExtractedPlugin", "app.plugin.skip_installation.app_error", map[string]any{"Id": manifest.Id}, "", http.StatusInternalServerError) } diff --git a/server/channels/web/web.go b/server/channels/web/web.go index 6b0b6ce299c..26d204bfd5c 100644 --- a/server/channels/web/web.go +++ b/server/channels/web/web.go @@ -8,8 +8,8 @@ import ( "path" "strings" + "github.com/Masterminds/semver/v3" "github.com/avct/uasurfer" - "github.com/blang/semver/v4" "github.com/gorilla/mux" "github.com/mattermost/mattermost/server/public/model" @@ -67,15 +67,15 @@ func CheckDesktopAppCompatibility(agentString string, minVersion *string) bool { if !ok { return true } - clientVersion, err := semver.ParseTolerant(clientVersionStr) + clientVersion, err := semver.NewVersion(clientVersionStr) if err != nil { return true } - required, err := semver.Parse(*minVersion) + required, err := semver.StrictNewVersion(*minVersion) if err != nil { return true } - return clientVersion.GTE(required) + return clientVersion.GreaterThanEqual(required) } func Handle404(a *app.App, w http.ResponseWriter, r *http.Request) { diff --git a/server/go.mod b/server/go.mod index fbb32f0bf53..316db905382 100644 --- a/server/go.mod +++ b/server/go.mod @@ -13,7 +13,6 @@ require ( github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.34.4 github.com/bep/imagemeta v0.12.0 - github.com/blang/semver/v4 v4.0.0 github.com/cespare/xxhash/v2 v2.3.0 github.com/dgryski/dgoogauth v0.0.0-20190221195224-5a805980a5f3 github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a @@ -76,6 +75,7 @@ require ( golang.org/x/sync v0.18.0 golang.org/x/sys v0.38.0 golang.org/x/term v0.37.0 + golang.org/x/text v0.31.0 gopkg.in/mail.v2 v2.3.1 ) @@ -104,6 +104,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.24.1 // indirect github.com/bits-and-blooms/bloom/v3 v3.7.0 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect github.com/bodgit/plumbing v1.3.0 // indirect github.com/bodgit/sevenzip v1.6.1 // indirect github.com/bodgit/windows v1.0.1 // indirect @@ -207,7 +208,6 @@ require ( go4.org v0.0.0-20230225012048-214862532bf5 // indirect golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b // indirect golang.org/x/mod v0.29.0 // indirect - golang.org/x/text v0.31.0 // indirect golang.org/x/tools v0.38.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251007200510-49b9836ed3ff // indirect google.golang.org/grpc v1.76.0 // indirect diff --git a/server/go.sum b/server/go.sum index 0a4b437b74d..09168547fd0 100644 --- a/server/go.sum +++ b/server/go.sum @@ -407,8 +407,6 @@ github.com/mattermost/ldap v0.0.0-20231116144001-0f480c025956 h1:Y1Tu/swM31pVwwb github.com/mattermost/ldap v0.0.0-20231116144001-0f480c025956/go.mod h1:SRl30Lb7/QoYyohYeVBuqYvvmXSZJxZgiV3Zf6VbxjI= github.com/mattermost/logr/v2 v2.0.22 h1:npFkXlkAWR9J8payh8ftPcCZvLbHSI125mAM5/r/lP4= github.com/mattermost/logr/v2 v2.0.22/go.mod h1:0sUKpO+XNMZApeumaid7PYaUZPBIydfuWZ0dqixXo+s= -github.com/mattermost/mattermost-plugin-ai v1.8.1 h1:qymxDayy3vJPhm59XA8q0oLR8uobPgx0SOB7IMG9ZMM= -github.com/mattermost/mattermost-plugin-ai v1.8.1/go.mod h1:Uco4K7ypsrZWcD256ezvgZDqolJfHYiExN2lYiHmVDo= github.com/mattermost/mattermost-plugin-ai v1.12.0 h1:cwRE2jjlqN5W42O9Xp0ncyHk7HL/ayMeypuINPX0WJ0= github.com/mattermost/mattermost-plugin-ai v1.12.0/go.mod h1:L/I/IpdWNGbxRfUduCstCYbhyX59OEftxcpDHtCT4EI= github.com/mattermost/mattermost/server/public v0.1.22-0.20251105210629-8bf4a00724e2 h1:RJtCnj9nF/wb0Fb+O0qAPgUoWP5CTTDnHzHD5ciGlJ8= diff --git a/server/public/go.mod b/server/public/go.mod index 46e6dd917e2..3ee28f3a634 100644 --- a/server/public/go.mod +++ b/server/public/go.mod @@ -3,7 +3,7 @@ module github.com/mattermost/mattermost/server/public go 1.24.13 require ( - github.com/blang/semver/v4 v4.0.0 + github.com/Masterminds/semver/v3 v3.4.0 github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a github.com/francoispqt/gojay v1.2.13 github.com/goccy/go-yaml v1.18.0 diff --git a/server/public/go.sum b/server/public/go.sum index f044752bd5a..c4b6122584a 100644 --- a/server/public/go.sum +++ b/server/public/go.sum @@ -10,13 +10,13 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beevik/etree v1.6.0 h1:u8Kwy8pp9D9XeITj2Z0XtA5qqZEmtJtuXZRQi+j03eE= github.com/beevik/etree v1.6.0/go.mod h1:bh4zJxiIr62SOf9pRzN7UUYaEDa9HEKafK25+sLc0Gc= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= diff --git a/server/public/model/config.go b/server/public/model/config.go index 2f4eb7a0b01..53894d4c6be 100644 --- a/server/public/model/config.go +++ b/server/public/model/config.go @@ -20,7 +20,7 @@ import ( "strings" "time" - "github.com/blang/semver/v4" + "github.com/Masterminds/semver/v3" "github.com/mattermost/ldap" "github.com/pkg/errors" @@ -4664,7 +4664,7 @@ func (s *ServiceSettings) isValid() *AppError { } if *s.MinimumDesktopAppVersion != "" { - if _, err := semver.Parse(*s.MinimumDesktopAppVersion); err != nil { + if _, err := semver.StrictNewVersion(*s.MinimumDesktopAppVersion); err != nil { return NewAppError("Config.IsValid", "model.config.is_valid.minimum_desktop_app_version.app_error", nil, "", http.StatusBadRequest).Wrap(err) } } diff --git a/server/public/model/manifest.go b/server/public/model/manifest.go index c8c248ad25d..64f9098d133 100644 --- a/server/public/model/manifest.go +++ b/server/public/model/manifest.go @@ -11,7 +11,7 @@ import ( "path/filepath" "strings" - "github.com/blang/semver/v4" + "github.com/Masterminds/semver/v3" "github.com/goccy/go-yaml" "github.com/pkg/errors" ) @@ -299,12 +299,12 @@ func (m *Manifest) HasWebapp() bool { } func (m *Manifest) MeetMinServerVersion(serverVersion string) (bool, error) { - minServerVersion, err := semver.Parse(m.MinServerVersion) + minServerVersion, err := semver.StrictNewVersion(m.MinServerVersion) if err != nil { return false, errors.New("failed to parse MinServerVersion") } sv := semver.MustParse(serverVersion) - if sv.LT(minServerVersion) { + if sv.LessThan(minServerVersion) { return false, nil } return true, nil @@ -332,14 +332,14 @@ func (m *Manifest) IsValid() error { } if m.Version != "" { - _, err := semver.Parse(m.Version) + _, err := semver.StrictNewVersion(m.Version) if err != nil { return errors.Wrap(err, "failed to parse Version") } } if m.MinServerVersion != "" { - _, err := semver.Parse(m.MinServerVersion) + _, err := semver.StrictNewVersion(m.MinServerVersion) if err != nil { return errors.Wrap(err, "failed to parse MinServerVersion") } diff --git a/server/public/model/metrics.go b/server/public/model/metrics.go index 4d422f5724e..3663380d401 100644 --- a/server/public/model/metrics.go +++ b/server/public/model/metrics.go @@ -7,7 +7,7 @@ import ( "fmt" "strings" - "github.com/blang/semver/v4" + "github.com/Masterminds/semver/v3" ) type MetricType string @@ -112,12 +112,12 @@ func (r *PerformanceReport) IsValid() error { return fmt.Errorf("the report is nil") } - reportVersion, err := semver.ParseTolerant(r.Version) + reportVersion, err := semver.NewVersion(r.Version) if err != nil { return fmt.Errorf("could not parse semver version: %s, %w", r.Version, err) } - if reportVersion.Major != performanceReportVersion.Major || reportVersion.Minor > performanceReportVersion.Minor { + if reportVersion.Major() != performanceReportVersion.Major() || reportVersion.Minor() > performanceReportVersion.Minor() { return fmt.Errorf("report version is not supported: server version: %s, report version: %s", performanceReportVersion.String(), r.Version) } diff --git a/server/public/model/packet_metadata.go b/server/public/model/packet_metadata.go index 62a9329d355..b86aff13858 100644 --- a/server/public/model/packet_metadata.go +++ b/server/public/model/packet_metadata.go @@ -6,7 +6,7 @@ package model import ( "fmt" - "github.com/blang/semver/v4" + "github.com/Masterminds/semver/v3" "github.com/goccy/go-yaml" ) @@ -54,7 +54,7 @@ func (md *PacketMetadata) Validate() error { return fmt.Errorf("generated_at should be a positive number") } - if _, err := semver.ParseTolerant(md.ServerVersion); err != nil { + if _, err := semver.NewVersion(md.ServerVersion); err != nil { return fmt.Errorf("could not parse server version: %w", err) } diff --git a/server/public/pluginapi/client.go b/server/public/pluginapi/client.go index 1255c690a9c..3b4a9e34349 100644 --- a/server/public/pluginapi/client.go +++ b/server/public/pluginapi/client.go @@ -1,7 +1,7 @@ package pluginapi import ( - "github.com/blang/semver/v4" + "github.com/Masterminds/semver/v3" "github.com/mattermost/mattermost/server/public/plugin" "github.com/pkg/errors" ) @@ -73,7 +73,7 @@ func ensureServerVersion(api plugin.API, required string) error { currentVersion := semver.MustParse(serverVersion) requiredVersion := semver.MustParse(required) - if currentVersion.LT(requiredVersion) { + if currentVersion.LessThan(requiredVersion) { return errors.Errorf("incompatible server version for plugin, minimum required version: %s, current version: %s", required, serverVersion) } diff --git a/server/public/pluginapi/system.go b/server/public/pluginapi/system.go index 4115b28f793..c0a5927298d 100644 --- a/server/public/pluginapi/system.go +++ b/server/public/pluginapi/system.go @@ -7,7 +7,7 @@ import ( filePath "path" "time" - "github.com/blang/semver/v4" + "github.com/Masterminds/semver/v3" "github.com/goccy/go-yaml" "github.com/pkg/errors" @@ -127,7 +127,7 @@ func (s *SystemService) RequestTrialLicense(requesterID string, users int, terms currentVersion := semver.MustParse(s.api.GetServerVersion()) requiredVersion := semver.MustParse("5.36.0") - if currentVersion.LT(requiredVersion) { + if currentVersion.LessThan(requiredVersion) { return errors.Errorf("current server version is lower than 5.36") }