// 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 // CopilotSpace represents a Copilot Space. type CopilotSpace struct { ID int64 `json:"id"` Number int `json:"number"` Name string `json:"name"` Description *string `json:"description,omitempty"` GeneralInstructions *string `json:"general_instructions,omitempty"` // Owner can either be a User or an Organization. Owner any `json:"owner"` Creator User `json:"creator"` CreatedAt Timestamp `json:"created_at"` UpdatedAt Timestamp `json:"updated_at"` HTMLURL string `json:"html_url"` APIURL string `json:"api_url"` BaseRole string `json:"base_role"` ResourcesAttributes []*CopilotSpaceResource `json:"resources_attributes,omitempty"` } // UnmarshalJSON implements the json.Unmarshaler interface. func (c *CopilotSpace) UnmarshalJSON(data []byte) error { // Define a new type without methods to avoid recursively calling UnmarshalJSON. type alias CopilotSpace var space alias if err := json.Unmarshal(data, &space); err != nil { return err } switch v := space.Owner.(type) { case nil: space.Owner = nil case map[string]any: if t, ok := v["type"].(string); ok && t == "User" { space.Owner = &User{} } else if t, ok := v["type"].(string); ok && t == "Organization" { space.Owner = &Organization{} } else if _, ok := v["hooks_url"]; ok { space.Owner = &Organization{} } else { return fmt.Errorf("unsupported owner type %v", v["type"]) } if err := json.Unmarshal(data, &space); err != nil { return err } default: return fmt.Errorf("unsupported owner type %T", v) } *c = CopilotSpace(space) return nil } // CopilotSpaceResource represents a resource attached to a Copilot Space. type CopilotSpaceResource struct { ID *int64 `json:"id,omitempty"` ResourceType *string `json:"resource_type,omitempty"` Metadata *CopilotSpaceMetadata `json:"metadata,omitempty"` CopilotChatAttachmentID *int64 `json:"copilot_chat_attachment_id,omitempty"` CreatedAt *Timestamp `json:"created_at,omitempty"` UpdatedAt *Timestamp `json:"updated_at,omitempty"` } // CreateCopilotSpaceResourceAttributes represents a resource to attach when creating a Copilot Space. type CreateCopilotSpaceResourceAttributes struct { ResourceType *string `json:"resource_type,omitempty"` Metadata *CopilotSpaceMetadata `json:"metadata,omitempty"` } // UpdateCopilotSpaceResourceAttributes represents a resource to attach, update, or remove when updating a Copilot Space. type UpdateCopilotSpaceResourceAttributes struct { ID *int64 `json:"id,omitempty"` ResourceType *string `json:"resource_type,omitempty"` Metadata *CopilotSpaceMetadata `json:"metadata,omitempty"` Destroy *bool `json:"_destroy,omitempty"` } // CopilotSpaceMetadata represents metadata specific to a Copilot Space resource type. type CopilotSpaceMetadata struct { RepositoryID *int64 `json:"repository_id,omitempty"` FilePath *string `json:"file_path,omitempty"` Text *string `json:"text,omitempty"` Name *string `json:"name,omitempty"` Number *int `json:"number,omitempty"` CopilotChatAttachmentID *int64 `json:"copilot_chat_attachment_id,omitempty"` MediaType *string `json:"media_type,omitempty"` URL *string `json:"url,omitempty"` Height *int `json:"height,omitempty"` Width *int `json:"width,omitempty"` } // CreateOrganizationCopilotSpaceRequest represents a request to create a Copilot Space. type CreateOrganizationCopilotSpaceRequest struct { Name string `json:"name"` Description *string `json:"description,omitempty"` GeneralInstructions *string `json:"general_instructions,omitempty"` BaseRole *string `json:"base_role,omitempty"` ResourcesAttributes []*CreateCopilotSpaceResourceAttributes `json:"resources_attributes,omitempty"` } // UpdateOrganizationCopilotSpaceRequest represents a request to update a Copilot Space. type UpdateOrganizationCopilotSpaceRequest struct { Name *string `json:"name,omitempty"` Description *string `json:"description,omitempty"` GeneralInstructions *string `json:"general_instructions,omitempty"` BaseRole *string `json:"base_role,omitempty"` ResourcesAttributes []*UpdateCopilotSpaceResourceAttributes `json:"resources_attributes,omitempty"` } // CopilotSpacesList represents a list of Copilot Spaces. type CopilotSpacesList struct { Spaces []*CopilotSpace `json:"spaces"` } // ListOrganizationCopilotSpaces lists Copilot Spaces for an organization. // // GitHub API docs: https://docs.github.com/rest/copilot-spaces/copilot-spaces?apiVersion=2022-11-28#list-organization-copilot-spaces // //meta:operation GET /orgs/{org}/copilot-spaces func (s *CopilotService) ListOrganizationCopilotSpaces(ctx context.Context, org string, opts *ListCursorOptions) (*CopilotSpacesList, *Response, error) { u := fmt.Sprintf("orgs/%v/copilot-spaces", 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 spaces *CopilotSpacesList resp, err := s.client.Do(req, &spaces) if err != nil { return nil, resp, err } return spaces, resp, nil } // GetOrganizationCopilotSpace gets a Copilot Space for an organization. // // GitHub API docs: https://docs.github.com/rest/copilot-spaces/copilot-spaces?apiVersion=2022-11-28#get-an-organization-copilot-space // //meta:operation GET /orgs/{org}/copilot-spaces/{space_number} func (s *CopilotService) GetOrganizationCopilotSpace(ctx context.Context, org string, spaceNumber int) (*CopilotSpace, *Response, error) { u := fmt.Sprintf("orgs/%v/copilot-spaces/%v", org, spaceNumber) req, err := s.client.NewRequest(ctx, "GET", u, nil) if err != nil { return nil, nil, err } var space *CopilotSpace resp, err := s.client.Do(req, &space) if err != nil { return nil, resp, err } return space, resp, nil } // CreateOrganizationCopilotSpace creates a Copilot Space for an organization. // // GitHub API docs: https://docs.github.com/rest/copilot-spaces/copilot-spaces?apiVersion=2022-11-28#create-an-organization-copilot-space // //meta:operation POST /orgs/{org}/copilot-spaces func (s *CopilotService) CreateOrganizationCopilotSpace(ctx context.Context, org string, body CreateOrganizationCopilotSpaceRequest) (*CopilotSpace, *Response, error) { u := fmt.Sprintf("orgs/%v/copilot-spaces", org) req, err := s.client.NewRequest(ctx, "POST", u, body) if err != nil { return nil, nil, err } var space *CopilotSpace resp, err := s.client.Do(req, &space) if err != nil { return nil, resp, err } return space, resp, nil } // UpdateOrganizationCopilotSpace updates a Copilot Space for an organization. // // GitHub API docs: https://docs.github.com/rest/copilot-spaces/copilot-spaces?apiVersion=2022-11-28#set-an-organization-copilot-space // //meta:operation PUT /orgs/{org}/copilot-spaces/{space_number} func (s *CopilotService) UpdateOrganizationCopilotSpace(ctx context.Context, org string, spaceNumber int, body UpdateOrganizationCopilotSpaceRequest) (*CopilotSpace, *Response, error) { u := fmt.Sprintf("orgs/%v/copilot-spaces/%v", org, spaceNumber) req, err := s.client.NewRequest(ctx, "PUT", u, body) if err != nil { return nil, nil, err } var space *CopilotSpace resp, err := s.client.Do(req, &space) if err != nil { return nil, resp, err } return space, resp, nil } // DeleteOrganizationCopilotSpace deletes a Copilot Space for an organization. // // GitHub API docs: https://docs.github.com/rest/copilot-spaces/copilot-spaces?apiVersion=2022-11-28#delete-an-organization-copilot-space // //meta:operation DELETE /orgs/{org}/copilot-spaces/{space_number} func (s *CopilotService) DeleteOrganizationCopilotSpace(ctx context.Context, org string, spaceNumber int) (*Response, error) { u := fmt.Sprintf("orgs/%v/copilot-spaces/%v", org, spaceNumber) req, err := s.client.NewRequest(ctx, "DELETE", u, nil) if err != nil { return nil, err } return s.client.Do(req, nil) } // 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 } // CopilotCodingAgentPermissions represents which repositories in an organization can use the Copilot coding agent. type CopilotCodingAgentPermissions struct { // EnabledRepositories is one of "all", "selected" or "none". EnabledRepositories string `json:"enabled_repositories"` SelectedRepositoriesURL *string `json:"selected_repositories_url,omitempty"` } // CopilotCodingAgentPermissionsRequest represents the request body to set the Copilot coding agent permissions for an organization. type CopilotCodingAgentPermissionsRequest struct { // EnabledRepositories is one of "all", "selected" or "none". EnabledRepositories string `json:"enabled_repositories"` } // GetOrganizationCodingAgentPermissions gets which repositories in an organization can use the Copilot coding agent. // // GitHub API docs: https://docs.github.com/rest/copilot/copilot-coding-agent-management?apiVersion=2022-11-28#get-copilot-cloud-agent-permissions-for-an-organization // //meta:operation GET /orgs/{org}/copilot/coding-agent/permissions func (s *CopilotService) GetOrganizationCodingAgentPermissions(ctx context.Context, org string) (*CopilotCodingAgentPermissions, *Response, error) { u := fmt.Sprintf("orgs/%v/copilot/coding-agent/permissions", org) req, err := s.client.NewRequest(ctx, "GET", u, nil) if err != nil { return nil, nil, err } var permissions *CopilotCodingAgentPermissions resp, err := s.client.Do(req, &permissions) if err != nil { return nil, resp, err } return permissions, resp, nil } // SetOrganizationCodingAgentPermissions sets which repositories in an organization can use the Copilot coding agent. // // GitHub API docs: https://docs.github.com/rest/copilot/copilot-coding-agent-management?apiVersion=2022-11-28#set-copilot-cloud-agent-permissions-for-an-organization // //meta:operation PUT /orgs/{org}/copilot/coding-agent/permissions func (s *CopilotService) SetOrganizationCodingAgentPermissions(ctx context.Context, org string, body CopilotCodingAgentPermissionsRequest) (*Response, error) { u := fmt.Sprintf("orgs/%v/copilot/coding-agent/permissions", org) req, err := s.client.NewRequest(ctx, "PUT", u, body) if err != nil { return nil, err } return s.client.Do(req, nil) } // SetOrganizationCodingAgentRepositories replaces the list of repositories enabled for the Copilot coding agent in an organization. // The organization's EnabledRepositories permission must be set to "selected". // // GitHub API docs: https://docs.github.com/rest/copilot/copilot-coding-agent-management?apiVersion=2022-11-28#set-selected-repositories-for-copilot-cloud-agent-in-an-organization // //meta:operation PUT /orgs/{org}/copilot/coding-agent/permissions/repositories func (s *CopilotService) SetOrganizationCodingAgentRepositories(ctx context.Context, org string, repositoryIDs []int64) (*Response, error) { u := fmt.Sprintf("orgs/%v/copilot/coding-agent/permissions/repositories", org) req, err := s.client.NewRequest(ctx, "PUT", u, struct { IDs []int64 `json:"selected_repository_ids"` }{IDs: repositoryIDs}) if err != nil { return nil, err } return s.client.Do(req, nil) } // EnableOrganizationCodingAgentRepository enables a repository 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#enable-a-repository-for-copilot-cloud-agent-in-an-organization // //meta:operation PUT /orgs/{org}/copilot/coding-agent/permissions/repositories/{repository_id} func (s *CopilotService) EnableOrganizationCodingAgentRepository(ctx context.Context, org string, repositoryID int64) (*Response, error) { u := fmt.Sprintf("orgs/%v/copilot/coding-agent/permissions/repositories/%v", org, repositoryID) req, err := s.client.NewRequest(ctx, "PUT", u, nil) if err != nil { return nil, err } return s.client.Do(req, nil) } // DisableOrganizationCodingAgentRepository disables a repository 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#disable-a-repository-for-copilot-cloud-agent-in-an-organization // //meta:operation DELETE /orgs/{org}/copilot/coding-agent/permissions/repositories/{repository_id} func (s *CopilotService) DisableOrganizationCodingAgentRepository(ctx context.Context, org string, repositoryID int64) (*Response, error) { u := fmt.Sprintf("orgs/%v/copilot/coding-agent/permissions/repositories/%v", org, repositoryID) req, err := s.client.NewRequest(ctx, "DELETE", u, nil) if err != nil { return nil, err } return s.client.Do(req, nil) } // CopilotContentExclusionDetails lists Copilot content exclusion path rules, // keyed by repository identifier. Each value is the list of file paths excluded // from Copilot for that repository. type CopilotContentExclusionDetails map[string][]string // CopilotSetContentExclusionDetailsRequest represents the Copilot content exclusion // rules to set, keyed by repository identifier. type CopilotSetContentExclusionDetailsRequest map[string][]*CopilotContentExclusionRule // CopilotContentExclusionRule represents a single Copilot content exclusion rule. // Exactly one of Path, IfAnyMatch, or IfNoneMatch should be set. type CopilotContentExclusionRule struct { Path *string `json:"-"` IfAnyMatch []string `json:"ifAnyMatch,omitempty"` IfNoneMatch []string `json:"ifNoneMatch,omitempty"` } // MarshalJSON implements the json.Marshaler interface. // A rule with Path set is encoded as a plain string. func (r CopilotContentExclusionRule) MarshalJSON() ([]byte, error) { if r.Path != nil { return json.Marshal(*r.Path) } type alias CopilotContentExclusionRule return json.Marshal(alias(r)) } // CopilotSetContentExclusionResponse represents the response from setting // Copilot content exclusion rules. type CopilotSetContentExclusionResponse struct { Message *string `json:"message,omitempty"` } // 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) (CopilotContentExclusionDetails, *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 := CopilotContentExclusionDetails{} resp, err := s.client.Do(req, &details) if err != nil { return nil, resp, err } return details, resp, nil } // SetOrganizationContentExclusionDetails sets 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#set-copilot-content-exclusion-rules-for-an-organization // //meta:operation PUT /orgs/{org}/copilot/content_exclusion func (s *CopilotService) SetOrganizationContentExclusionDetails(ctx context.Context, org string, body CopilotSetContentExclusionDetailsRequest) (*CopilotSetContentExclusionResponse, *Response, error) { u := fmt.Sprintf("orgs/%v/copilot/content_exclusion", org) req, err := s.client.NewRequest(ctx, "PUT", u, body) if err != nil { return nil, nil, err } var result *CopilotSetContentExclusionResponse resp, err := s.client.Do(req, &result) if err != nil { return nil, resp, err } return result, resp, nil } // GetEnterpriseContentExclusionDetails gets the Copilot content exclusion rules for an enterprise. // // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-content-exclusion-management?apiVersion=2022-11-28#get-copilot-content-exclusion-rules-for-an-enterprise // //meta:operation GET /enterprises/{enterprise}/copilot/content_exclusion func (s *CopilotService) GetEnterpriseContentExclusionDetails(ctx context.Context, enterprise string) (CopilotContentExclusionDetails, *Response, error) { u := fmt.Sprintf("enterprises/%v/copilot/content_exclusion", enterprise) req, err := s.client.NewRequest(ctx, "GET", u, nil) if err != nil { return nil, nil, err } details := CopilotContentExclusionDetails{} resp, err := s.client.Do(req, &details) if err != nil { return nil, resp, err } return details, resp, nil } // SetEnterpriseContentExclusionDetails sets the Copilot content exclusion rules for an enterprise. // // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/copilot/copilot-content-exclusion-management?apiVersion=2022-11-28#set-copilot-content-exclusion-rules-for-an-enterprise // //meta:operation PUT /enterprises/{enterprise}/copilot/content_exclusion func (s *CopilotService) SetEnterpriseContentExclusionDetails(ctx context.Context, enterprise string, body CopilotSetContentExclusionDetailsRequest) (*CopilotSetContentExclusionResponse, *Response, error) { u := fmt.Sprintf("enterprises/%v/copilot/content_exclusion", enterprise) req, err := s.client.NewRequest(ctx, "PUT", u, body) if err != nil { return nil, nil, err } var result *CopilotSetContentExclusionResponse resp, err := s.client.Do(req, &result) if err != nil { return nil, resp, err } return result, 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 } // GetEnterpriseRepositoriesDailyMetricsReport gets a report containing Copilot // repository-level pull request metrics for a single day for an enterprise. // // Use DownloadRepositoryDailyMetrics 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-repository-report-for-a-specific-day // //meta:operation GET /enterprises/{enterprise}/copilot/metrics/reports/repos-1-day func (s *CopilotService) GetEnterpriseRepositoriesDailyMetricsReport(ctx context.Context, enterprise string, opts *CopilotMetricsReportOptions) (*CopilotDailyMetricsReport, *Response, error) { u := fmt.Sprintf("enterprises/%v/copilot/metrics/reports/repos-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 } // GetOrganizationRepositoriesDailyMetricsReport gets a report containing Copilot // repository-level pull request metrics for a single day for an organization. // // Use DownloadRepositoryDailyMetrics 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-repository-report-for-a-specific-day // //meta:operation GET /orgs/{org}/copilot/metrics/reports/repos-1-day func (s *CopilotService) GetOrganizationRepositoriesDailyMetricsReport(ctx context.Context, org string, opts *CopilotMetricsReportOptions) (*CopilotDailyMetricsReport, *Response, error) { u := fmt.Sprintf("orgs/%v/copilot/metrics/reports/repos-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 } // GetEnterpriseUserTeamsDailyMetricsReport gets a report containing Copilot // user-team membership data for a single day for an enterprise. // // Use DownloadUserTeamsDailyMetrics to decode the payloads served at the returned download links. // Join these records with per-user usage metrics on user_id, day, and enterprise_id to // construct team-level metrics. // // GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage-metrics?apiVersion=2022-11-28#get-copilot-enterprise-user-teams-report-for-a-specific-day // //meta:operation GET /enterprises/{enterprise}/copilot/metrics/reports/user-teams-1-day func (s *CopilotService) GetEnterpriseUserTeamsDailyMetricsReport(ctx context.Context, enterprise string, opts *CopilotMetricsReportOptions) (*CopilotDailyMetricsReport, *Response, error) { u := fmt.Sprintf("enterprises/%v/copilot/metrics/reports/user-teams-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 } // GetOrganizationUserTeamsDailyMetricsReport gets a report containing Copilot // user-team membership data for a single day for an organization. // // Use DownloadUserTeamsDailyMetrics to decode the payloads served at the returned download links. // Join these records with per-user usage metrics on user_id, day, and organization_id to // construct team-level metrics. // // GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage-metrics?apiVersion=2022-11-28#get-copilot-organization-user-teams-report-for-a-specific-day // //meta:operation GET /orgs/{org}/copilot/metrics/reports/user-teams-1-day func (s *CopilotService) GetOrganizationUserTeamsDailyMetricsReport(ctx context.Context, org string, opts *CopilotMetricsReportOptions) (*CopilotDailyMetricsReport, *Response, error) { u := fmt.Sprintf("orgs/%v/copilot/metrics/reports/user-teams-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 } // DownloadCopilotMetrics downloads a Copilot metrics report from the provided download link // and decodes it as a []*CopilotMetrics. // // Deprecated: Use DownloadDailyMetrics, // DownloadPeriodicMetrics, DownloadUserDailyMetrics, DownloadUserPeriodicMetrics, // DownloadRepositoryDailyMetrics, DownloadUserTeamsDailyMetrics 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 } // CopilotMetricsCopilotSuggestionByCommentType represents Copilot code review suggestion // counts broken down by comment type in a pull_requests object. // // GitHub API docs: https://docs.github.com/en/copilot/reference/copilot-usage-metrics/copilot-usage-metrics#pull-request-activity-fields type CopilotMetricsCopilotSuggestionByCommentType struct { CommentType string `json:"comment_type"` TotalCopilotSuggestions *int `json:"total_copilot_suggestions,omitempty"` TotalCopilotAppliedSuggestions *int `json:"total_copilot_applied_suggestions,omitempty"` } // 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"` CopilotSuggestionsByCommentType []*CopilotMetricsCopilotSuggestionByCommentType `json:"copilot_suggestions_by_comment_type,omitempty"` } // CopilotRepositoryDailyMetrics represents a single repository's per-day Copilot pull request // metrics record from a repos-1-day report. Repository reports are served as newline-delimited JSON. // // GitHub API docs: https://docs.github.com/en/copilot/reference/copilot-usage-metrics/copilot-usage-metrics#repository-level-fields-api-only type CopilotRepositoryDailyMetrics struct { Day string `json:"day"` EnterpriseID *string `json:"enterprise_id,omitempty"` OrganizationID *string `json:"organization_id,omitempty"` RepoID int64 `json:"repo_id"` RepoOwnerName string `json:"repo_owner_name"` RepoName string `json:"repo_name"` RepoVisibility string `json:"repo_visibility"` PullRequests *CopilotMetricsPullRequests `json:"pull_requests,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"` } // CopilotUserTeamsDailyMetrics represents a user-team membership record from a user-teams-1-day // report. These records are joined with per-user usage metrics to construct team-level metrics. // Teams with fewer than 5 seated Copilot users are omitted from the report. // User-teams reports are served as newline-delimited JSON. // // GitHub API docs: https://docs.github.com/en/copilot/reference/copilot-usage-metrics/copilot-usage-metrics#user-teams-fields type CopilotUserTeamsDailyMetrics struct { UserID int64 `json:"user_id"` UserLogin string `json:"user_login"` Day string `json:"day"` OrganizationID *string `json:"organization_id,omitempty"` EnterpriseID *string `json:"enterprise_id,omitempty"` TeamID int64 `json:"team_id"` Slug string `json:"slug"` } // 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. // // The download URL is a value the caller reads out of a report response, which // may name any host. No host check belongs here: the client attaches its // credentials only to its configured API and upload origins, so a link that // points elsewhere is fetched without them, as is any redirect target. // // This is a GET with no body of the caller's, so only the credential half of the // origin rules applies to it; refusing a foreign host would break the ordinary // path, since GitHub hands back report links on a host of its own choosing. The // residual is that the body returned here is whatever that host served, and the // Download*Metrics methods decode it as GitHub's report. A caller that must be // sure the report is GitHub's should treat it as untrusted input. 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 } // DownloadRepositoryDailyMetrics downloads the payload of a 1-day Copilot repository metrics // report from a download link returned by GetEnterpriseRepositoriesDailyMetricsReport or // GetOrganizationRepositoriesDailyMetricsReport. // // The response is newline-delimited JSON, with one CopilotRepositoryDailyMetrics record per line. func (s *CopilotService) DownloadRepositoryDailyMetrics(ctx context.Context, url string) ([]*CopilotRepositoryDailyMetrics, *Response, error) { resp, r, err := s.fetchMetricsReport(ctx, url) if err != nil { return nil, r, err } defer resp.Body.Close() records, err := decodeNDJSONMetrics[CopilotRepositoryDailyMetrics](resp.Body) if err != nil { return nil, r, err } return records, r, nil } // DownloadUserTeamsDailyMetrics downloads the payload of a 1-day Copilot user-teams report from a // download link returned by GetEnterpriseUserTeamsDailyMetricsReport or // GetOrganizationUserTeamsDailyMetricsReport. // // The response is newline-delimited JSON, with one CopilotUserTeamsDailyMetrics record per line. func (s *CopilotService) DownloadUserTeamsDailyMetrics(ctx context.Context, url string) ([]*CopilotUserTeamsDailyMetrics, *Response, error) { resp, r, err := s.fetchMetricsReport(ctx, url) if err != nil { return nil, r, err } defer resp.Body.Close() records, err := decodeNDJSONMetrics[CopilotUserTeamsDailyMetrics](resp.Body) if err != nil { return nil, r, err } return records, r, nil }