github.com/google/go-github/v74@v74.0.0/github/copilot.go (about)

     1  // Copyright 2023 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  	"encoding/json"
    11  	"errors"
    12  	"fmt"
    13  	"time"
    14  )
    15  
    16  // CopilotService provides access to the Copilot-related functions
    17  // in the GitHub API.
    18  //
    19  // GitHub API docs: https://docs.github.com/en/rest/copilot/
    20  type CopilotService service
    21  
    22  // CopilotOrganizationDetails represents the details of an organization's Copilot for Business subscription.
    23  type CopilotOrganizationDetails struct {
    24  	SeatBreakdown         *CopilotSeatBreakdown `json:"seat_breakdown"`
    25  	PublicCodeSuggestions string                `json:"public_code_suggestions"`
    26  	CopilotChat           string                `json:"copilot_chat"`
    27  	SeatManagementSetting string                `json:"seat_management_setting"`
    28  }
    29  
    30  // CopilotSeatBreakdown represents the breakdown of Copilot for Business seats for the organization.
    31  type CopilotSeatBreakdown struct {
    32  	Total               int `json:"total"`
    33  	AddedThisCycle      int `json:"added_this_cycle"`
    34  	PendingCancellation int `json:"pending_cancellation"`
    35  	PendingInvitation   int `json:"pending_invitation"`
    36  	ActiveThisCycle     int `json:"active_this_cycle"`
    37  	InactiveThisCycle   int `json:"inactive_this_cycle"`
    38  }
    39  
    40  // ListCopilotSeatsResponse represents the Copilot for Business seat assignments for an organization.
    41  type ListCopilotSeatsResponse struct {
    42  	TotalSeats int64                 `json:"total_seats"`
    43  	Seats      []*CopilotSeatDetails `json:"seats"`
    44  }
    45  
    46  // CopilotSeatDetails represents the details of a Copilot for Business seat.
    47  type CopilotSeatDetails struct {
    48  	// Assignee can either be a User, Team, or Organization.
    49  	Assignee                any        `json:"assignee"`
    50  	AssigningTeam           *Team      `json:"assigning_team,omitempty"`
    51  	PendingCancellationDate *string    `json:"pending_cancellation_date,omitempty"`
    52  	LastActivityAt          *Timestamp `json:"last_activity_at,omitempty"`
    53  	LastActivityEditor      *string    `json:"last_activity_editor,omitempty"`
    54  	CreatedAt               *Timestamp `json:"created_at"`
    55  	UpdatedAt               *Timestamp `json:"updated_at,omitempty"`
    56  	PlanType                *string    `json:"plan_type,omitempty"`
    57  }
    58  
    59  // SeatAssignments represents the number of seats assigned.
    60  type SeatAssignments struct {
    61  	SeatsCreated int `json:"seats_created"`
    62  }
    63  
    64  // SeatCancellations represents the number of seats cancelled.
    65  type SeatCancellations struct {
    66  	SeatsCancelled int `json:"seats_cancelled"`
    67  }
    68  
    69  // CopilotMetricsListOptions represents the optional parameters to the CopilotService get metrics methods.
    70  type CopilotMetricsListOptions struct {
    71  	Since *time.Time `url:"since,omitempty"`
    72  	Until *time.Time `url:"until,omitempty"`
    73  
    74  	ListOptions
    75  }
    76  
    77  // CopilotIDECodeCompletionsLanguage represents Copilot usage metrics for completions in the IDE for a language.
    78  type CopilotIDECodeCompletionsLanguage struct {
    79  	Name              string `json:"name"`
    80  	TotalEngagedUsers int    `json:"total_engaged_users"`
    81  }
    82  
    83  // CopilotIDECodeCompletionsModelLanguage represents Copilot usage metrics for completions in the IDE for a model and language.
    84  type CopilotIDECodeCompletionsModelLanguage struct {
    85  	Name                    string `json:"name"`
    86  	TotalEngagedUsers       int    `json:"total_engaged_users"`
    87  	TotalCodeSuggestions    int    `json:"total_code_suggestions"`
    88  	TotalCodeAcceptances    int    `json:"total_code_acceptances"`
    89  	TotalCodeLinesSuggested int    `json:"total_code_lines_suggested"`
    90  	TotalCodeLinesAccepted  int    `json:"total_code_lines_accepted"`
    91  }
    92  
    93  // CopilotIDECodeCompletionsModel represents Copilot usage metrics for completions in the IDE for a model.
    94  type CopilotIDECodeCompletionsModel struct {
    95  	Name                    string                                    `json:"name"`
    96  	IsCustomModel           bool                                      `json:"is_custom_model"`
    97  	CustomModelTrainingDate *string                                   `json:"custom_model_training_date,omitempty"`
    98  	TotalEngagedUsers       int                                       `json:"total_engaged_users"`
    99  	Languages               []*CopilotIDECodeCompletionsModelLanguage `json:"languages"`
   100  }
   101  
   102  // CopilotIDECodeCompletionsEditor represents Copilot usage metrics for completions in the IDE for an editor.
   103  type CopilotIDECodeCompletionsEditor struct {
   104  	Name              string                            `json:"name"`
   105  	TotalEngagedUsers int                               `json:"total_engaged_users"`
   106  	Models            []*CopilotIDECodeCompletionsModel `json:"models"`
   107  }
   108  
   109  // CopilotIDECodeCompletions represents Copilot usage metrics for Copilot code completions in the IDE, categorized by editor, model and language.
   110  type CopilotIDECodeCompletions struct {
   111  	TotalEngagedUsers int                                  `json:"total_engaged_users"`
   112  	Languages         []*CopilotIDECodeCompletionsLanguage `json:"languages"`
   113  	Editors           []*CopilotIDECodeCompletionsEditor   `json:"editors"`
   114  }
   115  
   116  // CopilotIDEChatModel represents Copilot usage metrics for chatting with a model in the IDE.
   117  type CopilotIDEChatModel struct {
   118  	Name                     string  `json:"name"`
   119  	IsCustomModel            bool    `json:"is_custom_model"`
   120  	CustomModelTrainingDate  *string `json:"custom_model_training_date,omitempty"`
   121  	TotalEngagedUsers        int     `json:"total_engaged_users"`
   122  	TotalChats               int     `json:"total_chats"`
   123  	TotalChatInsertionEvents int     `json:"total_chat_insertion_events"`
   124  	TotalChatCopyEvents      int     `json:"total_chat_copy_events"`
   125  }
   126  
   127  // CopilotIDEChatEditor represents Copilot usage metrics for chatting with a model in the IDE, categorized by editor and model.
   128  type CopilotIDEChatEditor struct {
   129  	Name              string                 `json:"name"`
   130  	TotalEngagedUsers int                    `json:"total_engaged_users"`
   131  	Models            []*CopilotIDEChatModel `json:"models"`
   132  }
   133  
   134  // CopilotIDEChat represents Copilot usage metrics for Copilot Chat in the IDE, categorized by editor and model.
   135  type CopilotIDEChat struct {
   136  	TotalEngagedUsers int                     `json:"total_engaged_users"`
   137  	Editors           []*CopilotIDEChatEditor `json:"editors"`
   138  }
   139  
   140  // CopilotDotcomChatModel represents Copilot usage metrics for chatting with a model in the webbrowser.
   141  type CopilotDotcomChatModel struct {
   142  	Name                    string  `json:"name"`
   143  	IsCustomModel           bool    `json:"is_custom_model"`
   144  	CustomModelTrainingDate *string `json:"custom_model_training_date,omitempty"`
   145  	TotalEngagedUsers       int     `json:"total_engaged_users"`
   146  	TotalChats              int     `json:"total_chats"`
   147  }
   148  
   149  // CopilotDotcomChat represents Copilot usage metrics for Copilot Chat in the webbrowser, categorized by model.
   150  type CopilotDotcomChat struct {
   151  	TotalEngagedUsers int                       `json:"total_engaged_users"`
   152  	Models            []*CopilotDotcomChatModel `json:"models"`
   153  }
   154  
   155  // CopilotDotcomPullRequestsModel represents Copilot usage metrics for pull requests in the webbrowser, categorized by model.
   156  type CopilotDotcomPullRequestsModel struct {
   157  	Name                    string  `json:"name"`
   158  	IsCustomModel           bool    `json:"is_custom_model"`
   159  	CustomModelTrainingDate *string `json:"custom_model_training_date,omitempty"`
   160  	TotalPRSummariesCreated int     `json:"total_pr_summaries_created"`
   161  	TotalEngagedUsers       int     `json:"total_engaged_users"`
   162  }
   163  
   164  // CopilotDotcomPullRequestsRepository represents Copilot usage metrics for pull requests in the webbrowser, categorized by repository.
   165  type CopilotDotcomPullRequestsRepository struct {
   166  	Name              string                            `json:"name"`
   167  	TotalEngagedUsers int                               `json:"total_engaged_users"`
   168  	Models            []*CopilotDotcomPullRequestsModel `json:"models"`
   169  }
   170  
   171  // CopilotDotcomPullRequests represents Copilot usage metrics for pull requests in the webbrowser, categorized by repository and model.
   172  type CopilotDotcomPullRequests struct {
   173  	TotalEngagedUsers int                                    `json:"total_engaged_users"`
   174  	Repositories      []*CopilotDotcomPullRequestsRepository `json:"repositories"`
   175  }
   176  
   177  // CopilotMetrics represents Copilot usage metrics for a given day.
   178  type CopilotMetrics struct {
   179  	Date                      string                     `json:"date"`
   180  	TotalActiveUsers          *int                       `json:"total_active_users,omitempty"`
   181  	TotalEngagedUsers         *int                       `json:"total_engaged_users,omitempty"`
   182  	CopilotIDECodeCompletions *CopilotIDECodeCompletions `json:"copilot_ide_code_completions,omitempty"`
   183  	CopilotIDEChat            *CopilotIDEChat            `json:"copilot_ide_chat,omitempty"`
   184  	CopilotDotcomChat         *CopilotDotcomChat         `json:"copilot_dotcom_chat,omitempty"`
   185  	CopilotDotcomPullRequests *CopilotDotcomPullRequests `json:"copilot_dotcom_pull_requests,omitempty"`
   186  }
   187  
   188  func (cp *CopilotSeatDetails) UnmarshalJSON(data []byte) error {
   189  	// Using an alias to avoid infinite recursion when calling json.Unmarshal
   190  	type alias CopilotSeatDetails
   191  	var seatDetail alias
   192  
   193  	if err := json.Unmarshal(data, &seatDetail); err != nil {
   194  		return err
   195  	}
   196  
   197  	cp.AssigningTeam = seatDetail.AssigningTeam
   198  	cp.PendingCancellationDate = seatDetail.PendingCancellationDate
   199  	cp.LastActivityAt = seatDetail.LastActivityAt
   200  	cp.LastActivityEditor = seatDetail.LastActivityEditor
   201  	cp.CreatedAt = seatDetail.CreatedAt
   202  	cp.UpdatedAt = seatDetail.UpdatedAt
   203  	cp.PlanType = seatDetail.PlanType
   204  
   205  	switch v := seatDetail.Assignee.(type) {
   206  	case nil:
   207  		// Assignee can be null according to GitHub API specification.
   208  		// See: https://docs.github.com/en/rest/copilot/copilot-user-management?apiVersion=2022-11-28#list-all-copilot-seat-assignments-for-an-organization
   209  		// Note: Copilot API is in public preview and subject to change.
   210  		cp.Assignee = nil
   211  	case map[string]any:
   212  		jsonData, err := json.Marshal(seatDetail.Assignee)
   213  		if err != nil {
   214  			return err
   215  		}
   216  
   217  		if v["type"] == nil {
   218  			return errors.New("assignee type field is not set")
   219  		}
   220  
   221  		if t, ok := v["type"].(string); ok && t == "User" {
   222  			user := &User{}
   223  			if err := json.Unmarshal(jsonData, user); err != nil {
   224  				return err
   225  			}
   226  			cp.Assignee = user
   227  		} else if t, ok := v["type"].(string); ok && t == "Team" {
   228  			team := &Team{}
   229  			if err := json.Unmarshal(jsonData, team); err != nil {
   230  				return err
   231  			}
   232  			cp.Assignee = team
   233  		} else if t, ok := v["type"].(string); ok && t == "Organization" {
   234  			organization := &Organization{}
   235  			if err := json.Unmarshal(jsonData, organization); err != nil {
   236  				return err
   237  			}
   238  			cp.Assignee = organization
   239  		} else {
   240  			return fmt.Errorf("unsupported assignee type %v", v["type"])
   241  		}
   242  	default:
   243  		return fmt.Errorf("unsupported assignee type %T", v)
   244  	}
   245  
   246  	return nil
   247  }
   248  
   249  // GetUser gets the User from the CopilotSeatDetails if the assignee is a user.
   250  func (cp *CopilotSeatDetails) GetUser() (*User, bool) { u, ok := cp.Assignee.(*User); return u, ok }
   251  
   252  // GetTeam gets the Team from the CopilotSeatDetails if the assignee is a team.
   253  func (cp *CopilotSeatDetails) GetTeam() (*Team, bool) { t, ok := cp.Assignee.(*Team); return t, ok }
   254  
   255  // GetOrganization gets the Organization from the CopilotSeatDetails if the assignee is an organization.
   256  func (cp *CopilotSeatDetails) GetOrganization() (*Organization, bool) {
   257  	o, ok := cp.Assignee.(*Organization)
   258  	return o, ok
   259  }
   260  
   261  // GetCopilotBilling gets Copilot for Business billing information and settings for an organization.
   262  //
   263  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#get-copilot-seat-information-and-settings-for-an-organization
   264  //
   265  //meta:operation GET /orgs/{org}/copilot/billing
   266  func (s *CopilotService) GetCopilotBilling(ctx context.Context, org string) (*CopilotOrganizationDetails, *Response, error) {
   267  	u := fmt.Sprintf("orgs/%v/copilot/billing", org)
   268  
   269  	req, err := s.client.NewRequest("GET", u, nil)
   270  	if err != nil {
   271  		return nil, nil, err
   272  	}
   273  
   274  	var copilotDetails *CopilotOrganizationDetails
   275  	resp, err := s.client.Do(ctx, req, &copilotDetails)
   276  	if err != nil {
   277  		return nil, resp, err
   278  	}
   279  
   280  	return copilotDetails, resp, nil
   281  }
   282  
   283  // ListCopilotSeats lists Copilot for Business seat assignments for an organization.
   284  //
   285  // To paginate through all seats, populate 'Page' with the number of the last page.
   286  //
   287  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#list-all-copilot-seat-assignments-for-an-organization
   288  //
   289  //meta:operation GET /orgs/{org}/copilot/billing/seats
   290  func (s *CopilotService) ListCopilotSeats(ctx context.Context, org string, opts *ListOptions) (*ListCopilotSeatsResponse, *Response, error) {
   291  	u := fmt.Sprintf("orgs/%v/copilot/billing/seats", org)
   292  	u, err := addOptions(u, opts)
   293  	if err != nil {
   294  		return nil, nil, err
   295  	}
   296  
   297  	req, err := s.client.NewRequest("GET", u, nil)
   298  	if err != nil {
   299  		return nil, nil, err
   300  	}
   301  
   302  	var copilotSeats *ListCopilotSeatsResponse
   303  	resp, err := s.client.Do(ctx, req, &copilotSeats)
   304  	if err != nil {
   305  		return nil, resp, err
   306  	}
   307  
   308  	return copilotSeats, resp, nil
   309  }
   310  
   311  // ListCopilotEnterpriseSeats lists Copilot for Business seat assignments for an enterprise.
   312  //
   313  // To paginate through all seats, populate 'Page' with the number of the last page.
   314  //
   315  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-user-management#list-all-copilot-seat-assignments-for-an-enterprise
   316  //
   317  //meta:operation GET /enterprises/{enterprise}/copilot/billing/seats
   318  func (s *CopilotService) ListCopilotEnterpriseSeats(ctx context.Context, enterprise string, opts *ListOptions) (*ListCopilotSeatsResponse, *Response, error) {
   319  	u := fmt.Sprintf("enterprises/%v/copilot/billing/seats", enterprise)
   320  	u, err := addOptions(u, opts)
   321  	if err != nil {
   322  		return nil, nil, err
   323  	}
   324  
   325  	req, err := s.client.NewRequest("GET", u, nil)
   326  	if err != nil {
   327  		return nil, nil, err
   328  	}
   329  
   330  	var copilotSeats *ListCopilotSeatsResponse
   331  	resp, err := s.client.Do(ctx, req, &copilotSeats)
   332  	if err != nil {
   333  		return nil, resp, err
   334  	}
   335  
   336  	return copilotSeats, resp, nil
   337  }
   338  
   339  // AddCopilotTeams adds teams to the Copilot for Business subscription for an organization.
   340  //
   341  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#add-teams-to-the-copilot-subscription-for-an-organization
   342  //
   343  //meta:operation POST /orgs/{org}/copilot/billing/selected_teams
   344  func (s *CopilotService) AddCopilotTeams(ctx context.Context, org string, teamNames []string) (*SeatAssignments, *Response, error) {
   345  	u := fmt.Sprintf("orgs/%v/copilot/billing/selected_teams", org)
   346  
   347  	body := struct {
   348  		SelectedTeams []string `json:"selected_teams"`
   349  	}{
   350  		SelectedTeams: teamNames,
   351  	}
   352  
   353  	req, err := s.client.NewRequest("POST", u, body)
   354  	if err != nil {
   355  		return nil, nil, err
   356  	}
   357  
   358  	var seatAssignments *SeatAssignments
   359  	resp, err := s.client.Do(ctx, req, &seatAssignments)
   360  	if err != nil {
   361  		return nil, resp, err
   362  	}
   363  
   364  	return seatAssignments, resp, nil
   365  }
   366  
   367  // RemoveCopilotTeams removes teams from the Copilot for Business subscription for an organization.
   368  //
   369  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#remove-teams-from-the-copilot-subscription-for-an-organization
   370  //
   371  //meta:operation DELETE /orgs/{org}/copilot/billing/selected_teams
   372  func (s *CopilotService) RemoveCopilotTeams(ctx context.Context, org string, teamNames []string) (*SeatCancellations, *Response, error) {
   373  	u := fmt.Sprintf("orgs/%v/copilot/billing/selected_teams", org)
   374  
   375  	body := struct {
   376  		SelectedTeams []string `json:"selected_teams"`
   377  	}{
   378  		SelectedTeams: teamNames,
   379  	}
   380  
   381  	req, err := s.client.NewRequest("DELETE", u, body)
   382  	if err != nil {
   383  		return nil, nil, err
   384  	}
   385  
   386  	var seatCancellations *SeatCancellations
   387  	resp, err := s.client.Do(ctx, req, &seatCancellations)
   388  	if err != nil {
   389  		return nil, resp, err
   390  	}
   391  
   392  	return seatCancellations, resp, nil
   393  }
   394  
   395  // AddCopilotUsers adds users to the Copilot for Business subscription for an organization
   396  //
   397  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#add-users-to-the-copilot-subscription-for-an-organization
   398  //
   399  //meta:operation POST /orgs/{org}/copilot/billing/selected_users
   400  func (s *CopilotService) AddCopilotUsers(ctx context.Context, org string, users []string) (*SeatAssignments, *Response, error) {
   401  	u := fmt.Sprintf("orgs/%v/copilot/billing/selected_users", org)
   402  
   403  	body := struct {
   404  		SelectedUsernames []string `json:"selected_usernames"`
   405  	}{
   406  		SelectedUsernames: users,
   407  	}
   408  
   409  	req, err := s.client.NewRequest("POST", u, body)
   410  	if err != nil {
   411  		return nil, nil, err
   412  	}
   413  
   414  	var seatAssignments *SeatAssignments
   415  	resp, err := s.client.Do(ctx, req, &seatAssignments)
   416  	if err != nil {
   417  		return nil, resp, err
   418  	}
   419  
   420  	return seatAssignments, resp, nil
   421  }
   422  
   423  // RemoveCopilotUsers removes users from the Copilot for Business subscription for an organization.
   424  //
   425  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#remove-users-from-the-copilot-subscription-for-an-organization
   426  //
   427  //meta:operation DELETE /orgs/{org}/copilot/billing/selected_users
   428  func (s *CopilotService) RemoveCopilotUsers(ctx context.Context, org string, users []string) (*SeatCancellations, *Response, error) {
   429  	u := fmt.Sprintf("orgs/%v/copilot/billing/selected_users", org)
   430  
   431  	body := struct {
   432  		SelectedUsernames []string `json:"selected_usernames"`
   433  	}{
   434  		SelectedUsernames: users,
   435  	}
   436  
   437  	req, err := s.client.NewRequest("DELETE", u, body)
   438  	if err != nil {
   439  		return nil, nil, err
   440  	}
   441  
   442  	var seatCancellations *SeatCancellations
   443  	resp, err := s.client.Do(ctx, req, &seatCancellations)
   444  	if err != nil {
   445  		return nil, resp, err
   446  	}
   447  
   448  	return seatCancellations, resp, nil
   449  }
   450  
   451  // GetSeatDetails gets Copilot for Business seat assignment details for a user.
   452  //
   453  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#get-copilot-seat-assignment-details-for-a-user
   454  //
   455  //meta:operation GET /orgs/{org}/members/{username}/copilot
   456  func (s *CopilotService) GetSeatDetails(ctx context.Context, org, user string) (*CopilotSeatDetails, *Response, error) {
   457  	u := fmt.Sprintf("orgs/%v/members/%v/copilot", org, user)
   458  
   459  	req, err := s.client.NewRequest("GET", u, nil)
   460  	if err != nil {
   461  		return nil, nil, err
   462  	}
   463  
   464  	var seatDetails *CopilotSeatDetails
   465  	resp, err := s.client.Do(ctx, req, &seatDetails)
   466  	if err != nil {
   467  		return nil, resp, err
   468  	}
   469  
   470  	return seatDetails, resp, nil
   471  }
   472  
   473  // GetEnterpriseMetrics gets Copilot usage metrics for an enterprise.
   474  //
   475  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-metrics#get-copilot-metrics-for-an-enterprise
   476  //
   477  //meta:operation GET /enterprises/{enterprise}/copilot/metrics
   478  func (s *CopilotService) GetEnterpriseMetrics(ctx context.Context, enterprise string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) {
   479  	u := fmt.Sprintf("enterprises/%v/copilot/metrics", enterprise)
   480  	u, err := addOptions(u, opts)
   481  	if err != nil {
   482  		return nil, nil, err
   483  	}
   484  
   485  	req, err := s.client.NewRequest("GET", u, nil)
   486  	if err != nil {
   487  		return nil, nil, err
   488  	}
   489  
   490  	var metrics []*CopilotMetrics
   491  	resp, err := s.client.Do(ctx, req, &metrics)
   492  	if err != nil {
   493  		return nil, resp, err
   494  	}
   495  
   496  	return metrics, resp, nil
   497  }
   498  
   499  // GetEnterpriseTeamMetrics gets Copilot usage metrics for an enterprise team.
   500  //
   501  // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-metrics#get-copilot-metrics-for-an-enterprise-team
   502  //
   503  //meta:operation GET /enterprises/{enterprise}/team/{team_slug}/copilot/metrics
   504  func (s *CopilotService) GetEnterpriseTeamMetrics(ctx context.Context, enterprise, team string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) {
   505  	u := fmt.Sprintf("enterprises/%v/team/%v/copilot/metrics", enterprise, team)
   506  	u, err := addOptions(u, opts)
   507  	if err != nil {
   508  		return nil, nil, err
   509  	}
   510  
   511  	req, err := s.client.NewRequest("GET", u, nil)
   512  	if err != nil {
   513  		return nil, nil, err
   514  	}
   515  
   516  	var metrics []*CopilotMetrics
   517  	resp, err := s.client.Do(ctx, req, &metrics)
   518  	if err != nil {
   519  		return nil, resp, err
   520  	}
   521  
   522  	return metrics, resp, nil
   523  }
   524  
   525  // GetOrganizationMetrics gets Copilot usage metrics for an organization.
   526  //
   527  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-metrics#get-copilot-metrics-for-an-organization
   528  //
   529  //meta:operation GET /orgs/{org}/copilot/metrics
   530  func (s *CopilotService) GetOrganizationMetrics(ctx context.Context, org string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) {
   531  	u := fmt.Sprintf("orgs/%v/copilot/metrics", org)
   532  	u, err := addOptions(u, opts)
   533  	if err != nil {
   534  		return nil, nil, err
   535  	}
   536  
   537  	req, err := s.client.NewRequest("GET", u, nil)
   538  	if err != nil {
   539  		return nil, nil, err
   540  	}
   541  
   542  	var metrics []*CopilotMetrics
   543  	resp, err := s.client.Do(ctx, req, &metrics)
   544  	if err != nil {
   545  		return nil, resp, err
   546  	}
   547  
   548  	return metrics, resp, nil
   549  }
   550  
   551  // GetOrganizationTeamMetrics gets Copilot usage metrics for an organization team.
   552  //
   553  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-metrics#get-copilot-metrics-for-a-team
   554  //
   555  //meta:operation GET /orgs/{org}/team/{team_slug}/copilot/metrics
   556  func (s *CopilotService) GetOrganizationTeamMetrics(ctx context.Context, org, team string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) {
   557  	u := fmt.Sprintf("orgs/%v/team/%v/copilot/metrics", org, team)
   558  	u, err := addOptions(u, opts)
   559  	if err != nil {
   560  		return nil, nil, err
   561  	}
   562  
   563  	req, err := s.client.NewRequest("GET", u, nil)
   564  	if err != nil {
   565  		return nil, nil, err
   566  	}
   567  
   568  	var metrics []*CopilotMetrics
   569  	resp, err := s.client.Do(ctx, req, &metrics)
   570  	if err != nil {
   571  		return nil, resp, err
   572  	}
   573  
   574  	return metrics, resp, nil
   575  }