Skip to content

Add Copilot Usage Summary for Organization #3321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Oct 14, 2024
168 changes: 168 additions & 0 deletions github/copilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"encoding/json"
"errors"
"fmt"
"time"
)

// CopilotService provides access to the Copilot-related functions
Expand Down Expand Up @@ -52,6 +53,7 @@ type CopilotSeatDetails struct {
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.
Expand All @@ -64,6 +66,39 @@ type SeatCancellations struct {
SeatsCancelled int `json:"seats_cancelled"`
}

// CopilotUsageSummaryListOptions represents the optional parameters to the CopilotService.GetOrganizationUsage method.
type CopilotUsageSummaryListOptions struct {
Since *time.Time `url:"since,omitempty"`
Until *time.Time `url:"until,omitempty"`

ListOptions
}

// CopilotUsageBreakdown represents the breakdown of Copilot usage for a specific language and editor.
type CopilotUsageBreakdown struct {
Language string `json:"language"`
Editor string `json:"editor"`
SuggestionsCount int64 `json:"suggestions_count"`
AcceptancesCount int64 `json:"acceptances_count"`
LinesSuggested int64 `json:"lines_suggested"`
LinesAccepted int64 `json:"lines_accepted"`
ActiveUsers int `json:"active_users"`
}

// CopilotUsageSummary represents the daily breakdown of aggregated usage metrics for Copilot completions and Copilot Chat in the IDE across an organization.
type CopilotUsageSummary struct {
Day string `json:"day"`
TotalSuggestionsCount int64 `json:"total_suggestions_count"`
TotalAcceptancesCount int64 `json:"total_acceptances_count"`
TotalLinesSuggested int64 `json:"total_lines_suggested"`
TotalLinesAccepted int64 `json:"total_lines_accepted"`
TotalActiveUsers int64 `json:"total_active_users"`
TotalChatAcceptances int64 `json:"total_chat_acceptances"`
TotalChatTurns int64 `json:"total_chat_turns"`
TotalActiveChatUsers int `json:"total_active_chat_users"`
Breakdown []*CopilotUsageBreakdown `json:"breakdown"`
}

func (cp *CopilotSeatDetails) UnmarshalJSON(data []byte) error {
// Using an alias to avoid infinite recursion when calling json.Unmarshal
type alias CopilotSeatDetails
Expand All @@ -79,6 +114,7 @@ func (cp *CopilotSeatDetails) UnmarshalJSON(data []byte) error {
cp.LastActivityEditor = seatDetail.LastActivityEditor
cp.CreatedAt = seatDetail.CreatedAt
cp.UpdatedAt = seatDetail.UpdatedAt
cp.PlanType = seatDetail.PlanType

switch v := seatDetail.Assignee.(type) {
case map[string]interface{}:
Expand Down Expand Up @@ -181,6 +217,34 @@ func (s *CopilotService) ListCopilotSeats(ctx context.Context, org string, opts
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/rest/copilot/copilot-user-management#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("GET", u, nil)
if err != nil {
return nil, nil, err
}

var copilotSeats *ListCopilotSeatsResponse
resp, err := s.client.Do(ctx, req, &copilotSeats)
if err != nil {
return nil, resp, err
}

return copilotSeats, 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#add-teams-to-the-copilot-subscription-for-an-organization
Expand Down Expand Up @@ -314,3 +378,107 @@ func (s *CopilotService) GetSeatDetails(ctx context.Context, org, user string) (

return seatDetails, resp, nil
}

// GetOrganizationUsage gets daily breakdown of aggregated usage metrics for Copilot completions and Copilot Chat in the IDE across an organization.
//
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage#get-a-summary-of-copilot-usage-for-organization-members
//
//meta:operation GET /orgs/{org}/copilot/usage
func (s *CopilotService) GetOrganizationUsage(ctx context.Context, org string, opts *CopilotUsageSummaryListOptions) ([]*CopilotUsageSummary, *Response, error) {
u := fmt.Sprintf("orgs/%v/copilot/usage", org)
u, err := addOptions(u, opts)
if err != nil {
return nil, nil, err
}

req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}

var usage []*CopilotUsageSummary
resp, err := s.client.Do(ctx, req, &usage)
if err != nil {
return nil, resp, err
}

return usage, resp, nil
}

// GetEnterpriseUsage gets daily breakdown of aggregated usage metrics for Copilot completions and Copilot Chat in the IDE across an enterprise.
//
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage#get-a-summary-of-copilot-usage-for-enterprise-members
//
//meta:operation GET /enterprises/{enterprise}/copilot/usage
func (s *CopilotService) GetEnterpriseUsage(ctx context.Context, enterprise string, opts *CopilotUsageSummaryListOptions) ([]*CopilotUsageSummary, *Response, error) {
u := fmt.Sprintf("enterprises/%v/copilot/usage", enterprise)
u, err := addOptions(u, opts)
if err != nil {
return nil, nil, err
}

req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}

var usage []*CopilotUsageSummary
resp, err := s.client.Do(ctx, req, &usage)
if err != nil {
return nil, resp, err
}

return usage, resp, nil
}

// GetEnterpriseTeamUsage gets daily breakdown of aggregated usage metrics for Copilot completions and Copilot Chat in the IDE for a team in the enterprise.
//
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage#get-a-summary-of-copilot-usage-for-an-enterprise-team
//
//meta:operation GET /enterprises/{enterprise}/team/{team_slug}/copilot/usage
func (s *CopilotService) GetEnterpriseTeamUsage(ctx context.Context, enterprise, team string, opts *CopilotUsageSummaryListOptions) ([]*CopilotUsageSummary, *Response, error) {
u := fmt.Sprintf("enterprises/%v/team/%v/copilot/usage", enterprise, team)
u, err := addOptions(u, opts)
if err != nil {
return nil, nil, err
}

req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}

var usage []*CopilotUsageSummary
resp, err := s.client.Do(ctx, req, &usage)
if err != nil {
return nil, resp, err
}

return usage, resp, nil
}

// GetOrganizationTeamUsage gets daily breakdown of aggregated usage metrics for Copilot completions and Copilot Chat in the IDE for a team in the organization.
//
// GitHub API docs: https://docs.github.com/rest/copilot/copilot-usage#get-a-summary-of-copilot-usage-for-a-team
//
//meta:operation GET /orgs/{org}/team/{team_slug}/copilot/usage
func (s *CopilotService) GetOrganizationTeamUsage(ctx context.Context, org, team string, opts *CopilotUsageSummaryListOptions) ([]*CopilotUsageSummary, *Response, error) {
u := fmt.Sprintf("orgs/%v/team/%v/copilot/usage", org, team)
u, err := addOptions(u, opts)
if err != nil {
return nil, nil, err
}

req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}

var usage []*CopilotUsageSummary
resp, err := s.client.Do(ctx, req, &usage)
if err != nil {
return nil, resp, err
}

return usage, resp, nil
}
Loading
Loading