Skip to content

Commit

Permalink
feat: Refactors API client into hand rolled sdk in api/ directory
Browse files Browse the repository at this point in the history
Signed-off-by: John McBride <[email protected]>
  • Loading branch information
jpmcb committed Aug 29, 2024
1 parent eb6946f commit bcddef0
Show file tree
Hide file tree
Showing 17 changed files with 591 additions and 172 deletions.
47 changes: 47 additions & 0 deletions api/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package api

import (
"net/http"

"github.com/open-sauced/pizza-cli/api/services/contributors"
"github.com/open-sauced/pizza-cli/api/services/histogram"
"github.com/open-sauced/pizza-cli/api/services/repository"
)

type Client struct {
RepositoryService *repository.Service
ContributorService *contributors.Service
HistogramService *histogram.Service

// The configured http client for making API requests
httpClient *http.Client

// The API endpoint to use when making requests
// Example: https://api.opensauced.pizza
endpoint string
}

func NewClient(endpoint string) *Client {
client := Client{
httpClient: &http.Client{},
endpoint: endpoint,
}

repositoryService := repository.Service{
Endpoint: client.endpoint,
}

contributorService := contributors.Service{
Endpoint: client.endpoint,
}

histogramService := histogram.Service{
Endpoint: client.endpoint,
}

client.RepositoryService = &repositoryService
client.ContributorService = &contributorService
client.HistogramService = &histogramService

return &client
}
173 changes: 173 additions & 0 deletions api/services/contributors/contributors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package contributors

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

type Service struct {
Endpoint string
}

