Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ linters:
- "all"
- "-QF1008" # allow embedded field in selector
unparam:
check-exported: true
check-exported: true
usetesting:
context-background: true
context-todo: true
Expand Down Expand Up @@ -275,13 +275,6 @@ linters:
- ErrorResponse.DocumentationURL # TODO: Common
- GetCodeownersErrorsOptions.Ref # TODO: Repositories
- GistListOptions.Since # TODO: Gists
- HostedRunnerRequest.EnableStaticIP # TODO: Actions
- HostedRunnerRequest.Image # TODO: Actions
- HostedRunnerRequest.ImageVersion # TODO: Actions
- HostedRunnerRequest.MaximumRunners # TODO: Actions
- HostedRunnerRequest.Name # TODO: Actions
- HostedRunnerRequest.RunnerGroupID # TODO: Actions
- HostedRunnerRequest.Size # TODO: Actions
- IssueEvent.Action # TODO: Issues
- IssueListByRepoOptions.Assignee # TODO: Issues
- IssueListByRepoOptions.Assignee # TODO: Issues
Expand Down
84 changes: 36 additions & 48 deletions github/actions_hosted_runners.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,48 +83,55 @@ func (s *ActionsService) ListHostedRunners(ctx context.Context, org string, opts
}

// HostedRunnerImage represents the image of GitHub-hosted runners.
// To list all available images, use GET /actions/hosted-runners/images/github-owned or GET /actions/hosted-runners/images/partner.
type HostedRunnerImage struct {
ID string `json:"id"`
Source string `json:"source"`
Version string `json:"version"`
// The unique identifier of the runner image.
ID string `json:"id"`
// The source of the runner image. Can be one of: github, partner, custom.
Source string `json:"source"`
// The version of the runner image to deploy. This is relevant only for runners using custom images.
Version *string `json:"version,omitempty"`
}

