195 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
package simulator
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/google/go-github/v39/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
 | 
						|
}
 |