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

     1  // Copyright 2023 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"context"
    10  	"encoding/json"
    11  	"fmt"
    12  )
    13  
    14  // CopilotService provides access to the Copilot-related functions
    15  // in the GitHub API.
    16  //
    17  // GitHub API docs: https://docs.github.com/en/rest/copilot/
    18  type CopilotService service
    19  
    20  // CopilotOrganizationDetails represents the details of an organization's Copilot for Business subscription.
    21  type CopilotOrganizationDetails struct {
    22  	SeatBreakdown         *CopilotSeatBreakdown `json:"seat_breakdown"`
    23  	PublicCodeSuggestions string                `json:"public_code_suggestions"`
    24  	CopilotChat           string                `json:"copilot_chat"`
    25  	SeatManagementSetting string                `json:"seat_management_setting"`
    26  }
    27  
    28  // CopilotSeatBreakdown represents the breakdown of Copilot for Business seats for the organization.
    29  type CopilotSeatBreakdown struct {
    30  	Total               int `json:"total"`
    31  	AddedThisCycle      int `json:"added_this_cycle"`
    32  	PendingCancellation int `json:"pending_cancellation"`
    33  	PendingInvitation   int `json:"pending_invitation"`
    34  	ActiveThisCycle     int `json:"active_this_cycle"`
    35  	InactiveThisCycle   int `json:"inactive_this_cycle"`
    36  }
    37  
    38  // ListCopilotSeatsResponse represents the Copilot for Business seat assignments for an organization.
    39  type ListCopilotSeatsResponse struct {
    40  	TotalSeats int64                 `json:"total_seats"`
    41  	Seats      []*CopilotSeatDetails `json:"seats"`
    42  }
    43  
    44  // CopilotSeatDetails represents the details of a Copilot for Business seat.
    45  type CopilotSeatDetails struct {
    46  	// Assignee can either be a User, Team, or Organization.
    47  	Assignee                interface{} `json:"assignee"`
    48  	AssigningTeam           *Team       `json:"assigning_team,omitempty"`
    49  	PendingCancellationDate *string     `json:"pending_cancellation_date,omitempty"`
    50  	LastActivityAt          *Timestamp  `json:"last_activity_at,omitempty"`
    51  	LastActivityEditor      *string     `json:"last_activity_editor,omitempty"`
    52  	CreatedAt               *Timestamp  `json:"created_at"`
    53  	UpdatedAt               *Timestamp  `json:"updated_at,omitempty"`
    54  }
    55  
    56  // SeatAssignments represents the number of seats assigned.
    57  type SeatAssignments struct {
    58  	SeatsCreated int `json:"seats_created"`
    59  }
    60  
    61  // SeatCancellations represents the number of seats cancelled.
    62  type SeatCancellations struct {
    63  	SeatsCancelled int `json:"seats_cancelled"`
    64  }
    65  
    66  func (cp *CopilotSeatDetails) UnmarshalJSON(data []byte) error {
    67  	// Using an alias to avoid infinite recursion when calling json.Unmarshal
    68  	type alias CopilotSeatDetails
    69  	var seatDetail alias
    70  
    71  	if err := json.Unmarshal(data, &seatDetail); err != nil {
    72  		return err
    73  	}
    74  
    75  	cp.AssigningTeam = seatDetail.AssigningTeam
    76  	cp.PendingCancellationDate = seatDetail.PendingCancellationDate
    77  	cp.LastActivityAt = seatDetail.LastActivityAt
    78  	cp.LastActivityEditor = seatDetail.LastActivityEditor
    79  	cp.CreatedAt = seatDetail.CreatedAt
    80  	cp.UpdatedAt = seatDetail.UpdatedAt
    81  
    82  	switch v := seatDetail.Assignee.(type) {
    83  	case map[string]interface{}:
    84  		jsonData, err := json.Marshal(seatDetail.Assignee)
    85  		if err != nil {
    86  			return err
    87  		}
    88  
    89  		if v["type"] == nil {
    90  			return fmt.Errorf("assignee type field is not set")
    91  		}
    92  
    93  		if t, ok := v["type"].(string); ok && t == "User" {
    94  			user := &User{}
    95  			if err := json.Unmarshal(jsonData, user); err != nil {
    96  				return err
    97  			}
    98  			cp.Assignee = user
    99  		} else if t, ok := v["type"].(string); ok && t == "Team" {
   100  			team := &Team{}
   101  			if err := json.Unmarshal(jsonData, team); err != nil {
   102  				return err
   103  			}
   104  			cp.Assignee = team
   105  		} else if t, ok := v["type"].(string); ok && t == "Organization" {
   106  			organization := &Organization{}
   107  			if err := json.Unmarshal(jsonData, organization); err != nil {
   108  				return err
   109  			}
   110  			cp.Assignee = organization
   111  		} else {
   112  			return fmt.Errorf("unsupported assignee type %v", v["type"])
   113  		}
   114  	default:
   115  		return fmt.Errorf("unsupported assignee type %T", v)
   116  	}
   117  
   118  	return nil
   119  }
   120  
   121  // GetUser gets the User from the CopilotSeatDetails if the assignee is a user.
   122  func (cp *CopilotSeatDetails) GetUser() (*User, bool) { u, ok := cp.Assignee.(*User); return u, ok }
   123  
   124  // GetTeam gets the Team from the CopilotSeatDetails if the assignee is a team.
   125  func (cp *CopilotSeatDetails) GetTeam() (*Team, bool) { t, ok := cp.Assignee.(*Team); return t, ok }
   126  
   127  // GetOrganization gets the Organization from the CopilotSeatDetails if the assignee is an organization.
   128  func (cp *CopilotSeatDetails) GetOrganization() (*Organization, bool) {
   129  	o, ok := cp.Assignee.(*Organization)
   130  	return o, ok
   131  }
   132  
   133  // GetCopilotBilling gets Copilot for Business billing information and settings for an organization.
   134  //
   135  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#get-copilot-seat-information-and-settings-for-an-organization
   136  //
   137  //meta:operation GET /orgs/{org}/copilot/billing
   138  func (s *CopilotService) GetCopilotBilling(ctx context.Context, org string) (*CopilotOrganizationDetails, *Response, error) {
   139  	u := fmt.Sprintf("orgs/%v/copilot/billing", org)
   140  
   141  	req, err := s.client.NewRequest("GET", u, nil)
   142  	if err != nil {
   143  		return nil, nil, err
   144  	}
   145  
   146  	var copilotDetails *CopilotOrganizationDetails
   147  	resp, err := s.client.Do(ctx, req, &copilotDetails)
   148  	if err != nil {
   149  		return nil, resp, err
   150  	}
   151  
   152  	return copilotDetails, resp, nil
   153  }
   154  
   155  // ListCopilotSeats lists Copilot for Business seat assignments for an organization.
   156  //
   157  // To paginate through all seats, populate 'Page' with the number of the last page.
   158  //
   159  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#list-all-copilot-seat-assignments-for-an-organization
   160  //
   161  //meta:operation GET /orgs/{org}/copilot/billing/seats
   162  func (s *CopilotService) ListCopilotSeats(ctx context.Context, org string, opts *ListOptions) (*ListCopilotSeatsResponse, *Response, error) {
   163  	u := fmt.Sprintf("orgs/%v/copilot/billing/seats", org)
   164  	u, err := addOptions(u, opts)
   165  	if err != nil {
   166  		return nil, nil, err
   167  	}
   168  
   169  	req, err := s.client.NewRequest("GET", u, nil)
   170  	if err != nil {
   171  		return nil, nil, err
   172  	}
   173  
   174  	var copilotSeats *ListCopilotSeatsResponse
   175  	resp, err := s.client.Do(ctx, req, &copilotSeats)
   176  	if err != nil {
   177  		return nil, resp, err
   178  	}
   179  
   180  	return copilotSeats, resp, nil
   181  }
   182  
   183  // AddCopilotTeams adds teams to the Copilot for Business subscription for an organization.
   184  //
   185  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#add-teams-to-the-copilot-subscription-for-an-organization
   186  //
   187  //meta:operation POST /orgs/{org}/copilot/billing/selected_teams
   188  func (s *CopilotService) AddCopilotTeams(ctx context.Context, org string, teamNames []string) (*SeatAssignments, *Response, error) {
   189  	u := fmt.Sprintf("orgs/%v/copilot/billing/selected_teams", org)
   190  
   191  	body := struct {
   192  		SelectedTeams []string `json:"selected_teams"`
   193  	}{
   194  		SelectedTeams: teamNames,
   195  	}
   196  
   197  	req, err := s.client.NewRequest("POST", u, body)
   198  	if err != nil {
   199  		return nil, nil, err
   200  	}
   201  
   202  	var seatAssignments *SeatAssignments
   203  	resp, err := s.client.Do(ctx, req, &seatAssignments)
   204  	if err != nil {
   205  		return nil, resp, err
   206  	}
   207  
   208  	return seatAssignments, resp, nil
   209  }
   210  
   211  // RemoveCopilotTeams removes teams from the Copilot for Business subscription for an organization.
   212  //
   213  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#remove-teams-from-the-copilot-subscription-for-an-organization
   214  //
   215  //meta:operation DELETE /orgs/{org}/copilot/billing/selected_teams
   216  func (s *CopilotService) RemoveCopilotTeams(ctx context.Context, org string, teamNames []string) (*SeatCancellations, *Response, error) {
   217  	u := fmt.Sprintf("orgs/%v/copilot/billing/selected_teams", org)
   218  
   219  	body := struct {
   220  		SelectedTeams []string `json:"selected_teams"`
   221  	}{
   222  		SelectedTeams: teamNames,
   223  	}
   224  
   225  	req, err := s.client.NewRequest("DELETE", u, body)
   226  	if err != nil {
   227  		return nil, nil, err
   228  	}
   229  
   230  	var seatCancellations *SeatCancellations
   231  	resp, err := s.client.Do(ctx, req, &seatCancellations)
   232  	if err != nil {
   233  		return nil, resp, err
   234  	}
   235  
   236  	return seatCancellations, resp, nil
   237  }
   238  
   239  // AddCopilotUsers adds users to the Copilot for Business subscription for an organization
   240  //
   241  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#add-users-to-the-copilot-subscription-for-an-organization
   242  //
   243  //meta:operation POST /orgs/{org}/copilot/billing/selected_users
   244  func (s *CopilotService) AddCopilotUsers(ctx context.Context, org string, users []string) (*SeatAssignments, *Response, error) {
   245  	u := fmt.Sprintf("orgs/%v/copilot/billing/selected_users", org)
   246  
   247  	body := struct {
   248  		SelectedUsernames []string `json:"selected_usernames"`
   249  	}{
   250  		SelectedUsernames: users,
   251  	}
   252  
   253  	req, err := s.client.NewRequest("POST", u, body)
   254  	if err != nil {
   255  		return nil, nil, err
   256  	}
   257  
   258  	var seatAssignments *SeatAssignments
   259  	resp, err := s.client.Do(ctx, req, &seatAssignments)
   260  	if err != nil {
   261  		return nil, resp, err
   262  	}
   263  
   264  	return seatAssignments, resp, nil
   265  }
   266  
   267  // RemoveCopilotUsers removes users from the Copilot for Business subscription for an organization.
   268  //
   269  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#remove-users-from-the-copilot-subscription-for-an-organization
   270  //
   271  //meta:operation DELETE /orgs/{org}/copilot/billing/selected_users
   272  func (s *CopilotService) RemoveCopilotUsers(ctx context.Context, org string, users []string) (*SeatCancellations, *Response, error) {
   273  	u := fmt.Sprintf("orgs/%v/copilot/billing/selected_users", org)
   274  
   275  	body := struct {
   276  		SelectedUsernames []string `json:"selected_usernames"`
   277  	}{
   278  		SelectedUsernames: users,
   279  	}
   280  
   281  	req, err := s.client.NewRequest("DELETE", u, body)
   282  	if err != nil {
   283  		return nil, nil, err
   284  	}
   285  
   286  	var seatCancellations *SeatCancellations
   287  	resp, err := s.client.Do(ctx, req, &seatCancellations)
   288  	if err != nil {
   289  		return nil, resp, err
   290  	}
   291  
   292  	return seatCancellations, resp, nil
   293  }
   294  
   295  // GetSeatDetails gets Copilot for Business seat assignment details for a user.
   296  //
   297  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-user-management#get-copilot-seat-assignment-details-for-a-user
   298  //
   299  //meta:operation GET /orgs/{org}/members/{username}/copilot
   300  func (s *CopilotService) GetSeatDetails(ctx context.Context, org, user string) (*CopilotSeatDetails, *Response, error) {
   301  	u := fmt.Sprintf("orgs/%v/members/%v/copilot", org, user)
   302  
   303  	req, err := s.client.NewRequest("GET", u, nil)
   304  	if err != nil {
   305  		return nil, nil, err
   306  	}
   307  
   308  	var seatDetails *CopilotSeatDetails
   309  	resp, err := s.client.Do(ctx, req, &seatDetails)
   310  	if err != nil {
   311  		return nil, resp, err
   312  	}
   313  
   314  	return seatDetails, resp, nil
   315  }