func (s *Service) NewPullRequestContributors(repos []string, rangeVal int) (*ContribResponse, *http.Response, error) {
baseURL := fmt.Sprintf("%s/v2/contributors/insights/new", s.Endpoint)

// Create URL with query parameters
u, err := url.Parse(baseURL)
if err != nil {
return nil, nil, fmt.Errorf("error parsing URL: %v", err)
}

q := u.Query()
q.Set("range", fmt.Sprintf("%d", rangeVal))
q.Set("repos", strings.Join(repos, ","))
u.RawQuery = q.Encode()

resp, err := http.Get(u.String())
if err != nil {
return nil, resp, fmt.Errorf("error making request: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, resp, fmt.Errorf("API request failed with status code: %d", resp.StatusCode)
}

var newContributorsResponse ContribResponse
if err := json.NewDecoder(resp.Body).Decode(&newContributorsResponse); err != nil {
return nil, resp, fmt.Errorf("error decoding response: %v", err)
}

return &newContributorsResponse, resp, nil
}

func (s *Service) RecentPullRequestContributors(repos []string, rangeVal int) (*ContribResponse, *http.Response, error) {
baseURL := fmt.Sprintf("%s/v2/contributors/insights/recent", s.Endpoint)

// Create URL with query parameters
u, err := url.Parse(baseURL)
if err != nil {
return nil, nil, fmt.Errorf("error parsing URL: %v", err)
}

q := u.Query()
q.Set("range", fmt.Sprintf("%d", rangeVal))
q.Set("repos", strings.Join(repos, ","))
u.RawQuery = q.Encode()

resp, err := http.Get(u.String())
if err != nil {
return nil, resp, fmt.Errorf("error making request: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, resp, fmt.Errorf("API request failed with status code: %d", resp.StatusCode)
}

var recentContributorsResponse ContribResponse
if err := json.NewDecoder(resp.Body).Decode(&recentContributorsResponse); err != nil {
return nil, resp, fmt.Errorf("error decoding response: %v", err)
}

return &recentContributorsResponse, resp, nil
}

func (s *Service) AlumniPullRequestContributors(repos []string, rangeVal int) (*ContribResponse, *http.Response, error) {
baseURL := fmt.Sprintf("%s/v2/contributors/insights/alumni", s.Endpoint)

// Create URL with query parameters
u, err := url.Parse(baseURL)
if err != nil {
return nil, nil, fmt.Errorf("error parsing URL: %v", err)
}

q := u.Query()
q.Set("range", fmt.Sprintf("%d", rangeVal))
q.Set("repos", strings.Join(repos, ","))
u.RawQuery = q.Encode()

resp, err := http.Get(u.String())
if err != nil {
return nil, resp, fmt.Errorf("error making request: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, resp, fmt.Errorf("API request failed with status code: %d", resp.StatusCode)
}

var alumniContributorsResponse ContribResponse
if err := json.NewDecoder(resp.Body).Decode(&alumniContributorsResponse); err != nil {
return nil, resp, fmt.Errorf("error decoding response: %v", err)
}

return &alumniContributorsResponse, resp, nil
}

func (s *Service) RepeatPullRequestContributors(repos []string, rangeVal int) (*ContribResponse, *http.Response, error) {
baseURL := fmt.Sprintf("%s/v2/contributors/insights/repeat", s.Endpoint)

// Create URL with query parameters
u, err := url.Parse(baseURL)
if err != nil {
return nil, nil, fmt.Errorf("error parsing URL: %v", err)
}

q := u.Query()
q.Set("range", fmt.Sprintf("%d", rangeVal))
q.Set("repos", strings.Join(repos, ","))
u.RawQuery = q.Encode()

resp, err := http.Get(u.String())
if err != nil {
return nil, resp, fmt.Errorf("error making request: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, resp, fmt.Errorf("API request failed with status code: %d", resp.StatusCode)
}

var repeatContributorsResponse ContribResponse
if err := json.NewDecoder(resp.Body).Decode(&repeatContributorsResponse); err != nil {
return nil, resp, fmt.Errorf("error decoding response: %v", err)
}

return &repeatContributorsResponse, resp, nil
}

func (s *Service) SearchPullRequestContributors(repoIDs []int, rangeVal int) (*ContribResponse, *http.Response, error) {
baseURL := fmt.Sprintf("%s/v2/contributors/search", s.Endpoint)

// Create URL with query parameters
u, err := url.Parse(baseURL)
if err != nil {
return nil, nil, fmt.Errorf("error parsing URL: %v", err)
}

q := u.Query()
q.Set("range", fmt.Sprintf("%d", rangeVal))
q.Set("repoIds", strings.Join(strings.Fields(fmt.Sprint(repoIDs)), ","))
u.RawQuery = q.Encode()

resp, err := http.Get(u.String())
if err != nil {
return nil, resp, fmt.Errorf("error making request: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, resp, fmt.Errorf("API request failed with status code: %d", resp.StatusCode)
}

var searchContributorsResponse ContribResponse
if err := json.NewDecoder(resp.Body).Decode(&searchContributorsResponse); err != nil {
return nil, resp, fmt.Errorf("error decoding response: %v", err)
}

return &searchContributorsResponse, resp, nil
}
18 changes: 18 additions & 0 deletions api/services/contributors/spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package contributors

import (
"time"

"github.com/open-sauced/pizza-cli/api/services"
)

type DbContributor struct {
AuthorLogin string `json:"author_login"`
UserID int `json:"user_id"`
UpdatedAt time.Time `json:"updated_at"`
}

type ContribResponse struct {
Data []DbContributor `json:"data"`
Meta services.MetaData `json:"meta"`
}
44 changes: 44 additions & 0 deletions api/services/histogram/histogram.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package histogram

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

type Service struct {
Endpoint string
}

func (s *Service) PrsHistogram(repo string, rangeVal int) ([]PrHistogramData, *http.Response, error) {
baseURL := fmt.Sprintf("%s/v2/histogram/pull-requests", s.Endpoint)

// Create URL with query parameters
u, err := url.Parse(baseURL)
if err != nil {
return nil, nil, fmt.Errorf("error parsing URL: %v", err)
}

q := u.Query()
q.Set("range", fmt.Sprintf("%d", rangeVal))
q.Set("repo", repo)
u.RawQuery = q.Encode()

resp, err := http.Get(u.String())
if err != nil {
return nil, resp, fmt.Errorf("error making request: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, resp, fmt.Errorf("API request failed with status code: %d", resp.StatusCode)
}

var prHistogramData []PrHistogramData
if err := json.NewDecoder(resp.Body).Decode(&prHistogramData); err != nil {
return nil, resp, fmt.Errorf("error decoding response: %v", err)
}

return prHistogramData, resp, nil
}
22 changes: 22 additions & 0 deletions api/services/histogram/spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package histogram

import "time"

type PrHistogramData struct {
Bucket time.Time `json:"bucket"`
PrCount int `json:"pr_count"`
AcceptedPrs int `json:"accepted_prs"`
OpenPrs int `json:"open_prs"`
ClosedPrs int `json:"closed_prs"`
DraftPrs int `json:"draft_prs"`
ActivePrs int `json:"active_prs"`
SpamPrs int `json:"spam_prs"`
PRVelocity int `json:"pr_velocity"`
CollaboratorAssociatedPrs int `json:"collaborator_associated_prs"`
ContributorAssociatedPrs int `json:"contributor_associated_prs"`
MemberAssociatedPrs int `json:"member_associated_prs"`
NonAssociatedPrs int `json:"non_associated_prs"`
OwnerAssociatedPrs int `json:"owner_associated_prs"`
CommentsOnPrs int `json:"comments_on_prs"`
ReviewCommentsOnPrs int `json:"review_comments_on_prs"`
}
67 changes: 67 additions & 0 deletions api/services/repository/repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package repository

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

type Service struct {
Endpoint string
}

func (rs *Service) FindOneByOwnerAndRepo(owner string, repo string) (*DbRepository, *http.Response, error) {
url := fmt.Sprintf("%s/v2/repos/%s/%s", rs.Endpoint, owner, repo)

resp, err := http.Get(url)
if err != nil {
return nil, resp, fmt.Errorf("error making request: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return nil, resp, fmt.Errorf("API request failed with status code: %d", resp.StatusCode)
}

var repository DbRepository
if err := json.NewDecoder(resp.Body).Decode(&repository); err != nil {
return nil, resp, fmt.Errorf("error decoding response: %v", err)
}

return &repository, resp, nil
}

func (rs *Service) FindContributorsByOwnerAndRepo(owner string, repo string, rangeVal int) (*ContributorsResponse, *http.Response, error) {
baseURL := fmt.Sprintf("%s/v2/repos/%s/%s", rs.Endpoint, owner, repo)

// Create URL with query parameters
u, err := url.Parse(baseURL)
if err != nil {
return nil, nil, fmt.Errorf("error parsing URL: %v", err)
}

q := u.Query()
q.Set("range", fmt.Sprintf("%d", rangeVal))
u.RawQuery = q.Encode()

resp, err := http.Get(u.String())
if err != nil {
return nil, resp, err
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, resp, err
}

var contributorsResp ContributorsResponse
err = json.Unmarshal(body, &contributorsResp)
if err != nil {
return nil, resp, err
}

return &contributorsResp, resp, nil
}
Loading

0 comments on commit bcddef0

Please sign in to comment.