blob: e025ece4e57541c2265fc32cdb48fd64e5a49b88 [file] [log] [blame]
package poller
// Initializes and polls the various issue frameworks.
import (
"context"
"os/user"
"path/filepath"
"time"
"cloud.google.com/go/storage"
"golang.org/x/oauth2"
"google.golang.org/api/option"
"go.skia.org/infra/bugs-central/go/bugs"
"go.skia.org/infra/bugs-central/go/bugs/github"
"go.skia.org/infra/bugs-central/go/bugs/issuetracker"
"go.skia.org/infra/bugs-central/go/bugs/monorail"
"go.skia.org/infra/bugs-central/go/db"
"go.skia.org/infra/bugs-central/go/types"
"go.skia.org/infra/go/baseapp"
"go.skia.org/infra/go/cleanup"
github_lib "go.skia.org/infra/go/github"
"go.skia.org/infra/go/httputils"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/go/sklog"
)
const (
// All recognized clients.
AndroidClient types.RecognizedClient = "Android"
ChromiumClient types.RecognizedClient = "Chromium"
FlutterNativeClient types.RecognizedClient = "Flutter-native"
FlutterOnWebClient types.RecognizedClient = "Flutter-on-web"
SkiaClient types.RecognizedClient = "Skia"
)
// IssuesPoller will be used to poll the different issue frameworks.
type IssuesPoller struct {
storageClient *storage.Client
pathToGithubToken string
pathToServiceAccountFile string
dbClient *db.FirestoreDB
}
// New returns an instance of IssuesPoller.
func New(ctx context.Context, ts oauth2.TokenSource, pathToServiceAccountFile string, dbClient *db.FirestoreDB) (*IssuesPoller, error) {
httpClient := httputils.DefaultClientConfig().WithTokenSource(ts).With2xxOnly().Client()
storageClient, err := storage.NewClient(ctx, option.WithHTTPClient(httpClient))
if err != nil {
return nil, skerr.Wrapf(err, "failed to init storage client")
}
pathToGithubToken := filepath.Join(github_lib.GITHUB_TOKEN_SERVER_PATH, github_lib.GITHUB_TOKEN_FILENAME)
if *baseapp.Local {
usr, err := user.Current()
if err != nil {
return nil, err
}
pathToGithubToken = filepath.Join(usr.HomeDir, github_lib.GITHUB_TOKEN_FILENAME)
}
return &IssuesPoller{
storageClient: storageClient,
pathToGithubToken: pathToGithubToken,
pathToServiceAccountFile: pathToServiceAccountFile,
dbClient: dbClient,
}, nil
}
// Start polls the different issue frameworks and populates DB and an in-memory object with that data.
// It hardcodes information about Skia's various clients. It may be possible to extract some/all of these into
// flags or YAML config files in the future.
func (p *IssuesPoller) Start(ctx context.Context, pollInterval time.Duration) error {
// Instantiate the in-memory open issues object that will be passed to the different frameworks to
// populate.
openIssues := bugs.InitOpenIssues()
// Instantiate the bug frameworks with the different client configurations and then poll them.
bugFrameworks := []bugs.BugFramework{}
//////////////////// Android - IssueTracker ////////////////////
androidQueryConfig := &issuetracker.IssueTrackerQueryConfig{
Query: "componentid:1346 status:open",
Client: AndroidClient,
UntriagedPriorities: []string{"P4"},
UntriagedAliases: []string{"skia-android-triage@google.com"},
}
androidIssueTracker, err := issuetracker.New(p.storageClient, openIssues, androidQueryConfig)
if err != nil {
return skerr.Wrapf(err, "failed to init issuetracker for android")
}
bugFrameworks = append(bugFrameworks, androidIssueTracker)
//////////////////// Flutter_on_web - Github ////////////////////
flutterOnWebQueryConfig := &github.GithubQueryConfig{
Labels: []string{"e: web_canvaskit"},
Open: true,
PriorityRequired: true,
Client: FlutterOnWebClient,
}
flutterOnWebGithub, err := github.New(ctx, "flutter", "flutter", p.pathToGithubToken, openIssues, flutterOnWebQueryConfig)
if err != nil {
return skerr.Wrapf(err, "failed to init github for flutter-on-web")
}
bugFrameworks = append(bugFrameworks, flutterOnWebGithub)
//////////////////// Flutter_native - Github ////////////////////
flutterNativeQueryConfig := &github.GithubQueryConfig{
Labels: []string{"dependency: skia"},
ExcludeLabels: []string{"e: web_canvaskit"}, // These issues are already covered by flutter-on-web
Open: true,
PriorityRequired: false,
Client: FlutterNativeClient,
}
flutterNativeGithub, err := github.New(ctx, "flutter", "flutter", p.pathToGithubToken, openIssues, flutterNativeQueryConfig)
if err != nil {
return skerr.Wrapf(err, "failed to init github for flutter-on-web")
}
bugFrameworks = append(bugFrameworks, flutterNativeGithub)
//////////////////// Chromium:Internals>Skia - Monorail ////////////////////
crQueryConfig1 := &monorail.MonorailQueryConfig{
Instance: "chromium",
Query: "is:open component=Internals>Skia",
Client: ChromiumClient,
UntriagedStatuses: []string{"Untriaged", "Unconfirmed"},
}
crMonorail1, err := monorail.New(ctx, p.pathToServiceAccountFile, openIssues, crQueryConfig1)
if err != nil {
return skerr.Wrapf(err, "failed to init monorail for chromium")
}
bugFrameworks = append(bugFrameworks, crMonorail1)
//////////////////// Chromium:Internals>Skia>Compositing - Monorail ////////////////////
crQueryConfig2 := &monorail.MonorailQueryConfig{
Instance: "chromium",
Query: "is:open component=Internals>Skia>Compositing",
Client: ChromiumClient,
UntriagedStatuses: []string{"Untriaged", "Unconfirmed"},
}
crMonorail2, err := monorail.New(ctx, p.pathToServiceAccountFile, openIssues, crQueryConfig2)
if err != nil {
return skerr.Wrapf(err, "failed to init monorail for chromium")
}
bugFrameworks = append(bugFrameworks, crMonorail2)
//////////////////// Chromium:Internals>Skia>PDF - Monorail ////////////////////
crQueryConfig3 := &monorail.MonorailQueryConfig{
Instance: "chromium",
Query: "is:open component=Internals>Skia>PDF",
Client: ChromiumClient,
UntriagedStatuses: []string{"Untriaged", "Unconfirmed"},
}
crMonorail3, err := monorail.New(ctx, p.pathToServiceAccountFile, openIssues, crQueryConfig3)
if err != nil {
return skerr.Wrapf(err, "failed to init monorail for chromium")
}
bugFrameworks = append(bugFrameworks, crMonorail3)
//////////////////// Skia - Monorail ////////////////////
skQueryConfig := &monorail.MonorailQueryConfig{
Instance: "skia",
Query: "is:open",
Client: SkiaClient,
UntriagedStatuses: []string{"New"},
}
skMonorail, err := monorail.New(ctx, p.pathToServiceAccountFile, openIssues, skQueryConfig)
if err != nil {
return skerr.Wrapf(err, "failed to init monorail for skia")
}
bugFrameworks = append(bugFrameworks, skMonorail)
cleanup.Repeat(pollInterval, func(ctx context.Context) {
if !*baseapp.Local {
// Ignore the passed-in context; this allows us to continue running even if the
// context is canceled due to transient errors.
ctx = context.Background()
}
// Create a runID timestamp to associate all found issues with this poll iteration.
runId := p.dbClient.GenerateRunId(time.Now())
// Search all bug frameworks.
for _, b := range bugFrameworks {
if err := b.SearchClientAndPersist(ctx, p.dbClient, runId); err != nil {
sklog.Errorf("Error when searching and saving issues: %s", err)
return
}
}
// We are done with this iteration. Add the runId timestamp to the DB.
if err := p.dbClient.StoreRunId(context.Background(), runId); err != nil {
sklog.Errorf("Could not store runId in DB: %s", err)
return
}
openIssues.PrettyPrintOpenIssues()
}, nil)
return nil
}