From 3c3be138c5d3119d5f4f7d187e92974378de02e4 Mon Sep 17 00:00:00 2001 From: Henry McConville Date: Sun, 13 Apr 2025 17:24:00 +0100 Subject: [PATCH] replace http calls with github sdk --- config/config.go | 30 +++--- exporter/gather.go | 139 ------------------------- exporter/http.go | 160 ---------------------------- exporter/prometheus.go | 195 ++++++++++++++++++++++++++--------- exporter/structs.go | 24 +++-- go.mod | 6 +- go.sum | 7 +- main.go | 3 + test/github_exporter_test.go | 16 +-- 9 files changed, 198 insertions(+), 382 deletions(-) delete mode 100644 exporter/gather.go delete mode 100644 exporter/http.go diff --git a/config/config.go b/config/config.go index c81f63df..5d7b9d46 100644 --- a/config/config.go +++ b/config/config.go @@ -17,10 +17,12 @@ import ( // Config struct holds all the runtime configuration for the application type Config struct { *cfg.BaseConfig - apiUrl *url.URL - repositories []string - organisations []string - users []string + apiUrl *url.URL + + Repositories []string + Organisations []string + Users []string + apiToken string targetURLs []string gitHubApp bool @@ -148,19 +150,19 @@ func (c *Config) SetAPIURL(u string) error { // Overrides the entire list of repositories func (c *Config) SetRepositories(repos []string) { - c.repositories = repos + c.Repositories = repos c.setScrapeURLs() } // Overrides the entire list of organisations func (c *Config) SetOrganisations(orgs []string) { - c.organisations = orgs + c.Organisations = orgs c.setScrapeURLs() } // Overrides the entire list of users func (c *Config) SetUsers(users []string) { - c.users = users + c.Users = users c.setScrapeURLs() } @@ -226,13 +228,13 @@ func (c *Config) setScrapeURLs() error { opts := map[string]string{"per_page": "100"} // Used to set the Github API to return 100 results per page (max) - if len(c.repositories) == 0 && len(c.organisations) == 0 && len(c.users) == 0 { + if len(c.Repositories) == 0 && len(c.Organisations) == 0 && len(c.Users) == 0 { log.Info("No targets specified. Only rate limit endpoint will be scraped") } // Append repositories to the array - if len(c.repositories) > 0 { - for _, x := range c.repositories { + if len(c.Repositories) > 0 { + for _, x := range c.Repositories { y := *c.apiUrl y.Path = path.Join(y.Path, "repos", x) q := y.Query() @@ -246,8 +248,8 @@ func (c *Config) setScrapeURLs() error { // Append github orginisations to the array - if len(c.organisations) > 0 { - for _, x := range c.organisations { + if len(c.Organisations) > 0 { + for _, x := range c.Organisations { y := *c.apiUrl y.Path = path.Join(y.Path, "orgs", x, "repos") q := y.Query() @@ -259,8 +261,8 @@ func (c *Config) setScrapeURLs() error { } } - if len(c.users) > 0 { - for _, x := range c.users { + if len(c.Users) > 0 { + for _, x := range c.Users { y := *c.apiUrl y.Path = path.Join(y.Path, "users", x, "repos") q := y.Query() diff --git a/exporter/gather.go b/exporter/gather.go deleted file mode 100644 index 7a72db2d..00000000 --- a/exporter/gather.go +++ /dev/null @@ -1,139 +0,0 @@ -package exporter - -import ( - "encoding/json" - "fmt" - "path" - "strconv" - "strings" - - log "github.com/sirupsen/logrus" -) - -// gatherData - Collects the data from the API and stores into struct -func (e *Exporter) gatherData() ([]*Datum, error) { - - data := []*Datum{} - - responses, err := asyncHTTPGets(e.TargetURLs(), e.APIToken()) - - if err != nil { - return data, err - } - - for _, response := range responses { - - // Github can at times present an array, or an object for the same data set. - // This code checks handles this variation. - if isArray(response.body) { - ds := []*Datum{} - json.Unmarshal(response.body, &ds) - data = append(data, ds...) - } else { - d := new(Datum) - - // Get releases - if strings.Contains(response.url, "/repos/") { - getReleases(e, response.url, &d.Releases) - } - // Get PRs - if strings.Contains(response.url, "/repos/") { - getPRs(e, response.url, &d.Pulls) - } - json.Unmarshal(response.body, &d) - data = append(data, d) - } - - log.Infof("API data fetched for repository: %s", response.url) - } - - //return data, rates, err - return data, nil - -} - -// getRates obtains the rate limit data for requests against the github API. -// Especially useful when operating without oauth and the subsequent lower cap. -func (e *Exporter) getRates() (*RateLimits, error) { - u := *e.APIURL() - u.Path = path.Join(u.Path, "rate_limit") - - resp, err := getHTTPResponse(u.String(), e.APIToken()) - if err != nil { - return &RateLimits{}, err - } - defer resp.Body.Close() - - // Triggers if rate-limiting isn't enabled on private Github Enterprise installations - if resp.StatusCode == 404 { - return &RateLimits{}, fmt.Errorf("Rate Limiting not enabled in GitHub API") - } - - limit, err := strconv.ParseFloat(resp.Header.Get("X-RateLimit-Limit"), 64) - - if err != nil { - return &RateLimits{}, err - } - - rem, err := strconv.ParseFloat(resp.Header.Get("X-RateLimit-Remaining"), 64) - - if err != nil { - return &RateLimits{}, err - } - - reset, err := strconv.ParseFloat(resp.Header.Get("X-RateLimit-Reset"), 64) - - if err != nil { - return &RateLimits{}, err - } - - return &RateLimits{ - Limit: limit, - Remaining: rem, - Reset: reset, - }, err - -} - -func getReleases(e *Exporter, url string, data *[]Release) { - i := strings.Index(url, "?") - baseURL := url[:i] - releasesURL := baseURL + "/releases" - releasesResponse, err := asyncHTTPGets([]string{releasesURL}, e.APIToken()) - - if err != nil { - log.Errorf("Unable to obtain releases from API, Error: %s", err) - } - - json.Unmarshal(releasesResponse[0].body, &data) -} - -func getPRs(e *Exporter, url string, data *[]Pull) { - i := strings.Index(url, "?") - baseURL := url[:i] - pullsURL := baseURL + "/pulls" - pullsResponse, err := asyncHTTPGets([]string{pullsURL}, e.APIToken()) - - if err != nil { - log.Errorf("Unable to obtain pull requests from API, Error: %s", err) - } - - json.Unmarshal(pullsResponse[0].body, &data) -} - -// isArray simply looks for key details that determine if the JSON response is an array or not. -func isArray(body []byte) bool { - - isArray := false - - for _, c := range body { - if c == ' ' || c == '\t' || c == '\r' || c == '\n' { - continue - } - isArray = c == '[' - break - } - - return isArray - -} diff --git a/exporter/http.go b/exporter/http.go deleted file mode 100644 index 273f63f4..00000000 --- a/exporter/http.go +++ /dev/null @@ -1,160 +0,0 @@ -package exporter - -import ( - "fmt" - "io" - "net/http" - neturl "net/url" - "strconv" - "time" - - log "github.com/sirupsen/logrus" - "github.com/tomnomnom/linkheader" -) - -// RateLimitExceededStatus is the status response from github when the rate limit is exceeded. -const RateLimitExceededStatus = "403 rate limit exceeded" - -func asyncHTTPGets(targets []string, token string) ([]*Response, error) { - // Expand targets by following GitHub pagination links - targets = paginateTargets(targets, token) - - // Channels used to enable concurrent requests - ch := make(chan *Response, len(targets)) - - responses := []*Response{} - - for _, url := range targets { - - go func(url string) { - err := getResponse(url, token, ch) - if err != nil { - ch <- &Response{url, nil, []byte{}, err} - } - }(url) - - } - - for { - select { - case r := <-ch: - if r.err != nil { - log.Errorf("Error scraping API, Error: %v", r.err) - return nil, r.err - } - responses = append(responses, r) - - if len(responses) == len(targets) { - return responses, nil - } - } - - } -} - -// paginateTargets returns all pages for the provided targets -func paginateTargets(targets []string, token string) []string { - - paginated := targets - - for _, url := range targets { - - // make a request to the original target to get link header if it exists - resp, err := getHTTPResponse(url, token) - if err != nil { - log.Errorf("Error retrieving Link headers, Error: %s", err) - continue - } - - if resp.Header["Link"] != nil { - links := linkheader.Parse(resp.Header["Link"][0]) - - for _, link := range links { - if link.Rel == "last" { - - u, err := neturl.Parse(link.URL) - if err != nil { - log.Errorf("Unable to parse page URL, Error: %s", err) - } - - q := u.Query() - - lastPage, err := strconv.Atoi(q.Get("page")) - if err != nil { - log.Errorf("Unable to convert page substring to int, Error: %s", err) - } - - // add all pages to the slice of targets to return - for page := 2; page <= lastPage; page++ { - q.Set("page", strconv.Itoa(page)) - u.RawQuery = q.Encode() - paginated = append(paginated, u.String()) - } - - break - } - } - } - } - return paginated -} - -// getResponse collects an individual http.response and returns a *Response -func getResponse(url string, token string, ch chan<- *Response) error { - - log.Infof("Fetching %s \n", url) - - resp, err := getHTTPResponse(url, token) // do this earlier - if err != nil { - return fmt.Errorf("Error fetching http response: %v", err) - } - defer resp.Body.Close() - - // Read the body to a byte array so it can be used elsewhere - body, err := io.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf("Error converting body to byte array: %v", err) - } - - // Triggers if a user specifies an invalid or not visible repository - if resp.StatusCode == 404 { - return fmt.Errorf("Error: Received 404 status from Github API, ensure the repository URL is correct. If it's a private repository, also check the oauth token is correct") - } - - ch <- &Response{url, resp, body, err} - - return nil -} - -// getHTTPResponse handles the http client creation, token setting and returns the *http.response -func getHTTPResponse(url string, token string) (*http.Response, error) { - - client := &http.Client{ - Timeout: time.Second * 10, - } - - req, err := http.NewRequest("GET", url, nil) - - if err != nil { - return nil, err - } - - // If a token is present, add it to the http.request - if token != "" { - req.Header.Add("Authorization", "token "+token) - } - - resp, err := client.Do(req) - - if err != nil { - return nil, err - } - - // check rate limit exceeded. - if resp.Status == RateLimitExceededStatus { - resp.Body.Close() - return nil, fmt.Errorf("%s", resp.Status) - } - - return resp, err -} diff --git a/exporter/prometheus.go b/exporter/prometheus.go index 4023e1cc..5c02ddb7 100644 --- a/exporter/prometheus.go +++ b/exporter/prometheus.go @@ -1,11 +1,11 @@ package exporter import ( - "path" - "strconv" - + "context" + "github.com/google/go-github/v71/github" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" + "strings" ) // Describe - loops through the API metrics and passes them to prometheus.Describe @@ -18,76 +18,177 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) { } // Collect function, called on by Prometheus Client library -// This function is called when a scrape is peformed on the /metrics page +// This function is called when a scrape is performed on the /metrics endpoint func (e *Exporter) Collect(ch chan<- prometheus.Metric) { - data := []*Datum{} - var err error + client := github.NewClient(nil) + ctx := context.Background() + + log.Info("collecting metrics") + var data []*Datum + + repoMetrics, err := e.getRepoMetrics(ctx) + if err != nil { + log.Errorf("Error fetching repository metrics: %v", err) + return + } + + data = append(data, repoMetrics...) + + // TODO - get all rate limits, not just core + rates, _, err := client.RateLimit.Get(ctx) + if err != nil { + log.Errorf("Error fetching rate limits: %v", err) + return + } + + r := &RateLimits{ + Limit: float64(rates.Core.Limit), + Remaining: float64(rates.Core.Remaining), + Reset: float64(rates.Core.Reset.Unix()), + } + + // Set prometheus gauge metrics using the data gathered + err = e.processMetrics(data, r, ch) +} - if e.Config.GitHubApp() { - needReAuth, err := e.isTokenExpired() +// getOrganisationMetrics fetches metrics for the configured organisations +func (e *Exporter) getOrganisationMetrics(ctx context.Context) ([]*Datum, error) { + var data []*Datum + for _, o := range e.Config.Organisations { + repos, _, err := e.Client.Repositories.ListByOrg(ctx, o, nil) if err != nil { - log.Errorf("Error checking token expiration status: %v", err) - return + log.Errorf("Error fetching organisation repositories: %v", err) + continue } - if needReAuth { - err = e.Config.SetAPITokenFromGitHubApp() + for _, repo := range repos { + d, err := e.parseRepo(ctx, *repo) if err != nil { - log.Errorf("Error authenticating with GitHub app: %v", err) + log.Errorf("Error parsing organisation data: %v", err) + continue } + data = append(data, d) } } - // Scrape the Data from Github - if len(e.TargetURLs()) > 0 { - data, err = e.gatherData() + + return data, nil +} + +// getUserMetrics fetches metrics for the configured users +func (e *Exporter) getUserMetrics(ctx context.Context) ([]*Datum, error) { + var data []*Datum + for _, u := range e.Config.Users { + repos, _, err := e.Client.Repositories.ListByUser(ctx, u, nil) if err != nil { - log.Errorf("Error gathering Data from remote API: %v", err) - return + log.Errorf("Error fetching user data: %v", err) + continue } - } - rates, err := e.getRates() - if err != nil { - log.Errorf("Error gathering Rates from remote API: %v", err) - return + for _, repo := range repos { + d, err := e.parseRepo(ctx, *repo) + if err != nil { + log.Errorf("Error parsing user data: %v", err) + continue + } + data = append(data, d) + } } - // Set prometheus gauge metrics using the data gathered - err = e.processMetrics(data, rates, ch) + return data, nil +} - if err != nil { - log.Error("Error Processing Metrics", err) - return - } +// getRepoMetrics fetches metrics for the configured repositories +func (e *Exporter) getRepoMetrics(ctx context.Context) ([]*Datum, error) { + var data []*Datum + for _, m := range e.Config.Repositories { + // Split the repository string into owner and name + parts := strings.Split(m, "/") + if len(parts) != 2 { + log.Errorf("Invalid repository format: %s", m) + continue + } - log.Info("All Metrics successfully collected") + repo, _, err := e.Client.Repositories.Get(ctx, parts[0], parts[1]) + if err != nil { + log.Errorf("Error fetching repository data: %v", err) + continue + } -} + d, err := e.parseRepo(ctx, *repo) + if err != nil { + log.Errorf("Error parsing repository data: %v", err) + continue + } -func (e *Exporter) isTokenExpired() (bool, error) { - u := *e.APIURL() - u.Path = path.Join(u.Path, "rate_limit") + data = append(data, d) + } + + return data, nil +} - resp, err := getHTTPResponse(u.String(), e.APIToken()) +func (e *Exporter) parseRepo(ctx context.Context, repo github.Repository) (*Datum, error) { + repoOwner := repo.GetOwner().GetLogin() + repoName := repo.GetName() + rel, _, err := e.Client.Repositories.ListReleases(ctx, repoOwner, repoName, nil) if err != nil { - return false, err - } - defer resp.Body.Close() - // Triggers if rate-limiting isn't enabled on private Github Enterprise installations - if resp.StatusCode == 404 { - return false, nil + log.Errorf("Error fetching releases: %v", err) + return nil, err } - limit, err := strconv.ParseFloat(resp.Header.Get("X-RateLimit-Limit"), 64) + var releases []Release + for _, release := range rel { + var assets []Asset + for _, asset := range release.Assets { + a := Asset{ + Name: asset.GetName(), + } + assets = append(assets, a) + } + r := Release{ + Name: release.GetName(), + Tag: release.GetTagName(), + Assets: assets, + } + releases = append(releases, r) + } + + pullRequests, _, err := e.Client.PullRequests.List(ctx, repoOwner, repoName, nil) if err != nil { - return false, err + log.Errorf("Error fetching pull requests: %v", err) + return nil, err + } + var pulls []Pull + for _, pr := range pullRequests { + p := Pull{ + Url: pr.GetURL(), + User: User{ + Login: pr.GetUser().GetLogin(), + }, + } + pulls = append(pulls, p) } - defaultRateLimit := e.Config.GitHubRateLimit() - if limit < defaultRateLimit { - return true, nil + d := &Datum{ + Name: repo.GetName(), + Owner: User{ + Login: repo.GetOwner().GetLogin(), + }, + License: License{ + Key: repo.GetLicense().GetKey(), + }, + Language: repo.GetLanguage(), + Archived: repo.GetArchived(), + Private: repo.GetPrivate(), + Fork: repo.GetFork(), + Forks: float64(repo.GetForksCount()), + Stars: float64(repo.GetStargazersCount()), + OpenIssues: float64(repo.GetOpenIssuesCount()), + Watchers: float64(repo.GetSubscribersCount()), + Size: float64(repo.GetSize()), + Releases: releases, + Pulls: pulls, } - return false, nil + return d, nil } diff --git a/exporter/structs.go b/exporter/structs.go index 858b876f..614fb67d 100644 --- a/exporter/structs.go +++ b/exporter/structs.go @@ -1,6 +1,7 @@ package exporter import ( + "github.com/google/go-github/v71/github" "net/http" "github.com/githubexporter/github-exporter/config" @@ -12,6 +13,7 @@ import ( // user defined runtime configuration when the Collect method is called. type Exporter struct { APIMetrics map[string]*prometheus.Desc + Client *github.Client config.Config } @@ -21,13 +23,9 @@ type Data []Datum // Datum is used to store data from all the relevant endpoints in the API type Datum struct { - Name string `json:"name"` - Owner struct { - Login string `json:"login"` - } `json:"owner"` - License struct { - Key string `json:"key"` - } `json:"license"` + Name string `json:"name"` + Owner User `json:"owner"` + License License `json:"license"` Language string `json:"language"` Archived bool `json:"archived"` Private bool `json:"private"` @@ -41,6 +39,10 @@ type Datum struct { Pulls []Pull } +type License struct { + Key string `json:"key"` +} + type Release struct { Name string `json:"name"` Assets []Asset `json:"assets"` @@ -49,9 +51,11 @@ type Release struct { type Pull struct { Url string `json:"url"` - User struct { - Login string `json:"login"` - } `json:"user"` + User User +} + +type User struct { + Login string `json:"login"` } type Asset struct { diff --git a/go.mod b/go.mod index fdd6079e..9a496d71 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,16 @@ module github.com/githubexporter/github-exporter -go 1.22 +go 1.23.0 + +toolchain go1.24.2 require ( github.com/bradleyfalzon/ghinstallation/v2 v2.11.0 + github.com/google/go-github/v71 v71.0.0 github.com/infinityworks/go-common v0.0.0-20170820165359-7f20a140fd37 github.com/prometheus/client_golang v1.20.4 github.com/sirupsen/logrus v1.9.3 github.com/steinfletcher/apitest v1.3.8 - github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 ) require ( diff --git a/go.sum b/go.sum index ff4841e9..62111c2c 100644 --- a/go.sum +++ b/go.sum @@ -11,10 +11,13 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v62 v62.0.0 h1:/6mGCaRywZz9MuHyw9gD1CwsbmBX8GWsbFkwMmHdhl4= github.com/google/go-github/v62 v62.0.0/go.mod h1:EMxeUqGJq2xRu9DYBMwel/mr7kZrzUOfQmmpYrZn2a4= +github.com/google/go-github/v71 v71.0.0 h1:Zi16OymGKZZMm8ZliffVVJ/Q9YZreDKONCr+WUd0Z30= +github.com/google/go-github/v71 v71.0.0/go.mod h1:URZXObp2BLlMjwu0O8g4y6VBneUj2bCHgnI8FfgZ51M= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/infinityworks/go-common v0.0.0-20170820165359-7f20a140fd37 h1:Lm6kyC3JBiJQvJrus66He0E4viqDc/m5BdiFNSkIFfU= @@ -50,8 +53,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= -github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/main.go b/main.go index 35a54677..3a940ed8 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( conf "github.com/githubexporter/github-exporter/config" "github.com/githubexporter/github-exporter/exporter" "github.com/githubexporter/github-exporter/http" + "github.com/google/go-github/v71/github" "github.com/infinityworks/go-common/logger" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" @@ -24,9 +25,11 @@ func init() { func main() { log.Info("Starting Exporter") + // TODO - support github app/github enterprise exp := exporter.Exporter{ APIMetrics: mets, Config: applicationCfg, + Client: github.NewClient(nil), } http.NewServer(exp).Start() diff --git a/test/github_exporter_test.go b/test/github_exporter_test.go index 534e4fb9..a0cfca11 100644 --- a/test/github_exporter_test.go +++ b/test/github_exporter_test.go @@ -2,6 +2,7 @@ package test import ( "fmt" + "github.com/google/go-github/v71/github" "io" "net/http" "os" @@ -32,9 +33,9 @@ func TestGithubExporter(t *testing.T) { test.Mocks( githubRepos(), - githubRateLimit(), githubReleases(), githubPulls(), + githubRateLimit(), ). Get("/metrics"). Expect(t). @@ -75,6 +76,7 @@ func apiTest(conf config.Config) (*apitest.APITest, exporter.Exporter) { exp := exporter.Exporter{ APIMetrics: exporter.AddMetrics(), Config: conf, + Client: github.NewClient(nil), } server := web.NewServer(exp) @@ -92,8 +94,8 @@ func withConfig(repos string) config.Config { func githubRepos() *apitest.Mock { return apitest.NewMock(). Get("https://api.github.com/repos/myOrg/myRepo"). - Header("Authorization", "token 12345"). - Query("per_page", "100"). + //Header("Authorization", "token 12345"). + //Query("per_page", "100"). RespondWith(). Times(2). Body(readFile("testdata/my_repo_response.json")). @@ -104,7 +106,7 @@ func githubRepos() *apitest.Mock { func githubRateLimit() *apitest.Mock { return apitest.NewMock(). Get("https://api.github.com/rate_limit"). - Header("Authorization", "token 12345"). + //Header("Authorization", "token 12345"). RespondWith(). Header("X-RateLimit-Limit", "60"). Header("X-RateLimit-Remaining", "60"). @@ -116,7 +118,7 @@ func githubRateLimit() *apitest.Mock { func githubReleases() *apitest.Mock { return apitest.NewMock(). Get("https://api.github.com/repos/myOrg/myRepo/releases"). - Header("Authorization", "token 12345"). + //Header("Authorization", "token 12345"). RespondWith(). Times(2). Body(readFile("testdata/releases_response.json")). @@ -127,7 +129,7 @@ func githubReleases() *apitest.Mock { func githubPulls() *apitest.Mock { return apitest.NewMock(). Get("https://api.github.com/repos/myOrg/myRepo/pulls"). - Header("Authorization", "token 12345"). + //Header("Authorization", "token 12345"). RespondWith(). Times(2). Body(readFile("testdata/pulls_response.json")). @@ -138,7 +140,7 @@ func githubPulls() *apitest.Mock { func githubPullsError() *apitest.Mock { return apitest.NewMock(). Get("https://api.github.com/repos/myOrg/myRepo/pulls"). - Header("Authorization", "token 12345"). + //Header("Authorization", "token 12345"). RespondWith(). Status(http.StatusBadRequest). End()