blob: 01416e82fa3f263c5c561a63206bac25546c685b [file] [log] [blame]
package roller
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/url"
"strings"
"go.skia.org/infra/go/httputils"
"go.skia.org/infra/go/metrics2"
"go.skia.org/infra/go/sklog"
"go.skia.org/infra/go/util"
)
// Update the current sheriff list.
func getSheriff(parentName, childName, metricsName string, sheriffSources, backupSheriffs []string) ([]string, error) {
tags := map[string]string{
"roller": metricsName,
}
m := metrics2.GetInt64Metric("autoroll_get_sheriff_success", tags)
allEmails := []string{}
for _, s := range sheriffSources {
emails, err := getSheriffHelper(s)
if err != nil {
sklog.Errorf("Failed to retrieve sheriff(s): %s", err)
m.Update(0)
if len(backupSheriffs) == 0 {
return nil, fmt.Errorf("Failed to retrieve sheriffs and no backup sheriffs supplied! %s", err)
}
return backupSheriffs, nil
}
allEmails = append(allEmails, emails...)
}
m.Update(1)
return allEmails, nil
}
// Parse the sheriff list from JS. Expects the list in this format:
// document.write('somebody, somebodyelse')
// TODO(borenet): Remove this once Chromium has a proper sheriff endpoint, ie.
// https://bugs.chromium.org/p/chromium/issues/detail?id=769804
func getSheriffJS(js string) []string {
trimmed := strings.TrimSuffix(strings.TrimPrefix(strings.TrimSpace(js), "document.write('"), "')")
list := strings.Split(trimmed, ",")
rv := make([]string, 0, len(list))
for _, name := range list {
name = strings.TrimSpace(name)
if name != "" {
rv = append(rv, name+"@chromium.org")
}
}
return rv
}
// Helper for loading the sheriff list.
func getSheriffHelper(sheriffConfig string) ([]string, error) {
// If the passed-in sheriffConfig doesn't look like a URL, it's probably an
// email address. Use it directly.
if _, err := url.ParseRequestURI(sheriffConfig); err != nil {
if strings.Count(sheriffConfig, "@") == 1 {
return []string{sheriffConfig}, nil
} else {
return nil, fmt.Errorf("Sheriff must be an email address or a valid URL; %q doesn't look like either.", sheriffConfig)
}
}
// Hit the URL to get the email address. Expect JSON or a JS file which
// document.writes the Sheriff(s) in a comma-separated list.
client := httputils.NewTimeoutClient()
resp, err := client.Get(sheriffConfig)
if err != nil {
return nil, err
}
defer util.Close(resp.Body)
if strings.HasSuffix(sheriffConfig, ".js") {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return getSheriffJS(string(body)), nil
} else {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var sheriff struct {
Emails []string `json:"emails"`
Username string `json:"username"`
}
if err := json.NewDecoder(bytes.NewReader(body)).Decode(&sheriff); err != nil {
return nil, err
}
if sheriff.Emails != nil && len(sheriff.Emails) > 0 {
return sheriff.Emails, nil
}
if sheriff.Username != "" {
return []string{sheriff.Username}, nil
}
return nil, fmt.Errorf("Unable to parse sheriff email(s) from %q. JSON: %q", sheriffConfig, body)
}
}