Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions github/billing.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ type UsageReportOptions struct {
Hour *int `url:"hour,omitempty"`
}

// PremiumRequestUsageReportOptions specifies optional parameters
// for the enhanced billing platform premium request usage report.
type PremiumRequestUsageReportOptions struct {
UsageReportOptions

// The user name to query usage for. The name is not case sensitive.
User *string `url:"user,omitempty"`

// The model name to query usage for. The name is not case sensitive.
Model *string `url:"model,omitempty"`

// The product name to query usage for. The name is not case sensitive.
Product *string `url:"product,omitempty"`
}

// UsageItem represents a single usage item in the enhanced billing platform report.
type UsageItem struct {
Date *string `json:"date"`
Expand All @@ -95,6 +110,38 @@ type UsageReport struct {
UsageItems []*UsageItem `json:"usageItems,omitempty"`
}

// PremiumRequestUsageItem represents a single usage line item in premium request usage reports.
type PremiumRequestUsageItem struct {
Product string `json:"product"`
SKU string `json:"sku"`
Model string `json:"model"`
UnitType string `json:"unitType"`
PricePerUnit float64 `json:"pricePerUnit"`
GrossQuantity int `json:"grossQuantity"`
GrossAmount float64 `json:"grossAmount"`
DiscountQuantity int `json:"discountQuantity"`
DiscountAmount float64 `json:"discountAmount"`
NetQuantity int `json:"netQuantity"`
NetAmount float64 `json:"netAmount"`
}

// PremiumRequestUsageTimePeriod represents a time period for premium request usage reports.
type PremiumRequestUsageTimePeriod struct {
Year int `json:"year"`
Month *int `json:"month,omitempty"`
Day *int `json:"day,omitempty"`
}

// PremiumRequestUsageReport represents the premium request usage report response.
type PremiumRequestUsageReport struct {
TimePeriod PremiumRequestUsageTimePeriod `json:"timePeriod"`
Organization string `json:"organization"`
User *string `json:"user,omitempty"`
Product *string `json:"product,omitempty"`
Model *string `json:"model,omitempty"`
UsageItems []*PremiumRequestUsageItem `json:"usageItems"`
}

// GetPackagesBillingOrg returns the free and paid storage used for GitHub Packages in gigabytes for an Org.
//
// GitHub API docs: https://docs.github.com/rest/billing/billing#get-github-packages-billing-for-an-organization
Expand Down Expand Up @@ -262,3 +309,61 @@ func (s *BillingService) GetUsageReportUser(ctx context.Context, user string, op

return usageReport, resp, nil
}

// GetPremiumRequestUsageReportOrg returns a report of the premium request
// usage for an organization using the enhanced billing platform.
//
// Note: This endpoint is only available to organizations with access to the enhanced billing platform.
//
// GitHub API docs: https://docs.github.com/rest/billing/enhanced-billing#get-billing-premium-request-usage-report-for-an-organization
//
//meta:operation GET /organizations/{org}/settings/billing/premium_request/usage
func (s *BillingService) GetPremiumRequestUsageReportOrg(ctx context.Context, org string, opts *PremiumRequestUsageReportOptions) (*PremiumRequestUsageReport, *Response, error) {
u := fmt.Sprintf("organizations/%v/settings/billing/premium_request/usage", org)
u, err := addOptions(u, opts)
if err != nil {
return nil, nil, err
}

req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}

premiumRequestUsageReport := new(PremiumRequestUsageReport)
resp, err := s.client.Do(ctx, req, premiumRequestUsageReport)
if err != nil {
return nil, resp, err
}

return premiumRequestUsageReport, resp, nil
}

// GetPremiumRequestUsageReportUser returns a report of the premium request
// usage for a user using the enhanced billing platform.
//
// Note: This endpoint is only available to users with access to the enhanced billing platform.
//
// GitHub API docs: https://docs.github.com/rest/billing/enhanced-billing#get-billing-premium-request-usage-report-for-a-user
//
//meta:operation GET /users/{username}/settings/billing/premium_request/usage
func (s *BillingService) GetPremiumRequestUsageReportUser(ctx context.Context, user string, opts *PremiumRequestUsageReportOptions) (*PremiumRequestUsageReport, *Response, error) {
u := fmt.Sprintf("users/%v/settings/billing/premium_request/usage", user)
u, err := addOptions(u, opts)
if err != nil {
return nil, nil, err
}

req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}

premiumRequestUsageReport := new(PremiumRequestUsageReport)
resp, err := s.client.Do(ctx, req, premiumRequestUsageReport)
if err != nil {
return nil, resp, err
}

return premiumRequestUsageReport, resp, nil
}
196 changes: 196 additions & 0 deletions github/billing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,3 +520,199 @@ func TestBillingService_GetUsageReportUser_invalidUser(t *testing.T) {
_, _, err := client.Billing.GetUsageReportUser(ctx, "%", nil)
testURLParseError(t, err)
}

