diff --git a/github/codespaces_machines.go b/github/codespaces_machines.go new file mode 100644 index 00000000000..5277b1f4098 --- /dev/null +++ b/github/codespaces_machines.go @@ -0,0 +1,74 @@ +// Copyright 2025 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" +) + +// CodespacesMachines represent a list of machines. +type CodespacesMachines struct { + TotalCount int64 `json:"total_count"` + Machines []*CodespacesMachine `json:"machines"` +} + +// ListRepoMachineTypesOptions represent options for ListMachineTypesForRepository. +type ListRepoMachineTypesOptions struct { + // Ref represent the branch or commit to check for prebuild availability and devcontainer restrictions. + Ref *string `url:"ref,omitempty"` + // Location represent the location to check for available machines. Assigned by IP if not provided. + Location *string `url:"location,omitempty"` + // ClientIP represent the IP for location auto-detection when proxying a request + ClientIP *string `url:"client_ip,omitempty"` +} + +// ListRepositoryMachineTypes lists the machine types available for a given repository based on its configuration. +// +// GitHub API docs: https://docs.github.com/rest/codespaces/machines#list-available-machine-types-for-a-repository +// +//meta:operation GET /repos/{owner}/{repo}/codespaces/machines +func (s *CodespacesService) ListRepositoryMachineTypes(ctx context.Context, owner, repo string, opts *ListRepoMachineTypesOptions) (*CodespacesMachines, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/codespaces/machines", owner, repo) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var machines *CodespacesMachines + resp, err := s.client.Do(ctx, req, &machines) + if err != nil { + return nil, resp, err + } + + return machines, resp, nil +} + +// ListCodespaceMachineTypes lists the machine types a codespace can transition to use. +// +// GitHub API docs: https://docs.github.com/rest/codespaces/machines#list-machine-types-for-a-codespace +// +//meta:operation GET /user/codespaces/{codespace_name}/machines +func (s *CodespacesService) ListCodespaceMachineTypes(ctx context.Context, codespaceName string) (*CodespacesMachines, *Response, error) { + u := fmt.Sprintf("user/codespaces/%v/machines", codespaceName) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var machines *CodespacesMachines + resp, err := s.client.Do(ctx, req, &machines) + if err != nil { + return nil, resp, err + } + + return machines, resp, nil +} diff --git a/github/codespaces_machines_test.go b/github/codespaces_machines_test.go new file mode 100644 index 00000000000..d413d168b93 --- /dev/null +++ b/github/codespaces_machines_test.go @@ -0,0 +1,149 @@ +// Copyright 2025 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "fmt" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestCodespacesService_ListRepositoryMachineTypes(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/repos/owner/repo/codespaces/machines", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testFormValues(t, r, values{ + "ref": "main", + "location": "WestUs2", + "client_ip": "1.2.3.4", + }) + fmt.Fprint(w, `{ + "total_count": 1, + "machines": [ + { + "name": "standardLinux", + "display_name": "4 cores, 8 GB RAM, 64 GB storage", + "operating_system": "linux", + "storage_in_bytes": 68719476736, + "memory_in_bytes": 17179869184, + "cpus": 4, + "prebuild_availability": "ready" + } + ] + }`) + }) + + ctx := t.Context() + opts := &ListRepoMachineTypesOptions{ + Ref: Ptr("main"), + Location: Ptr("WestUs2"), + ClientIP: Ptr("1.2.3.4"), + } + + got, _, err := client.Codespaces.ListRepositoryMachineTypes( + ctx, + "owner", + "repo", + opts, + ) + if err != nil { + t.Fatalf("Codespaces.ListRepositoryMachineTypes returned error: %v", err) + } + + want := &CodespacesMachines{ + TotalCount: 1, + Machines: []*CodespacesMachine{ + { + Name: Ptr("standardLinux"), + DisplayName: Ptr("4 cores, 8 GB RAM, 64 GB storage"), + OperatingSystem: Ptr("linux"), + StorageInBytes: Ptr(int64(68719476736)), + MemoryInBytes: Ptr(int64(17179869184)), + CPUs: Ptr(4), + PrebuildAvailability: Ptr("ready"), + }, + }, + } + + if !cmp.Equal(got, want) { + t.Errorf("Codespaces.ListRepositoryMachineTypes returned %+v, want %+v", got, want) + } + + const methodName = "ListRepositoryMachineTypes" + testBadOptions(t, methodName, func() error { + _, _, err := client.Codespaces.ListRepositoryMachineTypes(ctx, "\n", "/n", opts) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Codespaces.ListRepositoryMachineTypes(ctx, "/n", "/n", opts) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestCodespacesService_ListCodespaceMachineTypes(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/user/codespaces/codespace_1/machines", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + + fmt.Fprint(w, `{ + "total_count": 1, + "machines": [ + { + "name": "standardLinux", + "display_name": "4 cores, 8 GB RAM, 64 GB storage", + "operating_system": "linux", + "storage_in_bytes": 68719476736, + "memory_in_bytes": 17179869184, + "cpus": 4, + "prebuild_availability": "ready" + } + ] + }`) + }) + + ctx := t.Context() + got, _, err := client.Codespaces.ListCodespaceMachineTypes(ctx, "codespace_1") + if err != nil { + t.Fatalf("Codespaces.ListCodespaceMachineTypes returned error: %v", err) + } + + want := &CodespacesMachines{ + TotalCount: 1, + Machines: []*CodespacesMachine{ + { + Name: Ptr("standardLinux"), + DisplayName: Ptr("4 cores, 8 GB RAM, 64 GB storage"), + OperatingSystem: Ptr("linux"), + StorageInBytes: Ptr(int64(68719476736)), + MemoryInBytes: Ptr(int64(17179869184)), + CPUs: Ptr(4), + PrebuildAvailability: Ptr("ready"), + }, + }, + } + + if !cmp.Equal(got, want) { + t.Errorf("Codespaces.ListCodespaceMachineTypes returned %+v, want %+v", got, want) + } + + const methodName = "ListCodespaceMachineTypes" + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Codespaces.ListCodespaceMachineTypes(ctx, "/n") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} diff --git a/github/github-accessors.go b/github/github-accessors.go index b907c2af56a..8b24b058ed5 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -14678,6 +14678,30 @@ func (l *ListProvisionedSCIMUsersEnterpriseOptions) GetStartIndex() int { return *l.StartIndex } +// GetClientIP returns the ClientIP field if it's non-nil, zero value otherwise. +func (l *ListRepoMachineTypesOptions) GetClientIP() string { + if l == nil || l.ClientIP == nil { + return "" + } + return *l.ClientIP +} + +// GetLocation returns the Location field if it's non-nil, zero value otherwise. +func (l *ListRepoMachineTypesOptions) GetLocation() string { + if l == nil || l.Location == nil { + return "" + } + return *l.Location +} + +// GetRef returns the Ref field if it's non-nil, zero value otherwise. +func (l *ListRepoMachineTypesOptions) GetRef() string { + if l == nil || l.Ref == nil { + return "" + } + return *l.Ref +} + // GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise. func (l *ListRepositories) GetTotalCount() int { if l == nil || l.TotalCount == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index b12c405d2bf..dbd85d0dc7d 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -19095,6 +19095,39 @@ func TestListProvisionedSCIMUsersEnterpriseOptions_GetStartIndex(tt *testing.T) l.GetStartIndex() } +func TestListRepoMachineTypesOptions_GetClientIP(tt *testing.T) { + tt.Parallel() + var zeroValue string + l := &ListRepoMachineTypesOptions{ClientIP: &zeroValue} + l.GetClientIP() + l = &ListRepoMachineTypesOptions{} + l.GetClientIP() + l = nil + l.GetClientIP() +} + +func TestListRepoMachineTypesOptions_GetLocation(tt *testing.T) { + tt.Parallel() + var zeroValue string + l := &ListRepoMachineTypesOptions{Location: &zeroValue} + l.GetLocation() + l = &ListRepoMachineTypesOptions{} + l.GetLocation() + l = nil + l.GetLocation() +} + +func TestListRepoMachineTypesOptions_GetRef(tt *testing.T) { + tt.Parallel() + var zeroValue string + l := &ListRepoMachineTypesOptions{Ref: &zeroValue} + l.GetRef() + l = &ListRepoMachineTypesOptions{} + l.GetRef() + l = nil + l.GetRef() +} + func TestListRepositories_GetTotalCount(tt *testing.T) { tt.Parallel() var zeroValue int