195 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
| package simulator
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"sort"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/google/go-github/v52/github"
 | |
| )
 | |
| 
 | |
| type RunnerGroupScope int
 | |
| 
 | |
| const (
 | |
| 	Organization RunnerGroupScope = iota
 | |
| 	Enterprise
 | |
| )
 | |
| 
 | |
| func (s RunnerGroupScope) String() string {
 | |
| 	switch s {
 | |
| 	case Organization:
 | |
| 		return "Organization"
 | |
| 	case Enterprise:
 | |
| 		return "Enterprise"
 | |
| 	default:
 | |
| 		panic(fmt.Sprintf("unimplemented RunnerGroupScope: %v", int(s)))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type RunnerGroupKind int
 | |
| 
 | |
| const (
 | |
| 	Default RunnerGroupKind = iota
 | |
| 	Custom
 | |
| )
 | |
| 
 | |
| func (s RunnerGroupKind) String() string {
 | |
| 	switch s {
 | |
| 	case Default:
 | |
| 		return "Default"
 | |
| 	case Custom:
 | |
| 		return "Custom"
 | |
| 	default:
 | |
| 		panic(fmt.Sprintf("unimplemented RunnerGroupKind: %v", int(s)))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func NewRunnerGroupFromGitHub(g *github.RunnerGroup) RunnerGroup {
 | |
| 	var name string
 | |
| 	if !g.GetDefault() {
 | |
| 		name = g.GetName()
 | |
| 	}
 | |
| 
 | |
| 	var scope RunnerGroupScope
 | |
| 
 | |
| 	if g.GetInherited() {
 | |
| 		scope = Enterprise
 | |
| 	} else {
 | |
| 		scope = Organization
 | |
| 	}
 | |
| 
 | |
| 	return newRunnerGroup(scope, name)
 | |
| }
 | |
| 
 | |
| func NewRunnerGroupFromProperties(enterprise, organization, group string) RunnerGroup {
 | |
| 	var scope RunnerGroupScope
 | |
| 
 | |
| 	if enterprise != "" {
 | |
| 		scope = Enterprise
 | |
| 	} else {
 | |
| 		scope = Organization
 | |
| 	}
 | |
| 
 | |
| 	return newRunnerGroup(scope, group)
 | |
| }
 | |
| 
 | |
| // newRunnerGroup creates a new RunnerGroup instance from the provided arguments.
 | |
| // There's a convention that an empty name implies a default runner group.
 | |
| func newRunnerGroup(scope RunnerGroupScope, name string) RunnerGroup {
 | |
| 	if name == "" {
 | |
| 		return RunnerGroup{
 | |
| 			Scope: scope,
 | |
| 			Kind:  Default,
 | |
| 			Name:  "",
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return RunnerGroup{
 | |
| 		Scope: scope,
 | |
| 		Kind:  Custom,
 | |
| 		Name:  name,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type RunnerGroup struct {
 | |
| 	Scope RunnerGroupScope
 | |
| 	Kind  RunnerGroupKind
 | |
| 	Name  string
 | |
| }
 | |
| 
 | |
| func (r RunnerGroup) String() string {
 | |
| 	return fmt.Sprintf("RunnerGroup{Scope:%s, Kind:%s, Name:%s}", r.Scope, r.Kind, r.Name)
 | |
| }
 | |
| 
 | |
| // VisibleRunnerGroups is a set of enterprise and organization runner groups
 | |
| // that are visible to a GitHub repository.
 | |
| // GitHub Actions chooses one of such visible group on which the workflow job is scheduled.
 | |
| // ARC chooses the same group as Actions as the scale target.
 | |
| type VisibleRunnerGroups struct {
 | |
| 	// sortedGroups is a pointer to a mutable list of RunnerGroups that contains all the runner sortedGroups
 | |
| 	// that are visible to the repository, including organization sortedGroups defined at the organization level,
 | |
| 	// and enterprise sortedGroups that are inherited down to the organization.
 | |
| 	sortedGroups []RunnerGroup
 | |
| }
 | |
| 
 | |
| func NewVisibleRunnerGroups() *VisibleRunnerGroups {
 | |
| 	return &VisibleRunnerGroups{}
 | |
| }
 | |
| 
 | |
| func (g *VisibleRunnerGroups) String() string {
 | |
| 	var gs []string
 | |
| 	for _, g := range g.sortedGroups {
 | |
| 		gs = append(gs, g.String())
 | |
| 	}
 | |
| 
 | |
| 	return strings.Join(gs, ", ")
 | |
| }
 | |
| 
 | |
| func (g *VisibleRunnerGroups) IsEmpty() bool {
 | |
| 	return len(g.sortedGroups) == 0
 | |
| }
 | |
| 
 | |
| func (r *VisibleRunnerGroups) Includes(ref RunnerGroup) bool {
 | |
| 	for _, r := range r.sortedGroups {
 | |
| 		if r.Scope == ref.Scope && r.Kind == ref.Kind && r.Name == ref.Name {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // Add adds a runner group into VisibleRunnerGroups
 | |
| // at a certain position in the list so that
 | |
| // Traverse can return runner groups in order of higher precedence to lower precedence.
 | |
| func (g *VisibleRunnerGroups) Add(rg RunnerGroup) error {
 | |
| 	n := len(g.sortedGroups)
 | |
| 	i := sort.Search(n, func(i int) bool {
 | |
| 		data := g.sortedGroups[i]
 | |
| 
 | |
| 		if rg.Kind > data.Kind {
 | |
| 			return false
 | |
| 		} else if rg.Kind < data.Kind {
 | |
| 			return true
 | |
| 		}
 | |
| 
 | |
| 		if rg.Scope > data.Scope {
 | |
| 			return false
 | |
| 		} else if rg.Scope < data.Scope {
 | |
| 			return true
 | |
| 		}
 | |
| 
 | |
| 		return false
 | |
| 	})
 | |
| 
 | |
| 	g.insert(rg, i)
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (g *VisibleRunnerGroups) insert(rg RunnerGroup, i int) {
 | |
| 	var result []RunnerGroup
 | |
| 
 | |
| 	result = append(result, g.sortedGroups[:i]...)
 | |
| 	result = append(result, rg)
 | |
| 	result = append(result, g.sortedGroups[i:]...)
 | |
| 
 | |
| 	g.sortedGroups = result
 | |
| }
 | |
| 
 | |
| // Traverse traverses all the runner groups visible to a repository
 | |
| // in order of higher precedence to lower precedence.
 | |
| func (g *VisibleRunnerGroups) Traverse(f func(RunnerGroup) (bool, error)) error {
 | |
| 	for _, rg := range g.sortedGroups {
 | |
| 		ok, err := f(rg)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		if ok {
 | |
| 			return nil
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 |