@@ -31,6 +31,8 @@ import (
3131 "github.com/uber-go/tally/v4"
3232 "github.com/uber/submitqueue/core/consumer"
3333 "github.com/uber/submitqueue/entity"
34+ "github.com/uber/submitqueue/extension/changeprovider"
35+ githubprovider "github.com/uber/submitqueue/extension/changeprovider/github"
3436 "github.com/uber/submitqueue/extension/counter"
3537 mysqlcounter "github.com/uber/submitqueue/extension/counter/mysql"
3638 "github.com/uber/submitqueue/extension/mergechecker"
@@ -190,8 +192,11 @@ func run() error {
190192 // Create merge checker
191193 mc := newMergeChecker (logger , scope )
192194
195+ // Create change provider
196+ cp := newChangeProvider (logger , scope )
197+
193198 // Register controllers
194- if err := registerControllers (c , logger .Sugar (), scope , registry , mc , cnt , store ); err != nil {
199+ if err := registerControllers (c , logger .Sugar (), scope , registry , mc , cp , cnt , store ); err != nil {
195200 return err
196201 }
197202
@@ -376,7 +381,7 @@ func newTopicRegistry(q extqueue.Queue, subscriberName string) (consumer.TopicRe
376381// │ │ │
377382// └────────┴────────────────────────┘
378383
379- func registerControllers (c consumer.Consumer , logger * zap.SugaredLogger , scope tally.Scope , registry consumer.TopicRegistry , mc mergechecker.MergeChecker , cnt counter.Counter , store storage.Storage ) error {
384+ func registerControllers (c consumer.Consumer , logger * zap.SugaredLogger , scope tally.Scope , registry consumer.TopicRegistry , mc mergechecker.MergeChecker , cp changeprovider. ChangeProvider , cnt counter.Counter , store storage.Storage ) error {
380385 requestController := start .NewController (
381386 logger ,
382387 scope ,
@@ -395,6 +400,7 @@ func registerControllers(c consumer.Consumer, logger *zap.SugaredLogger, scope t
395400 store ,
396401 registry ,
397402 mc ,
403+ cp ,
398404 consumer .TopicKeyValidate ,
399405 "orchestrator-validate" ,
400406 )
@@ -514,6 +520,36 @@ func registerControllers(c consumer.Consumer, logger *zap.SugaredLogger, scope t
514520 return nil
515521}
516522
523+ // getEnv returns environment variable value or default if not set.
524+ func getEnv (key , defaultVal string ) string {
525+ if val := os .Getenv (key ); val != "" {
526+ return val
527+ }
528+ return defaultVal
529+ }
530+
531+ // parseTimeout parses a duration from environment variable with fallback to default.
532+ // Returns defaultVal if envVal is empty or cannot be parsed.
533+ func parseTimeout (envVal string , defaultVal time.Duration ) time.Duration {
534+ if envVal == "" {
535+ return defaultVal
536+ }
537+ if d , err := time .ParseDuration (envVal ); err == nil {
538+ return d
539+ }
540+ return defaultVal
541+ }
542+
543+ // buildGitHubHTTPClient creates an http.Client configured for GitHub API calls.
544+ // Configures timeout and optional bearer token authentication.
545+ func buildGitHubHTTPClient (token string , timeout time.Duration ) * http.Client {
546+ httpClient := & http.Client {Timeout : timeout }
547+ if token != "" {
548+ httpClient .Transport = & bearerTransport {token : token }
549+ }
550+ return httpClient
551+ }
552+
517553// newMergeChecker creates a MergeChecker for GitHub (github.com).
518554// Configured via GITHUB_TOKEN and GITHUB_GRAPHQL_URL environment variables.
519555func newMergeChecker (logger * zap.Logger , scope tally.Scope ) mergechecker.MergeChecker {
@@ -539,6 +575,26 @@ func newMergeChecker(logger *zap.Logger, scope tally.Scope) mergechecker.MergeCh
539575 })
540576}
541577
578+ // newChangeProvider creates a ChangeProvider for GitHub (github.com).
579+ // Configured via GITHUB_BASE_URL, GITHUB_TOKEN, and GITHUB_TIMEOUT environment variables.
580+ // Uses pure dependency injection - creates http.Client with auth configured in Transport.
581+ func newChangeProvider (logger * zap.Logger , scope tally.Scope ) changeprovider.ChangeProvider {
582+ // 1. Read configuration from environment
583+ baseURL := getEnv ("GITHUB_BASE_URL" , "https://api.github.com" )
584+ token := os .Getenv ("GITHUB_TOKEN" )
585+ timeout := parseTimeout (os .Getenv ("GITHUB_TIMEOUT" ), 30 * time .Second )
586+
587+ // 2. Build HTTP client with caller-controlled config (auth + timeout)
588+ httpClient := buildGitHubHTTPClient (token , timeout )
589+
590+ // 3. Inject into provider
591+ return githubprovider .NewProvider (githubprovider.Params {
592+ Client : githubprovider .NewClient (httpClient , baseURL ),
593+ Logger : logger .Sugar (),
594+ MetricsScope : scope .SubScope ("changeprovider" ),
595+ })
596+ }
597+
542598// bearerTransport is an http.RoundTripper that adds a Bearer token to requests.
543599type bearerTransport struct {
544600 token string
0 commit comments