1
0
mirror of https://github.com/prometheus/alertmanager.git synced 2026-02-05 06:45:45 +01:00

Enable modernize linter (#4750)

Enable the golangci-lint modernize linter.
* Add exception for the omitempty struct issue.
* Apply modernize fixes.

Signed-off-by: SuperQ <superq@gmail.com>
This commit is contained in:
Ben Kochie
2025-11-18 11:46:15 +01:00
committed by GitHub
parent 023885c52c
commit f656273159
34 changed files with 73 additions and 124 deletions

View File

@@ -5,6 +5,7 @@ linters:
- errorlint
- godot
- misspell
- modernize
- revive
- sloglint
- testifylint
@@ -77,6 +78,9 @@ linters:
- linters:
- errcheck
path: _test.go
- linters:
- modernize
text: "omitzero: Omitempty has no effect on nested struct fields"
warn-unused: true
issues:
max-issues-per-linter: 0

View File

@@ -118,10 +118,7 @@ func New(opts Options) (*API, error) {
}
concurrency := opts.Concurrency
if concurrency < 1 {
concurrency = runtime.GOMAXPROCS(0)
if concurrency < 8 {
concurrency = 8
}
concurrency = max(runtime.GOMAXPROCS(0), 8)
}
v2, err := apiv2.NewAPI(

View File

@@ -20,6 +20,7 @@ import (
"log/slog"
"net/http"
"regexp"
"slices"
"sort"
"sync"
"time"
@@ -286,7 +287,7 @@ func (api *API) getAlertsHandler(params alert_ops.GetAlertsParams) middleware.Re
receivers = append(receivers, r.RouteOpts.Receiver)
}
if receiverFilter != nil && !receiversMatchFilter(receivers, receiverFilter) {
if receiverFilter != nil && !slices.ContainsFunc(receivers, receiverFilter.MatchString) {
continue
}
@@ -474,16 +475,6 @@ func removeEmptyLabels(ls prometheus_model.LabelSet) {
}
}
func receiversMatchFilter(receivers []string, filter *regexp.Regexp) bool {
for _, r := range receivers {
if filter.MatchString(r) {
return true
}
}
return false
}
func alertMatchesFilterLabels(a *prometheus_model.Alert, matchers []*labels.Matcher) bool {
sms := make(map[string]string)
for name, value := range a.Labels {

View File

@@ -216,10 +216,7 @@ func Create(
p.register(reg, name)
retransmit := len(knownPeers) / 2
if retransmit < 3 {
retransmit = 3
}
retransmit := max(len(knownPeers)/2, 3)
p.delegate = newDelegate(l, reg, p, retransmit)
cfg := memberlist.DefaultLANConfig()

View File

@@ -79,7 +79,6 @@ func TestExternalURL(t *testing.T) {
err: true,
},
} {
tc := tc
if tc.hostnameResolver == nil {
tc.hostnameResolver = func() (string, error) {
return hostname, nil

View File

@@ -1398,7 +1398,6 @@ func TestUnmarshalHostPort(t *testing.T) {
err: true,
},
} {
tc := tc
t.Run(tc.in, func(t *testing.T) {
hp := HostPort{}
err := yaml.Unmarshal([]byte(tc.in), &hp)

View File

@@ -569,7 +569,7 @@ type IncidentioConfig struct {
}
// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (c *IncidentioConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
func (c *IncidentioConfig) UnmarshalYAML(unmarshal func(any) error) error {
*c = DefaultIncidentioConfig
type plain IncidentioConfig
if err := unmarshal((*plain)(c)); err != nil {
@@ -1102,7 +1102,7 @@ type MattermostField struct {
}
// UnmarshalYAML implements the yaml.Unmarshaler interface for MattermostField.
func (c *MattermostField) UnmarshalYAML(unmarshal func(interface{}) error) error {
func (c *MattermostField) UnmarshalYAML(unmarshal func(any) error) error {
type plain MattermostField
if err := unmarshal((*plain)(c)); err != nil {
return err
@@ -1157,7 +1157,7 @@ type MattermostConfig struct {
}
// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (c *MattermostConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
func (c *MattermostConfig) UnmarshalYAML(unmarshal func(any) error) error {
*c = DefaultMattermostConfig
type plain MattermostConfig
if err := unmarshal((*plain)(c)); err != nil {

View File

@@ -69,7 +69,6 @@ func TestBuildReceiverIntegrations(t *testing.T) {
err: true,
},
} {
tc := tc
t.Run("", func(t *testing.T) {
integrations, err := BuildReceiverIntegrations(tc.receiver, nil, nil)
if tc.err {

View File

@@ -700,7 +700,7 @@ func TestDispatcherRaceOnFirstAlertNotDeliveredWhenGroupWaitIsZero(t *testing.T)
defer dispatcher.Stop()
// Push all alerts.
for i := 0; i < numAlerts; i++ {
for i := range numAlerts {
alert := newAlert(model.LabelSet{"alertname": model.LabelValue(fmt.Sprintf("Alert_%d", i))})
require.NoError(t, alerts.Put(alert))
}

View File

@@ -113,7 +113,7 @@ func NewFlags(logger *slog.Logger, features string) (Flagger, error) {
return NoopFlags{}, nil
}
for _, feature := range strings.Split(features, ",") {
for feature := range strings.SplitSeq(features, ",") {
switch feature {
case FeatureReceiverNameInMetrics:
opts = append(opts, enableReceiverNameInMetrics())

View File

@@ -759,7 +759,7 @@ func TestLexer_Peek(t *testing.T) {
// error has occurred.
func TestLexer_PeekError(t *testing.T) {
l := lexer{input: "\"hello"}
for i := 0; i < 10; i++ {
for range 10 {
tok, err := l.peek()
require.Equal(t, token{}, tok)
require.EqualError(t, err, "0:6: \"hello: missing end \"")

View File

@@ -16,6 +16,7 @@ package parse
import (
"errors"
"fmt"
"slices"
"strconv"
"unicode/utf8"
)
@@ -73,12 +74,7 @@ func (t token) isEOF() bool {
// isOneOf returns true if the token is one of the specified kinds.
func (t token) isOneOf(kinds ...tokenKind) bool {
for _, k := range kinds {
if k == t.kind {
return true
}
}
return false
return slices.Contains(kinds, t.kind)
}
// unquote the value in token. If unquoted returns it unmodified.

View File

@@ -23,6 +23,7 @@ import (
"fmt"
"io"
"log/slog"
"maps"
"math/rand"
"os"
"sync"
@@ -159,9 +160,7 @@ type state map[string]*pb.MeshEntry
func (s state) clone() state {
c := make(state, len(s))
for k, v := range s {
c[k] = v
}
maps.Copy(c, s)
return c
}

View File

@@ -80,7 +80,7 @@ func (n *Email) auth(mechs string) (smtp.Auth, error) {
}
err := &types.MultiError{}
for _, mech := range strings.Split(mechs, " ") {
for mech := range strings.SplitSeq(mechs, " ") {
switch mech {
case "CRAM-MD5":
secret := string(n.conf.AuthSecret)

View File

@@ -300,7 +300,6 @@ func TestEmailNotifyWithErrors(t *testing.T) {
hasEmail: true,
},
} {
tc := tc
t.Run(tc.title, func(t *testing.T) {
if len(tc.errMsg) == 0 {
t.Fatal("please define the expected error message")
@@ -579,7 +578,6 @@ func TestEmailNotifyWithAuthentication(t *testing.T) {
retry: true,
},
} {
tc := tc
t.Run(tc.title, func(t *testing.T) {
emailCfg := &config.EmailConfig{
Smarthost: c.Smarthost,

View File

@@ -142,7 +142,6 @@ func TestSearchExistingIssue(t *testing.T) {
expectedJQL: `statusCategory != Done and project="PROJ" and labels="ALERT{1}" order by status ASC,resolutiondate DESC`,
},
} {
tc := tc
t.Run(tc.title, func(t *testing.T) {
expectedJQL = tc.expectedJQL
tc.cfg.APIURL = &config.URL{URL: u}
@@ -300,7 +299,6 @@ func TestPrepareSearchRequest(t *testing.T) {
expectedURLPath: "/rest/api/2",
},
} {
tc := tc
t.Run(tc.title, func(t *testing.T) {
tc.cfg.HTTPConfig = &commoncfg.HTTPClientConfig{}
@@ -402,8 +400,6 @@ func TestJiraTemplating(t *testing.T) {
errMsg: "template: :1: unclosed action",
},
} {
tc := tc
t.Run(tc.title, func(t *testing.T) {
capturedBody = nil
@@ -778,8 +774,6 @@ func TestJiraNotify(t *testing.T) {
errMsg: "can't find transition REOPEN for issue OPS-3",
},
} {
tc := tc
t.Run(tc.title, func(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
@@ -1118,8 +1112,6 @@ func TestJiraPriority(t *testing.T) {
"Medium",
},
} {
tc := tc
t.Run(tc.title, func(t *testing.T) {
t.Parallel()
u, err := url.Parse("http://example.com/")

View File

@@ -15,6 +15,7 @@ package jira
import (
"encoding/json"
"maps"
)
type issue struct {
@@ -97,9 +98,7 @@ func (i issueFields) MarshalJSON() ([]byte, error) {
jsonFields["status"] = i.Status
}
for key, field := range i.Fields {
jsonFields[key] = field
}
maps.Copy(jsonFields, i.Fields)
return json.Marshal(jsonFields)
}

View File

@@ -58,7 +58,7 @@ func TestMattermostTemplating(t *testing.T) {
// Create a fake HTTP server to simulate the Mattermost webhook
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
dec := json.NewDecoder(r.Body)
out := make(map[string]interface{})
out := make(map[string]any)
err := dec.Decode(&out)
if err != nil {
panic(err)

View File

@@ -19,6 +19,7 @@ import (
"encoding/json"
"fmt"
"log/slog"
"maps"
"net/http"
"os"
"strings"
@@ -141,9 +142,7 @@ func (n *Notifier) createRequests(ctx context.Context, as ...*types.Alert) ([]*h
details := make(map[string]string)
for k, v := range data.CommonLabels {
details[k] = v
}
maps.Copy(details, data.CommonLabels)
for k, v := range n.conf.Details {
details[k] = tmpl(v)

View File

@@ -313,7 +313,6 @@ func TestErrDetails(t *testing.T) {
exp: "",
},
} {
tc := tc
t.Run("", func(t *testing.T) {
err := errDetails(tc.status, tc.body)
require.Contains(t, err, tc.exp)

View File

@@ -113,7 +113,6 @@ func TestNotifyWithInvalidTemplate(t *testing.T) {
},
},
} {
tc := tc
t.Run(tc.title, func(t *testing.T) {
snsCfg := &config.SNSConfig{
HTTPConfig: &commoncfg.HTTPClientConfig{},

View File

@@ -127,8 +127,8 @@ func ParseMatcher(s string) (_ *Matcher, err error) {
expectTrailingQuote bool
)
if strings.HasPrefix(rawValue, "\"") {
rawValue = strings.TrimPrefix(rawValue, "\"")
if after, ok := strings.CutPrefix(rawValue, "\""); ok {
rawValue = after
expectTrailingQuote = true
}

View File

@@ -166,13 +166,6 @@ func (a *Alerts) Close() {
}
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
// Subscribe returns an iterator over active alerts that have not been
// resolved and successfully notified about.
// They are not guaranteed to be in chronological order.

View File

@@ -221,8 +221,7 @@ func TestAlertsPut(t *testing.T) {
func TestAlertsSubscribe(t *testing.T) {
marker := types.NewMarker(prometheus.NewRegistry())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx := t.Context()
alerts, err := NewAlerts(ctx, marker, 30*time.Minute, noopCallback{}, promslog.NewNopLogger(), prometheus.NewRegistry())
if err != nil {
t.Fatal(err)
@@ -246,7 +245,7 @@ func TestAlertsSubscribe(t *testing.T) {
wg sync.WaitGroup
)
wg.Add(nb)
for i := 0; i < nb; i++ {
for i := range nb {
go func(i int) {
defer wg.Done()
@@ -576,7 +575,7 @@ func TestAlertsConcurrently(t *testing.T) {
}()
expire := 10 * time.Millisecond
wg := sync.WaitGroup{}
for i := 0; i < 100; i++ {
for range 100 {
wg.Add(1)
go func() {
defer wg.Done()

View File

@@ -25,6 +25,7 @@ import (
"os"
"reflect"
"regexp"
"slices"
"sort"
"sync"
"time"
@@ -932,10 +933,8 @@ func QState(states ...types.SilenceState) QueryParam {
f := func(sil *pb.Silence, _ *Silences, now time.Time) (bool, error) {
s := getState(sil, now)
for _, ps := range states {
if s == ps {
return true, nil
}
if slices.Contains(states, s) {
return true, nil
}
return false, nil
}

View File

@@ -422,7 +422,7 @@ func benchmarkQueryWithConcurrentAdds(b *testing.B, initialSilences int, addRati
lset := model.LabelSet{"aaaa": "AAAA", "bbbb": "BBBB", "cccc": "CCCC"}
// Create initial silences
for i := 0; i < initialSilences; i++ {
for i := range initialSilences {
id := strconv.Itoa(i)
patA := "A{4}|" + id
patB := id

View File

@@ -435,7 +435,7 @@ type TemplateFunc func(string) (string, error)
// deepCopyWithTemplate returns a deep copy of a map/slice/array/string/int/bool or combination thereof, executing the
// provided template (with the provided data) on all string keys or values. All maps are connverted to
// map[string]interface{}, with all non-string keys discarded.
func DeepCopyWithTemplate(value interface{}, tmplTextFunc TemplateFunc) (interface{}, error) {
func DeepCopyWithTemplate(value any, tmplTextFunc TemplateFunc) (any, error) {
if value == nil {
return value, nil
}
@@ -446,7 +446,7 @@ func DeepCopyWithTemplate(value interface{}, tmplTextFunc TemplateFunc) (interfa
case reflect.String:
parsed, ok := tmplTextFunc(value.(string))
if ok == nil {
var inlineType interface{}
var inlineType any
err := yaml.Unmarshal([]byte(parsed), &inlineType)
if err != nil || (inlineType != nil && reflect.TypeOf(inlineType).Kind() == reflect.String) {
// ignore error, thus the string is not an interface
@@ -458,8 +458,8 @@ func DeepCopyWithTemplate(value interface{}, tmplTextFunc TemplateFunc) (interfa
case reflect.Array, reflect.Slice:
arrayLen := valueMeta.Len()
converted := make([]interface{}, arrayLen)
for i := 0; i < arrayLen; i++ {
converted := make([]any, arrayLen)
for i := range arrayLen {
var err error
converted[i], err = DeepCopyWithTemplate(valueMeta.Index(i).Interface(), tmplTextFunc)
if err != nil {
@@ -470,7 +470,7 @@ func DeepCopyWithTemplate(value interface{}, tmplTextFunc TemplateFunc) (interfa
case reflect.Map:
keys := valueMeta.MapKeys()
converted := make(map[string]interface{}, len(keys))
converted := make(map[string]any, len(keys))
for _, keyMeta := range keys {
var err error

View File

@@ -278,7 +278,6 @@ func TestData(t *testing.T) {
},
},
} {
tc := tc
t.Run("", func(t *testing.T) {
got := tmpl.Data(tc.receiver, tc.groupLabels, tc.alerts...)
require.Equal(t, tc.exp, got)
@@ -403,7 +402,6 @@ func TestTemplateExpansion(t *testing.T) {
exp: "[key2 key4]",
},
} {
tc := tc
t.Run(tc.title, func(t *testing.T) {
f := tmpl.ExecuteTextString
if tc.html {
@@ -465,7 +463,6 @@ func TestTemplateExpansionWithOptions(t *testing.T) {
exp: "bar",
},
} {
tc := tc
t.Run(tc.title, func(t *testing.T) {
tmpl, err := FromGlobs([]string{}, tc.options...)
require.NoError(t, err)
@@ -579,10 +576,9 @@ func TestTemplateFuncs(t *testing.T) {
data: time.Now().Add(-1 * time.Hour),
exp: "1h 0m 0s",
}} {
tc := tc
t.Run(tc.title, func(t *testing.T) {
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
for range 10 {
wg.Add(1)
go func() {
defer wg.Done()
@@ -656,7 +652,6 @@ func TestDeepCopyWithTemplate(t *testing.T) {
want: nil,
},
} {
tc := tc
t.Run(tc.title, func(t *testing.T) {
got, err := DeepCopyWithTemplate(tc.input, tc.fn)
require.NoError(t, err)

View File

@@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"io"
"maps"
"net"
"net/http"
"os"
@@ -485,9 +486,7 @@ func (am *Alertmanager) addAlertCommand(omitEquals bool, alert *TestAlert) ([]by
args := []string{amURLFlag, "alert", "add"}
// Make a copy of the labels
labels := make(models.LabelSet, len(alert.labels))
for k, v := range alert.labels {
labels[k] = v
}
maps.Copy(labels, alert.labels)
if omitEquals {
// If alertname is present and omitEquals is true then the command should
// be `amtool alert add foo ...` and not `amtool alert add alertname=foo ...`.

View File

@@ -16,6 +16,7 @@ package test
import (
"encoding/json"
"fmt"
"strings"
"sync"
"testing"
"time"
@@ -105,12 +106,13 @@ func (c *Collector) add(alerts ...*models.GettableAlert) {
}
func (c *Collector) Check() string {
report := fmt.Sprintf("\ncollector %q:\n\n", c)
var report strings.Builder
report.WriteString(fmt.Sprintf("\ncollector %q:\n\n", c))
c.mtx.RLock()
defer c.mtx.RUnlock()
for iv, expected := range c.expected {
report += fmt.Sprintf("interval %v\n", iv)
report.WriteString(fmt.Sprintf("interval %v\n", iv))
var alerts []models.GettableAlerts
for at, got := range c.collected {
@@ -122,10 +124,10 @@ func (c *Collector) Check() string {
for _, exp := range expected {
found := len(exp) == 0 && len(alerts) == 0
report += "---\n"
report.WriteString("---\n")
for _, e := range exp {
report += fmt.Sprintf("- %v\n", c.opts.alertString(e))
report.WriteString(fmt.Sprintf("- %v\n", c.opts.alertString(e)))
}
for _, a := range alerts {
@@ -136,10 +138,10 @@ func (c *Collector) Check() string {
}
if found {
report += " [ ✓ ]\n"
report.WriteString(" [ ✓ ]\n")
} else {
c.t.Fail()
report += " [ ✗ ]\n"
report.WriteString(" [ ✗ ]\n")
}
}
}
@@ -161,23 +163,23 @@ func (c *Collector) Check() string {
}
if totalExp != totalAct {
c.t.Fail()
report += fmt.Sprintf("\nExpected total of %d alerts, got %d", totalExp, totalAct)
report.WriteString(fmt.Sprintf("\nExpected total of %d alerts, got %d", totalExp, totalAct))
}
if c.t.Failed() {
report += "\nreceived:\n"
report.WriteString("\nreceived:\n")
for at, col := range c.collected {
for _, alerts := range col {
report += fmt.Sprintf("@ %v\n", at)
report.WriteString(fmt.Sprintf("@ %v\n", at))
for _, a := range alerts {
report += fmt.Sprintf("- %v\n", c.opts.alertString(a))
report.WriteString(fmt.Sprintf("- %v\n", c.opts.alertString(a)))
}
}
}
}
return report
return report.String()
}
// alertsToString returns a string representation of the given Alerts. Use for

View File

@@ -16,6 +16,7 @@ package test
import (
"encoding/json"
"fmt"
"maps"
"net"
"net/http"
"reflect"
@@ -293,12 +294,8 @@ func (ws *MockWebhook) ServeHTTP(w http.ResponseWriter, req *http.Request) {
labels = models.LabelSet{}
annotations = models.LabelSet{}
)
for k, v := range a.Labels {
labels[k] = v
}
for k, v := range a.Annotations {
annotations[k] = v
}
maps.Copy(labels, a.Labels)
maps.Copy(annotations, a.Annotations)
start := strfmt.DateTime(a.StartsAt)
end := strfmt.DateTime(a.EndsAt)

View File

@@ -16,6 +16,7 @@ package test
import (
"encoding/json"
"fmt"
"strings"
"sync"
"testing"
"time"
@@ -105,12 +106,13 @@ func (c *Collector) add(alerts ...*models.GettableAlert) {
}
func (c *Collector) Check() string {
report := fmt.Sprintf("\ncollector %q:\n\n", c)
var report strings.Builder
report.WriteString(fmt.Sprintf("\ncollector %q:\n\n", c))
c.mtx.RLock()
defer c.mtx.RUnlock()
for iv, expected := range c.expected {
report += fmt.Sprintf("interval %v\n", iv)
report.WriteString(fmt.Sprintf("interval %v\n", iv))
var alerts []models.GettableAlerts
for at, got := range c.collected {
@@ -122,10 +124,10 @@ func (c *Collector) Check() string {
for _, exp := range expected {
found := len(exp) == 0 && len(alerts) == 0
report += "---\n"
report.WriteString("---\n")
for _, e := range exp {
report += fmt.Sprintf("- %v\n", c.opts.alertString(e))
report.WriteString(fmt.Sprintf("- %v\n", c.opts.alertString(e)))
}
for _, a := range alerts {
@@ -136,10 +138,10 @@ func (c *Collector) Check() string {
}
if found {
report += " [ ✓ ]\n"
report.WriteString(" [ ✓ ]\n")
} else {
c.t.Fail()
report += " [ ✗ ]\n"
report.WriteString(" [ ✗ ]\n")
}
}
}
@@ -161,23 +163,23 @@ func (c *Collector) Check() string {
}
if totalExp != totalAct {
c.t.Fail()
report += fmt.Sprintf("\nExpected total of %d alerts, got %d", totalExp, totalAct)
report.WriteString(fmt.Sprintf("\nExpected total of %d alerts, got %d", totalExp, totalAct))
}
if c.t.Failed() {
report += "\nreceived:\n"
report.WriteString("\nreceived:\n")
for at, col := range c.collected {
for _, alerts := range col {
report += fmt.Sprintf("@ %v\n", at)
report.WriteString(fmt.Sprintf("@ %v\n", at))
for _, a := range alerts {
report += fmt.Sprintf("- %v\n", c.opts.alertString(a))
report.WriteString(fmt.Sprintf("- %v\n", c.opts.alertString(a)))
}
}
}
}
return report
return report.String()
}
// alertsToString returns a string representation of the given Alerts. Use for

View File

@@ -16,6 +16,7 @@ package test
import (
"encoding/json"
"fmt"
"maps"
"net/http"
"net/http/httptest"
"reflect"
@@ -306,12 +307,8 @@ func (ws *MockWebhook) ServeHTTP(w http.ResponseWriter, req *http.Request) {
labels = models.LabelSet{}
annotations = models.LabelSet{}
)
for k, v := range a.Labels {
labels[k] = v
}
for k, v := range a.Annotations {
annotations[k] = v
}
maps.Copy(labels, a.Labels)
maps.Copy(annotations, a.Annotations)
start := strfmt.DateTime(a.StartsAt)
end := strfmt.DateTime(a.EndsAt)

View File

@@ -367,7 +367,6 @@ func TestAlertMerge(t *testing.T) {
}
for i, p := range pairs {
p := p
t.Run(strconv.Itoa(i), func(t *testing.T) {
if res := p.A.Merge(p.B); !reflect.DeepEqual(p.Res, res) {
t.Errorf("unexpected merged alert %#v", res)