Files
actions-runner-controller/simulator/runnergroup_visibility.go
Tingluo Huang ebe7d060cb Find runner groups that visible to repository using a single API call. (#1324)
The [ListRunnerGroup API](https://docs.github.com/en/rest/reference/actions#list-self-hosted-runner-groups-for-an-organization) now add a new query parameter `visible_to_repository`.

We were doing `N+1` lookup when trying to find which runner group can be used for job from a certain repository.
- List all runner groups
- Loop through all groups to check repository access for each of them via [API](https://docs.github.com/en/rest/reference/actions#list-repository-access-to-a-self-hosted-runner-group-in-an-organization)

The new query parameter `visible_to_repository` should allow us to get the runner groups with access in one call.

Limitation:
- The new query parameter is only supported in GitHub.com, which means anyone who uses ARC in GitHub Enterprise Server won't get this.
- I am working on a PR to update `go-github` library to support the new parameter, but it will take a few weeks for a newer `go-github` to be released, so in the meantime, I am duplicating the implementation in ARC as well to support the new query parameter.
2022-04-24 10:54:40 +09:00

81 lines
1.7 KiB
Go

package simulator
import (
"context"
"fmt"
"github.com/actions-runner-controller/actions-runner-controller/github"
)
type Simulator struct {
Client *github.Client
}
func (c *Simulator) GetRunnerGroupsVisibleToRepository(ctx context.Context, org, repo string, managed *VisibleRunnerGroups) (*VisibleRunnerGroups, error) {
visible := NewVisibleRunnerGroups()
if org == "" {
panic(fmt.Sprintf("BUG: owner should not be empty in this context. repo=%v", repo))
}
if c.Client.GithubBaseURL == "https://github.com/" {
runnerGroups, err := c.Client.ListOrganizationRunnerGroupsForRepository(ctx, org, repo)
if err != nil {
return visible, err
}
for _, runnerGroup := range runnerGroups {
ref := NewRunnerGroupFromGitHub(runnerGroup)
if !managed.Includes(ref) {
continue
}
visible.Add(ref)
}
} else {
runnerGroups, err := c.Client.ListOrganizationRunnerGroups(ctx, org)
if err != nil {
return visible, err
}
for _, runnerGroup := range runnerGroups {
ref := NewRunnerGroupFromGitHub(runnerGroup)
if !managed.Includes(ref) {
continue
}
if runnerGroup.GetVisibility() != "all" {
hasAccess, err := c.hasRepoAccessToOrganizationRunnerGroup(ctx, org, runnerGroup.GetID(), repo)
if err != nil {
return visible, err
}
if !hasAccess {
continue
}
}
visible.Add(ref)
}
}
return visible, nil
}
func (c *Simulator) hasRepoAccessToOrganizationRunnerGroup(ctx context.Context, org string, runnerGroupId int64, repo string) (bool, error) {
repos, err := c.Client.ListRunnerGroupRepositoryAccesses(ctx, org, runnerGroupId)
if err != nil {
return false, err
}
for _, githubRepo := range repos {
if githubRepo.GetFullName() == repo {
return true, nil
}
}
return false, nil
}