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  }