Add godoc comments and unexport (#27)

* Add separate constructors for each credential type

* Add godoc comments to client

* Unexport GitHubConfig

* Add godoc comments for listener package

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Francesco Renzi
2025-11-26 16:05:39 +01:00
committed by GitHub
parent 7442885c99
commit cec89c5b7b
5 changed files with 309 additions and 250 deletions
+81 -29
View File
@@ -61,9 +61,11 @@ func (v *atomicValue[T]) Swap(new T) (old T) {
return v.v.Swap(new).(T)
}
// HeaderScaleSetMaxCapacity used to propagate capacity information to the back-end
// HeaderScaleSetMaxCapacity is used to propagate the scale set max
// capacity when polling for messages.
const HeaderScaleSetMaxCapacity = "X-ScaleSetMaxCapacity"
// Client implements a GitHub Actions Scale Set client.
type Client struct {
httpClient *http.Client
@@ -75,8 +77,8 @@ type Client struct {
retryMax int
retryWaitMax time.Duration
creds *ActionsAuth
config *GitHubConfig
creds *actionsAuth
config *gitHubConfig
logger *slog.Logger
userAgent atomicValue[string]
@@ -87,6 +89,7 @@ type Client struct {
proxyFunc ProxyFunc
}
// GitHubAppAuth contains the GitHub App authentication credentials. All fields are required.
type GitHubAppAuth struct {
// ClientID is the Client ID of the application (app id also works)
ClientID string
@@ -96,6 +99,7 @@ type GitHubAppAuth struct {
PrivateKey string
}
// Validate returns an error if any required field is missing.
func (a *GitHubAppAuth) Validate() error {
if a.ClientID == "" {
return fmt.Errorf("client ID is required")
@@ -109,17 +113,20 @@ func (a *GitHubAppAuth) Validate() error {
return nil
}
type ActionsAuth struct {
// AppCreds is the GitHub App credentials
App *GitHubAppAuth
type actionsAuth struct {
// app is the GitHub app credentials
app *GitHubAppAuth
// GitHub PAT
Token string
token string
}
// ProxyFunc defines the function signature for a proxy function.
type ProxyFunc func(req *http.Request) (*url.URL, error)
// Option defines a functional option for configuring the Client.
type Option func(*Client)
// UserAgentInfo contains information for constructing the user agent string.
type UserAgentInfo struct {
// System is the name of the scale set implementation
System string
@@ -152,44 +159,66 @@ func (u UserAgentInfo) String() string {
)
}
// WithLogger sets a custom logger for the Client.
func WithLogger(logger slog.Logger) Option {
return func(c *Client) {
c.logger = &logger
}
}
// WithRetryMax sets the maximum number of retries for the Client.
func WithRetryMax(retryMax int) Option {
return func(c *Client) {
c.retryMax = retryMax
}
}
// WithRetryWaitMax sets the maximum wait time between retries for the Client.
func WithRetryWaitMax(retryWaitMax time.Duration) Option {
return func(c *Client) {
c.retryWaitMax = retryWaitMax
}
}
// WithRootCAs sets custom root certificate authorities for the Client.
func WithRootCAs(rootCAs *x509.CertPool) Option {
return func(c *Client) {
c.rootCAs = rootCAs
}
}
// WithoutTLSVerify disables TLS certificate verification for the Client.
func WithoutTLSVerify() Option {
return func(c *Client) {
c.tlsInsecureSkipVerify = true
}
}
// WithProxy sets a custom proxy function for the Client.
func WithProxy(proxyFunc ProxyFunc) Option {
return func(c *Client) {
c.proxyFunc = proxyFunc
}
}
func NewClient(githubConfigURL string, creds *ActionsAuth, options ...Option) (*Client, error) {
config, err := ParseGitHubConfigFromURL(githubConfigURL)
// NewClientWithGitHubApp creates a new Client using GitHub App credentials.
func NewClientWithGitHubApp(githubConfigURL string, appCreds *GitHubAppAuth, options ...Option) (*Client, error) {
creds := &actionsAuth{
app: appCreds,
}
return newClient(githubConfigURL, creds, options...)
}
// NewClientWithPersonalAccessToken creates a new Client using a personal access token.
func NewClientWithPersonalAccessToken(githubConfigURL, personalAccessToken string, options ...Option) (*Client, error) {
creds := &actionsAuth{
token: personalAccessToken,
}
return newClient(githubConfigURL, creds, options...)
}
func newClient(githubConfigURL string, creds *actionsAuth, options ...Option) (*Client, error) {
config, err := parseGitHubConfigFromURL(githubConfigURL)
if err != nil {
return nil, fmt.Errorf("failed to parse githubConfigURL: %w", err)
}
@@ -279,7 +308,7 @@ func (c *Client) do(req *http.Request) (*http.Response, error) {
}
func (c *Client) newGitHubAPIRequest(ctx context.Context, method, path string, body io.Reader) (*http.Request, error) {
u := c.config.GitHubAPIURL(path)
u := c.config.gitHubAPIURL(path)
req, err := http.NewRequestWithContext(ctx, method, u.String(), body)
if err != nil {
return nil, fmt.Errorf("failed to create new GitHub API request: %w", err)
@@ -331,6 +360,7 @@ func (c *Client) newActionsServiceRequest(ctx context.Context, method, path stri
return req, nil
}
// GetRunnerScaleSet fetches a runner scale set by its name within a runner group.
func (c *Client) GetRunnerScaleSet(ctx context.Context, runnerGroupID int, runnerScaleSetName string) (*RunnerScaleSet, error) {
path := fmt.Sprintf("/%s?runnerGroupId=%d&name=%s", scaleSetEndpoint, runnerGroupID, runnerScaleSetName)
req, err := c.newActionsServiceRequest(ctx, http.MethodGet, path, nil)
@@ -371,6 +401,7 @@ func (c *Client) GetRunnerScaleSet(ctx context.Context, runnerGroupID int, runne
return &runnerScaleSetList.RunnerScaleSets[0], nil
}
// GetRunnerScaleSetByID fetches a runner scale set by its ID.
func (c *Client) GetRunnerScaleSetByID(ctx context.Context, runnerScaleSetID uint64) (*RunnerScaleSet, error) {
path := fmt.Sprintf("/%s/%d", scaleSetEndpoint, runnerScaleSetID)
req, err := c.newActionsServiceRequest(ctx, http.MethodGet, path, nil)
@@ -399,6 +430,7 @@ func (c *Client) GetRunnerScaleSetByID(ctx context.Context, runnerScaleSetID uin
return runnerScaleSet, nil
}
// GetRunnerGroupByName fetches a runner group by its name.
func (c *Client) GetRunnerGroupByName(ctx context.Context, runnerGroup string) (*RunnerGroup, error) {
path := fmt.Sprintf("/_apis/runtime/runnergroups/?groupName=%s", runnerGroup)
req, err := c.newActionsServiceRequest(ctx, http.MethodGet, path, nil)
@@ -456,6 +488,7 @@ func (c *Client) GetRunnerGroupByName(ctx context.Context, runnerGroup string) (
return &runnerGroupList.RunnerGroups[0], nil
}
// CreateRunnerScaleSet creates a new runner scale set. Note that runner scale set names must be unique within a runner group.
func (c *Client) CreateRunnerScaleSet(ctx context.Context, runnerScaleSet *RunnerScaleSet) (*RunnerScaleSet, error) {
body, err := json.Marshal(runnerScaleSet)
if err != nil {
@@ -486,6 +519,7 @@ func (c *Client) CreateRunnerScaleSet(ctx context.Context, runnerScaleSet *Runne
return createdRunnerScaleSet, nil
}
// UpdateRunnerScaleSet updates an existing runner scale set.
func (c *Client) UpdateRunnerScaleSet(ctx context.Context, runnerScaleSetID int, runnerScaleSet *RunnerScaleSet) (*RunnerScaleSet, error) {
path := fmt.Sprintf("%s/%d", scaleSetEndpoint, runnerScaleSetID)
@@ -519,6 +553,7 @@ func (c *Client) UpdateRunnerScaleSet(ctx context.Context, runnerScaleSetID int,
return updatedRunnerScaleSet, nil
}
// DeleteRunnerScaleSet deletes a runner scale set by its ID.
func (c *Client) DeleteRunnerScaleSet(ctx context.Context, runnerScaleSetID int) error {
path := fmt.Sprintf("/%s/%d", scaleSetEndpoint, runnerScaleSetID)
req, err := c.newActionsServiceRequest(ctx, http.MethodDelete, path, nil)
@@ -539,7 +574,10 @@ func (c *Client) DeleteRunnerScaleSet(ctx context.Context, runnerScaleSetID int)
return nil
}
// GetMessage fetches a message from the runner scale set message queue.
// GetMessage fetches a message from the runner scale set message queue. If there are no messages available, it returns (nil, nil).
// Unless a message is deleted after being processed (using DeleteMessage), it will be returned again in subsequent calls.
// If the current session token is expired, it returns a MessageQueueTokenExpiredError.
// In these cases the caller should refresh the session with RefreshMessageSession.
func (c *Client) GetMessage(ctx context.Context, messageQueueURL, messageQueueAccessToken string, lastMessageID uint64, maxCapacity uint32) (*RunnerScaleSetMessage, error) {
u, err := url.Parse(messageQueueURL)
if err != nil {
@@ -604,6 +642,10 @@ func (c *Client) GetMessage(ctx context.Context, messageQueueURL, messageQueueAc
return message, nil
}
// DeleteMessage deletes a message from the runner scale set message queue.
// This should typically be done after processing the message and acts as an acknowledgment.
// If the current session token is expired, it returns a MessageQueueTokenExpiredError.
// In these cases the caller should refresh the session with RefreshMessageSession.
func (c *Client) DeleteMessage(ctx context.Context, messageQueueURL, messageQueueAccessToken string, messageID uint64) error {
u, err := url.Parse(messageQueueURL)
if err != nil {
@@ -651,6 +693,8 @@ func (c *Client) DeleteMessage(ctx context.Context, messageQueueURL, messageQueu
}
}
// CreateMessageSession creates a new message session for the specified runner scale set.
// The resulting session contains the message queue URL and access token used to GetMessage.
func (c *Client) CreateMessageSession(ctx context.Context, runnerScaleSetID uint64, owner string) (*RunnerScaleSetSession, error) {
path := fmt.Sprintf("/%s/%d/sessions", scaleSetEndpoint, runnerScaleSetID)
@@ -672,11 +716,14 @@ func (c *Client) CreateMessageSession(ctx context.Context, runnerScaleSetID uint
return createdSession, nil
}
// DeleteMessageSession deletes a message session for the specified runner scale set.
func (c *Client) DeleteMessageSession(ctx context.Context, runnerScaleSetID uint64, sessionID uuid.UUID) error {
path := fmt.Sprintf("/%s/%d/sessions/%s", scaleSetEndpoint, runnerScaleSetID, sessionID.String())
return c.doSessionRequest(ctx, http.MethodDelete, path, nil, http.StatusNoContent, nil)
}
// RefreshMessageSession refreshes a message session for the specified runner scale set.
// This should be used when a MessageQueueTokenExpiredError is encountered.
func (c *Client) RefreshMessageSession(ctx context.Context, runnerScaleSetID uint64, sessionID uuid.UUID) (*RunnerScaleSetSession, error) {
path := fmt.Sprintf("/%s/%d/sessions/%s", scaleSetEndpoint, runnerScaleSetID, sessionID.String())
refreshedSession := &RunnerScaleSetSession{}
@@ -735,6 +782,8 @@ func (c *Client) doSessionRequest(ctx context.Context, method, path string, requ
})
}
// GenerateJitRunnerConfig generates a JIT runner configuration for the specified runner scale set. This returns an encoded
// configuration that can be used to directly start a new runner.
func (c *Client) GenerateJitRunnerConfig(ctx context.Context, jitRunnerSetting *RunnerScaleSetJitRunnerSetting, scaleSetID int) (*RunnerScaleSetJitRunnerConfig, error) {
path := fmt.Sprintf("/%s/%d/generatejitconfig", scaleSetEndpoint, scaleSetID)
@@ -769,6 +818,7 @@ func (c *Client) GenerateJitRunnerConfig(ctx context.Context, jitRunnerSetting *
return runnerJitConfig, nil
}
// GetRunner fetches a runner by its ID. This can be used to check if a runner exists.
func (c *Client) GetRunner(ctx context.Context, runnerID int64) (*RunnerReference, error) {
path := fmt.Sprintf("/%s/%d", runnerEndpoint, runnerID)
@@ -799,6 +849,7 @@ func (c *Client) GetRunner(ctx context.Context, runnerID int64) (*RunnerReferenc
return runnerReference, nil
}
// GetRunnerByName fetches a runner by its name. This can be used to check if a runner exists.
func (c *Client) GetRunnerByName(ctx context.Context, runnerName string) (*RunnerReference, error) {
path := fmt.Sprintf("/%s?agentName=%s", runnerEndpoint, runnerName)
@@ -841,6 +892,7 @@ func (c *Client) GetRunnerByName(ctx context.Context, runnerName string) (*Runne
return &runnerList.RunnerReferences[0], nil
}
// RemoveRunner removes a runner by its ID.
func (c *Client) RemoveRunner(ctx context.Context, runnerID int64) error {
path := fmt.Sprintf("/%s/%d", runnerEndpoint, runnerID)
@@ -881,10 +933,10 @@ func (c *Client) getRunnerRegistrationToken(ctx context.Context) (*registrationT
bearerToken := ""
if c.creds.Token != "" {
bearerToken = fmt.Sprintf("Bearer %v", c.creds.Token)
if c.creds.token != "" {
bearerToken = fmt.Sprintf("Bearer %v", c.creds.token)
} else {
accessToken, err := c.fetchAccessToken(ctx, c.creds.App)
accessToken, err := c.fetchAccessToken(ctx, c.creds.app)
if err != nil {
return nil, fmt.Errorf("failed to fetch access token: %w", err)
}
@@ -981,19 +1033,19 @@ func (c *Client) fetchAccessToken(ctx context.Context, creds *GitHubAppAuth) (*a
return accessToken, nil
}
type ActionsServiceAdminConnection struct {
type actionsServiceAdminConnection struct {
ActionsServiceURL *string `json:"url,omitempty"`
AdminToken *string `json:"token,omitempty"`
}
func (c *Client) getActionsServiceAdminConnection(ctx context.Context, rt *registrationToken) (*ActionsServiceAdminConnection, error) {
func (c *Client) getActionsServiceAdminConnection(ctx context.Context, rt *registrationToken) (*actionsServiceAdminConnection, error) {
path := "/actions/runner-registration"
body := struct {
URL string `json:"url"`
RunnerEvent string `json:"runner_event"`
}{
URL: c.config.ConfigURL.String(),
URL: c.config.configURL.String(),
RunnerEvent: "register",
}
@@ -1059,7 +1111,7 @@ func (c *Client) getActionsServiceAdminConnection(ctx context.Context, rt *regis
}
}
func (c *Client) getActionsServiceAdminConnectionRequest(req *http.Request) (*ActionsServiceAdminConnection, error) {
func (c *Client) getActionsServiceAdminConnectionRequest(req *http.Request) (*actionsServiceAdminConnection, error) {
resp, err := c.do(req)
if err != nil {
return nil, fmt.Errorf("failed to issue the request: %w", err)
@@ -1067,7 +1119,7 @@ func (c *Client) getActionsServiceAdminConnectionRequest(req *http.Request) (*Ac
defer resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
var actionsServiceAdminConnection *ActionsServiceAdminConnection
var actionsServiceAdminConnection *actionsServiceAdminConnection
if err := json.NewDecoder(resp.Body).Decode(&actionsServiceAdminConnection); err != nil {
return nil, &GitHubAPIError{
StatusCode: resp.StatusCode,
@@ -1094,22 +1146,22 @@ func (c *Client) getActionsServiceAdminConnectionRequest(req *http.Request) (*Ac
}
}
func createRegistrationTokenPath(config *GitHubConfig) (string, error) {
switch config.Scope {
case GitHubScopeOrganization:
path := fmt.Sprintf("/orgs/%s/actions/runners/registration-token", config.Organization)
func createRegistrationTokenPath(config *gitHubConfig) (string, error) {
switch config.scope {
case gitHubScopeOrganization:
path := fmt.Sprintf("/orgs/%s/actions/runners/registration-token", config.organization)
return path, nil
case GitHubScopeEnterprise:
path := fmt.Sprintf("/enterprises/%s/actions/runners/registration-token", config.Enterprise)
case gitHubScopeEnterprise:
path := fmt.Sprintf("/enterprises/%s/actions/runners/registration-token", config.enterprise)
return path, nil
case GitHubScopeRepository:
path := fmt.Sprintf("/repos/%s/%s/actions/runners/registration-token", config.Organization, config.Repository)
case gitHubScopeRepository:
path := fmt.Sprintf("/repos/%s/%s/actions/runners/registration-token", config.organization, config.repository)
return path, nil
default:
return "", fmt.Errorf("unknown scope for config url: %s", config.ConfigURL)
return "", fmt.Errorf("unknown scope for config url: %s", config.configURL)
}
}
@@ -1168,7 +1220,7 @@ func (c *Client) updateTokenIfNeeded(ctx context.Context) error {
return nil
}
c.logger.Info("refreshing token", "githubConfigUrl", c.config.ConfigURL.String())
c.logger.Info("refreshing token", "githubConfigUrl", c.config.configURL.String())
rt, err := c.getRunnerRegistrationToken(ctx)
if err != nil {
return fmt.Errorf("failed to get runner registration token on refresh: %w", err)
+106 -106
View File
@@ -72,7 +72,7 @@ func TestNewGitHubAPIRequest(t *testing.T) {
}
for _, scenario := range scenarios {
client, err := NewClient(scenario.configURL, nil)
client, err := newClient(scenario.configURL, nil)
require.NoError(t, err)
req, err := client.newGitHubAPIRequest(ctx, http.MethodGet, scenario.path, nil)
@@ -82,7 +82,7 @@ func TestNewGitHubAPIRequest(t *testing.T) {
})
t.Run("sets user agent header if present", func(t *testing.T) {
client, err := NewClient("http://localhost/my-org", nil)
client, err := newClient("http://localhost/my-org", nil)
require.NoError(t, err)
client.SetUserAgent(testUserAgent)
@@ -94,7 +94,7 @@ func TestNewGitHubAPIRequest(t *testing.T) {
})
t.Run("sets the body we pass", func(t *testing.T) {
client, err := NewClient("http://localhost/my-org", nil)
client, err := newClient("http://localhost/my-org", nil)
require.NoError(t, err)
req, err := client.newGitHubAPIRequest(
@@ -113,14 +113,14 @@ func TestNewGitHubAPIRequest(t *testing.T) {
func TestNewActionsServiceRequest(t *testing.T) {
ctx := context.Background()
defaultCreds := &ActionsAuth{Token: "token"}
defaultCreds := &actionsAuth{token: "token"}
t.Run("manages authentication", func(t *testing.T) {
t.Run("client is brand new", func(t *testing.T) {
token := defaultActionsToken(t)
server := testserver.New(t, nil, testserver.WithActionsToken(token))
client, err := NewClient(server.ConfigURLForOrg("my-org"), defaultCreds)
client, err := newClient(server.ConfigURLForOrg("my-org"), defaultCreds)
require.NoError(t, err)
req, err := client.newActionsServiceRequest(ctx, http.MethodGet, "my-path", nil)
@@ -133,7 +133,7 @@ func TestNewActionsServiceRequest(t *testing.T) {
newToken := defaultActionsToken(t)
server := testserver.New(t, nil, testserver.WithActionsToken(newToken))
client, err := NewClient(server.ConfigURLForOrg("my-org"), defaultCreds)
client, err := newClient(server.ConfigURLForOrg("my-org"), defaultCreds)
require.NoError(t, err)
client.actionsServiceAdminToken = "expiring-token"
client.actionsServiceAdminTokenExpiresAt = time.Now().Add(59 * time.Second)
@@ -159,7 +159,7 @@ func TestNewActionsServiceRequest(t *testing.T) {
testserver.WithActionsToken(newToken),
testserver.WithActionsRegistrationTokenHandler(unauthorizedHandler),
)
client, err := NewClient(server.ConfigURLForOrg("my-org"), defaultCreds)
client, err := newClient(server.ConfigURLForOrg("my-org"), defaultCreds)
require.NoError(t, err)
expiringToken := "expiring-token"
expiresAt := time.Now().Add(59 * time.Second)
@@ -177,7 +177,7 @@ func TestNewActionsServiceRequest(t *testing.T) {
errMessage := `{"message":"test"}`
srv := "http://github.com/my-org"
resp := &ActionsServiceAdminConnection{
resp := &actionsServiceAdminConnection{
AdminToken: &newToken,
ActionsServiceURL: &srv,
}
@@ -195,7 +195,7 @@ func TestNewActionsServiceRequest(t *testing.T) {
_ = json.NewEncoder(w).Encode(resp)
}
server := testserver.New(t, nil, testserver.WithActionsToken("random-token"), testserver.WithActionsToken(newToken), testserver.WithActionsRegistrationTokenHandler(unauthorizedHandler))
client, err := NewClient(server.ConfigURLForOrg("my-org"), defaultCreds)
client, err := newClient(server.ConfigURLForOrg("my-org"), defaultCreds)
require.NoError(t, err)
expiringToken := "expiring-token"
expiresAt := time.Now().Add(59 * time.Second)
@@ -213,7 +213,7 @@ func TestNewActionsServiceRequest(t *testing.T) {
tokenThatShouldNotBeFetched := defaultActionsToken(t)
server := testserver.New(t, nil, testserver.WithActionsToken(tokenThatShouldNotBeFetched))
client, err := NewClient(server.ConfigURLForOrg("my-org"), defaultCreds)
client, err := newClient(server.ConfigURLForOrg("my-org"), defaultCreds)
require.NoError(t, err)
client.actionsServiceAdminToken = "healthy-token"
client.actionsServiceAdminTokenExpiresAt = time.Now().Add(1 * time.Hour)
@@ -228,7 +228,7 @@ func TestNewActionsServiceRequest(t *testing.T) {
t.Run("builds the right URL including api version", func(t *testing.T) {
server := testserver.New(t, nil)
client, err := NewClient(server.ConfigURLForOrg("my-org"), defaultCreds)
client, err := newClient(server.ConfigURLForOrg("my-org"), defaultCreds)
require.NoError(t, err)
req, err := client.newActionsServiceRequest(ctx, http.MethodGet, "/my/path?name=banana", nil)
@@ -247,7 +247,7 @@ func TestNewActionsServiceRequest(t *testing.T) {
t.Run("populates header", func(t *testing.T) {
server := testserver.New(t, nil)
client, err := NewClient(server.ConfigURLForOrg("my-org"), defaultCreds)
client, err := newClient(server.ConfigURLForOrg("my-org"), defaultCreds)
require.NoError(t, err)
client.SetUserAgent(testUserAgent)
@@ -262,8 +262,8 @@ func TestNewActionsServiceRequest(t *testing.T) {
func TestGetRunner(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
t.Run("Get Runner", func(t *testing.T) {
@@ -278,7 +278,7 @@ func TestGetRunner(t *testing.T) {
w.Write(response)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.GetRunner(ctx, runnerID)
@@ -299,7 +299,7 @@ func TestGetRunner(t *testing.T) {
actualRetry++
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth, WithRetryMax(retryMax), WithRetryWaitMax(retryWaitMax))
client, err := newClient(server.configURLForOrg("my-org"), auth, WithRetryMax(retryMax), WithRetryWaitMax(retryWaitMax))
require.NoError(t, err)
_, err = client.GetRunner(ctx, runnerID)
@@ -310,8 +310,8 @@ func TestGetRunner(t *testing.T) {
func TestGetRunnerByName(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
t.Run("Get Runner by Name", func(t *testing.T) {
@@ -327,7 +327,7 @@ func TestGetRunnerByName(t *testing.T) {
w.Write(response)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.GetRunnerByName(ctx, runnerName)
@@ -343,7 +343,7 @@ func TestGetRunnerByName(t *testing.T) {
w.Write(response)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.GetRunnerByName(ctx, runnerName)
@@ -365,7 +365,7 @@ func TestGetRunnerByName(t *testing.T) {
actualRetry++
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth, WithRetryMax(retryMax), WithRetryWaitMax(retryWaitMax))
client, err := newClient(server.configURLForOrg("my-org"), auth, WithRetryMax(retryMax), WithRetryWaitMax(retryWaitMax))
require.NoError(t, err)
_, err = client.GetRunnerByName(ctx, runnerName)
@@ -376,8 +376,8 @@ func TestGetRunnerByName(t *testing.T) {
func TestDeleteRunner(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
t.Run("Delete Runner", func(t *testing.T) {
@@ -387,7 +387,7 @@ func TestDeleteRunner(t *testing.T) {
w.WriteHeader(http.StatusNoContent)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
err = client.RemoveRunner(ctx, runnerID)
@@ -408,7 +408,7 @@ func TestDeleteRunner(t *testing.T) {
actualRetry++
}))
client, err := NewClient(
client, err := newClient(
server.configURLForOrg("my-org"),
auth,
WithRetryMax(retryMax),
@@ -424,8 +424,8 @@ func TestDeleteRunner(t *testing.T) {
func TestGetRunnerGroupByName(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
t.Run("Get RunnerGroup by Name", func(t *testing.T) {
@@ -441,7 +441,7 @@ func TestGetRunnerGroupByName(t *testing.T) {
w.Write(response)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.GetRunnerGroupByName(ctx, runnerGroupName)
@@ -457,7 +457,7 @@ func TestGetRunnerGroupByName(t *testing.T) {
w.Write(response)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.GetRunnerGroupByName(ctx, runnerGroupName)
@@ -468,8 +468,8 @@ func TestGetRunnerGroupByName(t *testing.T) {
func TestGetRunnerScaleSet(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
scaleSetName := "ScaleSet"
@@ -482,7 +482,7 @@ func TestGetRunnerScaleSet(t *testing.T) {
w.Write(runnerScaleSetsResp)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.GetRunnerScaleSet(ctx, 1, scaleSetName)
@@ -498,7 +498,7 @@ func TestGetRunnerScaleSet(t *testing.T) {
url = *r.URL
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.GetRunnerScaleSet(ctx, 1, scaleSetName)
@@ -515,7 +515,7 @@ func TestGetRunnerScaleSet(t *testing.T) {
w.WriteHeader(http.StatusNotFound)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.GetRunnerScaleSet(ctx, 1, scaleSetName)
@@ -528,7 +528,7 @@ func TestGetRunnerScaleSet(t *testing.T) {
w.Header().Set("Content-Type", "text/plain")
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.GetRunnerScaleSet(ctx, 1, scaleSetName)
@@ -545,7 +545,7 @@ func TestGetRunnerScaleSet(t *testing.T) {
retryMax := 1
retryWaitMax := 1 * time.Microsecond
client, err := NewClient(
client, err := newClient(
server.configURLForOrg("my-org"),
auth,
WithRetryMax(retryMax),
@@ -566,7 +566,7 @@ func TestGetRunnerScaleSet(t *testing.T) {
w.Write(runnerScaleSetsResp)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.GetRunnerScaleSet(ctx, 1, scaleSetName)
@@ -587,7 +587,7 @@ func TestGetRunnerScaleSet(t *testing.T) {
w.Write(runnerScaleSetsResp)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.GetRunnerScaleSet(ctx, 1, scaleSetName)
@@ -598,8 +598,8 @@ func TestGetRunnerScaleSet(t *testing.T) {
func TestGetRunnerScaleSetByID(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
scaleSetCreationDateTime := time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)
@@ -613,7 +613,7 @@ func TestGetRunnerScaleSetByID(t *testing.T) {
w.Write(rsl)
}))
client, err := NewClient(sservere.configURLForOrg("my-org"), auth)
client, err := newClient(sservere.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.GetRunnerScaleSetByID(ctx, runnerScaleSet.ID)
@@ -631,7 +631,7 @@ func TestGetRunnerScaleSetByID(t *testing.T) {
url = *r.URL
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.GetRunnerScaleSetByID(ctx, runnerScaleSet.ID)
@@ -647,7 +647,7 @@ func TestGetRunnerScaleSetByID(t *testing.T) {
w.WriteHeader(http.StatusNotFound)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.GetRunnerScaleSetByID(ctx, runnerScaleSet.ID)
@@ -660,7 +660,7 @@ func TestGetRunnerScaleSetByID(t *testing.T) {
w.Header().Set("Content-Type", "text/plain")
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.GetRunnerScaleSetByID(ctx, runnerScaleSet.ID)
@@ -676,7 +676,7 @@ func TestGetRunnerScaleSetByID(t *testing.T) {
retryMax := 1
retryWaitMax := 1 * time.Microsecond
client, err := NewClient(
client, err := newClient(
server.configURLForOrg("my-org"),
auth,
WithRetryMax(retryMax),
@@ -698,7 +698,7 @@ func TestGetRunnerScaleSetByID(t *testing.T) {
w.Write(rsl)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.GetRunnerScaleSetByID(ctx, runnerScaleSet.ID)
@@ -709,8 +709,8 @@ func TestGetRunnerScaleSetByID(t *testing.T) {
func TestCreateRunnerScaleSet(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
scaleSetCreationDateTime := time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)
@@ -724,7 +724,7 @@ func TestCreateRunnerScaleSet(t *testing.T) {
w.Write(rsl)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.CreateRunnerScaleSet(ctx, &runnerScaleSet)
@@ -741,7 +741,7 @@ func TestCreateRunnerScaleSet(t *testing.T) {
url = *r.URL
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.CreateRunnerScaleSet(ctx, &runnerScaleSet)
@@ -758,7 +758,7 @@ func TestCreateRunnerScaleSet(t *testing.T) {
w.Header().Set("Content-Type", "text/plain")
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.CreateRunnerScaleSet(ctx, &runnerScaleSet)
@@ -777,7 +777,7 @@ func TestCreateRunnerScaleSet(t *testing.T) {
retryMax := 1
retryWaitMax := 1 * time.Microsecond
client, err := NewClient(
client, err := newClient(
server.configURLForOrg("my-org"),
auth,
WithRetryMax(retryMax),
@@ -794,8 +794,8 @@ func TestCreateRunnerScaleSet(t *testing.T) {
func TestUpdateRunnerScaleSet(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
scaleSetCreationDateTime := time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)
@@ -809,7 +809,7 @@ func TestUpdateRunnerScaleSet(t *testing.T) {
w.Write(rsl)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.UpdateRunnerScaleSet(ctx, 1, &RunnerScaleSet{RunnerGroupID: 1})
@@ -829,7 +829,7 @@ func TestUpdateRunnerScaleSet(t *testing.T) {
w.Write(rsl)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.UpdateRunnerScaleSet(ctx, 1, &runnerScaleSet)
@@ -839,8 +839,8 @@ func TestUpdateRunnerScaleSet(t *testing.T) {
func TestDeleteRunnerScaleSet(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
t.Run("Delete runner scale set", func(t *testing.T) {
@@ -850,7 +850,7 @@ func TestDeleteRunnerScaleSet(t *testing.T) {
w.WriteHeader(http.StatusNoContent)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
err = client.DeleteRunnerScaleSet(ctx, 10)
@@ -865,7 +865,7 @@ func TestDeleteRunnerScaleSet(t *testing.T) {
w.Write([]byte(`{"message": "test error"}`))
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
err = client.DeleteRunnerScaleSet(ctx, 10)
@@ -875,8 +875,8 @@ func TestDeleteRunnerScaleSet(t *testing.T) {
func TestCreateMessageSession(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
t.Run("CreateMessageSession unmarshals correctly", func(t *testing.T) {
@@ -911,7 +911,7 @@ func TestCreateMessageSession(t *testing.T) {
w.Write(resp)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.CreateMessageSession(ctx, runnerScaleSet.ID, owner)
@@ -945,7 +945,7 @@ func TestCreateMessageSession(t *testing.T) {
w.Write(resp)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.CreateMessageSession(ctx, runnerScaleSet.ID, owner)
@@ -982,7 +982,7 @@ func TestCreateMessageSession(t *testing.T) {
wantRetries := retryMax + 1
client, err := NewClient(
client, err := newClient(
server.configURLForOrg("my-org"),
auth,
WithRetryMax(retryMax),
@@ -998,8 +998,8 @@ func TestCreateMessageSession(t *testing.T) {
func TestDeleteMessageSession(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
t.Run("DeleteMessageSession call is retried the correct amount of times", func(t *testing.T) {
@@ -1021,7 +1021,7 @@ func TestDeleteMessageSession(t *testing.T) {
wantRetries := retryMax + 1
client, err := NewClient(
client, err := newClient(
server.configURLForOrg("my-org"),
auth,
WithRetryMax(retryMax),
@@ -1038,8 +1038,8 @@ func TestDeleteMessageSession(t *testing.T) {
}
func TestRefreshMessageSession(t *testing.T) {
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
t.Run("RefreshMessageSession call is retried the correct amount of times", func(t *testing.T) {
@@ -1061,7 +1061,7 @@ func TestRefreshMessageSession(t *testing.T) {
wantRetries := retryMax + 1
client, err := NewClient(
client, err := newClient(
server.configURLForOrg("my-org"),
auth,
WithRetryMax(retryMax),
@@ -1079,8 +1079,8 @@ func TestRefreshMessageSession(t *testing.T) {
func TestGetMessage(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
@@ -1096,7 +1096,7 @@ func TestGetMessage(t *testing.T) {
w.Write(response)
}))
client, err := NewClient(s.configURLForOrg("my-org"), auth)
client, err := newClient(s.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.GetMessage(ctx, s.URL, token, 0, 10)
@@ -1113,7 +1113,7 @@ func TestGetMessage(t *testing.T) {
w.Write(response)
}))
client, err := NewClient(s.configURLForOrg("my-org"), auth)
client, err := newClient(s.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.GetMessage(ctx, s.URL, token, 1, 10)
@@ -1132,7 +1132,7 @@ func TestGetMessage(t *testing.T) {
actualRetry++
}))
client, err := NewClient(
client, err := newClient(
server.configURLForOrg("my-org"),
auth,
WithRetryMax(retryMax),
@@ -1150,7 +1150,7 @@ func TestGetMessage(t *testing.T) {
w.WriteHeader(http.StatusUnauthorized)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.GetMessage(ctx, server.URL, token, 0, 10)
@@ -1169,7 +1169,7 @@ func TestGetMessage(t *testing.T) {
w.WriteHeader(http.StatusNotFound)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.GetMessage(ctx, server.URL, token, 0, 10)
@@ -1183,7 +1183,7 @@ func TestGetMessage(t *testing.T) {
w.Header().Set("Content-Type", "text/plain")
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.GetMessage(ctx, server.URL, token, 0, 10)
@@ -1201,7 +1201,7 @@ func TestGetMessage(t *testing.T) {
w.Header().Set("Content-Type", "text/plain")
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
_, err = client.GetMessage(ctx, server.URL, token, 0, 0)
@@ -1214,8 +1214,8 @@ func TestGetMessage(t *testing.T) {
func TestDeleteMessage(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
@@ -1229,7 +1229,7 @@ func TestDeleteMessage(t *testing.T) {
w.WriteHeader(http.StatusNoContent)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
err = client.DeleteMessage(ctx, server.URL, token, runnerScaleSetMessage.MessageID)
@@ -1241,7 +1241,7 @@ func TestDeleteMessage(t *testing.T) {
w.WriteHeader(http.StatusUnauthorized)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
err = client.DeleteMessage(ctx, server.URL, token, 0)
@@ -1256,7 +1256,7 @@ func TestDeleteMessage(t *testing.T) {
w.Header().Set("Content-Type", "text/plain")
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
err = client.DeleteMessage(ctx, server.URL, token, runnerScaleSetMessage.MessageID)
@@ -1274,7 +1274,7 @@ func TestDeleteMessage(t *testing.T) {
}))
retryMax := 1
client, err := NewClient(
client, err := newClient(
server.configURLForOrg("my-org"),
auth,
WithRetryMax(retryMax),
@@ -1296,7 +1296,7 @@ func TestDeleteMessage(t *testing.T) {
w.Write(rsl)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
err = client.DeleteMessage(ctx, server.URL, token, runnerScaleSetMessage.MessageID+1)
@@ -1319,7 +1319,7 @@ func TestClientProxy(t *testing.T) {
return proxyConfig.ProxyFunc()(req.URL)
}
c, err := NewClient("http://github.com/org/repo", nil, WithProxy(proxyFunc))
c, err := newClient("http://github.com/org/repo", nil, WithProxy(proxyFunc))
require.NoError(t, err)
req, err := http.NewRequest(http.MethodGet, "http://example.com", nil)
@@ -1333,8 +1333,8 @@ func TestClientProxy(t *testing.T) {
func TestGenerateJitRunnerConfig(t *testing.T) {
ctx := context.Background()
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
t.Run("Get JIT Config for Runner", func(t *testing.T) {
@@ -1346,7 +1346,7 @@ func TestGenerateJitRunnerConfig(t *testing.T) {
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Write(response)
}))
client, err := NewClient(server.configURLForOrg("my-org"), auth)
client, err := newClient(server.configURLForOrg("my-org"), auth)
require.NoError(t, err)
got, err := client.GenerateJitRunnerConfig(ctx, runnerSettings, 1)
@@ -1366,7 +1366,7 @@ func TestGenerateJitRunnerConfig(t *testing.T) {
actualRetry++
}))
client, err := NewClient(
client, err := newClient(
server.configURLForOrg("my-org"),
auth,
WithRetryMax(1),
@@ -1387,7 +1387,7 @@ func TestClient_Do(t *testing.T) {
}))
defer server.Close()
client, err := NewClient("https://localhost/org/repo", &ActionsAuth{Token: "token"})
client, err := newClient("https://localhost/org/repo", &actionsAuth{token: "token"})
require.NoError(t, err)
req, err := http.NewRequest("GET", server.URL, nil)
@@ -1413,7 +1413,7 @@ func TestClient_Do(t *testing.T) {
}))
defer server.Close()
client, err := NewClient("https://localhost/org/repo", &ActionsAuth{Token: "token"})
client, err := newClient("https://localhost/org/repo", &actionsAuth{token: "token"})
require.NoError(t, err)
req, err := http.NewRequest("GET", server.URL, nil)
@@ -1543,10 +1543,10 @@ func TestServerWithSelfSignedCertificates(t *testing.T) {
u = server.URL
configURL := server.URL + "/my-org"
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
client, err := NewClient(configURL, auth)
client, err := newClient(configURL, auth)
require.NoError(t, err)
require.NotNil(t, client)
@@ -1574,8 +1574,8 @@ func TestServerWithSelfSignedCertificates(t *testing.T) {
u = server.URL
configURL := server.URL + "/my-org"
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
cert, err := os.ReadFile(filepath.Join("testdata", "rootCA.crt"))
@@ -1584,7 +1584,7 @@ func TestServerWithSelfSignedCertificates(t *testing.T) {
pool := x509.NewCertPool()
require.True(t, pool.AppendCertsFromPEM(cert))
client, err := NewClient(
client, err := newClient(
configURL,
auth,
WithRootCAs(pool),
@@ -1606,8 +1606,8 @@ func TestServerWithSelfSignedCertificates(t *testing.T) {
u = server.URL
configURL := server.URL + "/my-org"
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
cert, err := os.ReadFile(filepath.Join("testdata", "intermediate.crt"))
@@ -1616,7 +1616,7 @@ func TestServerWithSelfSignedCertificates(t *testing.T) {
pool := x509.NewCertPool()
require.True(t, pool.AppendCertsFromPEM(cert))
client, err := NewClient(
client, err := newClient(
configURL,
auth,
WithRootCAs(pool),
@@ -1633,11 +1633,11 @@ func TestServerWithSelfSignedCertificates(t *testing.T) {
server := startNewTLSTestServer(t, certPath, keyPath, http.HandlerFunc(h))
configURL := server.URL + "/my-org"
auth := &ActionsAuth{
Token: "token",
auth := &actionsAuth{
token: "token",
}
client, err := NewClient(configURL, auth, WithoutTLSVerify())
client, err := newClient(configURL, auth, WithoutTLSVerify())
require.NoError(t, err)
assert.NotNil(t, client)
})
+29 -29
View File
@@ -9,27 +9,27 @@ import (
var ErrInvalidGitHubConfigURL = fmt.Errorf("invalid config URL, should point to an enterprise, org, or repository")
type GitHubScope int
type gitHubScope int
const (
GitHubScopeUnknown GitHubScope = iota
GitHubScopeEnterprise
GitHubScopeOrganization
GitHubScopeRepository
gitHubScopeUnknown gitHubScope = iota
gitHubScopeEnterprise
gitHubScopeOrganization
gitHubScopeRepository
)
type GitHubConfig struct {
ConfigURL *url.URL
Scope GitHubScope
type gitHubConfig struct {
configURL *url.URL
scope gitHubScope
Enterprise string
Organization string
Repository string
enterprise string
organization string
repository string
IsHosted bool
isHosted bool
}
func ParseGitHubConfigFromURL(in string) (*GitHubConfig, error) {
func parseGitHubConfigFromURL(in string) (*gitHubConfig, error) {
u, err := url.Parse(strings.Trim(in, "/"))
if err != nil {
return nil, fmt.Errorf("failed to parse URL: %w", err)
@@ -37,9 +37,9 @@ func ParseGitHubConfigFromURL(in string) (*GitHubConfig, error) {
isHosted := isHostedGitHubURL(u)
configURL := &GitHubConfig{
ConfigURL: u,
IsHosted: isHosted,
configURL := &gitHubConfig{
configURL: u,
isHosted: isHosted,
}
invalidURLError := fmt.Errorf("%q: %w", u.String(), ErrInvalidGitHubConfigURL)
@@ -52,19 +52,19 @@ func ParseGitHubConfigFromURL(in string) (*GitHubConfig, error) {
return nil, invalidURLError
}
configURL.Scope = GitHubScopeOrganization
configURL.Organization = pathParts[0]
configURL.scope = gitHubScopeOrganization
configURL.organization = pathParts[0]
case 2: // Repository or enterprise
if strings.ToLower(pathParts[0]) == "enterprises" {
configURL.Scope = GitHubScopeEnterprise
configURL.Enterprise = pathParts[1]
configURL.scope = gitHubScopeEnterprise
configURL.enterprise = pathParts[1]
break
}
configURL.Scope = GitHubScopeRepository
configURL.Organization = pathParts[0]
configURL.Repository = pathParts[1]
configURL.scope = gitHubScopeRepository
configURL.organization = pathParts[0]
configURL.repository = pathParts[1]
default:
return nil, invalidURLError
}
@@ -72,20 +72,20 @@ func ParseGitHubConfigFromURL(in string) (*GitHubConfig, error) {
return configURL, nil
}
func (c *GitHubConfig) GitHubAPIURL(path string) *url.URL {
func (c *gitHubConfig) gitHubAPIURL(path string) *url.URL {
result := &url.URL{
Scheme: c.ConfigURL.Scheme,
Host: c.ConfigURL.Host, // default for Enterprise mode
Scheme: c.configURL.Scheme,
Host: c.configURL.Host, // default for Enterprise mode
Path: "/api/v3", // default for Enterprise mode
}
isHosted := isHostedGitHubURL(c.ConfigURL)
isHosted := isHostedGitHubURL(c.configURL)
if isHosted {
result.Host = fmt.Sprintf("api.%s", c.ConfigURL.Host)
result.Host = fmt.Sprintf("api.%s", c.configURL.Host)
result.Path = ""
if strings.EqualFold("www.github.com", c.ConfigURL.Host) {
if strings.EqualFold("www.github.com", c.configURL.Host) {
// re-routing www.github.com to api.github.com
result.Host = "api.github.com"
}
+82 -82
View File
@@ -15,116 +15,116 @@ func TestGitHubConfig(t *testing.T) {
t.Run("when given a valid URL", func(t *testing.T) {
tests := []struct {
configURL string
expected *GitHubConfig
expected *gitHubConfig
}{
{
configURL: "https://github.com/org/repo",
expected: &GitHubConfig{
Scope: GitHubScopeRepository,
Enterprise: "",
Organization: "org",
Repository: "repo",
IsHosted: true,
expected: &gitHubConfig{
scope: gitHubScopeRepository,
enterprise: "",
organization: "org",
repository: "repo",
isHosted: true,
},
},
{
configURL: "https://github.com/org/repo/",
expected: &GitHubConfig{
Scope: GitHubScopeRepository,
Enterprise: "",
Organization: "org",
Repository: "repo",
IsHosted: true,
expected: &gitHubConfig{
scope: gitHubScopeRepository,
enterprise: "",
organization: "org",
repository: "repo",
isHosted: true,
},
},
{
configURL: "https://github.com/org",
expected: &GitHubConfig{
Scope: GitHubScopeOrganization,
Enterprise: "",
Organization: "org",
Repository: "",
IsHosted: true,
expected: &gitHubConfig{
scope: gitHubScopeOrganization,
enterprise: "",
organization: "org",
repository: "",
isHosted: true,
},
},
{
configURL: "https://github.com/enterprises/my-enterprise",
expected: &GitHubConfig{
Scope: GitHubScopeEnterprise,
Enterprise: "my-enterprise",
Organization: "",
Repository: "",
IsHosted: true,
expected: &gitHubConfig{
scope: gitHubScopeEnterprise,
enterprise: "my-enterprise",
organization: "",
repository: "",
isHosted: true,
},
},
{
configURL: "https://github.com/enterprises/my-enterprise/",
expected: &GitHubConfig{
Scope: GitHubScopeEnterprise,
Enterprise: "my-enterprise",
Organization: "",
Repository: "",
IsHosted: true,
expected: &gitHubConfig{
scope: gitHubScopeEnterprise,
enterprise: "my-enterprise",
organization: "",
repository: "",
isHosted: true,
},
},
{
configURL: "https://www.github.com/org",
expected: &GitHubConfig{
Scope: GitHubScopeOrganization,
Enterprise: "",
Organization: "org",
Repository: "",
IsHosted: true,
expected: &gitHubConfig{
scope: gitHubScopeOrganization,
enterprise: "",
organization: "org",
repository: "",
isHosted: true,
},
},
{
configURL: "https://www.github.com/org/",
expected: &GitHubConfig{
Scope: GitHubScopeOrganization,
Enterprise: "",
Organization: "org",
Repository: "",
IsHosted: true,
expected: &gitHubConfig{
scope: gitHubScopeOrganization,
enterprise: "",
organization: "org",
repository: "",
isHosted: true,
},
},
{
configURL: "https://github.localhost/org",
expected: &GitHubConfig{
Scope: GitHubScopeOrganization,
Enterprise: "",
Organization: "org",
Repository: "",
IsHosted: true,
expected: &gitHubConfig{
scope: gitHubScopeOrganization,
enterprise: "",
organization: "org",
repository: "",
isHosted: true,
},
},
{
configURL: "https://my-ghes.com/org",
expected: &GitHubConfig{
Scope: GitHubScopeOrganization,
Enterprise: "",
Organization: "org",
Repository: "",
IsHosted: false,
expected: &gitHubConfig{
scope: gitHubScopeOrganization,
enterprise: "",
organization: "org",
repository: "",
isHosted: false,
},
},
{
configURL: "https://my-ghes.com/org/",
expected: &GitHubConfig{
Scope: GitHubScopeOrganization,
Enterprise: "",
Organization: "org",
Repository: "",
IsHosted: false,
expected: &gitHubConfig{
scope: gitHubScopeOrganization,
enterprise: "",
organization: "org",
repository: "",
isHosted: false,
},
},
{
configURL: "https://my-ghes.ghe.com/org/",
expected: &GitHubConfig{
Scope: GitHubScopeOrganization,
Enterprise: "",
Organization: "org",
Repository: "",
IsHosted: true,
expected: &gitHubConfig{
scope: gitHubScopeOrganization,
enterprise: "",
organization: "org",
repository: "",
isHosted: true,
},
},
}
@@ -133,9 +133,9 @@ func TestGitHubConfig(t *testing.T) {
t.Run(test.configURL, func(t *testing.T) {
parsedURL, err := url.Parse(strings.Trim(test.configURL, "/"))
require.NoError(t, err)
test.expected.ConfigURL = parsedURL
test.expected.configURL = parsedURL
cfg, err := ParseGitHubConfigFromURL(test.configURL)
cfg, err := parseGitHubConfigFromURL(test.configURL)
require.NoError(t, err)
assert.Equal(t, test.expected, cfg)
})
@@ -150,7 +150,7 @@ func TestGitHubConfig(t *testing.T) {
}
for _, u := range invalidURLs {
_, err := ParseGitHubConfigFromURL(u)
_, err := parseGitHubConfigFromURL(u)
require.Error(t, err)
assert.True(t, errors.Is(err, ErrInvalidGitHubConfigURL))
}
@@ -159,37 +159,37 @@ func TestGitHubConfig(t *testing.T) {
func TestGitHubConfig_GitHubAPIURL(t *testing.T) {
t.Run("when hosted", func(t *testing.T) {
config, err := ParseGitHubConfigFromURL("https://github.com/org/repo")
config, err := parseGitHubConfigFromURL("https://github.com/org/repo")
require.NoError(t, err)
assert.True(t, config.IsHosted)
assert.True(t, config.isHosted)
result := config.GitHubAPIURL("/some/path")
result := config.gitHubAPIURL("/some/path")
assert.Equal(t, "https://api.github.com/some/path", result.String())
})
t.Run("when hosted with ghe.com", func(t *testing.T) {
config, err := ParseGitHubConfigFromURL("https://github.ghe.com/org/repo")
config, err := parseGitHubConfigFromURL("https://github.ghe.com/org/repo")
require.NoError(t, err)
assert.True(t, config.IsHosted)
assert.True(t, config.isHosted)
result := config.GitHubAPIURL("/some/path")
result := config.gitHubAPIURL("/some/path")
assert.Equal(t, "https://api.github.ghe.com/some/path", result.String())
})
t.Run("when not hosted", func(t *testing.T) {
config, err := ParseGitHubConfigFromURL("https://ghes.com/org/repo")
config, err := parseGitHubConfigFromURL("https://ghes.com/org/repo")
require.NoError(t, err)
assert.False(t, config.IsHosted)
assert.False(t, config.isHosted)
result := config.GitHubAPIURL("/some/path")
result := config.gitHubAPIURL("/some/path")
assert.Equal(t, "https://ghes.com/api/v3/some/path", result.String())
})
t.Run("when not hosted with ghe.com", func(t *testing.T) {
os.Setenv("GITHUB_ACTIONS_FORCE_GHES", "1")
defer os.Unsetenv("GITHUB_ACTIONS_FORCE_GHES")
config, err := ParseGitHubConfigFromURL("https://test.ghe.com/org/repo")
config, err := parseGitHubConfigFromURL("https://test.ghe.com/org/repo")
require.NoError(t, err)
assert.False(t, config.IsHosted)
assert.False(t, config.isHosted)
result := config.GitHubAPIURL("/some/path")
result := config.gitHubAPIURL("/some/path")
assert.Equal(t, "https://test.ghe.com/api/v3/some/path", result.String())
})
}
+11 -4
View File
@@ -20,6 +20,7 @@ const (
sessionCreationMaxRetries = 10
)
// Config holds the configuration for the Listener.
type Config struct {
ScaleSetID uint64
MinRunners uint32
@@ -33,6 +34,7 @@ func (c *Config) defaults() {
}
}
// Validate returns an error if the configuration is invalid.
func (c *Config) Validate() error {
c.defaults()
@@ -45,6 +47,8 @@ func (c *Config) Validate() error {
return nil
}
// Listener listens for messages from the scaleset service and handles them. It automatically handles session
// creation/deletion/refreshing and message polling and acking.
type Listener struct {
// The main client responsible for communicating with the scaleset service
client *scaleset.Client
@@ -68,6 +72,7 @@ func (l *Listener) SetMaxRunners(count uint32) {
l.maxRunners.Store(count)
}
// New creates a new Listener with the given configuration.
func New(client *scaleset.Client, config Config) (*Listener, error) {
if client == nil {
return nil, errors.New("client is required")
@@ -94,13 +99,15 @@ func New(client *scaleset.Client, config Config) (*Listener, error) {
return listener, nil
}
// Scaler defines the interface for handling scale set messages.
type Scaler interface {
HandleJobStarted(ctx context.Context, jobInfo *scaleset.JobStarted) error
HandleJobCompleted(ctx context.Context, jobInfo *scaleset.JobCompleted) error
HandleDesiredRunnerCount(ctx context.Context, count uint64) (int, error)
}
func (l *Listener) Run(ctx context.Context, handler Scaler) error {
// Run starts the listener and processes messages using the provided scaler.
func (l *Listener) Run(ctx context.Context, scaler Scaler) error {
l.logger.Info("Creating message session")
if err := l.createSession(ctx); err != nil {
return fmt.Errorf("failed to create session: %w", err)
@@ -120,7 +127,7 @@ func (l *Listener) Run(ctx context.Context, handler Scaler) error {
l.logger.Info("Message session created; listening for messages", "sessionID", l.session.SessionID)
// Handle initial statistics
if _, err := handler.HandleDesiredRunnerCount(ctx, l.session.Statistics.TotalAssignedJobs); err != nil {
if _, err := scaler.HandleDesiredRunnerCount(ctx, l.session.Statistics.TotalAssignedJobs); err != nil {
return fmt.Errorf("handling initial message failed: %w", err)
}
@@ -137,7 +144,7 @@ func (l *Listener) Run(ctx context.Context, handler Scaler) error {
}
if msg == nil {
_, err := handler.HandleDesiredRunnerCount(ctx, 0)
_, err := scaler.HandleDesiredRunnerCount(ctx, 0)
if err != nil {
return fmt.Errorf("handling nil message failed: %w", err)
}
@@ -146,7 +153,7 @@ func (l *Listener) Run(ctx context.Context, handler Scaler) error {
}
// Remove cancellation from the context to avoid cancelling the message handling.
if err := l.handleMessage(context.WithoutCancel(ctx), handler, msg); err != nil {
if err := l.handleMessage(context.WithoutCancel(ctx), scaler, msg); err != nil {
return fmt.Errorf("failed to handle message: %w", err)
}
}