ponzi2

Getting GitHub Commit Counts with Go and GraphQL

By Brian Muramatsu

2018-11-19

Overview

Want to get how many commits you've made to a GitHub repository?

Query the GitHub GraphQL API v4 using Go and GraphQL! Let's walk through some code that gets the commit count for ponzi2.

Encode the Query

First, we're going to start crafting the request to send to the GitHub API. Define a struct that mirrors the required JSON object with a "query" field. Then set the "query" field to the actual GraphQL query. Finally, encode it and store it in a buffer for later use.

    // GitHub API: https://developer.github.com/v4/query/
    q := struct {
        Query string `json:"query"`
    }{
        Query: `
            query { 
                repository(owner: "btmura", name: "ponzi2") {
                    defaultBranchRef {
                        target {
                            ... on Commit {
                                history {
                                    totalCount
                                }
                            }
                        }
                    }
                }
            }
        `,
    }

    body := &bytes.Buffer{}
    if err := json.NewEncoder(body).Encode(q); err != nil {
        return 0, err
    }
    

Notes:

Send the Request with Authorization Headers

After crafting the request body, we need to create a request to attach the body to! Make an HTTP POST request to the GraphQL endpoint with the body set to the buffer prepared earlier. Finally, set an Authorization header on the request to get permissions to your repository.

    hReq, err := http.NewRequest(http.MethodPost, "https://api.github.com/graphql", body)
    if err != nil {
        return 0, err
    }

    hReq.Header.Add("Authorization", "bearer YOUR_PERSONAL_ACCESS_TOKEN")

    hResp, err := http.DefaultClient.Do(hReq.WithContext(ctx))
    if err != nil {
        return 0, err
    }

    defer func() {
        if err := hResp.Body.Close(); err != nil {
            log.Printf("http close failed: %v", err)
        }
    }()
    

Notes:

Parse the Response

Finally, we need to decode the JSON API response. Define an anonymous struct of anonymous structs to mirror the response's JSON structure which in turn mirrors the GraphQL query we encoded in the first step. Finally, just decode the response body into this anonymous struct and get the count! That's it!

    var r struct {
        Data struct {
            Repository struct {
                DefaultBranchRef struct {
                    Target struct {
                        History struct {
                            TotalCount int
                        }
                    }
                }
            }
        }
    }

    if err := json.NewDecoder(hResp.Body).Decode(&r); err != nil {
        return 0, err
    }

    return r.Data.Repository.DefaultBranchRef.Target.History.TotalCount, nil
    

Full Code

func CommitCount(ctx context.Context) (int, error) {
    // GitHub API: https://developer.github.com/v4/query/
    q := struct {
        Query string `json:"query"`
    }{
        Query: `
            query { 
                repository(owner: "btmura", name: "ponzi2") {
                    defaultBranchRef {
                        target {
                            ... on Commit {
                                history {
                                    totalCount
                                }
                            }
                        }
                    }
                }
            }
        `,
    }

    body := &bytes.Buffer{}
    if err := json.NewEncoder(body).Encode(q); err != nil {
        return 0, err
    }

    hReq, err := http.NewRequest(http.MethodPost, "https://api.github.com/graphql", body)
    if err != nil {
        return 0, err
    }

    hReq.Header.Add("Authorization", "bearer YOUR_PERSONAL_ACCESS_TOKEN")

    hResp, err := http.DefaultClient.Do(hReq.WithContext(ctx))
    if err != nil {
        return 0, err
    }

    defer func() {
        if err := hResp.Body.Close(); err != nil {
            log.Printf("http close failed: %v", err)
        }
    }()

    var r struct {
        Data struct {
            Repository struct {
                DefaultBranchRef struct {
                    Target struct {
                        History struct {
                            TotalCount int
                        }
                    }
                }
            }
        }
    }

    if err := json.NewDecoder(hResp.Body).Decode(&r); err != nil {
        return 0, err
    }

    return r.Data.Repository.DefaultBranchRef.Target.History.TotalCount, nil
}
    

Support

Donate to keep development chugging (992 commits) or just star the repository like 15 others!

bitcoin:38vo2oWYmqBUXCxL3avpueye6dPRahX7gC

© 2019 Brian Muramatsu