Repository: prometheus/alertmanager
File: config/notifiers.go (Go)

Code before:
func (c *EmailConfig) UnmarshalYAML(unmarshal func(any) error) error {
	*c = DefaultEmailConfig
	type plain EmailConfig
	if err := unmarshal((*plain)(c)); err != nil {
		return err
	}
	if c.To == "" {
		return errors.New("missing to address in email config")
	}
	// Header names are case-insensitive, check for collisions.
	normalizedHeaders := map[string]string{}
	for h, v := range c.Headers {
		normalized := textproto.CanonicalMIMEHeaderKey(h)
		if _, ok := normalizedHeaders[normalized]; ok {
			return fmt.Errorf("duplicate header %q in email config", normalized)
		}
		normalizedHeaders[normalized] = v
	}
	c.Headers = normalizedHeaders

	if c.Threading.Enabled {
		if _, ok := normalizedHeaders["References"]; ok {
			return errors.New("conflicting configuration: threading.enabled conflicts with custom References header")
		}
		if _, ok := normalizedHeaders["In-Reply-To"]; ok {
			return errors.New("conflicting configuration: threading.enabled conflicts with custom In-Reply-to header")
		}
	}

	return nil
}

// PagerdutyConfig configures notifications via PagerDuty.
type PagerdutyConfig struct {
	NotifierConfig `yaml:",inline" json:",inline"`

	HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`

	ServiceKey     Secret            `yaml:"service_key,omitempty" json:"service_key,omitempty"`
	ServiceKeyFile string            `yaml:"service_key_file,omitempty" json:"service_key_file,omitempty"`
	RoutingKey     Secret            `yaml:"routing_key,omitempty" json:"routing_key,omitempty"`
	RoutingKeyFile string            `yaml:"routing_key_file,omitempty" json:"routing_key_file,omitempty"`
	URL            *URL              `yaml:"url,omitempty" json:"url,omitempty"`
	Client         string            `yaml:"client,omitempty" json:"client,omitempty"`
	ClientURL      string            `yaml:"client_url,omitempty" json:"client_url,omitempty"`
	Description    string            `yaml:"description,omitempty" json:"description,omitempty"`
	Details        map[string]string `yaml:"details,omitempty" json:"details,omitempty"`
	Images         []PagerdutyImage  `yaml:"images,omitempty" json:"images,omitempty"`
	Links          []PagerdutyLink   `yaml:"links,omitempty" json:"links,omitempty"`
	Source         string            `yaml:"source,omitempty" json:"source,omitempty"`
	Severity       string            `yaml:"severity,omitempty" json:"severity,omitempty"`

Review comment (suggestion):
tiny nitpick
```suggestion
			return errors.New("conflicting configuration: threading.enabled conflicts with custom In-Reply-To header")
```

Code after:
func (c *EmailConfig) UnmarshalYAML(unmarshal func(any) error) error {
	*c = DefaultEmailConfig
	type plain EmailConfig
	if err := unmarshal((*plain)(c)); err != nil {
		return err
	}
	if c.To == "" {
		return errors.New("missing to address in email config")
	}
	// Header names are case-insensitive, check for collisions.
	normalizedHeaders := map[string]string{}
	for h, v := range c.Headers {
		normalized := textproto.CanonicalMIMEHeaderKey(h)
		if _, ok := normalizedHeaders[normalized]; ok {
			return fmt.Errorf("duplicate header %q in email config", normalized)
		}
		normalizedHeaders[normalized] = v
	}
	c.Headers = normalizedHeaders

	if c.Threading.Enabled {
		if _, ok := normalizedHeaders["References"]; ok {
			return errors.New("conflicting configuration: threading.enabled conflicts with custom References header")
		}
		if _, ok := normalizedHeaders["In-Reply-To"]; ok {
			return errors.New("conflicting configuration: threading.enabled conflicts with custom In-Reply-To header")
		}
	}

	return nil
}

// PagerdutyConfig configures notifications via PagerDuty.
type PagerdutyConfig struct {
	NotifierConfig `yaml:",inline" json:",inline"`

	HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`

	ServiceKey     Secret            `yaml:"service_key,omitempty" json:"service_key,omitempty"`
	ServiceKeyFile string            `yaml:"service_key_file,omitempty" json:"service_key_file,omitempty"`
	RoutingKey     Secret            `yaml:"routing_key,omitempty" json:"routing_key,omitempty"`
	RoutingKeyFile string            `yaml:"routing_key_file,omitempty" json:"routing_key_file,omitempty"`
	URL            *URL              `yaml:"url,omitempty" json:"url,omitempty"`
	Client         string            `yaml:"client,omitempty" json:"client,omitempty"`
	ClientURL      string            `yaml:"client_url,omitempty" json:"client_url,omitempty"`
	Description    string            `yaml:"description,omitempty" json:"description,omitempty"`
	Details        map[string]string `yaml:"details,omitempty" json:"details,omitempty"`
	Images         []PagerdutyImage  `yaml:"images,omitempty" json:"images,omitempty"`
	Links          []PagerdutyLink   `yaml:"links,omitempty" json:"links,omitempty"`
	Source         string            `yaml:"source,omitempty" json:"source,omitempty"`
	Severity       string            `yaml:"severity,omitempty" json:"severity,omitempty"`