func TestBillingService_GetPremiumRequestUsageReportOrg(t *testing.T) {
t.Parallel()
client, mux, _ := setup(t)
mux.HandleFunc("/organizations/o/settings/billing/premium_request/usage", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"year": "2025",
"month": "10",
"user": "testuser",
})
fmt.Fprint(w, `{
"timePeriod": {
"year": 2025,
"month": 10
},
"organization": "GitHub",
"user": "testuser",
"product": "Copilot",
"model": "GPT-5",
"usageItems": [
{
"product": "Copilot",
"sku": "Copilot Premium Request",
"model": "GPT-5",
"unitType": "requests",
"pricePerUnit": 0.04,
"grossQuantity": 100,
"grossAmount": 4.0,
"discountQuantity": 0,
"discountAmount": 0.0,
"netQuantity": 100,
"netAmount": 4.0
}
]
}`)
})
ctx := t.Context()
opts := &PremiumRequestUsageReportOptions{
UsageReportOptions: UsageReportOptions{
Year: Ptr(2025),
Month: Ptr(10),
},
User: Ptr("testuser"),
}
report, _, err := client.Billing.GetPremiumRequestUsageReportOrg(ctx, "o", opts)
if err != nil {
t.Errorf("Billing.GetPremiumRequestUsageReportOrg returned error: %v", err)
}
want := &PremiumRequestUsageReport{
TimePeriod: PremiumRequestUsageTimePeriod{
Year: 2025,
Month: Ptr(10),
},
Organization: "GitHub",
User: Ptr("testuser"),
Product: Ptr("Copilot"),
Model: Ptr("GPT-5"),
UsageItems: []*PremiumRequestUsageItem{
{
Product: "Copilot",
SKU: "Copilot Premium Request",
Model: "GPT-5",
UnitType: "requests",
PricePerUnit: 0.04,
GrossQuantity: 100,
GrossAmount: 4.0,
DiscountQuantity: 0,
DiscountAmount: 0.0,
NetQuantity: 100,
NetAmount: 4.0,
},
},
}
if !cmp.Equal(report, want) {
t.Errorf("Billing.GetPremiumRequestUsageReportOrg returned %+v, want %+v", report, want)
}

const methodName = "GetPremiumRequestUsageReportOrg"
testBadOptions(t, methodName, func() (err error) {
_, _, err = client.Billing.GetPremiumRequestUsageReportOrg(ctx, "\n", opts)
return err
})

testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
got, resp, err := client.Billing.GetPremiumRequestUsageReportOrg(ctx, "o", nil)
if got != nil {
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
}
return resp, err
})
}

func TestBillingService_GetPremiumRequestUsageReportOrg_invalidOrg(t *testing.T) {
t.Parallel()
client, _, _ := setup(t)

ctx := t.Context()
_, _, err := client.Billing.GetPremiumRequestUsageReportOrg(ctx, "%", nil)
testURLParseError(t, err)
}

func TestBillingService_GetPremiumRequestUsageReportUser(t *testing.T) {
t.Parallel()
client, mux, _ := setup(t)
mux.HandleFunc("/users/u/settings/billing/premium_request/usage", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"year": "2025",
"day": "15",
})
fmt.Fprint(w, `{
"timePeriod": {
"year": 2025,
"day": 15
},
"organization": "UserOrg",
"product": "Copilot",
"usageItems": [
{
"product": "Copilot",
"sku": "Copilot Premium Request",
"model": "GPT-4",
"unitType": "requests",
"pricePerUnit": 0.02,
"grossQuantity": 50,
"grossAmount": 1.0,
"discountQuantity": 5,
"discountAmount": 0.1,
"netQuantity": 45,
"netAmount": 0.9
}
]
}`)
})
ctx := t.Context()
opts := &PremiumRequestUsageReportOptions{
UsageReportOptions: UsageReportOptions{
Year: Ptr(2025),
Day: Ptr(15),
},
}
report, _, err := client.Billing.GetPremiumRequestUsageReportUser(ctx, "u", opts)
if err != nil {
t.Errorf("Billing.GetPremiumRequestUsageReportUser returned error: %v", err)
}
want := &PremiumRequestUsageReport{
TimePeriod: PremiumRequestUsageTimePeriod{
Year: 2025,
Day: Ptr(15),
},
Organization: "UserOrg",
Product: Ptr("Copilot"),
UsageItems: []*PremiumRequestUsageItem{
{
Product: "Copilot",
SKU: "Copilot Premium Request",
Model: "GPT-4",
UnitType: "requests",
PricePerUnit: 0.02,
GrossQuantity: 50,
GrossAmount: 1.0,
DiscountQuantity: 5,
DiscountAmount: 0.1,
NetQuantity: 45,
NetAmount: 0.9,
},
},
}
if !cmp.Equal(report, want) {
t.Errorf("Billing.GetPremiumRequestUsageReportUser returned %+v, want %+v", report, want)
}

const methodName = "GetPremiumRequestUsageReportUser"
testBadOptions(t, methodName, func() (err error) {
_, _, err = client.Billing.GetPremiumRequestUsageReportUser(ctx, "\n", opts)
return err
})

testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
got, resp, err := client.Billing.GetPremiumRequestUsageReportUser(ctx, "u", nil)
if got != nil {
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
}
return resp, err
})
}

func TestBillingService_GetPremiumRequestUsageReportUser_invalidUser(t *testing.T) {
t.Parallel()
client, _, _ := setup(t)

ctx := t.Context()
_, _, err := client.Billing.GetPremiumRequestUsageReportUser(ctx, "%", nil)
testURLParseError(t, err)
}
64 changes: 64 additions & 0 deletions github/github-accessors.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading