Skip to content

Commit fcb9235

Browse files
authored
feat!: Add pagination to Enterprise.ListBudgets and add GetUserStatesForBudget (#4408) (#4501)
BREAKING CHANGE: `EnterpriseService.ListBudgets` now takes `EnterpriseListBudgetsOptions`.
1 parent b8acf75 commit fcb9235

9 files changed

Lines changed: 642 additions & 9 deletions

‎github/enterprise_budgets.go‎

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,49 @@ type EnterpriseListBudgets struct {
5353
TotalCount *int `json:"total_count,omitempty"`
5454
}
5555

56+
// EnterpriseListBudgetsOptions specifies the optional parameters to the
57+
// EnterpriseService.ListBudgets method.
58+
type EnterpriseListBudgetsOptions struct {
59+
Scope string `url:"scope,omitempty"`
60+
User string `url:"user,omitempty"`
61+
62+
ListOptions
63+
}
64+
65+
// EnterpriseBudgetUserState represents the budget status and consumption of an individual user.
66+
type EnterpriseBudgetUserState struct {
67+
User *string `json:"user,omitempty"`
68+
ConsumedAmount float64 `json:"consumed_amount"`
69+
TargetAmount float64 `json:"target_amount"`
70+
OverrideBudgetID *string `json:"override_budget_id,omitempty"`
71+
}
72+
73+
func (u EnterpriseBudgetUserState) String() string {
74+
return Stringify(u)
75+
}
76+
77+
// EnterpriseBudgetUserStates represents the response when retrieving user states for a budget.
78+
type EnterpriseBudgetUserStates struct {
79+
UserStates []*EnterpriseBudgetUserState `json:"user_states"`
80+
HasNextPage bool `json:"has_next_page"`
81+
TotalCount int `json:"total_count"`
82+
}
83+
84+
func (u EnterpriseBudgetUserStates) String() string {
85+
return Stringify(u)
86+
}
87+
88+
// EnterpriseGetUserStatesOptions specifies the optional parameters to the
89+
// EnterpriseService.GetUserStatesForBudget method.
90+
type EnterpriseGetUserStatesOptions struct {
91+
SortOrder int `url:"sort_order,omitempty"`
92+
User string `url:"user,omitempty"`
93+
ThresholdLowerBound float64 `url:"threshold_lower_bound,omitempty"`
94+
ThresholdUpperBound float64 `url:"threshold_upper_bound,omitempty"`
95+
96+
ListOptions
97+
}
98+
5699
// EnterpriseCreateBudget represents the payload to create a GitHub enterprise budget.
57100
type EnterpriseCreateBudget struct {
58101
BudgetAmount int `json:"budget_amount"`
@@ -92,8 +135,12 @@ type EnterpriseDeleteBudgetResponse struct {
92135
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/billing/budgets?apiVersion=2022-11-28#get-all-budgets
93136
//
94137
//meta:operation GET /enterprises/{enterprise}/settings/billing/budgets
95-
func (s *EnterpriseService) ListBudgets(ctx context.Context, enterprise string) (*EnterpriseListBudgets, *Response, error) {
138+
func (s *EnterpriseService) ListBudgets(ctx context.Context, enterprise string, opts *EnterpriseListBudgetsOptions) (*EnterpriseListBudgets, *Response, error) {
96139
u := fmt.Sprintf("enterprises/%v/settings/billing/budgets", enterprise)
140+
u, err := addOptions(u, opts)
141+
if err != nil {
142+
return nil, nil, err
143+
}
97144

98145
req, err := s.client.NewRequest(ctx, "GET", u, nil)
99146
if err != nil {
@@ -109,6 +156,32 @@ func (s *EnterpriseService) ListBudgets(ctx context.Context, enterprise string)
109156
return budgets, resp, nil
110157
}
111158

159+
// GetUserStatesForBudget gets user states for a multi-user budget in an enterprise.
160+
//
161+
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/billing/budgets?apiVersion=2022-11-28#get-user-states-for-a-multi-user-budget
162+
//
163+
//meta:operation GET /enterprises/{enterprise}/settings/billing/budgets/{budget_id}/user-states
164+
func (s *EnterpriseService) GetUserStatesForBudget(ctx context.Context, enterprise, budgetID string, opts *EnterpriseGetUserStatesOptions) (*EnterpriseBudgetUserStates, *Response, error) {
165+
u := fmt.Sprintf("enterprises/%v/settings/billing/budgets/%v/user-states", enterprise, budgetID)
166+
u, err := addOptions(u, opts)
167+
if err != nil {
168+
return nil, nil, err
169+
}
170+
171+
req, err := s.client.NewRequest(ctx, "GET", u, nil)
172+
if err != nil {
173+
return nil, nil, err
174+
}
175+
176+
var userStates *EnterpriseBudgetUserStates
177+
resp, err := s.client.Do(req, &userStates)
178+
if err != nil {
179+
return nil, resp, err
180+
}
181+
182+
return userStates, resp, nil
183+
}
184+
112185
// CreateBudget creates a new budget for an enterprise.
113186
//
114187
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/billing/budgets?apiVersion=2022-11-28#create-a-budget

‎github/enterprise_budgets_test.go‎

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ func TestEnterpriseService_ListBudgets(t *testing.T) {
1919

2020
mux.HandleFunc("/enterprises/e/settings/billing/budgets", func(w http.ResponseWriter, r *http.Request) {
2121
testMethod(t, r, "GET")
22+
testFormValues(t, r, values{
23+
"page": "2",
24+
"per_page": "10",
25+
"scope": "enterprise",
26+
"user": "octocat",
27+
})
2228
fmt.Fprint(w, `{
2329
"budgets": [
2430
{
@@ -39,8 +45,13 @@ func TestEnterpriseService_ListBudgets(t *testing.T) {
3945
}`)
4046
})
4147

48+
opts := &EnterpriseListBudgetsOptions{
49+
Scope: "enterprise",
50+
User: "octocat",
51+
ListOptions: ListOptions{Page: 2, PerPage: 10},
52+
}
4253
ctx := t.Context()
43-
budgets, _, err := client.Enterprise.ListBudgets(ctx, "e")
54+
budgets, _, err := client.Enterprise.ListBudgets(ctx, "e", opts)
4455
if err != nil {
4556
t.Errorf("Enterprise.ListBudgets returned error: %v", err)
4657
}
@@ -69,15 +80,15 @@ func TestEnterpriseService_ListBudgets(t *testing.T) {
6980

7081
const methodName = "ListBudgets"
7182
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
72-
got, resp, err := client.Enterprise.ListBudgets(ctx, "e")
83+
got, resp, err := client.Enterprise.ListBudgets(ctx, "e", nil)
7384
if got != nil {
7485
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
7586
}
7687
return resp, err
7788
})
7889

7990
testBadOptions(t, methodName, func() (err error) {
80-
_, _, err = client.Enterprise.ListBudgets(ctx, "\n")
91+
_, _, err = client.Enterprise.ListBudgets(ctx, "\n", opts)
8192
return err
8293
})
8394
}
@@ -87,7 +98,98 @@ func TestEnterpriseService_ListBudgets_invalidEnterprise(t *testing.T) {
8798
client, _, _ := setup(t)
8899

89100
ctx := t.Context()
90-
_, _, err := client.Enterprise.ListBudgets(ctx, "%")
101+
_, _, err := client.Enterprise.ListBudgets(ctx, "%", nil)
102+
testURLParseError(t, err)
103+
}
104+
105+
func TestEnterpriseService_GetUserStatesForBudget(t *testing.T) {
106+
t.Parallel()
107+
client, mux, _ := setup(t)
108+
109+
mux.HandleFunc("/enterprises/e/settings/billing/budgets/b-123/user-states", func(w http.ResponseWriter, r *http.Request) {
110+
testMethod(t, r, "GET")
111+
testFormValues(t, r, values{
112+
"page": "1",
113+
"per_page": "2",
114+
"sort_order": "1",
115+
"user": "octocat",
116+
"threshold_lower_bound": "50.5",
117+
"threshold_upper_bound": "100",
118+
})
119+
fmt.Fprint(w, `{
120+
"user_states": [
121+
{
122+
"user": "octocat",
123+
"consumed_amount": 50.5,
124+
"target_amount": 1000
125+
},
126+
{
127+
"user": "monalisa",
128+
"consumed_amount": 250,
129+
"target_amount": 1000,
130+
"override_budget_id": "2066deda-923f-43f9-88d2-62395a28c0cdd"
131+
}
132+
],
133+
"has_next_page": false,
134+
"total_count": 2
135+
}`)
136+
})
137+
138+
opts := &EnterpriseGetUserStatesOptions{
139+
SortOrder: 1,
140+
User: "octocat",
141+
ThresholdLowerBound: 50.5,
142+
ThresholdUpperBound: 100.0,
143+
ListOptions: ListOptions{Page: 1, PerPage: 2},
144+
}
145+
ctx := t.Context()
146+
states, _, err := client.Enterprise.GetUserStatesForBudget(ctx, "e", "b-123", opts)
147+
if err != nil {
148+
t.Errorf("Enterprise.GetUserStatesForBudget returned error: %v", err)
149+
}
150+
151+
want := &EnterpriseBudgetUserStates{
152+
UserStates: []*EnterpriseBudgetUserState{
153+
{
154+
User: new("octocat"),
155+
ConsumedAmount: 50.5,
156+
TargetAmount: 1000.0,
157+
},
158+
{
159+
User: new("monalisa"),
160+
ConsumedAmount: 250.0,
161+
TargetAmount: 1000.0,
162+
OverrideBudgetID: new("2066deda-923f-43f9-88d2-62395a28c0cdd"),
163+
},
164+
},
165+
HasNextPage: false,
166+
TotalCount: 2,
167+
}
168+
if !cmp.Equal(states, want) {
169+
t.Errorf("Enterprise.GetUserStatesForBudget returned %+v, want %+v", states, want)
170+
}
171+
172+
const methodName = "GetUserStatesForBudget"
173+
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
174+
got, resp, err := client.Enterprise.GetUserStatesForBudget(ctx, "e", "b-123", nil)
175+
if got != nil {
176+
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
177+
}
178+
return resp, err
179+
})
180+
181+
testBadOptions(t, methodName, func() (err error) {
182+
_, _, err = client.Enterprise.GetUserStatesForBudget(ctx, "\n", "\n", opts)
183+
return err
184+
})
185+
}
186+
187+
func TestEnterpriseService_GetUserStatesForBudget_invalidEnterprise(t *testing.T) {
188+
t.Parallel()
189+
client, _, _ := setup(t)
190+
191+
ctx := t.Context()
192+
_, _, err := client.Enterprise.GetUserStatesForBudget(ctx, "%", "b-123", nil)
91193
testURLParseError(t, err)
92194
}
93195

‎github/gen-iterators.go‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,10 @@ var useCursorPagination = map[string]bool{
164164

165165
// customNames provides custom names for iterator methods where the default methodName + "Iter" would be confusing.
166166
var customNames = map[string]string{
167-
"RepositoriesService.GetCommit": "ListCommitFiles",
168-
"RepositoriesService.CompareCommits": "ListCommitComparisonFiles",
169-
"RepositoriesService.GetCombinedStatus": "ListCombinedStatus",
167+
"EnterpriseService.GetUserStatesForBudget": "ListUserStatesForBudget",
168+
"RepositoriesService.GetCommit": "ListCommitFiles",
169+
"RepositoriesService.CompareCommits": "ListCommitComparisonFiles",
170+
"RepositoriesService.GetCombinedStatus": "ListCombinedStatus",
170171
}
171172

172173
// sliceToBeUsedForIteration identifies methods where the wrapper struct contains multiple []*T fields,

‎github/gen-stringify-test.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ var (
6161
return "false"
6262
case "new(false)":
6363
return "false"
64-
case "new(0.0)":
64+
case "0.0", "new(0.0)":
6565
return "0"
6666
case "0", "new(0)", "new(int64(0))":
6767
return "0"

‎github/github-accessors.go‎

Lines changed: 104 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)