Skip to content

Commit 0b4687e

Browse files
committed
perf: optimize user node ID retrieval for team settings excluded members
- Replace single-user getUserNodeId with batch getBatchUserNodeIds function - Use GraphQL field aliases to fetch multiple user node IDs in one request - Reduce API calls from N individual requests to 1 batch request - Follow existing pattern from data_source_github_users.go - Improve performance and API rate limit usage for teams with multiple excluded members - Add proper error wrapping with %w format verb
1 parent 9750a01 commit 0b4687e

1 file changed

Lines changed: 54 additions & 15 deletions

File tree

github/resource_github_team_settings.go

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,56 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"reflect"
78
"strconv"
89

910
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1011
"github.com/shurcooL/githubv4"
1112
)
1213

13-
// getUserNodeId retrieves the GraphQL node ID for a given username
14-
func getUserNodeId(ctx context.Context, meta interface{}, username string) (string, error) {
14+
// getBatchUserNodeIds retrieves the GraphQL node IDs for multiple usernames in a single request.
15+
func getBatchUserNodeIds(ctx context.Context, meta any, usernames []string) (map[string]string, error) {
16+
if len(usernames) == 0 {
17+
return make(map[string]string), nil
18+
}
19+
1520
client := meta.(*Owner).v4client
1621

17-
var query struct {
18-
User struct {
19-
ID githubv4.ID `graphql:"id"`
20-
} `graphql:"user(login: $username)"`
22+
// Create GraphQL variables and query struct using reflection (similar to data_source_github_users.go)
23+
type UserFragment struct {
24+
ID githubv4.ID `graphql:"id"`
2125
}
2226

23-
variables := map[string]interface{}{
24-
"username": githubv4.String(username),
27+
var fields []reflect.StructField
28+
variables := make(map[string]any)
29+
30+
for idx, username := range usernames {
31+
label := fmt.Sprintf("User%d", idx)
32+
variables[label] = githubv4.String(username)
33+
fields = append(fields, reflect.StructField{
34+
Name: label,
35+
Type: reflect.TypeFor[UserFragment](),
36+
Tag: reflect.StructTag(fmt.Sprintf("graphql:\"%[1]s: user(login: $%[1]s)\"", label)),
37+
})
2538
}
2639

27-
err := client.Query(ctx, &query, variables)
40+
query := reflect.New(reflect.StructOf(fields)).Elem()
41+
42+
err := client.Query(ctx, query.Addr().Interface(), variables)
2843
if err != nil {
29-
return "", fmt.Errorf("failed to query user %s: %v", username, err)
44+
return nil, fmt.Errorf("failed to query users in batch: %w", err)
45+
}
46+
47+
result := make(map[string]string)
48+
for idx, username := range usernames {
49+
label := fmt.Sprintf("User%d", idx)
50+
user := query.FieldByName(label).Interface().(UserFragment)
51+
if user.ID != "" {
52+
result[username] = string(user.ID.(githubv4.String))
53+
}
3054
}
3155

32-
return string(query.User.ID.(githubv4.String)), nil
56+
return result, nil
3357
}
3458

3559
func resourceGithubTeamSettings() *schema.Resource {
@@ -212,14 +236,29 @@ func resourceGithubTeamSettingsUpdate(d *schema.ResourceData, meta any) error {
212236

213237
exclusionList := make([]githubv4.ID, 0)
214238
if excludedMembers, ok := settings["excluded_team_members"]; ok && excludedMembers != nil {
239+
// Collect all usernames first
240+
usernames := make([]string, 0)
215241
for _, v := range excludedMembers.(*schema.Set).List() {
216242
if v != nil {
217243
username := v.(string)
218-
nodeId, err := getUserNodeId(ctx, meta, username)
219-
if err != nil {
220-
return fmt.Errorf("failed to get node ID for user %s: %v", username, err)
244+
usernames = append(usernames, username)
245+
}
246+
}
247+
248+
// Get all node IDs in a single batch request
249+
if len(usernames) > 0 {
250+
nodeIds, err := getBatchUserNodeIds(ctx, meta, usernames)
251+
if err != nil {
252+
return fmt.Errorf("failed to get node IDs for excluded members: %w", err)
253+
}
254+
255+
// Convert to the exclusion list
256+
for _, username := range usernames {
257+
if nodeId, exists := nodeIds[username]; exists {
258+
exclusionList = append(exclusionList, githubv4.ID(nodeId))
259+
} else {
260+
return fmt.Errorf("failed to get node ID for user %s: user not found", username)
221261
}
222-
exclusionList = append(exclusionList, githubv4.ID(nodeId))
223262
}
224263
}
225264
}

0 commit comments

Comments
 (0)