mirror of
https://github.com/google/go-github.git
synced 2026-10-29 00:44:52 +08:00
1351 lines
59 KiB
Go
1351 lines
59 KiB
Go
// Copyright 2023 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"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// CopilotService provides access to the Copilot-related functions
|
|
// in the GitHub API.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot?apiVersion=2022-11-28
|
|
type CopilotService service
|
|
|
|
// CopilotOrganizationDetails represents the details of an organization's Copilot for Business subscription.
|
|
type CopilotOrganizationDetails struct {
|
|
SeatBreakdown *CopilotSeatBreakdown `json:"seat_breakdown"`
|
|
PublicCodeSuggestions string `json:"public_code_suggestions"`
|
|
CopilotChat string `json:"copilot_chat"`
|
|
SeatManagementSetting string `json:"seat_management_setting"`
|
|
}
|
|
|
|
// CopilotSeatBreakdown represents the breakdown of Copilot for Business seats for the organization.
|
|
type CopilotSeatBreakdown struct {
|
|
Total int `json:"total"`
|
|
AddedThisCycle int `json:"added_this_cycle"`
|
|
PendingCancellation int `json:"pending_cancellation"`
|
|
PendingInvitation int `json:"pending_invitation"`
|
|
ActiveThisCycle int `json:"active_this_cycle"`
|
|
InactiveThisCycle int `json:"inactive_this_cycle"`
|
|
}
|
|
|
|
// ListCopilotSeatsResponse represents the Copilot for Business seat assignments for an organization.
|
|
type ListCopilotSeatsResponse struct {
|
|
TotalSeats int64 `json:"total_seats"`
|
|
Seats []*CopilotSeatDetails `json:"seats"`
|
|
}
|
|
|
|
// CopilotSeatDetails represents the details of a Copilot for Business seat.
|
|
type CopilotSeatDetails struct {
|
|
// Assignee can either be a User, Team, or Organization.
|
|
Assignee any `json:"assignee"`
|
|
AssigningTeam *Team `json:"assigning_team,omitempty"`
|
|
PendingCancellationDate *string `json:"pending_cancellation_date,omitempty"`
|
|
LastActivityAt *Timestamp `json:"last_activity_at,omitempty"`
|
|
LastActivityEditor *string `json:"last_activity_editor,omitempty"`
|
|
CreatedAt *Timestamp `json:"created_at"`
|
|
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
|
|
PlanType *string `json:"plan_type,omitempty"`
|
|
}
|
|
|
|
// SeatAssignments represents the number of seats assigned.
|
|
type SeatAssignments struct {
|
|
SeatsCreated int `json:"seats_created"`
|
|
}
|
|
|
|
// SeatCancellations represents the number of seats cancelled.
|
|
type SeatCancellations struct {
|
|
SeatsCancelled int `json:"seats_cancelled"`
|
|
}
|
|
|
|
// CopilotMetricsListOptions represents the optional parameters to the CopilotService get metrics methods.
|
|
type CopilotMetricsListOptions struct {
|
|
Since *time.Time `url:"since,omitempty"`
|
|
Until *time.Time `url:"until,omitempty"`
|
|
|
|
ListOptions
|
|
}
|
|
|
|
// CopilotIDECodeCompletionsLanguage represents Copilot usage metrics for completions in the IDE for a language.
|
|
type CopilotIDECodeCompletionsLanguage struct {
|
|
Name string `json:"name"`
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
}
|
|
|
|
// CopilotIDECodeCompletionsModelLanguage represents Copilot usage metrics for completions in the IDE for a model and language.
|
|
type CopilotIDECodeCompletionsModelLanguage struct {
|
|
Name string `json:"name"`
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
TotalCodeSuggestions int `json:"total_code_suggestions"`
|
|
TotalCodeAcceptances int `json:"total_code_acceptances"`
|
|
TotalCodeLinesSuggested int `json:"total_code_lines_suggested"`
|
|
TotalCodeLinesAccepted int `json:"total_code_lines_accepted"`
|
|
}
|
|
|
|
// CopilotIDECodeCompletionsModel represents Copilot usage metrics for completions in the IDE for a model.
|
|
type CopilotIDECodeCompletionsModel struct {
|
|
Name string `json:"name"`
|
|
IsCustomModel bool `json:"is_custom_model"`
|
|
CustomModelTrainingDate *string `json:"custom_model_training_date,omitempty"`
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
Languages []*CopilotIDECodeCompletionsModelLanguage `json:"languages"`
|
|
}
|
|
|
|
// CopilotIDECodeCompletionsEditor represents Copilot usage metrics for completions in the IDE for an editor.
|
|
type CopilotIDECodeCompletionsEditor struct {
|
|
Name string `json:"name"`
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
Models []*CopilotIDECodeCompletionsModel `json:"models"`
|
|
}
|
|
|
|
// CopilotIDECodeCompletions represents Copilot usage metrics for Copilot code completions in the IDE, categorized by editor, model and language.
|
|
type CopilotIDECodeCompletions struct {
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
Languages []*CopilotIDECodeCompletionsLanguage `json:"languages"`
|
|
Editors []*CopilotIDECodeCompletionsEditor `json:"editors"`
|
|
}
|
|
|
|
// CopilotIDEChatModel represents Copilot usage metrics for chatting with a model in the IDE.
|
|
type CopilotIDEChatModel struct {
|
|
Name string `json:"name"`
|
|
IsCustomModel bool `json:"is_custom_model"`
|
|
CustomModelTrainingDate *string `json:"custom_model_training_date,omitempty"`
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
TotalChats int `json:"total_chats"`
|
|
TotalChatInsertionEvents int `json:"total_chat_insertion_events"`
|
|
TotalChatCopyEvents int `json:"total_chat_copy_events"`
|
|
}
|
|
|
|
// CopilotIDEChatEditor represents Copilot usage metrics for chatting with a model in the IDE, categorized by editor and model.
|
|
type CopilotIDEChatEditor struct {
|
|
Name string `json:"name"`
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
Models []*CopilotIDEChatModel `json:"models"`
|
|
}
|
|
|
|
// CopilotIDEChat represents Copilot usage metrics for Copilot Chat in the IDE, categorized by editor and model.
|
|
type CopilotIDEChat struct {
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
Editors []*CopilotIDEChatEditor `json:"editors"`
|
|
}
|
|
|
|
// CopilotDotcomChatModel represents Copilot usage metrics for chatting with a model in the webbrowser.
|
|
type CopilotDotcomChatModel struct {
|
|
Name string `json:"name"`
|
|
IsCustomModel bool `json:"is_custom_model"`
|
|
CustomModelTrainingDate *string `json:"custom_model_training_date,omitempty"`
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
TotalChats int `json:"total_chats"`
|
|
}
|
|
|
|
// CopilotDotcomChat represents Copilot usage metrics for Copilot Chat in the webbrowser, categorized by model.
|
|
type CopilotDotcomChat struct {
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
Models []*CopilotDotcomChatModel `json:"models"`
|
|
}
|
|
|
|
// CopilotDotcomPullRequestsModel represents Copilot usage metrics for pull requests in the webbrowser, categorized by model.
|
|
type CopilotDotcomPullRequestsModel struct {
|
|
Name string `json:"name"`
|
|
IsCustomModel bool `json:"is_custom_model"`
|
|
CustomModelTrainingDate *string `json:"custom_model_training_date,omitempty"`
|
|
TotalPRSummariesCreated int `json:"total_pr_summaries_created"`
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
}
|
|
|
|
// CopilotDotcomPullRequestsRepository represents Copilot usage metrics for pull requests in the webbrowser, categorized by repository.
|
|
type CopilotDotcomPullRequestsRepository struct {
|
|
Name string `json:"name"`
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
Models []*CopilotDotcomPullRequestsModel `json:"models"`
|
|
}
|
|
|
|
// CopilotDotcomPullRequests represents Copilot usage metrics for pull requests in the webbrowser, categorized by repository and model.
|
|
type CopilotDotcomPullRequests struct {
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
Repositories []*CopilotDotcomPullRequestsRepository `json:"repositories"`
|
|
}
|
|
|
|
// CopilotMetrics represents Copilot usage metrics for a given day.
|
|
type CopilotMetrics struct {
|
|
Date string `json:"date"`
|
|
TotalActiveUsers *int `json:"total_active_users,omitempty"`
|
|
TotalEngagedUsers *int `json:"total_engaged_users,omitempty"`
|
|
CopilotIDECodeCompletions *CopilotIDECodeCompletions `json:"copilot_ide_code_completions,omitempty"`
|
|
CopilotIDEChat *CopilotIDEChat `json:"copilot_ide_chat,omitempty"`
|
|
CopilotDotcomChat *CopilotDotcomChat `json:"copilot_dotcom_chat,omitempty"`
|
|
CopilotDotcomPullRequests *CopilotDotcomPullRequests `json:"copilot_dotcom_pull_requests,omitempty"`
|
|
}
|
|
|
|
// CopilotMetricsReportOptions specifies the optional parameters for single-day metrics report endpoints.
|
|
type CopilotMetricsReportOptions struct {
|
|
Day string `url:"day"` // Required, format: YYYY-MM-DD
|
|
}
|
|
|
|
// CopilotDailyMetricsReport represents the response from 1-day Copilot metrics report endpoints.
|
|
type CopilotDailyMetricsReport struct {
|
|
DownloadLinks []string `json:"download_links"`
|
|
ReportDay string `json:"report_day"`
|
|
}
|
|
|
|
// CopilotMetricsReport represents the response from 28-day Copilot metrics report endpoints.
|
|
type CopilotMetricsReport struct {
|
|
DownloadLinks []string `json:"download_links"`
|
|
ReportStartDay string `json:"report_start_day"`
|
|
ReportEndDay string `json:"report_end_day"`
|
|
}
|
|
|
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
|
func (cp *CopilotSeatDetails) UnmarshalJSON(data []byte) error {
|
|
// Using an alias to avoid infinite recursion when calling json.Unmarshal
|
|
type alias CopilotSeatDetails
|
|
var seatDetail alias
|
|
|
|
if err := json.Unmarshal(data, &seatDetail); err != nil {
|
|
return err
|
|
}
|
|
|
|
cp.AssigningTeam = seatDetail.AssigningTeam
|
|
cp.PendingCancellationDate = seatDetail.PendingCancellationDate
|
|
cp.LastActivityAt = seatDetail.LastActivityAt
|
|
cp.LastActivityEditor = seatDetail.LastActivityEditor
|
|
cp.CreatedAt = seatDetail.CreatedAt
|
|
cp.UpdatedAt = seatDetail.UpdatedAt
|
|
cp.PlanType = seatDetail.PlanType
|
|
|
|
switch v := seatDetail.Assignee.(type) {
|
|
case nil:
|
|
// Assignee can be null according to GitHub API specification.
|
|
// See: https://docs.github.com/rest/copilot/copilot-user-management?apiVersion=2022-11-28#list-all-copilot-seat-assignments-for-an-organization
|
|
// Note: Copilot API is in public preview and subject to change.
|
|
cp.Assignee = nil
|
|
case map[string]any:
|
|
jsonData, err := json.Marshal(seatDetail.Assignee)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v["type"] == nil {
|
|
return errors.New("assignee type field is not set")
|
|
}
|
|
|
|
if t, ok := v["type"].(string); ok && t == "User" {
|
|
var user *User
|
|
if err := json.Unmarshal(jsonData, &user); err != nil {
|
|
return err
|
|
}
|
|
cp.Assignee = user
|
|
} else if t, ok := v["type"].(string); ok && t == "Team" {
|
|
var team *Team
|
|
if err := json.Unmarshal(jsonData, &team); err != nil {
|
|
return err
|
|
}
|
|
cp.Assignee = team
|
|
} else if t, ok := v["type"].(string); ok && t == "Organization" {
|
|
var organization *Organization
|
|
if err := json.Unmarshal(jsonData, &organization); err != nil {
|
|
return err
|
|
}
|
|
cp.Assignee = organization
|
|
} else {
|
|
return fmt.Errorf("unsupported assignee type %v", v["type"])
|
|
}
|
|
default:
|
|
return fmt.Errorf("unsupported assignee type %T", v)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetUser gets the User from the CopilotSeatDetails if the assignee is a user.
|
|
func (cp *CopilotSeatDetails) GetUser() (*User, bool) { u, ok := cp.Assignee.(*User); return u, ok }
|
|
|
|
// GetTeam gets the Team from the CopilotSeatDetails if the assignee is a team.
|
|
func (cp *CopilotSeatDetails) GetTeam() (*Team, bool) { t, ok := cp.Assignee.(*Team); return t, ok }
|
|
|
|
// GetOrganization gets the Organization from the CopilotSeatDetails if the assignee is an organization.
|
|
func (cp *CopilotSeatDetails) GetOrganization() (*Organization, bool) {
|
|
o, ok := cp.Assignee.(*Organization)
|
|
return o, ok
|
|
}
|
|
|
|
// GetCopilotBilling gets Copilot for Business billing information and settings for an organization.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management?apiVersion=2022-11-28#get-copilot-seat-information-and-settings-for-an-organization
|
|
//
|
|
//meta:operation GET /orgs/{org}/copilot/billing
|
|
func (s *CopilotService) GetCopilotBilling(ctx context.Context, org string) (*CopilotOrganizationDetails, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/billing", org)
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var copilotDetails *CopilotOrganizationDetails
|
|
resp, err := s.client.Do(req, &copilotDetails)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return copilotDetails, resp, nil
|
|
}
|
|
|
|
// ListCopilotSeats lists Copilot for Business seat assignments for an organization.
|
|
//
|
|
// To paginate through all seats, populate 'Page' with the number of the last page.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management?apiVersion=2022-11-28#list-all-copilot-seat-assignments-for-an-organization
|
|
//
|
|
//meta:operation GET /orgs/{org}/copilot/billing/seats
|
|
func (s *CopilotService) ListCopilotSeats(ctx context.Context, org string, opts *ListOptions) (*ListCopilotSeatsResponse, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/billing/seats", org)
|
|
u, err := addOptions(u, opts)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var copilotSeats *ListCopilotSeatsResponse
|
|
resp, err := s.client.Do(req, &copilotSeats)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return copilotSeats, resp, nil
|
|
}
|
|
|
|
// ListCopilotEnterpriseSeats lists Copilot for Business seat assignments for an enterprise.
|
|
//
|
|
// To paginate through all seats, populate 'Page' with the number of the last page.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-user-management?apiVersion=2022-11-28#list-all-copilot-seat-assignments-for-an-enterprise
|
|
//
|
|
//meta:operation GET /enterprises/{enterprise}/copilot/billing/seats
|
|
func (s *CopilotService) ListCopilotEnterpriseSeats(ctx context.Context, enterprise string, opts *ListOptions) (*ListCopilotSeatsResponse, *Response, error) {
|
|
u := fmt.Sprintf("enterprises/%v/copilot/billing/seats", enterprise)
|
|
u, err := addOptions(u, opts)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var copilotSeats *ListCopilotSeatsResponse
|
|
resp, err := s.client.Do(req, &copilotSeats)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return copilotSeats, resp, nil
|
|
}
|
|
|
|
// ListOrganizationCopilotCodingAgentRepositoriesResponse represents the response from listing
|
|
// repositories enabled for the Copilot coding agent in an organization.
|
|
type ListOrganizationCopilotCodingAgentRepositoriesResponse struct {
|
|
TotalCount int `json:"total_count"`
|
|
Repositories []*Repository `json:"repositories"`
|
|
}
|
|
|
|
// ListOrganizationCodingAgentRepositories lists repositories enabled for the Copilot coding agent in an organization.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-coding-agent-management?apiVersion=2022-11-28#list-repositories-enabled-for-copilot-cloud-agent-in-an-organization
|
|
//
|
|
//meta:operation GET /orgs/{org}/copilot/coding-agent/permissions/repositories
|
|
func (s *CopilotService) ListOrganizationCodingAgentRepositories(ctx context.Context, org string, opts *ListOptions) (*ListOrganizationCopilotCodingAgentRepositoriesResponse, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/coding-agent/permissions/repositories", org)
|
|
u, err := addOptions(u, opts)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var result *ListOrganizationCopilotCodingAgentRepositoriesResponse
|
|
resp, err := s.client.Do(req, &result)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return result, resp, nil
|
|
}
|
|
|
|
// CopilotOrganizationContentExclusionDetails lists all Copilot content exclusion
|
|
// rules for an organization, keyed by repository full name. Each value is the
|
|
// list of file paths excluded from Copilot for that repository.
|
|
type CopilotOrganizationContentExclusionDetails map[string][]string
|
|
|
|
// GetOrganizationContentExclusionDetails gets the Copilot content exclusion rules for an organization.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-content-exclusion-management?apiVersion=2022-11-28#get-copilot-content-exclusion-rules-for-an-organization
|
|
//
|
|
//meta:operation GET /orgs/{org}/copilot/content_exclusion
|
|
func (s *CopilotService) GetOrganizationContentExclusionDetails(ctx context.Context, org string) (CopilotOrganizationContentExclusionDetails, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/content_exclusion", org)
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
details := CopilotOrganizationContentExclusionDetails{}
|
|
resp, err := s.client.Do(req, &details)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return details, resp, nil
|
|
}
|
|
|
|
// AddCopilotTeams adds teams to the Copilot for Business subscription for an organization.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management?apiVersion=2022-11-28#add-teams-to-the-copilot-subscription-for-an-organization
|
|
//
|
|
//meta:operation POST /orgs/{org}/copilot/billing/selected_teams
|
|
func (s *CopilotService) AddCopilotTeams(ctx context.Context, org string, teamNames []string) (*SeatAssignments, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/billing/selected_teams", org)
|
|
|
|
body := struct {
|
|
SelectedTeams []string `json:"selected_teams"`
|
|
}{
|
|
SelectedTeams: teamNames,
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "POST", u, body)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var seatAssignments *SeatAssignments
|
|
resp, err := s.client.Do(req, &seatAssignments)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return seatAssignments, resp, nil
|
|
}
|
|
|
|
// RemoveCopilotTeams removes teams from the Copilot for Business subscription for an organization.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management?apiVersion=2022-11-28#remove-teams-from-the-copilot-subscription-for-an-organization
|
|
//
|
|
//meta:operation DELETE /orgs/{org}/copilot/billing/selected_teams
|
|
func (s *CopilotService) RemoveCopilotTeams(ctx context.Context, org string, teamNames []string) (*SeatCancellations, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/billing/selected_teams", org)
|
|
|
|
body := struct {
|
|
SelectedTeams []string `json:"selected_teams"`
|
|
}{
|
|
SelectedTeams: teamNames,
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "DELETE", u, body)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var seatCancellations *SeatCancellations
|
|
resp, err := s.client.Do(req, &seatCancellations)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return seatCancellations, resp, nil
|
|
}
|
|
|
|
// AddCopilotUsers adds users to the Copilot for Business subscription for an organization
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management?apiVersion=2022-11-28#add-users-to-the-copilot-subscription-for-an-organization
|
|
//
|
|
//meta:operation POST /orgs/{org}/copilot/billing/selected_users
|
|
func (s *CopilotService) AddCopilotUsers(ctx context.Context, org string, users []string) (*SeatAssignments, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/billing/selected_users", org)
|
|
|
|
body := struct {
|
|
SelectedUsernames []string `json:"selected_usernames"`
|
|
}{
|
|
SelectedUsernames: users,
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "POST", u, body)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var seatAssignments *SeatAssignments
|
|
resp, err := s.client.Do(req, &seatAssignments)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return seatAssignments, resp, nil
|
|
}
|
|
|
|
// RemoveCopilotUsers removes users from the Copilot for Business subscription for an organization.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management?apiVersion=2022-11-28#remove-users-from-the-copilot-subscription-for-an-organization
|
|
//
|
|
//meta:operation DELETE /orgs/{org}/copilot/billing/selected_users
|
|
func (s *CopilotService) RemoveCopilotUsers(ctx context.Context, org string, users []string) (*SeatCancellations, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/billing/selected_users", org)
|
|
|
|
body := struct {
|
|
SelectedUsernames []string `json:"selected_usernames"`
|
|
}{
|
|
SelectedUsernames: users,
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "DELETE", u, body)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var seatCancellations *SeatCancellations
|
|
resp, err := s.client.Do(req, &seatCancellations)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return seatCancellations, resp, nil
|
|
}
|
|
|
|
// GetSeatDetails gets Copilot for Business seat assignment details for a user.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management?apiVersion=2022-11-28#get-copilot-seat-assignment-details-for-a-user
|
|
//
|
|
//meta:operation GET /orgs/{org}/members/{username}/copilot
|
|
func (s *CopilotService) GetSeatDetails(ctx context.Context, org, user string) (*CopilotSeatDetails, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/members/%v/copilot", org, user)
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var seatDetails *CopilotSeatDetails
|
|
resp, err := s.client.Do(req, &seatDetails)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return seatDetails, resp, nil
|
|
}
|
|
|
|
// GetEnterpriseMetrics gets Copilot usage metrics for an enterprise.
|
|
//
|
|
// Deprecated: This endpoint was closed down on April 2, 2026 for github.com.
|
|
// It may still be available for GitHub Enterprise Server. Use GetEnterpriseDailyMetricsReport
|
|
// or GetEnterpriseMetricsReport instead.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-metrics?apiVersion=2022-11-28#get-copilot-metrics-for-an-enterprise
|
|
//
|
|
//meta:operation GET /enterprises/{enterprise}/copilot/metrics
|
|
func (s *CopilotService) GetEnterpriseMetrics(ctx context.Context, enterprise string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) {
|
|
u := fmt.Sprintf("enterprises/%v/copilot/metrics", enterprise)
|
|
u, err := addOptions(u, opts)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var metrics []*CopilotMetrics
|
|
resp, err := s.client.Do(req, &metrics)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return metrics, resp, nil
|
|
}
|
|
|
|
// GetEnterpriseTeamMetrics gets Copilot usage metrics for an enterprise team.
|
|
//
|
|
// Deprecated: This endpoint was closed down on April 2, 2026 for github.com.
|
|
// It may still be available for GitHub Enterprise Server. Use GetEnterpriseDailyMetricsReport
|
|
// or GetEnterpriseMetricsReport instead.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-metrics?apiVersion=2022-11-28#get-copilot-metrics-for-an-enterprise-team
|
|
//
|
|
//meta:operation GET /enterprises/{enterprise}/team/{team_slug}/copilot/metrics
|
|
func (s *CopilotService) GetEnterpriseTeamMetrics(ctx context.Context, enterprise, team string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) {
|
|
u := fmt.Sprintf("enterprises/%v/team/%v/copilot/metrics", enterprise, team)
|
|
u, err := addOptions(u, opts)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var metrics []*CopilotMetrics
|
|
resp, err := s.client.Do(req, &metrics)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return metrics, resp, nil
|
|
}
|
|
|
|
// GetOrganizationMetrics gets Copilot usage metrics for an organization.
|
|
//
|
|
// Deprecated: This endpoint was closed down on April 2, 2026 for github.com.
|
|
// It may still be available for GitHub Enterprise Server. Use GetOrganizationDailyMetricsReport
|
|
// or GetOrganizationMetricsReport instead.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-metrics?apiVersion=2022-11-28#get-copilot-metrics-for-an-organization
|
|
//
|
|
//meta:operation GET /orgs/{org}/copilot/metrics
|
|
func (s *CopilotService) GetOrganizationMetrics(ctx context.Context, org string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/metrics", org)
|
|
u, err := addOptions(u, opts)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var metrics []*CopilotMetrics
|
|
resp, err := s.client.Do(req, &metrics)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return metrics, resp, nil
|
|
}
|
|
|
|
// GetOrganizationTeamMetrics gets Copilot usage metrics for an organization team.
|
|
//
|
|
// Deprecated: This endpoint was closed down on April 2, 2026 for github.com.
|
|
// It may still be available for GitHub Enterprise Server. Use GetOrganizationDailyMetricsReport
|
|
// or GetOrganizationMetricsReport instead.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-metrics?apiVersion=2022-11-28#get-copilot-metrics-for-a-team
|
|
//
|
|
//meta:operation GET /orgs/{org}/team/{team_slug}/copilot/metrics
|
|
func (s *CopilotService) GetOrganizationTeamMetrics(ctx context.Context, org, team string, opts *CopilotMetricsListOptions) ([]*CopilotMetrics, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/team/%v/copilot/metrics", org, team)
|
|
u, err := addOptions(u, opts)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var metrics []*CopilotMetrics
|
|
resp, err := s.client.Do(req, &metrics)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return metrics, resp, nil
|
|
}
|
|
|
|
// GetEnterpriseDailyMetricsReport gets a report containing Copilot metrics for a single day for an enterprise.
|
|
//
|
|
// Use DownloadDailyMetrics to decode the payloads served at the returned download links.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage-metrics?apiVersion=2022-11-28#get-copilot-enterprise-usage-metrics-for-a-specific-day
|
|
//
|
|
//meta:operation GET /enterprises/{enterprise}/copilot/metrics/reports/enterprise-1-day
|
|
func (s *CopilotService) GetEnterpriseDailyMetricsReport(ctx context.Context, enterprise string, opts *CopilotMetricsReportOptions) (*CopilotDailyMetricsReport, *Response, error) {
|
|
u := fmt.Sprintf("enterprises/%v/copilot/metrics/reports/enterprise-1-day", enterprise)
|
|
u, err := addOptions(u, opts)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var report *CopilotDailyMetricsReport
|
|
resp, err := s.client.Do(req, &report)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return report, resp, nil
|
|
}
|
|
|
|
// GetEnterpriseMetricsReport gets a report containing Copilot metrics for a 28-day rolling window for an enterprise.
|
|
//
|
|
// Use DownloadPeriodicMetrics to decode the payloads served at the returned download links.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage-metrics?apiVersion=2022-11-28#get-copilot-enterprise-usage-metrics
|
|
//
|
|
//meta:operation GET /enterprises/{enterprise}/copilot/metrics/reports/enterprise-28-day/latest
|
|
func (s *CopilotService) GetEnterpriseMetricsReport(ctx context.Context, enterprise string) (*CopilotMetricsReport, *Response, error) {
|
|
u := fmt.Sprintf("enterprises/%v/copilot/metrics/reports/enterprise-28-day/latest", enterprise)
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var report *CopilotMetricsReport
|
|
resp, err := s.client.Do(req, &report)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return report, resp, nil
|
|
}
|
|
|
|
// GetEnterpriseUsersDailyMetricsReport gets a report containing Copilot user metrics for a single day for an enterprise.
|
|
//
|
|
// Use DownloadUserDailyMetrics to decode the payloads served at the returned download links.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage-metrics?apiVersion=2022-11-28#get-copilot-users-usage-metrics-for-a-specific-day
|
|
//
|
|
//meta:operation GET /enterprises/{enterprise}/copilot/metrics/reports/users-1-day
|
|
func (s *CopilotService) GetEnterpriseUsersDailyMetricsReport(ctx context.Context, enterprise string, opts *CopilotMetricsReportOptions) (*CopilotDailyMetricsReport, *Response, error) {
|
|
u := fmt.Sprintf("enterprises/%v/copilot/metrics/reports/users-1-day", enterprise)
|
|
u, err := addOptions(u, opts)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var report *CopilotDailyMetricsReport
|
|
resp, err := s.client.Do(req, &report)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return report, resp, nil
|
|
}
|
|
|
|
// GetEnterpriseUsersMetricsReport gets a report containing Copilot user metrics for a 28-day rolling window for an enterprise.
|
|
//
|
|
// Use DownloadUserPeriodicMetrics to decode the payloads served at the returned download links.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage-metrics?apiVersion=2022-11-28#get-copilot-users-usage-metrics
|
|
//
|
|
//meta:operation GET /enterprises/{enterprise}/copilot/metrics/reports/users-28-day/latest
|
|
func (s *CopilotService) GetEnterpriseUsersMetricsReport(ctx context.Context, enterprise string) (*CopilotMetricsReport, *Response, error) {
|
|
u := fmt.Sprintf("enterprises/%v/copilot/metrics/reports/users-28-day/latest", enterprise)
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var report *CopilotMetricsReport
|
|
resp, err := s.client.Do(req, &report)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return report, resp, nil
|
|
}
|
|
|
|
// GetOrganizationDailyMetricsReport gets a report containing Copilot metrics for a single day for an organization.
|
|
//
|
|
// Use DownloadDailyMetrics to decode the payloads served at the returned download links.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage-metrics?apiVersion=2022-11-28#get-copilot-organization-usage-metrics-for-a-specific-day
|
|
//
|
|
//meta:operation GET /orgs/{org}/copilot/metrics/reports/organization-1-day
|
|
func (s *CopilotService) GetOrganizationDailyMetricsReport(ctx context.Context, org string, opts *CopilotMetricsReportOptions) (*CopilotDailyMetricsReport, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/metrics/reports/organization-1-day", org)
|
|
u, err := addOptions(u, opts)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var report *CopilotDailyMetricsReport
|
|
resp, err := s.client.Do(req, &report)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return report, resp, nil
|
|
}
|
|
|
|
// GetOrganizationMetricsReport gets a report containing Copilot metrics for a 28-day rolling window for an organization.
|
|
//
|
|
// Use DownloadPeriodicMetrics to decode the payloads served at the returned download links.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage-metrics?apiVersion=2022-11-28#get-copilot-organization-usage-metrics
|
|
//
|
|
//meta:operation GET /orgs/{org}/copilot/metrics/reports/organization-28-day/latest
|
|
func (s *CopilotService) GetOrganizationMetricsReport(ctx context.Context, org string) (*CopilotMetricsReport, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/metrics/reports/organization-28-day/latest", org)
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var report *CopilotMetricsReport
|
|
resp, err := s.client.Do(req, &report)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return report, resp, nil
|
|
}
|
|
|
|
// GetOrganizationUsersDailyMetricsReport gets a report containing Copilot user metrics for a single day for an organization.
|
|
//
|
|
// Use DownloadUserDailyMetrics to decode the payloads served at the returned download links.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage-metrics?apiVersion=2022-11-28#get-copilot-organization-users-usage-metrics-for-a-specific-day
|
|
//
|
|
//meta:operation GET /orgs/{org}/copilot/metrics/reports/users-1-day
|
|
func (s *CopilotService) GetOrganizationUsersDailyMetricsReport(ctx context.Context, org string, opts *CopilotMetricsReportOptions) (*CopilotDailyMetricsReport, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/metrics/reports/users-1-day", org)
|
|
u, err := addOptions(u, opts)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var report *CopilotDailyMetricsReport
|
|
resp, err := s.client.Do(req, &report)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return report, resp, nil
|
|
}
|
|
|
|
// GetOrganizationUsersMetricsReport gets a report containing Copilot user metrics for a 28-day rolling window for an organization.
|
|
//
|
|
// Use DownloadUserPeriodicMetrics to decode the payloads served at the returned download links.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage-metrics?apiVersion=2022-11-28#get-copilot-organization-users-usage-metrics
|
|
//
|
|
//meta:operation GET /orgs/{org}/copilot/metrics/reports/users-28-day/latest
|
|
func (s *CopilotService) GetOrganizationUsersMetricsReport(ctx context.Context, org string) (*CopilotMetricsReport, *Response, error) {
|
|
u := fmt.Sprintf("orgs/%v/copilot/metrics/reports/users-28-day/latest", org)
|
|
|
|
req, err := s.client.NewRequest(ctx, "GET", u, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var report *CopilotMetricsReport
|
|
resp, err := s.client.Do(req, &report)
|
|
if err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return report, resp, nil
|
|
}
|
|
|
|
// DownloadCopilotMetrics downloads a Copilot metrics report from the provided download link
|
|
// and decodes it as a []*CopilotMetrics.
|
|
//
|
|
// Deprecated: Use DownloadDailyMetrics,
|
|
// DownloadPeriodicMetrics, DownloadUserDailyMetrics, DownloadUserPeriodicMetrics instead.
|
|
// The payloads served at the download links returned by the new
|
|
// Get*MetricsReport endpoints on GitHub.com do not match the CopilotMetrics shape
|
|
// (see https://github.com/google/go-github/issues/4136).
|
|
// This method is retained
|
|
// for GitHub Enterprise Server installations that may still serve the legacy shape.
|
|
func (s *CopilotService) DownloadCopilotMetrics(ctx context.Context, url string) ([]*CopilotMetrics, *Response, error) {
|
|
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
resp, err := s.client.BareDo(req)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var metrics []*CopilotMetrics
|
|
if err := json.NewDecoder(resp.Body).Decode(&metrics); err != nil {
|
|
return nil, resp, err
|
|
}
|
|
|
|
return metrics, resp, nil
|
|
}
|
|
|
|
// CopilotMetricsPullRequests represents pull request totals in a Copilot metrics report.
|
|
type CopilotMetricsPullRequests struct {
|
|
TotalReviewed *int `json:"total_reviewed,omitempty"`
|
|
TotalCreated *int `json:"total_created,omitempty"`
|
|
TotalCreatedByCopilot *int `json:"total_created_by_copilot,omitempty"`
|
|
TotalReviewedByCopilot *int `json:"total_reviewed_by_copilot,omitempty"`
|
|
TotalMerged *int `json:"total_merged,omitempty"`
|
|
MedianMinutesToMerge *float64 `json:"median_minutes_to_merge,omitempty"`
|
|
TotalSuggestions *int `json:"total_suggestions,omitempty"`
|
|
TotalAppliedSuggestions *int `json:"total_applied_suggestions,omitempty"`
|
|
TotalMergedCreatedByCopilot *int `json:"total_merged_created_by_copilot,omitempty"`
|
|
MedianMinutesToMergeCopilotAuthored *float64 `json:"median_minutes_to_merge_copilot_authored,omitempty"`
|
|
TotalCopilotSuggestions *int `json:"total_copilot_suggestions,omitempty"`
|
|
TotalCopilotAppliedSuggestions *int `json:"total_copilot_applied_suggestions,omitempty"`
|
|
MedianMinutesToMergeCopilotReviewed *float64 `json:"median_minutes_to_merge_copilot_reviewed,omitempty"`
|
|
TotalMergedReviewedByCopilot *int `json:"total_merged_reviewed_by_copilot,omitempty"`
|
|
}
|
|
|
|
// CopilotMetricsCodeActivity captures the code-generation activity counts and lines-of-code (LOC)
|
|
// suggestion totals shared across the per-IDE, per-feature, per-language, and per-model breakdowns
|
|
// in a Copilot metrics report.
|
|
type CopilotMetricsCodeActivity struct {
|
|
CodeGenerationActivityCount *int `json:"code_generation_activity_count,omitempty"`
|
|
CodeAcceptanceActivityCount *int `json:"code_acceptance_activity_count,omitempty"`
|
|
LOCSuggestedToAddSum *int `json:"loc_suggested_to_add_sum,omitempty"`
|
|
LOCSuggestedToDeleteSum *int `json:"loc_suggested_to_delete_sum,omitempty"`
|
|
LOCAddedSum *int `json:"loc_added_sum,omitempty"`
|
|
LOCDeletedSum *int `json:"loc_deleted_sum,omitempty"`
|
|
}
|
|
|
|
// CopilotMetricsChatPanel captures per-mode chat panel interaction counts shared across daily,
|
|
// periodic, and user metrics reports. Each field is a subset of user_initiated_interaction_count
|
|
// attributed to that chat panel mode.
|
|
type CopilotMetricsChatPanel struct {
|
|
ChatPanelAgentMode *int `json:"chat_panel_agent_mode,omitempty"`
|
|
ChatPanelAskMode *int `json:"chat_panel_ask_mode,omitempty"`
|
|
ChatPanelCustomMode *int `json:"chat_panel_custom_mode,omitempty"`
|
|
ChatPanelEditMode *int `json:"chat_panel_edit_mode,omitempty"`
|
|
ChatPanelUnknownMode *int `json:"chat_panel_unknown_mode,omitempty"`
|
|
}
|
|
|
|
// CopilotMetricsIDE represents per-IDE aggregate totals in a Copilot metrics report.
|
|
type CopilotMetricsIDE struct {
|
|
IDE string `json:"ide"`
|
|
UserInitiatedInteractionCount *int `json:"user_initiated_interaction_count,omitempty"`
|
|
CopilotMetricsCodeActivity
|
|
}
|
|
|
|
// CopilotMetricsFeature represents per-feature aggregate totals in a Copilot metrics report.
|
|
type CopilotMetricsFeature struct {
|
|
Feature string `json:"feature"`
|
|
UserInitiatedInteractionCount *int `json:"user_initiated_interaction_count,omitempty"`
|
|
CopilotMetricsCodeActivity
|
|
}
|
|
|
|
// CopilotMetricsLanguageFeature represents per-language-feature totals in a Copilot metrics report.
|
|
type CopilotMetricsLanguageFeature struct {
|
|
Language string `json:"language"`
|
|
Feature string `json:"feature"`
|
|
CopilotMetricsCodeActivity
|
|
}
|
|
|
|
// CopilotMetricsLanguageModel represents per-language-model totals in a Copilot metrics report.
|
|
type CopilotMetricsLanguageModel struct {
|
|
Language string `json:"language"`
|
|
Model string `json:"model"`
|
|
CopilotMetricsCodeActivity
|
|
}
|
|
|
|
// CopilotMetricsModelFeature represents per-model-feature totals in a Copilot metrics report.
|
|
type CopilotMetricsModelFeature struct {
|
|
Model string `json:"model"`
|
|
Feature string `json:"feature"`
|
|
UserInitiatedInteractionCount *int `json:"user_initiated_interaction_count,omitempty"`
|
|
CopilotMetricsCodeActivity
|
|
}
|
|
|
|
// CopilotMetricsCLIVersion represents the last known Copilot CLI version seen in a metrics report.
|
|
type CopilotMetricsCLIVersion struct {
|
|
SampledAt *Timestamp `json:"sampled_at,omitempty"`
|
|
CLIVersion string `json:"cli_version"`
|
|
}
|
|
|
|
// CopilotMetricsCLITokenUsage represents Copilot CLI token totals in a metrics report.
|
|
type CopilotMetricsCLITokenUsage struct {
|
|
AvgTokensPerRequest *float64 `json:"avg_tokens_per_request,omitempty"`
|
|
OutputTokensSum *int `json:"output_tokens_sum,omitempty"`
|
|
PromptTokensSum *int `json:"prompt_tokens_sum,omitempty"`
|
|
}
|
|
|
|
// CopilotMetricsCLI represents Copilot CLI totals in a metrics report.
|
|
type CopilotMetricsCLI struct {
|
|
SessionCount *int `json:"session_count,omitempty"`
|
|
RequestCount *int `json:"request_count,omitempty"`
|
|
PromptCount *int `json:"prompt_count,omitempty"`
|
|
TokenUsage *CopilotMetricsCLITokenUsage `json:"token_usage,omitempty"`
|
|
LastKnownCLIVersion *CopilotMetricsCLIVersion `json:"last_known_cli_version,omitempty"`
|
|
}
|
|
|
|
// CopilotMetricsCopilotAppTokenUsage represents Copilot app token totals in a metrics report.
|
|
type CopilotMetricsCopilotAppTokenUsage struct {
|
|
AvgTokensPerRequest *float64 `json:"avg_tokens_per_request,omitempty"`
|
|
OutputTokensSum *int `json:"output_tokens_sum,omitempty"`
|
|
PromptTokensSum *int `json:"prompt_tokens_sum,omitempty"`
|
|
}
|
|
|
|
// CopilotMetricsCopilotApp represents Copilot app totals in a metrics report.
|
|
//
|
|
// Unlike totals_by_cli, there is no last_known_app_version field.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/en/copilot/reference/copilot-usage-metrics/copilot-usage-metrics#copilot-app-metrics-fields
|
|
type CopilotMetricsCopilotApp struct {
|
|
SessionCount *int `json:"session_count,omitempty"`
|
|
RequestCount *int `json:"request_count,omitempty"`
|
|
PromptCount *int `json:"prompt_count,omitempty"`
|
|
TokenUsage *CopilotMetricsCopilotAppTokenUsage `json:"token_usage,omitempty"`
|
|
}
|
|
|
|
// CopilotMetricsThirdPartyAgent represents per-agent app totals in a Copilot usage metrics report.
|
|
//
|
|
// AgentID is the stable grouping key. AgentName is for display and can change.
|
|
// UserInitiatedInteractionCount is agent-app job starts; it is not the same as
|
|
// the top-level user_initiated_interaction_count on the parent metrics object.
|
|
// SessionCount is included on aggregated enterprise and organization reports
|
|
// and omitted from per-user reports.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/en/copilot/reference/copilot-usage-metrics/copilot-usage-metrics#agent-apps-metrics-fields
|
|
type CopilotMetricsThirdPartyAgent struct {
|
|
AgentName string `json:"agent_name"`
|
|
AgentID string `json:"agent_id"`
|
|
UserInitiatedInteractionCount *int `json:"user_initiated_interaction_count,omitempty"`
|
|
SessionCount *int `json:"session_count,omitempty"`
|
|
}
|
|
|
|
// CopilotMetricsAIAdoptionPhase represents a user's AI adoption phase classification
|
|
// in a Copilot usage metrics report.
|
|
//
|
|
// Phase assignment uses a trailing 28-day engagement window and may change day to day.
|
|
// Version identifies the classification model (for example, "v1").
|
|
//
|
|
// GitHub API docs: https://docs.github.com/en/copilot/reference/copilot-usage-metrics/copilot-usage-metrics#ai-adoption-phase-fields
|
|
type CopilotMetricsAIAdoptionPhase struct {
|
|
PhaseNumber int `json:"phase_number"`
|
|
Phase string `json:"phase"`
|
|
Version string `json:"version"`
|
|
}
|
|
|
|
// CopilotMetricsAIAdoptionPhaseTotals represents aggregated per-phase averages in an
|
|
// enterprise or organization Copilot usage metrics report.
|
|
//
|
|
// Aggregated metrics report the average per user within each phase rather than the sum,
|
|
// except TotalEngagedUsers and TotalPullRequestsMerged.
|
|
//
|
|
// GitHub API docs: https://docs.github.com/en/copilot/reference/copilot-usage-metrics/copilot-usage-metrics#ai-adoption-phase-fields
|
|
type CopilotMetricsAIAdoptionPhaseTotals struct {
|
|
Phase string `json:"phase"`
|
|
PhaseNumber int `json:"phase_number"`
|
|
TotalEngagedUsers int `json:"total_engaged_users"`
|
|
AvgUserInitiatedInteractions float64 `json:"avg_user_initiated_interactions"`
|
|
AvgCodeGenerationActivities float64 `json:"avg_code_generation_activities"`
|
|
AvgCodeAcceptanceActivities float64 `json:"avg_code_acceptance_activities"`
|
|
AvgLOCAdded float64 `json:"avg_loc_added"`
|
|
AvgLOCDeleted float64 `json:"avg_loc_deleted"`
|
|
AvgPullRequestsReviewed float64 `json:"avg_pull_requests_reviewed"`
|
|
AvgPullRequestsCreated float64 `json:"avg_pull_requests_created"`
|
|
AvgPullRequestsMerged float64 `json:"avg_pull_requests_merged"`
|
|
TotalPullRequestsMerged int `json:"total_pull_requests_merged"`
|
|
AvgPullRequestsMedianMinutesToMerge float64 `json:"avg_pull_requests_median_minutes_to_merge"`
|
|
AvgPullRequestsMinutesToReview float64 `json:"avg_pull_requests_minutes_to_review"`
|
|
AvgPullRequestsReviewCycles float64 `json:"avg_pull_requests_review_cycles"`
|
|
}
|
|
|
|
// CopilotDailyMetrics represents the payload downloaded from a 1-day Copilot usage metrics report.
|
|
type CopilotDailyMetrics struct {
|
|
Day string `json:"day"`
|
|
OrganizationID *string `json:"organization_id,omitempty"`
|
|
EnterpriseID *string `json:"enterprise_id,omitempty"`
|
|
DailyActiveCLIUsers *int `json:"daily_active_cli_users,omitempty"`
|
|
DailyActiveCopilotAppUsers *int `json:"daily_active_copilot_app_users,omitempty"`
|
|
DailyActiveUsers *int `json:"daily_active_users,omitempty"`
|
|
DailyActiveCopilotCloudAgentUsers *int `json:"daily_active_copilot_cloud_agent_users,omitempty"`
|
|
WeeklyActiveUsers *int `json:"weekly_active_users,omitempty"`
|
|
WeeklyActiveCopilotCloudAgentUsers *int `json:"weekly_active_copilot_cloud_agent_users,omitempty"`
|
|
MonthlyActiveUsers *int `json:"monthly_active_users,omitempty"`
|
|
MonthlyActiveChatUsers *int `json:"monthly_active_chat_users,omitempty"`
|
|
MonthlyActiveAgentUsers *int `json:"monthly_active_agent_users,omitempty"`
|
|
MonthlyActiveCopilotCloudAgentUsers *int `json:"monthly_active_copilot_cloud_agent_users,omitempty"`
|
|
DailyActiveCopilotCodeReviewUsers *int `json:"daily_active_copilot_code_review_users,omitempty"`
|
|
WeeklyActiveCopilotCodeReviewUsers *int `json:"weekly_active_copilot_code_review_users,omitempty"`
|
|
MonthlyActiveCopilotCodeReviewUsers *int `json:"monthly_active_copilot_code_review_users,omitempty"`
|
|
DailyPassiveCopilotCodeReviewUsers *int `json:"daily_passive_copilot_code_review_users,omitempty"`
|
|
WeeklyPassiveCopilotCodeReviewUsers *int `json:"weekly_passive_copilot_code_review_users,omitempty"`
|
|
MonthlyPassiveCopilotCodeReviewUsers *int `json:"monthly_passive_copilot_code_review_users,omitempty"`
|
|
UserInitiatedInteractionCount *int `json:"user_initiated_interaction_count,omitempty"`
|
|
CopilotMetricsChatPanel
|
|
CodeGenerationActivityCount *int `json:"code_generation_activity_count,omitempty"`
|
|
CodeAcceptanceActivityCount *int `json:"code_acceptance_activity_count,omitempty"`
|
|
TotalsByIDE []*CopilotMetricsIDE `json:"totals_by_ide,omitempty"`
|
|
TotalsByFeature []*CopilotMetricsFeature `json:"totals_by_feature,omitempty"`
|
|
TotalsByLanguageFeature []*CopilotMetricsLanguageFeature `json:"totals_by_language_feature,omitempty"`
|
|
TotalsByLanguageModel []*CopilotMetricsLanguageModel `json:"totals_by_language_model,omitempty"`
|
|
TotalsByModelFeature []*CopilotMetricsModelFeature `json:"totals_by_model_feature,omitempty"`
|
|
TotalsByCLI *CopilotMetricsCLI `json:"totals_by_cli,omitempty"`
|
|
TotalsByCopilotApp *CopilotMetricsCopilotApp `json:"totals_by_copilot_app,omitempty"`
|
|
TotalsBy3rdPartyAgent []*CopilotMetricsThirdPartyAgent `json:"totals_by_3rd_party_agent,omitempty"`
|
|
TotalsByAIAdoptionPhase []*CopilotMetricsAIAdoptionPhaseTotals `json:"totals_by_ai_adoption_phase,omitempty"`
|
|
LOCSuggestedToAddSum *int `json:"loc_suggested_to_add_sum,omitempty"`
|
|
LOCSuggestedToDeleteSum *int `json:"loc_suggested_to_delete_sum,omitempty"`
|
|
LOCAddedSum *int `json:"loc_added_sum,omitempty"`
|
|
LOCDeletedSum *int `json:"loc_deleted_sum,omitempty"`
|
|
PullRequests *CopilotMetricsPullRequests `json:"pull_requests,omitempty"`
|
|
}
|
|
|
|
// CopilotPeriodicMetrics represents the payload downloaded from a multi-day (e.g. 28-day rolling)
|
|
// Copilot usage metrics report. The DayTotals field contains one CopilotDailyMetrics entry per day
|
|
// in the reporting window. Window-level metadata (ReportStartDay, ReportEndDay, CreatedAt) lives on
|
|
// this parent struct; each DayTotals entry only populates fields scoped to that day.
|
|
type CopilotPeriodicMetrics struct {
|
|
ReportStartDay string `json:"report_start_day"`
|
|
ReportEndDay string `json:"report_end_day"`
|
|
OrganizationID *string `json:"organization_id,omitempty"`
|
|
EnterpriseID *string `json:"enterprise_id,omitempty"`
|
|
CreatedAt *Timestamp `json:"created_at,omitempty"`
|
|
DayTotals []*CopilotDailyMetrics `json:"day_totals,omitempty"`
|
|
}
|
|
|
|
// CopilotUserMetricsPluginVersion represents the last known plugin version used in an IDE by a Copilot user.
|
|
type CopilotUserMetricsPluginVersion struct {
|
|
SampledAt *Timestamp `json:"sampled_at,omitempty"`
|
|
Plugin string `json:"plugin"`
|
|
PluginVersion string `json:"plugin_version"`
|
|
}
|
|
|
|
// CopilotUserMetricsIDEVersion represents the last known IDE version used by a Copilot user.
|
|
type CopilotUserMetricsIDEVersion struct {
|
|
SampledAt *Timestamp `json:"sampled_at,omitempty"`
|
|
IDEVersion string `json:"ide_version"`
|
|
}
|
|
|
|
// CopilotUserMetricsIDE represents per-IDE totals for a single Copilot user in a user metrics report.
|
|
type CopilotUserMetricsIDE struct {
|
|
IDE string `json:"ide"`
|
|
UserInitiatedInteractionCount *int `json:"user_initiated_interaction_count,omitempty"`
|
|
CopilotMetricsCodeActivity
|
|
LastKnownPluginVersion *CopilotUserMetricsPluginVersion `json:"last_known_plugin_version,omitempty"`
|
|
LastKnownIDEVersion *CopilotUserMetricsIDEVersion `json:"last_known_ide_version,omitempty"`
|
|
}
|
|
|
|
// CopilotUserDailyMetrics represents a single user's per-day Copilot usage metrics record from a
|
|
// 1-day user metrics report. User metrics reports are served as newline-delimited JSON.
|
|
type CopilotUserDailyMetrics struct {
|
|
UserID int `json:"user_id"`
|
|
UserLogin string `json:"user_login"`
|
|
Day string `json:"day"`
|
|
OrganizationID *string `json:"organization_id,omitempty"`
|
|
EnterpriseID *string `json:"enterprise_id,omitempty"`
|
|
AICreditsUsed *float64 `json:"ai_credits_used,omitempty"`
|
|
UserInitiatedInteractionCount *int `json:"user_initiated_interaction_count,omitempty"`
|
|
CopilotMetricsChatPanel
|
|
CodeGenerationActivityCount *int `json:"code_generation_activity_count,omitempty"`
|
|
CodeAcceptanceActivityCount *int `json:"code_acceptance_activity_count,omitempty"`
|
|
TotalsByIDE []*CopilotUserMetricsIDE `json:"totals_by_ide,omitempty"`
|
|
TotalsByFeature []*CopilotMetricsFeature `json:"totals_by_feature,omitempty"`
|
|
TotalsByLanguageFeature []*CopilotMetricsLanguageFeature `json:"totals_by_language_feature,omitempty"`
|
|
TotalsByLanguageModel []*CopilotMetricsLanguageModel `json:"totals_by_language_model,omitempty"`
|
|
TotalsByModelFeature []*CopilotMetricsModelFeature `json:"totals_by_model_feature,omitempty"`
|
|
TotalsByCLI *CopilotMetricsCLI `json:"totals_by_cli,omitempty"`
|
|
TotalsByCopilotApp *CopilotMetricsCopilotApp `json:"totals_by_copilot_app,omitempty"`
|
|
TotalsBy3rdPartyAgent []*CopilotMetricsThirdPartyAgent `json:"totals_by_3rd_party_agent,omitempty"`
|
|
AIAdoptionPhase *CopilotMetricsAIAdoptionPhase `json:"ai_adoption_phase,omitempty"`
|
|
UsedAgent *bool `json:"used_agent,omitempty"`
|
|
UsedChat *bool `json:"used_chat,omitempty"`
|
|
UsedCLI *bool `json:"used_cli,omitempty"`
|
|
UsedCopilotApp *bool `json:"used_copilot_app,omitempty"`
|
|
UsedCopilotCloudAgent *bool `json:"used_copilot_cloud_agent,omitempty"`
|
|
UsedCopilotCodeReviewActive *bool `json:"used_copilot_code_review_active,omitempty"`
|
|
UsedCopilotCodeReviewPassive *bool `json:"used_copilot_code_review_passive,omitempty"`
|
|
UsedCopilotCodingAgent *bool `json:"used_copilot_coding_agent,omitempty"`
|
|
LOCSuggestedToAddSum *int `json:"loc_suggested_to_add_sum,omitempty"`
|
|
LOCSuggestedToDeleteSum *int `json:"loc_suggested_to_delete_sum,omitempty"`
|
|
LOCAddedSum *int `json:"loc_added_sum,omitempty"`
|
|
LOCDeletedSum *int `json:"loc_deleted_sum,omitempty"`
|
|
}
|
|
|
|
// CopilotUserPeriodicMetrics represents a single user's per-day Copilot usage metrics record from a
|
|
// multi-day (e.g. 28-day rolling) user metrics report. User metrics reports are served as
|
|
// newline-delimited JSON.
|
|
type CopilotUserPeriodicMetrics struct {
|
|
ReportStartDay string `json:"report_start_day"`
|
|
ReportEndDay string `json:"report_end_day"`
|
|
Day string `json:"day"`
|
|
OrganizationID *string `json:"organization_id,omitempty"`
|
|
EnterpriseID *string `json:"enterprise_id,omitempty"`
|
|
UserID int `json:"user_id"`
|
|
UserLogin string `json:"user_login"`
|
|
AICreditsUsed *float64 `json:"ai_credits_used,omitempty"`
|
|
UserInitiatedInteractionCount *int `json:"user_initiated_interaction_count,omitempty"`
|
|
CopilotMetricsChatPanel
|
|
CodeGenerationActivityCount *int `json:"code_generation_activity_count,omitempty"`
|
|
CodeAcceptanceActivityCount *int `json:"code_acceptance_activity_count,omitempty"`
|
|
TotalsByIDE []*CopilotUserMetricsIDE `json:"totals_by_ide,omitempty"`
|
|
TotalsByFeature []*CopilotMetricsFeature `json:"totals_by_feature,omitempty"`
|
|
TotalsByLanguageFeature []*CopilotMetricsLanguageFeature `json:"totals_by_language_feature,omitempty"`
|
|
TotalsByLanguageModel []*CopilotMetricsLanguageModel `json:"totals_by_language_model,omitempty"`
|
|
TotalsByModelFeature []*CopilotMetricsModelFeature `json:"totals_by_model_feature,omitempty"`
|
|
TotalsByCLI *CopilotMetricsCLI `json:"totals_by_cli,omitempty"`
|
|
TotalsByCopilotApp *CopilotMetricsCopilotApp `json:"totals_by_copilot_app,omitempty"`
|
|
TotalsBy3rdPartyAgent []*CopilotMetricsThirdPartyAgent `json:"totals_by_3rd_party_agent,omitempty"`
|
|
AIAdoptionPhase *CopilotMetricsAIAdoptionPhase `json:"ai_adoption_phase,omitempty"`
|
|
UsedAgent *bool `json:"used_agent,omitempty"`
|
|
UsedChat *bool `json:"used_chat,omitempty"`
|
|
UsedCLI *bool `json:"used_cli,omitempty"`
|
|
UsedCopilotApp *bool `json:"used_copilot_app,omitempty"`
|
|
UsedCopilotCloudAgent *bool `json:"used_copilot_cloud_agent,omitempty"`
|
|
UsedCopilotCodeReviewActive *bool `json:"used_copilot_code_review_active,omitempty"`
|
|
UsedCopilotCodeReviewPassive *bool `json:"used_copilot_code_review_passive,omitempty"`
|
|
UsedCopilotCodingAgent *bool `json:"used_copilot_coding_agent,omitempty"`
|
|
LOCSuggestedToAddSum *int `json:"loc_suggested_to_add_sum,omitempty"`
|
|
LOCSuggestedToDeleteSum *int `json:"loc_suggested_to_delete_sum,omitempty"`
|
|
LOCAddedSum *int `json:"loc_added_sum,omitempty"`
|
|
LOCDeletedSum *int `json:"loc_deleted_sum,omitempty"`
|
|
}
|
|
|
|
// fetchMetricsReport performs a GET against the provided download URL and returns the raw
|
|
// http.Response. The caller is responsible for closing the body.
|
|
func (s *CopilotService) fetchMetricsReport(ctx context.Context, url string) (*http.Response, *Response, error) {
|
|
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
resp, err := s.client.client.Do(req)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// CheckResponse substitutes resp.Body with a re-readable copy on error
|
|
// responses, so capture the original body first: it is the one that must
|
|
// be closed.
|
|
origBody := resp.Body
|
|
if err := CheckResponse(resp); err != nil {
|
|
_ = origBody.Close()
|
|
return nil, newResponse(resp), err
|
|
}
|
|
|
|
return resp, newResponse(resp), nil
|
|
}
|
|
|
|
// decodeNDJSONMetrics streams a newline-delimited JSON response body into a slice of *T,
|
|
// returning a nil slice when the body is empty.
|
|
func decodeNDJSONMetrics[T any](r io.Reader) ([]*T, error) {
|
|
var records []*T
|
|
dec := json.NewDecoder(r)
|
|
for {
|
|
var rec *T
|
|
if err := dec.Decode(&rec); err != nil {
|
|
if errors.Is(err, io.EOF) {
|
|
break
|
|
}
|
|
return nil, err
|
|
}
|
|
records = append(records, rec)
|
|
}
|
|
return records, nil
|
|
}
|
|
|
|
// DownloadDailyMetrics downloads the payload of a 1-day Copilot usage metrics report from a
|
|
// download link returned by GetEnterpriseDailyMetricsReport or GetOrganizationDailyMetricsReport.
|
|
func (s *CopilotService) DownloadDailyMetrics(ctx context.Context, url string) (*CopilotDailyMetrics, *Response, error) {
|
|
resp, r, err := s.fetchMetricsReport(ctx, url)
|
|
if err != nil {
|
|
return nil, r, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var metrics *CopilotDailyMetrics
|
|
if err := json.NewDecoder(resp.Body).Decode(&metrics); err != nil {
|
|
return nil, r, err
|
|
}
|
|
|
|
return metrics, r, nil
|
|
}
|
|
|
|
// DownloadPeriodicMetrics downloads the payload of a multi-day (e.g. 28-day rolling) Copilot
|
|
// usage metrics report from a download link returned by GetEnterpriseMetricsReport or
|
|
// GetOrganizationMetricsReport.
|
|
func (s *CopilotService) DownloadPeriodicMetrics(ctx context.Context, url string) (*CopilotPeriodicMetrics, *Response, error) {
|
|
resp, r, err := s.fetchMetricsReport(ctx, url)
|
|
if err != nil {
|
|
return nil, r, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var metrics *CopilotPeriodicMetrics
|
|
if err := json.NewDecoder(resp.Body).Decode(&metrics); err != nil {
|
|
return nil, r, err
|
|
}
|
|
|
|
return metrics, r, nil
|
|
}
|
|
|
|
// DownloadUserDailyMetrics downloads the payload of a 1-day Copilot user metrics report from a
|
|
// download link returned by GetEnterpriseUsersDailyMetricsReport or
|
|
// GetOrganizationUsersDailyMetricsReport.
|
|
//
|
|
// The response is newline-delimited JSON, with one CopilotUserDailyMetrics record per line.
|
|
func (s *CopilotService) DownloadUserDailyMetrics(ctx context.Context, url string) ([]*CopilotUserDailyMetrics, *Response, error) {
|
|
resp, r, err := s.fetchMetricsReport(ctx, url)
|
|
if err != nil {
|
|
return nil, r, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
records, err := decodeNDJSONMetrics[CopilotUserDailyMetrics](resp.Body)
|
|
if err != nil {
|
|
return nil, r, err
|
|
}
|
|
return records, r, nil
|
|
}
|
|
|
|
// DownloadUserPeriodicMetrics downloads the payload of a multi-day (e.g. 28-day rolling) Copilot
|
|
// user metrics report from a download link returned by GetEnterpriseUsersMetricsReport or
|
|
// GetOrganizationUsersMetricsReport.
|
|
//
|
|
// The response is newline-delimited JSON, with one CopilotUserPeriodicMetrics record per
|
|
// user-day in the reporting window.
|
|
func (s *CopilotService) DownloadUserPeriodicMetrics(ctx context.Context, url string) ([]*CopilotUserPeriodicMetrics, *Response, error) {
|
|
resp, r, err := s.fetchMetricsReport(ctx, url)
|
|
if err != nil {
|
|
return nil, r, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
records, err := decodeNDJSONMetrics[CopilotUserPeriodicMetrics](resp.Body)
|
|
if err != nil {
|
|
return nil, r, err
|
|
}
|
|
return records, r, nil
|
|
}
|