feat: Add support for GitHub Budgets API#3931
feat: Add support for GitHub Budgets API#3931youneedgreg wants to merge 7 commits intogoogle:masterfrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3931 +/- ##
==========================================
+ Coverage 92.44% 92.48% +0.04%
==========================================
Files 203 205 +2
Lines 14960 15043 +83
==========================================
+ Hits 13830 13913 +83
Misses 927 927
Partials 203 203 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
gmlewis
left a comment
There was a problem hiding this comment.
Thank you, @youneedgreg!
Just a few tweaks, please, then we should be ready for a second LGTM+Approval from any other contributor to this repo before merging.
cc: @stevehipwell - @alexandear - @zyfy29 - @Not-Dhananjay-Mishra
|
Also, please fix the linter failures and check the code coverage. Step 4 in CONTRIBUTING.md discusses these things. |
github/billing_budgets.go
Outdated
| // | ||
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#get-all-budgets-for-an-organization | ||
| // | ||
| // meta:operation GET /organizations/{org}/settings/billing/budgets |
There was a problem hiding this comment.
For consistency use //meta: (no space).
| // meta:operation GET /organizations/{org}/settings/billing/budgets | |
| //meta:operation GET /organizations/{org}/settings/billing/budgets |
Same applies to other occurrences in this PR.
github/billing_budgets.go
Outdated
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#delete-a-budget-for-an-organization | ||
| // | ||
| // meta:operation DELETE /organizations/{org}/settings/billing/budgets/{budget_id} | ||
| func (s *BillingService) DeleteOrganizationBudget(ctx context.Context, org string, budgetID string) (*Response, error) { |
There was a problem hiding this comment.
According to Docs this endpoint also returns an object.

github/enterprise_billing_budgets.go
Outdated
|
|
||
| // GetEnterpriseBudget gets a specific budget for an enterprise. | ||
| // | ||
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#get-a-budget-for-an-enterprise |
There was a problem hiding this comment.
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#get-a-budget-for-an-enterprise | |
| // GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#get-a-budget-by-id |
https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#get-a-budget-by-id
github/enterprise_billing_budgets.go
Outdated
|
|
||
| // CreateEnterpriseBudget creates a specific budget for an enterprise. | ||
| // | ||
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#create-a-budget |
There was a problem hiding this comment.
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#create-a-budget | |
| // GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#create-a-budget |
https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#create-a-budget
github/enterprise_billing_budgets.go
Outdated
|
|
||
| // UpdateEnterpriseBudget updates a specific budget for an enterprise. | ||
| // | ||
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#update-a-budget-for-an-enterprise |
There was a problem hiding this comment.
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#update-a-budget-for-an-enterprise | |
| // GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#update-a-budget |
https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#update-a-budget
github/enterprise_billing_budgets.go
Outdated
|
|
||
| // DeleteEnterpriseBudget deletes a specific budget for an enterprise. | ||
| // | ||
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#delete-a-budget-for-an-enterprise |
There was a problem hiding this comment.
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#delete-a-budget-for-an-enterprise | |
| // GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#delete-a-budget |
https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#delete-a-budget
github/enterprise_billing_budgets.go
Outdated
|
|
||
| // ListEnterpriseBudgets lists all budgets for an enterprise. | ||
| // | ||
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#get-all-budgets-for-an-enterprise |
There was a problem hiding this comment.
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#get-all-budgets-for-an-enterprise | |
| // GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#get-all-budgets |
https://docs.github.com/en/enterprise-cloud@latest/rest/billing/budgets#get-all-budgets
| ) | ||
|
|
||
| // Budget represents a GitHub budget. | ||
| type Budget struct { |
There was a problem hiding this comment.
Response schema of Budget
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "ID of the budget."
},
"budget_scope": {
"type": "string",
"description": "The type of scope for the budget",
"enum": [
"enterprise",
"organization",
"repository",
"cost_center"
],
"examples": [
"enterprise"
]
},
"budget_entity_name": {
"type": "string",
"description": "The name of the entity to apply the budget to",
"examples": [
"octocat/hello-world"
]
},
"budget_amount": {
"type": "integer",
"description": "The budget amount in whole dollars. For license-based products, this represents the number of licenses."
},
"prevent_further_usage": {
"type": "boolean",
"description": "Whether to prevent additional spending once the budget is exceeded",
"examples": [
true
]
},
"budget_product_sku": {
"type": "string",
"description": "A single product or sku to apply the budget to.",
"examples": [
"actions_linux"
]
},
"budget_type": {
"type": "string",
"description": "The type of pricing for the budget",
"enum": [
"ProductPricing",
"SkuPricing"
],
"examples": [
"ProductPricing"
]
},
"budget_alerting": {
"type": "object",
"properties": {
"will_alert": {
"type": "boolean",
"description": "Whether alerts are enabled for this budget",
"examples": [
true
]
},
"alert_recipients": {
"type": "array",
"items": {
"type": "string"
},
"description": "Array of user login names who will receive alerts",
"examples": [
"mona",
"lisa"
]
}
}
}
},
"required": [
"id",
"budget_amount",
"prevent_further_usage",
"budget_product_sku",
"budget_type",
"budget_alerting",
"budget_scope",
"budget_entity_name"
]
}it has few missing items -
budget_scope, budget_entity_name, budget_amount, prevent_further_usage, budget_product_sku.
github/enterprise_billing_budgets.go
Outdated
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#delete-a-budget-for-an-enterprise | ||
| // | ||
| // meta:operation DELETE /enterprises/{enterprise}/settings/billing/budgets/{budget_id} | ||
| func (s *EnterpriseService) DeleteEnterpriseBudget(ctx context.Context, enterprise string, budgetID string) (*Response, error) { |
|
Hi @gmlewis , finished and made sure all checks passed, Thank you. |
github/enterprise_billing_budgets.go
Outdated
| // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/billing/budgets#get-all-budgets | ||
| // | ||
| //meta:operation GET /enterprises/{enterprise}/settings/billing/budgets | ||
| func (s *EnterpriseService) ListEnterpriseBudgets(ctx context.Context, enterprise string) ([]*Budget, *Response, error) { |
There was a problem hiding this comment.
Since we call this in Enterprise service we can simplify naming:
| func (s *EnterpriseService) ListEnterpriseBudgets(ctx context.Context, enterprise string) ([]*Budget, *Response, error) { | |
| func (s *EnterpriseService) ListBudgets(ctx context.Context, enterprise string) ([]*Budget, *Response, error) { |
Am I missing something?
github/billing_budgets.go
Outdated
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#get-all-budgets-for-an-organization | ||
| // | ||
| //meta:operation GET /organizations/{org}/settings/billing/budgets | ||
| func (s *BillingService) ListOrganizationBudgets(ctx context.Context, org string) ([]*Budget, *Response, error) { |
There was a problem hiding this comment.
This endpoint returns a response with the following shape:
{
"budgets": [
{
"id": "2066deda-923f-43f9-88d2-62395a28c0cdd",
"budget_type": "ProductPricing",
"budget_product_skus": [
"actions"
],
"budget_scope": "enterprise",
"budget_amount": 1000,
"prevent_further_usage": true,
"budget_alerting": {
"will_alert": true,
"alert_recipients": [
"enterprise-admin",
"billing-manager"
]
}
},
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"budget_type": "SkuPricing",
"budget_product_skus": [
"actions_linux"
],
"budget_scope": "organization",
"budget_amount": 500,
"prevent_further_usage": false,
"budget_alerting": {
"will_alert": true,
"alert_recipients": [
"org-owner"
]
}
}
],
"has_next_page": false
}
I believe it should return a struct like
{
Budgets []Budget `json:"budgets"`
HasNextPage bool `json:"has_next_page,omitempty"`
}
github/billing_budgets.go
Outdated
| // GitHub API docs: https://docs.github.com/rest/billing/budgets#update-a-budget-for-an-organization | ||
| // | ||
| //meta:operation PATCH /organizations/{org}/settings/billing/budgets/{budget_id} | ||
| func (s *BillingService) UpdateOrganizationBudget(ctx context.Context, org, budgetID string, budget *Budget) (*Budget, *Response, error) { |
There was a problem hiding this comment.
This endpoint returns a response with the following shape:
{
"message": "Budget successfully updated.",
"budget": {
"id": "2066deda-923f-43f9-88d2-62395a28c0cdd",
"budget_type": "SkuPricing",
"budget_product_sku": "actions",
"budget_scope": "enterprise",
"budget_amount": 500,
"prevent_further_usage": true,
"budget_alerting": {
"will_alert": true,
"alert_recipients": ["mona"]
}
}
}
I believe it should return a struct like
{
Budget Budget `json:"budget"`
Message string `json:"message"`
}
github/enterprise_billing_budgets.go
Outdated
| // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/billing/budgets#get-all-budgets | ||
| // | ||
| //meta:operation GET /enterprises/{enterprise}/settings/billing/budgets | ||
| func (s *EnterpriseService) ListBudgets(ctx context.Context, enterprise string) ([]*Budget, *Response, error) { |
| // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/billing/budgets#create-a-budget | ||
| // | ||
| //meta:operation POST /enterprises/{enterprise}/settings/billing/budgets | ||
| func (s *EnterpriseService) CreateBudget(ctx context.Context, enterprise string, budget *Budget) (*Budget, *Response, error) { |
github/enterprise_billing_budgets.go
Outdated
| // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/billing/budgets#update-a-budget | ||
| // | ||
| //meta:operation PATCH /enterprises/{enterprise}/settings/billing/budgets/{budget_id} | ||
| func (s *EnterpriseService) UpdateBudget(ctx context.Context, enterprise, budgetID string, budget *Budget) (*Budget, *Response, error) { |
|
@youneedgreg - please let us know when you have address all the comments from @Not-Dhananjay-Mishra and @alexandear and then we will perform another review. As far as I can tell, there are still comments that have not yet been addressed. |

Pull Request Description: Add Support for GitHub Budgets API
Closes #3930
Summary
This PR adds support for the GitHub Budgets REST API, allowing users to programmatically manage budgets for both Organizations and Enterprises. This includes listing, retrieving, creating (Enterprise only), updating, and deleting budgets.
Changes
Data Structures
limit_amount,current_amount, and alerting configurations.Organization Budgets ([BillingService])
Added the following methods to [BillingService]:
GET /organizations/{org}/settings/billing/budgetsGET /organizations/{org}/settings/billing/budgets/{budget_id}PATCH /organizations/{org}/settings/billing/budgets/{budget_id}DELETE /organizations/{org}/settings/billing/budgets/{budget_id}Enterprise Budgets ([EnterpriseService])
Added the following methods to [EnterpriseService]:
GET /enterprises/{enterprise}/settings/billing/budgetsGET /enterprises/{enterprise}/settings/billing/budgets/{budget_id}POST /enterprises/{enterprise}/settings/billing/budgetsPATCH /enterprises/{enterprise}/settings/billing/budgets/{budget_id}DELETE /enterprises/{enterprise}/settings/billing/budgets/{budget_id}Verification Plan
Automated Tests
Budgetstruct.All tests passed: