<commit_before>package issues

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"

	"go.skia.org/infra/go/util"
)

const (
	CODESITE_BASE_URL = "https://www.googleapis.com/projecthosting/v2/projects/skia/issues"
	MONORAIL_BASE_URL = "https://monorail-prod.appspot.com/_ah/api/monorail/v1/projects/skia/issues"
)

// IssueTracker is a genric interface to an issue tracker that allows us
// to connect issues with items (identified by an id).
type IssueTracker interface {
	// FromQueury returns issue that match the given query string.
	FromQuery(q string) ([]Issue, error)
}

// CodesiteIssueTracker implements IssueTracker.
type CodesiteIssueTracker struct {
	apiKey string
	client *http.Client
}

func NewIssueTracker(apiKey string) IssueTracker {
	return &CodesiteIssueTracker{
		apiKey: apiKey,
		client: util.NewTimeoutClient(),
	}
}

// Issue is an individual issue returned from the project hosting response.
type Issue struct {
	ID    int64  `json:"id"`
	Title string `json:"title"`
	State string `json:"state"`
}

// IssueResponse is used to decode JSON responses from the project hosting API.
type IssueResponse struct {
	Items []Issue `json:"items"`
}

// FromQuery is part of the IssueTracker interface. See documentation there.
func (c *CodesiteIssueTracker) FromQuery(q string) ([]Issue, error) {
	query := url.Values{}
	query.Add("q", q)
	query.Add("key", c.apiKey)
	query.Add("fields", "items/id,items/state,items/title")
	return get(c.client, CODESITE_BASE_URL+"?"+query.Encode())
}

// MonorailIssueTracker implements IssueTracker.
type MonorailIssueTracker struct {
	client *http.Client
}

func NewMonorailIssueTracker(client *http.Client) IssueTracker {
	return &MonorailIssueTracker{
		client: client,
	}
}

// FromQuery is part of the IssueTracker interface. See documentation there.
func (m *MonorailIssueTracker) FromQuery(q string) ([]Issue, error) {
	query := url.Values{}
	query.Add("q", q)
	query.Add("fields", "items/id,items/state,items/title")
	return get(m.client, MONORAIL_BASE_URL+"?"+query.Encode())
}

func get(client *http.Client, url string) ([]Issue, error) {
	resp, err := client.Get(url)
	if err != nil || resp == nil || resp.StatusCode != 200 {
		return nil, fmt.Errorf("Failed to retrieve issue tracker response: %s", err)
	}<commit_msg>Add client id and scope note to MonorailIssueTracker.<commit_after>package issues

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"

	"go.skia.org/infra/go/util"
)

const (
	CODESITE_BASE_URL = "https://www.googleapis.com/projecthosting/v2/projects/skia/issues"
	MONORAIL_BASE_URL = "https://monorail-prod.appspot.com/_ah/api/monorail/v1/projects/skia/issues"
)

// IssueTracker is a genric interface to an issue tracker that allows us
// to connect issues with items (identified by an id).
type IssueTracker interface {
	// FromQueury returns issue that match the given query string.
	FromQuery(q string) ([]Issue, error)
}

// CodesiteIssueTracker implements IssueTracker.
type CodesiteIssueTracker struct {
	apiKey string
	client *http.Client
}

func NewIssueTracker(apiKey string) IssueTracker {
	return &CodesiteIssueTracker{
		apiKey: apiKey,
		client: util.NewTimeoutClient(),
	}
}

// Issue is an individual issue returned from the project hosting response.
type Issue struct {
	ID    int64  `json:"id"`
	Title string `json:"title"`
	State string `json:"state"`
}

// IssueResponse is used to decode JSON responses from the project hosting API.
type IssueResponse struct {
	Items []Issue `json:"items"`
}

// FromQuery is part of the IssueTracker interface. See documentation there.
func (c *CodesiteIssueTracker) FromQuery(q string) ([]Issue, error) {
	query := url.Values{}
	query.Add("q", q)
	query.Add("key", c.apiKey)
	query.Add("fields", "items/id,items/state,items/title")
	return get(c.client, CODESITE_BASE_URL+"?"+query.Encode())
}

// MonorailIssueTracker implements IssueTracker.
//
// Note that to use a MonorailIssueTracker from GCE that client id of the
// project needs to be whitelisted in Monorail, which is already done for Skia
// Infra. Also note that the instance running needs to have the
// https://www.googleapis.com/auth/userinfo.email scope added to it.
type MonorailIssueTracker struct {
	client *http.Client
}

func NewMonorailIssueTracker(client *http.Client) IssueTracker {
	return &MonorailIssueTracker{
		client: client,
	}
}

// FromQuery is part of the IssueTracker interface. See documentation there.
func (m *MonorailIssueTracker) FromQuery(q string) ([]Issue, error) {
	query := url.Values{}
	query.Add("q", q)
	query.Add("fields", "items/id,items/state,items/title")
	return get(m.client, MONORAIL_BASE_URL+"?"+query.Encode())
}

func get(client *http.Client, url string) ([]Issue, error) {
	resp, err := client.Get(url)
	if err != nil || resp == nil || resp.StatusCode != 200 {
		return nil, fmt.Errorf("Failed to retrieve issue tracker response: %s", err)
	}
{'fraction_non_alphanumeric': 0.12451520718513982, 'fraction_numerical': 0.0028577260665441926, 'mean_word_length': 4.691056910569106, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 5, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '467356', 'n_tokens_mistral': 1634, 'n_tokens_neox': 1579, 'n_words': 465}