blob: 9f84fc0516023e6a8f9b4d7e3af1b412e550cf4f [file] [log] [blame]
/*
Package rotations provides helpers for sheriff/trooper rotations.
*/
package rotations
import (
"bytes"
"encoding/json"
"io"
"net/http"
"sort"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/go/util"
)
const (
SkiaGardenerURL = "https://chrome-ops-rotation-proxy.appspot.com/current/grotation:skia-gardener"
InfraGardenerURL = "https://chrome-ops-rotation-proxy.appspot.com/current/grotation:skia-infra-gardener"
errMsgTmpl = "Unable to parse rotation member(s) from %q. JSON: %q"
)
// FromURL attempts to load the current rotation member(s) from the given URL.
func FromURL(c *http.Client, url string) ([]string, error) {
// Hit the URL to get the email address. Expect JSON or a JS file which
// document.writes the email(s) in a comma-separated list.
resp, err := c.Get(url)
if err != nil {
return nil, skerr.Wrap(err)
}
defer util.Close(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, skerr.Wrap(err)
}
var rotation struct {
Emails []string `json:"emails"`
Username string `json:"username"`
}
if err := json.NewDecoder(bytes.NewReader(body)).Decode(&rotation); err != nil {
return nil, skerr.Wrapf(err, errMsgTmpl, url, body)
}
found := false
emails := util.StringSet{}
if rotation.Emails != nil {
emails.AddLists(rotation.Emails)
found = true
}
if rotation.Username != "" {
emails[rotation.Username] = true
found = true
}
if found {
// Sort for consistency in testing.
rv := emails.Keys()
sort.Strings(rv)
return rv, nil
} else {
return nil, skerr.Wrapf(skerr.Fmt("Missing 'emails' and 'username' field"), errMsgTmpl, url, body)
}
}