Repository: google/go-github
Pull request #1797 (2021-02-07 14:02:06)

billing: implement billing services
This PR adds the new services to the go-github client: Billing Services

https://docs.github.com/en/rest/reference/billing

Fixes: https://github.com/google/go-github/issues/1788

/cc @gmlewis 

codecov[bot]: # [Codecov](https://codecov.io/gh/google/go-github/pull/1797?src=pr&el=h1) Report
> Merging [#1797](https://codecov.io/gh/google/go-github/pull/1797?src=pr&el=desc) (e7f2954) into [master](https://codecov.io/gh/google/go-github/commit/974597c3c0a21d5f8be9199ad621c093074ac689?el=desc) (974597c) will **increase** coverage by `0.01%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/google/go-github/pull/1797/graphs/tree.svg?width=650&height=150&src=pr&token=EgYjGjZlI0)](https://codecov.io/gh/google/go-github/pull/1797?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #1797      +/-   ##
==========================================
+ Coverage   97.54%   97.55%   +0.01%     
==========================================
  Files          98       99       +1     
  Lines        6383     6426      +43     
==========================================
+ Hits         6226     6269      +43     
  Misses         85       85              
  Partials       72       72              
```


| [Impacted Files](https://codecov.io/gh/google/go-github/pull/1797?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [github/billing.go](https://codecov.io/gh/google/go-github/pull/1797/diff?src=pr&el=tree#diff-Z2l0aHViL2JpbGxpbmcuZ28=) | `100.00% <100.00%> (ø)` | |
| [github/github.go](https://codecov.io/gh/google/go-github/pull/1797/diff?src=pr&el=tree#diff-Z2l0aHViL2dpdGh1Yi5nbw==) | `96.62% <100.00%> (+0.01%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/google/go-github/pull/1797?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/google/go-github/pull/1797?src=pr&el=footer). Last update [974597c...e7f2954](https://codecov.io/gh/google/go-github/pull/1797?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

gmlewis: Thank you, @wesleimp !
Merging.

Patch:
diff --git a/github/billing.go b/github/billing.go
new file mode 100644
index 00000000..fa0e034d
--- /dev/null
+++ b/github/billing.go
@@ -0,0 +1,131 @@
+// Copyright 2021 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"fmt"
+)
+
+// BillingService provides access to the billing related functions
+// in the GitHub API.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/billing
+type BillingService service
+
+// ActionBilling represents a GitHub Action billing.
+type ActionBilling struct {
+	TotalMinutesUsed     int                  `json:"total_minutes_used"`
+	TotalPaidMinutesUsed int                  `json:"total_paid_minutes_used"`
+	IncludedMinutes      int                  `json:"included_minutes"`
+	MinutesUsedBreakdown MinutesUsedBreakdown `json:"minutes_used_breakdown"`
+}
+
+type MinutesUsedBreakdown struct {
+	Ubuntu  int `json:"UBUNTU"`
+	MacOS   int `json:"MACOS"`
+	Windows int `json:"WINDOWS"`
+}
+
+// PackageBilling represents a GitHub Package billing.
+type PackageBilling struct {
+	TotalGigabytesBandwidthUsed     int `json:"total_gigabytes_bandwidth_used"`
+	TotalPaidGigabytesBandwidthUsed int `json:"total_paid_gigabytes_bandwidth_used"`
+	IncludedGigabytesBandwidth      int `json:"included_gigabytes_bandwidth"`
+}
+
+// StorageBilling represents a GitHub Storage billing.
+type StorageBilling struct {
+	DaysLeftInBillingCycle       int `json:"days_left_in_billing_cycle"`
+	EstimatedPaidStorageForMonth int `json:"estimated_paid_storage_for_month"`
+	EstimatedStorageForMonth     int `json:"estimated_storage_for_month"`
+}
+
+// GetActionsBillingOrg returns the summary of the free and paid GitHub Actions minutes used for an Org.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-github-actions-billing-for-an-organization
+func (s *BillingService) GetActionsBillingOrg(ctx context.Context, org string) (*ActionBilling, *Response, error) {
+	u := fmt.Sprintf("orgs/%v/settings/billing/actions", org)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+	actionsOrgBilling := new(ActionBilling)
+	resp, err := s.client.Do(ctx, req, actionsOrgBilling)
+	return actionsOrgBilling, resp, err
+}
+
+// GetPackagesBillingOrg returns the free and paid storage used for GitHub Packages in gigabytes for an Org.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-github-packages-billing-for-an-organization
+func (s *BillingService) GetPackagesBillingOrg(ctx context.Context, org string) (*PackageBilling, *Response, error) {
+	u := fmt.Sprintf("orgs/%v/settings/billing/packages", org)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+	packagesOrgBilling := new(PackageBilling)
+	resp, err := s.client.Do(ctx, req, packagesOrgBilling)
+	return packagesOrgBilling, resp, err
+}
+
+// GetStorageBillingOrg returns the estimated paid and estimated total storage used for GitHub Actions
+// and GitHub Packages in gigabytes for an Org.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-shared-storage-billing-for-an-organization
+func (s *BillingService) GetStorageBillingOrg(ctx context.Context, org string) (*StorageBilling, *Response, error) {
+	u := fmt.Sprintf("orgs/%v/settings/billing/shared-storage", org)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+	storageOrgBilling := new(StorageBilling)
+	resp, err := s.client.Do(ctx, req, storageOrgBilling)
+	return storageOrgBilling, resp, err
+}
+
+// GetActionsBillingUser returns the summary of the free and paid GitHub Actions minutes used for a user.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-github-actions-billing-for-a-user
+func (s *BillingService) GetActionsBillingUser(ctx context.Context, user string) (*ActionBilling, *Response, error) {
+	u := fmt.Sprintf("users/%v/settings/billing/actions", user)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+	actionsUserBilling := new(ActionBilling)
+	resp, err := s.client.Do(ctx, req, actionsUserBilling)
+	return actionsUserBilling, resp, err
+}
+
+// GetPackagesBillingUser returns the free and paid storage used for GitHub Packages in gigabytes for a user.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-github-packages-billing-for-an-organization
+func (s *BillingService) GetPackagesBillingUser(ctx context.Context, user string) (*PackageBilling, *Response, error) {
+	u := fmt.Sprintf("users/%v/settings/billing/packages", user)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+	packagesUserBilling := new(PackageBilling)
+	resp, err := s.client.Do(ctx, req, packagesUserBilling)
+	return packagesUserBilling, resp, err
+}
+
+// GetStorageBillingUser returns the estimated paid and estimated total storage used for GitHub Actions
+// and GitHub Packages in gigabytes for a user.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/billing#get-shared-storage-billing-for-a-user
+func (s *BillingService) GetStorageBillingUser(ctx context.Context, user string) (*StorageBilling, *Response, error) {
+	u := fmt.Sprintf("users/%v/settings/billing/shared-storage", user)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+	storageUserBilling := new(StorageBilling)
+	resp, err := s.client.Do(ctx, req, storageUserBilling)
+	return storageUserBilling, resp, err
+}
diff --git a/github/github.go b/github/github.go
index 0a32a53c..e9dfa923 100644
--- a/github/github.go
+++ b/github/github.go
@@ -159,6 +159,7 @@ type Client struct {
 	Admin          *AdminService
 	Apps           *AppsService
 	Authorizations *AuthorizationsService
+	Billing        *BillingService
 	Checks         *ChecksService
 	CodeScanning   *CodeScanningService
 	Enterprise     *EnterpriseService
@@ -268,6 +269,7 @@ func NewClient(httpClient *http.Client) *Client {
 	c.Admin = (*AdminService)(&c.common)
 	c.Apps = (*AppsService)(&c.common)
 	c.Authorizations = (*AuthorizationsService)(&c.common)
+	c.Billing = (*BillingService)(&c.common)
 	c.Checks = (*ChecksService)(&c.common)
 	c.CodeScanning = (*CodeScanningService)(&c.common)
 	c.Enterprise = (*EnterpriseService)(&c.common)


Test patch:
diff --git a/github/billing_test.go b/github/billing_test.go
new file mode 100644
index 00000000..fc070f0b
--- /dev/null
+++ b/github/billing_test.go
@@ -0,0 +1,298 @@
+// Copyright 2021 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+)
+
+func TestBillingService_GetActionsBillingOrg(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/settings/billing/actions", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{
+				"total_minutes_used": 305,
+				"total_paid_minutes_used": 0,
+				"included_minutes": 3000,
+				"minutes_used_breakdown": {
+					"UBUNTU": 205,
+					"MACOS": 10,
+					"WINDOWS": 90
+				}
+			}`)
+	})
+
+	ctx := context.Background()
+	hook, _, err := client.Billing.GetActionsBillingOrg(ctx, "o")
+	if err != nil {
+		t.Errorf("Billing.GetActionsBillingOrg returned error: %v", err)
+	}
+
+	want := &ActionBilling{
+		TotalMinutesUsed:     305,
+		TotalPaidMinutesUsed: 0,
+		IncludedMinutes:      3000,
+		MinutesUsedBreakdown: MinutesUsedBreakdown{
+			Ubuntu:  205,
+			MacOS:   10,
+			Windows: 90,
+		},
+	}
+	if !reflect.DeepEqual(hook, want) {
+		t.Errorf("Billing.GetActionsBillingOrg returned %+v, want %+v", hook, want)
+	}
+
+	const methodName = "GetActionsBillingOrg"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Billing.GetActionsBillingOrg(ctx, "\n")
+		return err
+	})
+}
+
+func TestBillingService_GetActionsBillingOrg_invalidOrg(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Billing.GetActionsBillingOrg(ctx, "%")
+	testURLParseError(t, err)
+}
+
+func TestBillingService_GetPackagesBillingOrg(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/settings/billing/packages", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{
+				"total_gigabytes_bandwidth_used": 50,
+				"total_paid_gigabytes_bandwidth_used": 40,
+				"included_gigabytes_bandwidth": 10
+			}`)
+	})
+
+	ctx := context.Background()
+	hook, _, err := client.Billing.GetPackagesBillingOrg(ctx, "o")
+	if err != nil {
+		t.Errorf("Billing.GetPackagesBillingOrg returned error: %v", err)
+	}
+
+	want := &PackageBilling{
+		TotalGigabytesBandwidthUsed:     50,
+		TotalPaidGigabytesBandwidthUsed: 40,
+		IncludedGigabytesBandwidth:      10,
+	}
+	if !reflect.DeepEqual(hook, want) {
+		t.Errorf("Billing.GetPackagesBillingOrg returned %+v, want %+v", hook, want)
+	}
+
+	const methodName = "GetPackagesBillingOrg"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Billing.GetPackagesBillingOrg(ctx, "\n")
+		return err
+	})
+}
+
+func TestBillingService_GetPackagesBillingOrg_invalidOrg(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Billing.GetPackagesBillingOrg(ctx, "%")
+	testURLParseError(t, err)
+}
+
+func TestBillingService_GetStorageBillingOrg(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/settings/billing/shared-storage", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{
+				"days_left_in_billing_cycle": 20,
+				"estimated_paid_storage_for_month": 15,
+				"estimated_storage_for_month": 40
+			}`)
+	})
+
+	ctx := context.Background()
+	hook, _, err := client.Billing.GetStorageBillingOrg(ctx, "o")
+	if err != nil {
+		t.Errorf("Billing.GetStorageBillingOrg returned error: %v", err)
+	}
+
+	want := &StorageBilling{
+		DaysLeftInBillingCycle:       20,
+		EstimatedPaidStorageForMonth: 15,
+		EstimatedStorageForMonth:     40,
+	}
+	if !reflect.DeepEqual(hook, want) {
+		t.Errorf("Billing.GetStorageBillingOrg returned %+v, want %+v", hook, want)
+	}
+
+	const methodName = "GetStorageBillingOrg"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Billing.GetStorageBillingOrg(ctx, "\n")
+		return err
+	})
+}
+
+func TestBillingService_GetStorageBillingOrg_invalidOrg(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Billing.GetStorageBillingOrg(ctx, "%")
+	testURLParseError(t, err)
+}
+
+func TestBillingService_GetActionsBillingUser(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/users/u/settings/billing/actions", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{
+				"total_minutes_used": 10,
+				"total_paid_minutes_used": 0,
+				"included_minutes": 3000,
+				"minutes_used_breakdown": {
+					"UBUNTU": 205,
+					"MACOS": 10,
+					"WINDOWS": 90
+				}
+			}`)
+	})
+
+	ctx := context.Background()
+	hook, _, err := client.Billing.GetActionsBillingUser(ctx, "u")
+	if err != nil {
+		t.Errorf("Billing.GetActionsBillingUser returned error: %v", err)
+	}
+
+	want := &ActionBilling{
+		TotalMinutesUsed:     10,
+		TotalPaidMinutesUsed: 0,
+		IncludedMinutes:      3000,
+		MinutesUsedBreakdown: MinutesUsedBreakdown{
+			Ubuntu:  205,
+			MacOS:   10,
+			Windows: 90,
+		},
+	}
+	if !reflect.DeepEqual(hook, want) {
+		t.Errorf("Billing.GetActionsBillingUser returned %+v, want %+v", hook, want)
+	}
+
+	const methodName = "GetActionsBillingUser"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Billing.GetActionsBillingOrg(ctx, "\n")
+		return err
+	})
+}
+
+func TestBillingService_GetActionsBillingUser_invalidUser(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Billing.GetActionsBillingUser(ctx, "%")
+	testURLParseError(t, err)
+}
+
+func TestBillingService_GetPackagesBillingUser(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/users/u/settings/billing/packages", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{
+				"total_gigabytes_bandwidth_used": 50,
+				"total_paid_gigabytes_bandwidth_used": 40,
+				"included_gigabytes_bandwidth": 10
+			}`)
+	})
+
+	ctx := context.Background()
+	hook, _, err := client.Billing.GetPackagesBillingUser(ctx, "u")
+	if err != nil {
+		t.Errorf("Billing.GetPackagesBillingUser returned error: %v", err)
+	}
+
+	want := &PackageBilling{
+		TotalGigabytesBandwidthUsed:     50,
+		TotalPaidGigabytesBandwidthUsed: 40,
+		IncludedGigabytesBandwidth:      10,
+	}
+	if !reflect.DeepEqual(hook, want) {
+		t.Errorf("Billing.GetPackagesBillingUser returned %+v, want %+v", hook, want)
+	}
+
+	const methodName = "GetPackagesBillingUser"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Billing.GetPackagesBillingUser(ctx, "\n")
+		return err
+	})
+}
+
+func TestBillingService_GetPackagesBillingUser_invalidUser(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Billing.GetPackagesBillingUser(ctx, "%")
+	testURLParseError(t, err)
+}
+
+func TestBillingService_GetStorageBillingUser(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/users/u/settings/billing/shared-storage", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{
+				"days_left_in_billing_cycle": 20,
+				"estimated_paid_storage_for_month": 15,
+				"estimated_storage_for_month": 40
+			}`)
+	})
+
+	ctx := context.Background()
+	hook, _, err := client.Billing.GetStorageBillingUser(ctx, "u")
+	if err != nil {
+		t.Errorf("Billing.GetStorageBillingUser returned error: %v", err)
+	}
+
+	want := &StorageBilling{
+		DaysLeftInBillingCycle:       20,
+		EstimatedPaidStorageForMonth: 15,
+		EstimatedStorageForMonth:     40,
+	}
+	if !reflect.DeepEqual(hook, want) {
+		t.Errorf("Billing.GetStorageBillingUser returned %+v, want %+v", hook, want)
+	}
+
+	const methodName = "GetStorageBillingUser"
+	testBadOptions(t, methodName, func() (err error) {
+		_, _, err = client.Billing.GetStorageBillingUser(ctx, "\n")
+		return err
+	})
+}
+
+func TestBillingService_GetStorageBillingUser_invalidUser(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	ctx := context.Background()
+	_, _, err := client.Billing.GetStorageBillingUser(ctx, "%")
+	testURLParseError(t, err)
+}