blob: b903252dd81af7adc333d3db0b0940a3d022c6d1 [file] [log] [blame]
package pinpoint
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"go.skia.org/infra/go/auth"
"go.skia.org/infra/go/httputils"
"go.skia.org/infra/go/metrics2"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/go/sklog"
"golang.org/x/oauth2/google"
)
const (
pinpointURL = "https://pinpoint-dot-chromeperf.appspot.com/api/new"
contentType = "application/json"
)
type CreateBisectRequest struct {
ComparisonMode string `json:"comparison_mode"`
StartGitHash string `json:"start_git_hash"`
EndGitHash string `json:"end_git_hash"`
Configuration string `json:"configuration"`
Benchmark string `json:"benchmark"`
Story string `json:"story"`
Chart string `json:"chart"`
Statistic string `json:"statistic"`
ComparisonMagnitude string `json:"comparison_magnitude"`
Pin string `json:"pin"`
Project string `json:"project"`
BugId string `json:"bug_id"`
User string `json:"user"`
}
type CreateBisectResponse struct {
JobID string `json:"jobId"`
JobURL string `json:"jobUrl"`
}
type Client struct {
httpClient *http.Client
createBisectCalled metrics2.Counter
createBisectFailed metrics2.Counter
}
// New returns a new PinpointClient instance.
func New(ctx context.Context) (*Client, error) {
tokenSource, err := google.DefaultTokenSource(ctx, auth.ScopeUserinfoEmail)
if err != nil {
return nil, skerr.Wrapf(err, "Failed to create pinpoint client.")
}
client := httputils.DefaultClientConfig().WithTokenSource(tokenSource).Client()
return &Client{
httpClient: client,
createBisectCalled: metrics2.GetCounter("pinpoint_create_bisect_called"),
createBisectFailed: metrics2.GetCounter("pinpoint_create_bisect_failed"),
}, nil
}
// CreateBisect calls pinpoint API to create bisect job.
func (pc *Client) CreateBisect(ctx context.Context, createBisectRequest CreateBisectRequest) (*CreateBisectResponse, error) {
pc.createBisectCalled.Inc(1)
requestURL := buildPinpointRequestURL(createBisectRequest)
sklog.Debugf("Preparing to call this Pinpoint service URL: %s", requestURL)
httpResponse, err := httputils.PostWithContext(ctx, pc.httpClient, requestURL, contentType, nil)
if err != nil {
pc.createBisectFailed.Inc(1)
return nil, skerr.Wrapf(err, "Failed to get pinpoint response.")
}
sklog.Debugf("Got response from Pinpoint service: %+v", *httpResponse)
respBody, err := io.ReadAll(httpResponse.Body)
if err != nil {
pc.createBisectFailed.Inc(1)
return nil, skerr.Wrapf(err, "Failed to read body from pinpoint response.")
}
if httpResponse.StatusCode != http.StatusOK {
errMsg := fmt.Sprintf("The request failed with status code %d and body: %s", httpResponse.StatusCode, string(respBody))
err = errors.New(errMsg)
pc.createBisectFailed.Inc(1)
return nil, skerr.Wrapf(err, "Pinpoint request failed.")
}
resp := CreateBisectResponse{}
err = json.Unmarshal([]byte(respBody), &resp)
if err != nil {
pc.createBisectFailed.Inc(1)
return nil, skerr.Wrapf(err, "Failed to parse pinpoint response body.")
}
return &resp, nil
}
func buildPinpointRequestURL(createBisectRequest CreateBisectRequest) string {
params := url.Values{}
if createBisectRequest.ComparisonMode != "" {
params.Set("comparison_mode", createBisectRequest.ComparisonMode)
}
if createBisectRequest.StartGitHash != "" {
params.Set("start_git_hash", createBisectRequest.StartGitHash)
}
if createBisectRequest.EndGitHash != "" {
params.Set("end_git_hash", createBisectRequest.EndGitHash)
}
if createBisectRequest.Configuration != "" {
params.Set("configuration", createBisectRequest.Configuration)
}
if createBisectRequest.Benchmark != "" {
params.Set("benchmark", createBisectRequest.Benchmark)
}
if createBisectRequest.Story != "" {
params.Set("story", createBisectRequest.Story)
}
if createBisectRequest.Chart != "" {
params.Set("chart", createBisectRequest.Chart)
}
if createBisectRequest.Statistic != "" {
params.Set("statistic", createBisectRequest.Statistic)
}
if createBisectRequest.ComparisonMagnitude != "" {
params.Set("comparison_magnitude", createBisectRequest.ComparisonMagnitude)
}
if createBisectRequest.Pin != "" {
params.Set("pin", createBisectRequest.Pin)
}
if createBisectRequest.Project != "" {
params.Set("project", createBisectRequest.Project)
}
if createBisectRequest.BugId != "" {
params.Set("bug_id", createBisectRequest.BugId)
}
if createBisectRequest.User != "" {
params.Set("user", createBisectRequest.User)
}
params.Set("tags", "{\"origin\":\"skia_perf\"}")
return fmt.Sprintf("%s?%s", pinpointURL, params.Encode())
}