pkg/degradation-detector/mergeDegradations.go (100 lines of code) (raw):
package degradation_detector
import (
"fmt"
"slices"
"strings"
)
type multipleDegradationWithSettings struct {
Details []Degradation
Settings Settings
}
type mergeInfoProvider interface {
GetMetric() string
GetMetricOrAlias() string
GetProject() string
MergeAnother(settings Settings) Settings
}
func (s PerformanceSettings) MergeAnother(settings Settings) Settings {
if !strings.Contains(s.Project, settings.GetProject()) {
s.Project = fmt.Sprintf("%s,%s", s.Project, settings.GetProject())
}
if s.MetricAlias != "" && s.Metric != settings.GetMetric() && !strings.Contains(s.Metric, settings.GetMetric()) {
s.Metric = fmt.Sprintf("%s,%s", s.Metric, settings.GetMetric())
}
return s
}
func (s BaseSettings) GetMetric() string {
return s.Metric
}
func (s BaseSettings) GetMetricOrAlias() string {
return s.Metric
}
func (s PerformanceSettings) GetMetricOrAlias() string {
if s.MetricAlias != "" {
return s.MetricAlias
}
return s.Metric
}
func (s PerformanceSettings) GetProject() string {
return s.Project
}
func (s StartupSettings) GetProject() string {
return s.Project
}
func (s StartupSettings) MergeAnother(settings Settings) Settings {
s.Project = fmt.Sprintf("%s,%s", s.Project, settings.GetProject())
return s
}
func (s FleetStartupSettings) GetProject() string {
return "fleet"
}
func (s FleetStartupSettings) MergeAnother(settings Settings) Settings {
s.Metric = fmt.Sprintf("%s,%s", s.Metric, settings.GetMetric())
return s
}
func MergeDegradations(degradations <-chan DegradationWithSettings) chan DegradationWithSettings {
c := make(chan DegradationWithSettings, 100)
go func() {
defer close(c)
type degradationKey struct {
slackChannel string
metric string
build string
}
m := make(map[degradationKey]multipleDegradationWithSettings, 100)
// Collect and merge degradations
for d := range degradations {
key := degradationKey{
slackChannel: d.Settings.SlackChannel(),
metric: d.Settings.GetMetricOrAlias(),
build: d.Details.Build,
}
if existing, found := m[key]; found {
m[key] = multipleDegradationWithSettings{
Details: append([]Degradation{d.Details}, existing.Details...),
Settings: existing.Settings.MergeAnother(d.Settings),
}
} else {
m[key] = multipleDegradationWithSettings{
Details: []Degradation{d.Details},
Settings: d.Settings,
}
}
}
// Find the largest degradation
for _, v := range m {
slices.SortFunc(v.Details, func(a, b Degradation) int {
return int(b.medianValues.PercentageChange() - a.medianValues.PercentageChange())
})
highest := v.Details[0]
c <- DegradationWithSettings{
Details: Degradation{
Build: highest.Build,
timestamp: highest.timestamp,
medianValues: highest.medianValues,
IsDegradation: highest.IsDegradation,
},
Settings: v.Settings,
}
}
}()
return c
}