// HostedRunnerRequest specifies body parameters to Hosted Runner configuration.
type HostedRunnerRequest struct {
Name string `json:"name,omitempty"`
Image HostedRunnerImage `json:"image,omitempty"`
RunnerGroupID int64 `json:"runner_group_id,omitempty"`
Size string `json:"size,omitempty"`
MaximumRunners int64 `json:"maximum_runners,omitempty"`
EnableStaticIP bool `json:"enable_static_ip,omitempty"`
ImageVersion string `json:"image_version,omitempty"`
// CreateHostedRunnerRequest specifies body parameters to create Hosted Runner configuration.
type CreateHostedRunnerRequest struct {
Name string `json:"name"`
Image HostedRunnerImage `json:"image"`
Size string `json:"size"`
RunnerGroupID int64 `json:"runner_group_id"`
MaximumRunners *int64 `json:"maximum_runners,omitempty"`
EnableStaticIP *bool `json:"enable_static_ip,omitempty"`
ImageGen *bool `json:"image_gen,omitempty"`
}

// validateCreateHostedRunnerRequest validates the provided HostedRunnerRequest to ensure
// UpdateHostedRunnerRequest specifies body parameters to update Hosted Runner configuration.
type UpdateHostedRunnerRequest struct {
Name *string `json:"name,omitempty"`
RunnerGroupID *int64 `json:"runner_group_id,omitempty"`
MaximumRunners *int64 `json:"maximum_runners,omitempty"`
EnableStaticIP *bool `json:"enable_static_ip,omitempty"`
Size *string `json:"size,omitempty"`
ImageID *string `json:"image_id,omitempty"`
ImageVersion *string `json:"image_version,omitempty"`
}

// validateCreateHostedRunnerRequest validates the provided CreateHostedRunnerRequest to ensure
// that all required fields are properly set and that no invalid fields are present for hosted runner create request.
//
// If any of these conditions are violated, an appropriate error message is returned.
// Otherwise, nil is returned, indicating the request is valid.
func validateCreateHostedRunnerRequest(request *HostedRunnerRequest) error {
if request == nil {
return errors.New("request is required for creating a hosted runner")
}
if request.Size == "" {
return errors.New("size is required for creating a hosted runner")
func validateCreateHostedRunnerRequest(request *CreateHostedRunnerRequest) error {
if request.Name == "" {
return errors.New("name is required for creating a hosted runner")
}
if request.Image == (HostedRunnerImage{}) {
return errors.New("image is required for creating a hosted runner")
}
if request.Name == "" {
return errors.New("name is required for creating a hosted runner")
if request.Size == "" {
return errors.New("size is required for creating a hosted runner")
}
if request.RunnerGroupID == 0 {
return errors.New("runner group ID is required for creating a hosted runner")
}
if request.ImageVersion != "" {
return errors.New("imageVersion should not be set directly; use the Image struct to specify image details")
}
return nil
}

Expand All @@ -133,8 +140,8 @@ func validateCreateHostedRunnerRequest(request *HostedRunnerRequest) error {
// GitHub API docs: https://docs.github.com/rest/actions/hosted-runners#create-a-github-hosted-runner-for-an-organization
//
//meta:operation POST /orgs/{org}/actions/hosted-runners
func (s *ActionsService) CreateHostedRunner(ctx context.Context, org string, request *HostedRunnerRequest) (*HostedRunner, *Response, error) {
if err := validateCreateHostedRunnerRequest(request); err != nil {
func (s *ActionsService) CreateHostedRunner(ctx context.Context, org string, request CreateHostedRunnerRequest) (*HostedRunner, *Response, error) {
if err := validateCreateHostedRunnerRequest(&request); err != nil {
return nil, nil, fmt.Errorf("validation failed: %w", err)
}

Expand Down Expand Up @@ -317,33 +324,14 @@ func (s *ActionsService) GetHostedRunner(ctx context.Context, org string, runner
return hostedRunner, resp, nil
}

// validateUpdateHostedRunnerRequest validates the provided HostedRunnerRequest to ensure
// that no disallowed updates are made for a hosted runner update request.
//
// If any of these conditions are violated, an appropriate error message is returned.
// Otherwise, nil is returned, indicating the request is valid for an update.
func validateUpdateHostedRunnerRequest(request *HostedRunnerRequest) error {
if request.Size != "" {
return errors.New("size cannot be updated, API does not support updating size")
}
if request.Image != (HostedRunnerImage{}) {
return errors.New("image struct should not be set directly; use the ImageVersion to specify version details")
}
return nil
}

// UpdateHostedRunner updates a GitHub-hosted runner for an organization.
//
// GitHub API docs: https://docs.github.com/rest/actions/hosted-runners#update-a-github-hosted-runner-for-an-organization
//
//meta:operation PATCH /orgs/{org}/actions/hosted-runners/{hosted_runner_id}
func (s *ActionsService) UpdateHostedRunner(ctx context.Context, org string, runnerID int64, updateReq HostedRunnerRequest) (*HostedRunner, *Response, error) {
if err := validateUpdateHostedRunnerRequest(&updateReq); err != nil {
return nil, nil, fmt.Errorf("validation failed: %w", err)
}

func (s *ActionsService) UpdateHostedRunner(ctx context.Context, org string, runnerID int64, request UpdateHostedRunnerRequest) (*HostedRunner, *Response, error) {
u := fmt.Sprintf("orgs/%v/actions/hosted-runners/%v", org, runnerID)
req, err := s.client.NewRequest("PATCH", u, updateReq)
req, err := s.client.NewRequest("PATCH", u, request)
if err != nil {
return nil, nil, err
}
Expand Down
100 changes: 19 additions & 81 deletions github/actions_hosted_runners_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,17 +192,18 @@ func TestActionsService_CreateHostedRunner(t *testing.T) {

ctx := t.Context()

validReq := &HostedRunnerRequest{
validReq := CreateHostedRunnerRequest{
Name: "My Hosted runner",
Image: HostedRunnerImage{
ID: "ubuntu-latest",
Source: "github",
Version: "latest",
Version: Ptr("latest"),
},
RunnerGroupID: 1,
Size: "4-core",
MaximumRunners: 50,
EnableStaticIP: false,
MaximumRunners: Ptr(int64(50)),
EnableStaticIP: Ptr(false),
ImageGen: Ptr(true),
}
hostedRunner, _, err := client.Actions.CreateHostedRunner(ctx, "o", validReq)
if err != nil {
Expand Down Expand Up @@ -245,30 +246,25 @@ func TestActionsService_CreateHostedRunner(t *testing.T) {
// Validation tests
testCases := []struct {
name string
request *HostedRunnerRequest
request CreateHostedRunnerRequest
expectedError string
}{
{
name: "Missing Request",
request: nil,
expectedError: "validation failed: request is required for creating a hosted runner",
},
{
name: "Missing Size",
request: &HostedRunnerRequest{
request: CreateHostedRunnerRequest{
Name: "My Hosted runner",
Image: HostedRunnerImage{
ID: "ubuntu-latest",
Source: "github",
Version: "latest",
Version: Ptr("latest"),
},
RunnerGroupID: 1,
},
expectedError: "validation failed: size is required for creating a hosted runner",
},
{
name: "Missing Image",
request: &HostedRunnerRequest{
request: CreateHostedRunnerRequest{
Name: "My Hosted runner",
RunnerGroupID: 1,
Size: "4-core",
Expand All @@ -277,11 +273,11 @@ func TestActionsService_CreateHostedRunner(t *testing.T) {
},
{
name: "Missing Name",
request: &HostedRunnerRequest{
request: CreateHostedRunnerRequest{
Image: HostedRunnerImage{
ID: "ubuntu-latest",
Source: "github",
Version: "latest",
Version: Ptr("latest"),
},
RunnerGroupID: 1,
Size: "4-core",
Expand All @@ -290,34 +286,17 @@ func TestActionsService_CreateHostedRunner(t *testing.T) {
},
{
name: "Missing RunnerGroupID",
request: &HostedRunnerRequest{
request: CreateHostedRunnerRequest{
Name: "My Hosted runner",
Image: HostedRunnerImage{
ID: "ubuntu-latest",
Source: "github",
Version: "latest",
Version: Ptr("latest"),
},
Size: "4-core",
},
expectedError: "validation failed: runner group ID is required for creating a hosted runner",
},
{
name: "ImageVersion Set Instead of Image Struct",
request: &HostedRunnerRequest{
Name: "My Hosted runner",
Image: HostedRunnerImage{
ID: "ubuntu-latest",
Source: "github",
Version: "latest",
},
RunnerGroupID: 1,
Size: "4-core",
ImageVersion: "1.0.0",
MaximumRunners: 50,
EnableStaticIP: false,
},
expectedError: "validation failed: imageVersion should not be set directly; use the Image struct to specify image details",
},
}

for _, tt := range testCases {
Expand Down Expand Up @@ -731,12 +710,12 @@ func TestActionsService_UpdateHostedRunner(t *testing.T) {
})

ctx := t.Context()
validReq := HostedRunnerRequest{
Name: "My larger runner",
RunnerGroupID: 1,
MaximumRunners: 50,
EnableStaticIP: false,
ImageVersion: "1.0.0",
validReq := UpdateHostedRunnerRequest{
Name: Ptr("My larger runner"),
RunnerGroupID: Ptr(int64(1)),
MaximumRunners: Ptr(int64(50)),
EnableStaticIP: Ptr(false),
ImageVersion: Ptr("1.0.0"),
}
hostedRunner, _, err := client.Actions.UpdateHostedRunner(ctx, "o", 23, validReq)
if err != nil {
Expand Down Expand Up @@ -776,47 +755,6 @@ func TestActionsService_UpdateHostedRunner(t *testing.T) {
t.Errorf("Actions.UpdateHostedRunner returned %+v, want %+v", hostedRunner, want)
}

testCases := []struct {
name string
request HostedRunnerRequest
expectedError string
}{
{
name: "Size Set in Update Request",
request: HostedRunnerRequest{
Name: "My larger runner",
RunnerGroupID: 1,
MaximumRunners: 50,
EnableStaticIP: false,
ImageVersion: "1.0.0",
Size: "4-core", // Should cause validation error
},
expectedError: "validation failed: size cannot be updated, API does not support updating size",
},
{
name: "Image Set in Update Request",
request: HostedRunnerRequest{
Name: "My larger runner",
RunnerGroupID: 1,
MaximumRunners: 50,
EnableStaticIP: false,
ImageVersion: "1.0.0",
Image: HostedRunnerImage{ // Should cause validation error
ID: "ubuntu-latest",
Source: "github",
Version: "latest",
},
},
expectedError: "validation failed: image struct should not be set directly; use the ImageVersion to specify version details",
},
}
for _, tt := range testCases {
_, _, err := client.Enterprise.UpdateHostedRunner(ctx, "o", 23, tt.request)
if err == nil || err.Error() != tt.expectedError {
t.Errorf("expected error: %v, got: %v", tt.expectedError, err)
}
}

const methodName = "UpdateHostedRunner"
testBadOptions(t, methodName, func() (err error) {
_, _, err = client.Actions.UpdateHostedRunner(ctx, "\n", 23, validReq)
Expand Down
12 changes: 4 additions & 8 deletions github/enterprise_actions_hosted_runners.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ func (s *EnterpriseService) ListHostedRunners(ctx context.Context, enterprise st
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/actions/hosted-runners#create-a-github-hosted-runner-for-an-enterprise
//
//meta:operation POST /enterprises/{enterprise}/actions/hosted-runners
func (s *EnterpriseService) CreateHostedRunner(ctx context.Context, enterprise string, request *HostedRunnerRequest) (*HostedRunner, *Response, error) {
if err := validateCreateHostedRunnerRequest(request); err != nil {
func (s *EnterpriseService) CreateHostedRunner(ctx context.Context, enterprise string, request CreateHostedRunnerRequest) (*HostedRunner, *Response, error) {
if err := validateCreateHostedRunnerRequest(&request); err != nil {
return nil, nil, fmt.Errorf("validation failed: %w", err)
}

Expand Down Expand Up @@ -192,13 +192,9 @@ func (s *EnterpriseService) GetHostedRunner(ctx context.Context, enterprise stri
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/actions/hosted-runners#update-a-github-hosted-runner-for-an-enterprise
//
//meta:operation PATCH /enterprises/{enterprise}/actions/hosted-runners/{hosted_runner_id}
func (s *EnterpriseService) UpdateHostedRunner(ctx context.Context, enterprise string, runnerID int64, updateReq HostedRunnerRequest) (*HostedRunner, *Response, error) {
if err := validateUpdateHostedRunnerRequest(&updateReq); err != nil {
return nil, nil, fmt.Errorf("validation failed: %w", err)
}

func (s *EnterpriseService) UpdateHostedRunner(ctx context.Context, enterprise string, runnerID int64, request UpdateHostedRunnerRequest) (*HostedRunner, *Response, error) {
u := fmt.Sprintf("enterprises/%v/actions/hosted-runners/%v", enterprise, runnerID)
req, err := s.client.NewRequest("PATCH", u, updateReq)
req, err := s.client.NewRequest("PATCH", u, request)
if err != nil {
return nil, nil, err
}
Expand Down
Loading
Loading