Skip to content

Commit 4b99b4d

Browse files
skwashdploxiln
authored andcommitted
Fix GitHub teams for large orgs
Some large organisations have more than 100 teams. The current implementation only checks the first 100 teams returned by the API. This checks all teams the user is a member of. Added support for GitHub's new nested team feature which means inheritence works as designed. Again useful for large orgs. Updated the limit from 200 to the documented limit of 100: https://developer.github.com/v3/#pagination
1 parent 05dee28 commit 4b99b4d

File tree

2 files changed

+48
-34
lines changed

2 files changed

+48
-34
lines changed

providers/github.go

+47-33
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/http"
99
"net/url"
1010
"path"
11+
"regexp"
1112
"strconv"
1213
"strings"
1314
)
@@ -69,7 +70,7 @@ func (p *GitHubProvider) hasOrg(accessToken string) (bool, error) {
6970
pn := 1
7071
for {
7172
params := url.Values{
72-
"limit": {"200"},
73+
"limit": {"100"},
7374
"page": {strconv.Itoa(pn)},
7475
}
7576

@@ -134,7 +135,7 @@ func (p *GitHubProvider) hasOrgAndTeam(accessToken string) (bool, error) {
134135
}
135136

136137
params := url.Values{
137-
"limit": {"200"},
138+
"limit": {"100"},
138139
}
139140

140141
endpoint := &url.URL{
@@ -143,45 +144,58 @@ func (p *GitHubProvider) hasOrgAndTeam(accessToken string) (bool, error) {
143144
Path: path.Join(p.ValidateURL.Path, "/user/teams"),
144145
RawQuery: params.Encode(),
145146
}
146-
req, _ := http.NewRequest("GET", endpoint.String(), nil)
147-
req.Header.Set("Accept", "application/vnd.github.v3+json")
148-
req.Header.Set("Authorization", fmt.Sprintf("token %s", accessToken))
149-
resp, err := http.DefaultClient.Do(req)
150-
if err != nil {
151-
return false, err
152-
}
153-
154-
body, err := ioutil.ReadAll(resp.Body)
155-
resp.Body.Close()
156-
if err != nil {
157-
return false, err
158-
}
159-
if resp.StatusCode != 200 {
160-
return false, fmt.Errorf(
161-
"got %d from %q %s", resp.StatusCode, endpoint.String(), body)
162-
}
163-
164-
if err := json.Unmarshal(body, &teams); err != nil {
165-
return false, fmt.Errorf("%s unmarshaling %s", err, body)
166-
}
147+
team_url := endpoint.String()
167148

149+
pattern := regexp.MustCompile(`<([^>]+)>; rel="next"`)
168150
var hasOrg bool
169151
presentOrgs := make(map[string]bool)
170152
var presentTeams []string
171-
for _, team := range teams {
172-
presentOrgs[team.Org.Login] = true
173-
if p.Org == team.Org.Login {
174-
hasOrg = true
175-
ts := strings.Split(p.Team, ",")
176-
for _, t := range ts {
177-
if t == team.Slug {
178-
log.Printf("Found Github Organization:%q Team:%q (Name:%q)", team.Org.Login, team.Slug, team.Name)
179-
return true, nil
153+
for {
154+
req, _ := http.NewRequest("GET", team_url, nil)
155+
req.Header.Set("Accept", "application/vnd.github.hellcat-preview+json")
156+
req.Header.Set("Authorization", fmt.Sprintf("token %s", accessToken))
157+
resp, err := http.DefaultClient.Do(req)
158+
if err != nil {
159+
return false, err
160+
}
161+
162+
body, err := ioutil.ReadAll(resp.Body)
163+
resp.Body.Close()
164+
if err != nil {
165+
return false, err
166+
}
167+
if resp.StatusCode != 200 {
168+
return false, fmt.Errorf(
169+
"got %d from %q %s", resp.StatusCode, endpoint.String(), body)
170+
}
171+
172+
if err := json.Unmarshal(body, &teams); err != nil {
173+
return false, fmt.Errorf("%s unmarshaling %s", err, body)
174+
}
175+
176+
for _, team := range teams {
177+
presentOrgs[team.Org.Login] = true
178+
if p.Org == team.Org.Login {
179+
hasOrg = true
180+
ts := strings.Split(p.Team, ",")
181+
for _, t := range ts {
182+
if t == team.Slug {
183+
log.Printf("Found Github Organization:%q Team:%q (Name:%q)",
184+
team.Org.Login, team.Slug, team.Name)
185+
return true, nil
186+
}
180187
}
188+
presentTeams = append(presentTeams, team.Slug)
181189
}
182-
presentTeams = append(presentTeams, team.Slug)
183190
}
191+
192+
matches := pattern.FindStringSubmatch(resp.Header["Link"][0])
193+
if len(matches) == 0 {
194+
break
195+
}
196+
team_url = matches[1]
184197
}
198+
185199
if hasOrg {
186200
log.Printf("Missing Team:%q from Org:%q in teams: %v", p.Team, p.Org, presentTeams)
187201
} else {

providers/github_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func testGitHubBackend(payload []string) *httptest.Server {
3131
pathToQueryMap := map[string][]string{
3232
"/user": []string{""},
3333
"/user/emails": []string{""},
34-
"/user/orgs": []string{"limit=200&page=1", "limit=200&page=2", "limit=200&page=3"},
34+
"/user/orgs": []string{"limit=100&page=1", "limit=100&page=2", "limit=100&page=3"},
3535
}
3636

3737
return httptest.NewServer(http.HandlerFunc(

0 commit comments

Comments
 (0)