github.com/google/go-github/v70@v70.0.0/github/actions_hosted_runners.go (about) 1 // Copyright 2025 The go-github AUTHORS. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 package github 7 8 import ( 9 "context" 10 "errors" 11 "fmt" 12 ) 13 14 // HostedRunnerPublicIP represents the details of a public IP for GitHub-hosted runner. 15 type HostedRunnerPublicIP struct { 16 Enabled bool `json:"enabled"` // Whether public IP is enabled. 17 Prefix string `json:"prefix"` // The prefix for the public IP. Example: 20.80.208.150 18 Length int `json:"length"` // The length of the IP prefix. Example: 28 19 } 20 21 // HostedRunnerMachineSpec represents the details of a particular machine specification for GitHub-hosted runner. 22 type HostedRunnerMachineSpec struct { 23 ID string `json:"id"` // The ID used for the `size` parameter when creating a new runner. Example: 8-core 24 CPUCores int `json:"cpu_cores"` // The number of cores. Example: 8 25 MemoryGB int `json:"memory_gb"` // The available RAM for the machine spec. Example: 32 26 StorageGB int `json:"storage_gb"` // The available SSD storage for the machine spec. Example: 300 27 } 28 29 // HostedRunner represents a single GitHub-hosted runner with additional details. 30 type HostedRunner struct { 31 ID *int64 `json:"id,omitempty"` 32 Name *string `json:"name,omitempty"` 33 RunnerGroupID *int64 `json:"runner_group_id,omitempty"` 34 Platform *string `json:"platform,omitempty"` 35 ImageDetails *HostedRunnerImageDetail `json:"image_details,omitempty"` 36 MachineSizeDetails *HostedRunnerMachineSpec `json:"machine_size_details,omitempty"` 37 Status *string `json:"status,omitempty"` 38 MaximumRunners *int64 `json:"maximum_runners,omitempty"` 39 PublicIPEnabled *bool `json:"public_ip_enabled,omitempty"` 40 PublicIPs []*HostedRunnerPublicIP `json:"public_ips,omitempty"` 41 LastActiveOn *Timestamp `json:"last_active_on,omitempty"` 42 } 43 44 // HostedRunnerImageDetail represents the image details of a GitHub-hosted runners. 45 type HostedRunnerImageDetail struct { 46 ID *string `json:"id"` // The ID of the image. Use this ID for the `image` parameter when creating a new larger runner. Example: ubuntu-20.04 47 SizeGB *int64 `json:"size_gb"` // Image size in GB. Example: 86 48 DisplayName *string `json:"display_name"` // Display name for this image. Example: 20.04 49 Source *string `json:"source"` // The image provider. Example: github, partner, custom 50 Version *string `json:"version"` // The image version of the hosted runner pool. Example: latest 51 } 52 53 // HostedRunners represents a collection of GitHub-hosted runners for an organization. 54 type HostedRunners struct { 55 TotalCount int `json:"total_count"` 56 Runners []*HostedRunner `json:"runners"` 57 } 58 59 // ListHostedRunners lists all the GitHub-hosted runners for an organization. 60 // 61 // GitHub API docs: https://docs.github.com/rest/actions/hosted-runners#list-github-hosted-runners-for-an-organization 62 // 63 //meta:operation GET /orgs/{org}/actions/hosted-runners 64 func (s *ActionsService) ListHostedRunners(ctx context.Context, org string, opts *ListOptions) (*HostedRunners, *Response, error) { 65 u := fmt.Sprintf("orgs/%v/actions/hosted-runners", org) 66 u, err := addOptions(u, opts) 67 if err != nil { 68 return nil, nil, err 69 } 70 71 req, err := s.client.NewRequest("GET", u, nil) 72 if err != nil { 73 return nil, nil, err 74 } 75 76 runners := &HostedRunners{} 77 resp, err := s.client.Do(ctx, req, &runners) 78 if err != nil { 79 return nil, resp, err 80 } 81 82 return runners, resp, nil 83 } 84 85 // HostedRunnerImage represents the image of GitHub-hosted runners. 86 // To list all available images, use GET /actions/hosted-runners/images/github-owned or GET /actions/hosted-runners/images/partner. 87 type HostedRunnerImage struct { 88 ID string `json:"id"` 89 Source string `json:"source"` 90 Version string `json:"version"` 91 } 92 93 // HostedRunnerRequest specifies body parameters to Hosted Runner configuration. 94 type HostedRunnerRequest struct { 95 Name string `json:"name,omitempty"` 96 Image HostedRunnerImage `json:"image,omitempty"` 97 RunnerGroupID int64 `json:"runner_group_id,omitempty"` 98 Size string `json:"size,omitempty"` 99 MaximumRunners int64 `json:"maximum_runners,omitempty"` 100 EnableStaticIP bool `json:"enable_static_ip,omitempty"` 101 ImageVersion string `json:"image_version,omitempty"` 102 } 103 104 // validateCreateHostedRunnerRequest validates the provided HostedRunnerRequest to ensure 105 // that all required fields are properly set and that no invalid fields are present for hosted runner create request. 106 // 107 // If any of these conditions are violated, an appropriate error message is returned. 108 // Otherwise, nil is returned, indicating the request is valid. 109 func validateCreateHostedRunnerRequest(request *HostedRunnerRequest) error { 110 if request.Size == "" { 111 return errors.New("size is required for creating a hosted runner") 112 } 113 if request.Image == (HostedRunnerImage{}) { 114 return errors.New("image is required for creating a hosted runner") 115 } 116 if request.Name == "" { 117 return errors.New("name is required for creating a hosted runner") 118 } 119 if request.RunnerGroupID == 0 { 120 return errors.New("runner group ID is required for creating a hosted runner") 121 } 122 if request.ImageVersion != "" { 123 return errors.New("imageVersion should not be set directly; use the Image struct to specify image details") 124 } 125 return nil 126 } 127 128 // CreateHostedRunner creates a GitHub-hosted runner for an organization. 129 // 130 // GitHub API docs: https://docs.github.com/rest/actions/hosted-runners#create-a-github-hosted-runner-for-an-organization 131 // 132 //meta:operation POST /orgs/{org}/actions/hosted-runners 133 func (s *ActionsService) CreateHostedRunner(ctx context.Context, org string, request *HostedRunnerRequest) (*HostedRunner, *Response, error) { 134 if err := validateCreateHostedRunnerRequest(request); err != nil { 135 return nil, nil, fmt.Errorf("validation failed: %w", err) 136 } 137 138 u := fmt.Sprintf("orgs/%v/actions/hosted-runners", org) 139 req, err := s.client.NewRequest("POST", u, request) 140 if err != nil { 141 return nil, nil, err 142 } 143 144 hostedRunner := new(HostedRunner) 145 resp, err := s.client.Do(ctx, req, hostedRunner) 146 if err != nil { 147 return nil, resp, err 148 } 149 150 return hostedRunner, resp, nil 151 } 152 153 // HostedRunnerImageSpecs represents the details of a GitHub-hosted runner image. 154 type HostedRunnerImageSpecs struct { 155 ID string `json:"id"` 156 Platform string `json:"platform"` 157 SizeGB int `json:"size_gb"` 158 DisplayName string `json:"display_name"` 159 Source string `json:"source"` 160 } 161 162 // HostedRunnerImages represents the response containing the total count and details of runner images. 163 type HostedRunnerImages struct { 164 TotalCount int `json:"total_count"` 165 Images []*HostedRunnerImageSpecs `json:"images"` 166 } 167 168 // GetHostedRunnerGitHubOwnedImages gets the list of GitHub-owned images available for GitHub-hosted runners for an organization. 169 // 170 // GitHub API docs: https://docs.github.com/rest/actions/hosted-runners#get-github-owned-images-for-github-hosted-runners-in-an-organization 171 // 172 //meta:operation GET /orgs/{org}/actions/hosted-runners/images/github-owned 173 func (s *ActionsService) GetHostedRunnerGitHubOwnedImages(ctx context.Context, org string) (*HostedRunnerImages, *Response, error) { 174 u := fmt.Sprintf("orgs/%v/actions/hosted-runners/images/github-owned", org) 175 req, err := s.client.NewRequest("GET", u, nil) 176 if err != nil { 177 return nil, nil, err 178 } 179 180 hostedRunnerImages := new(HostedRunnerImages) 181 resp, err := s.client.Do(ctx, req, hostedRunnerImages) 182 if err != nil { 183 return nil, resp, err 184 } 185 186 return hostedRunnerImages, resp, nil 187 } 188 189 // GetHostedRunnerPartnerImages gets the list of partner images available for GitHub-hosted runners for an organization. 190 // 191 // GitHub API docs: https://docs.github.com/rest/actions/hosted-runners#get-partner-images-for-github-hosted-runners-in-an-organization 192 // 193 //meta:operation GET /orgs/{org}/actions/hosted-runners/images/partner 194 func (s *ActionsService) GetHostedRunnerPartnerImages(ctx context.Context, org string) (*HostedRunnerImages, *Response, error) { 195 u := fmt.Sprintf("orgs/%v/actions/hosted-runners/images/partner", org) 196 req, err := s.client.NewRequest("GET", u, nil) 197 if err != nil { 198 return nil, nil, err 199 } 200 201 hostedRunnerImages := new(HostedRunnerImages) 202 resp, err := s.client.Do(ctx, req, hostedRunnerImages) 203 if err != nil { 204 return nil, resp, err 205 } 206 207 return hostedRunnerImages, resp, nil 208 } 209 210 // HostedRunnerPublicIPLimits represents the static public IP limits for GitHub-hosted runners. 211 type HostedRunnerPublicIPLimits struct { 212 PublicIPs *PublicIPUsage `json:"public_ips"` 213 } 214 215 // PublicIPUsage provides details of static public IP limits for GitHub-hosted runners. 216 type PublicIPUsage struct { 217 Maximum int64 `json:"maximum"` // The maximum number of static public IP addresses that can be used for Hosted Runners. Example: 50 218 CurrentUsage int64 `json:"current_usage"` // The current number of static public IP addresses in use by Hosted Runners. Example: 17 219 } 220 221 // GetHostedRunnerLimits gets the GitHub-hosted runners Static public IP Limits for an organization. 222 // 223 // GitHub API docs: https://docs.github.com/rest/actions/hosted-runners#get-limits-on-github-hosted-runners-for-an-organization 224 // 225 //meta:operation GET /orgs/{org}/actions/hosted-runners/limits 226 func (s *ActionsService) GetHostedRunnerLimits(ctx context.Context, org string) (*HostedRunnerPublicIPLimits, *Response, error) { 227 u := fmt.Sprintf("orgs/%v/actions/hosted-runners/limits", org) 228 req, err := s.client.NewRequest("GET", u, nil) 229 if err != nil { 230 return nil, nil, err 231 } 232 233 publicIPLimits := new(HostedRunnerPublicIPLimits) 234 resp, err := s.client.Do(ctx, req, publicIPLimits) 235 if err != nil { 236 return nil, resp, err 237 } 238 239 return publicIPLimits, resp, nil 240 } 241 242 // HostedRunnerMachineSpecs represents the response containing the total count and details of machine specs for GitHub-hosted runners. 243 type HostedRunnerMachineSpecs struct { 244 TotalCount int `json:"total_count"` 245 MachineSpecs []*HostedRunnerMachineSpec `json:"machine_specs"` 246 } 247 248 // GetHostedRunnerMachineSpecs gets the list of machine specs available for GitHub-hosted runners for an organization. 249 // 250 // GitHub API docs: https://docs.github.com/rest/actions/hosted-runners#get-github-hosted-runners-machine-specs-for-an-organization 251 // 252 //meta:operation GET /orgs/{org}/actions/hosted-runners/machine-sizes 253 func (s *ActionsService) GetHostedRunnerMachineSpecs(ctx context.Context, org string) (*HostedRunnerMachineSpecs, *Response, error) { 254 u := fmt.Sprintf("orgs/%v/actions/hosted-runners/machine-sizes", org) 255 req, err := s.client.NewRequest("GET", u, nil) 256 if err != nil { 257 return nil, nil, err 258 } 259 260 machineSpecs := new(HostedRunnerMachineSpecs) 261 resp, err := s.client.Do(ctx, req, machineSpecs) 262 if err != nil { 263 return nil, resp, err 264 } 265 266 return machineSpecs, resp, nil 267 } 268 269 // HostedRunnerPlatforms represents the response containing the total count and platforms for GitHub-hosted runners. 270 type HostedRunnerPlatforms struct { 271 TotalCount int `json:"total_count"` 272 Platforms []string `json:"platforms"` 273 } 274 275 // GetHostedRunnerPlatforms gets list of platforms available for GitHub-hosted runners for an organization. 276 // 277 // GitHub API docs: https://docs.github.com/rest/actions/hosted-runners#get-platforms-for-github-hosted-runners-in-an-organization 278 // 279 //meta:operation GET /orgs/{org}/actions/hosted-runners/platforms 280 func (s *ActionsService) GetHostedRunnerPlatforms(ctx context.Context, org string) (*HostedRunnerPlatforms, *Response, error) { 281 u := fmt.Sprintf("orgs/%v/actions/hosted-runners/platforms", org) 282 req, err := s.client.NewRequest("GET", u, nil) 283 if err != nil { 284 return nil, nil, err 285 } 286 287 platforms := new(HostedRunnerPlatforms) 288 resp, err := s.client.Do(ctx, req, platforms) 289 if err != nil { 290 return nil, resp, err 291 } 292 293 return platforms, resp, nil 294 } 295 296 // GetHostedRunner gets a GitHub-hosted runner in an organization. 297 // 298 // GitHub API docs: https://docs.github.com/rest/actions/hosted-runners#get-a-github-hosted-runner-for-an-organization 299 // 300 //meta:operation GET /orgs/{org}/actions/hosted-runners/{hosted_runner_id} 301 func (s *ActionsService) GetHostedRunner(ctx context.Context, org string, runnerID int64) (*HostedRunner, *Response, error) { 302 u := fmt.Sprintf("orgs/%v/actions/hosted-runners/%v", org, runnerID) 303 req, err := s.client.NewRequest("GET", u, nil) 304 if err != nil { 305 return nil, nil, err 306 } 307 308 hostedRunner := new(HostedRunner) 309 resp, err := s.client.Do(ctx, req, hostedRunner) 310 if err != nil { 311 return nil, resp, err 312 } 313 314 return hostedRunner, resp, nil 315 } 316 317 // validateUpdateHostedRunnerRequest validates the provided HostedRunnerRequest to ensure 318 // that no disallowed updates are made for a hosted runner update request. 319 // 320 // If any of these conditions are violated, an appropriate error message is returned. 321 // Otherwise, nil is returned, indicating the request is valid for an update. 322 func validateUpdateHostedRunnerRequest(request *HostedRunnerRequest) error { 323 if request.Size != "" { 324 return errors.New("size cannot be updated, API does not support updating size") 325 } 326 if request.Image != (HostedRunnerImage{}) { 327 return errors.New("image struct should not be set directly; use the ImageVersion to specify version details") 328 } 329 return nil 330 } 331 332 // UpdateHostedRunner updates a GitHub-hosted runner for an organization. 333 // 334 // GitHub API docs: https://docs.github.com/rest/actions/hosted-runners#update-a-github-hosted-runner-for-an-organization 335 // 336 //meta:operation PATCH /orgs/{org}/actions/hosted-runners/{hosted_runner_id} 337 func (s *ActionsService) UpdateHostedRunner(ctx context.Context, org string, runnerID int64, updateReq HostedRunnerRequest) (*HostedRunner, *Response, error) { 338 if err := validateUpdateHostedRunnerRequest(&updateReq); err != nil { 339 return nil, nil, fmt.Errorf("validation failed: %w", err) 340 } 341 342 u := fmt.Sprintf("orgs/%v/actions/hosted-runners/%v", org, runnerID) 343 req, err := s.client.NewRequest("PATCH", u, updateReq) 344 if err != nil { 345 return nil, nil, err 346 } 347 348 hostedRunner := new(HostedRunner) 349 resp, err := s.client.Do(ctx, req, hostedRunner) 350 if err != nil { 351 return nil, resp, err 352 } 353 354 return hostedRunner, resp, nil 355 } 356 357 // DeleteHostedRunner deletes GitHub-hosted runner from an organization. 358 // 359 // GitHub API docs: https://docs.github.com/rest/actions/hosted-runners#delete-a-github-hosted-runner-for-an-organization 360 // 361 //meta:operation DELETE /orgs/{org}/actions/hosted-runners/{hosted_runner_id} 362 func (s *ActionsService) DeleteHostedRunner(ctx context.Context, org string, runnerID int64) (*HostedRunner, *Response, error) { 363 u := fmt.Sprintf("orgs/%v/actions/hosted-runners/%v", org, runnerID) 364 req, err := s.client.NewRequest("DELETE", u, nil) 365 if err != nil { 366 return nil, nil, err 367 } 368 369 hostedRunner := new(HostedRunner) 370 resp, err := s.client.Do(ctx, req, hostedRunner) 371 if err != nil { 372 return nil, resp, err 373 } 374 375 return hostedRunner, resp, nil 376 }