github.com/google/go-github/v60@v60.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-business#get-copilot-business-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-business#list-all-copilot-business-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  
   165  	req, err := s.client.NewRequest("GET", u, opts)
   166  	if err != nil {
   167  		return nil, nil, err
   168  	}
   169  
   170  	var copilotSeats *ListCopilotSeatsResponse
   171  	resp, err := s.client.Do(ctx, req, &copilotSeats)
   172  	if err != nil {
   173  		return nil, resp, err
   174  	}
   175  
   176  	return copilotSeats, resp, nil
   177  }
   178  
   179  // AddCopilotTeams adds teams to the Copilot for Business subscription for an organization.
   180  //
   181  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-business#add-teams-to-the-copilot-business-subscription-for-an-organization
   182  //
   183  //meta:operation POST /orgs/{org}/copilot/billing/selected_teams
   184  func (s *CopilotService) AddCopilotTeams(ctx context.Context, org string, teamNames []string) (*SeatAssignments, *Response, error) {
   185  	u := fmt.Sprintf("orgs/%v/copilot/billing/selected_teams", org)
   186  
   187  	body := struct {
   188  		SelectedTeams []string `json:"selected_teams"`
   189  	}{
   190  		SelectedTeams: teamNames,
   191  	}
   192  
   193  	req, err := s.client.NewRequest("POST", u, body)
   194  	if err != nil {
   195  		return nil, nil, err
   196  	}
   197  
   198  	var seatAssignments *SeatAssignments
   199  	resp, err := s.client.Do(ctx, req, &seatAssignments)
   200  	if err != nil {
   201  		return nil, resp, err
   202  	}
   203  
   204  	return seatAssignments, resp, nil
   205  }
   206  
   207  // RemoveCopilotTeams removes teams from the Copilot for Business subscription for an organization.
   208  //
   209  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-business#remove-teams-from-the-copilot-business-subscription-for-an-organization
   210  //
   211  //meta:operation DELETE /orgs/{org}/copilot/billing/selected_teams
   212  func (s *CopilotService) RemoveCopilotTeams(ctx context.Context, org string, teamNames []string) (*SeatCancellations, *Response, error) {
   213  	u := fmt.Sprintf("orgs/%v/copilot/billing/selected_teams", org)
   214  
   215  	body := struct {
   216  		SelectedTeams []string `json:"selected_teams"`
   217  	}{
   218  		SelectedTeams: teamNames,
   219  	}
   220  
   221  	req, err := s.client.NewRequest("DELETE", u, body)
   222  	if err != nil {
   223  		return nil, nil, err
   224  	}
   225  
   226  	var seatCancellations *SeatCancellations
   227  	resp, err := s.client.Do(ctx, req, &seatCancellations)
   228  	if err != nil {
   229  		return nil, resp, err
   230  	}
   231  
   232  	return seatCancellations, resp, nil
   233  }
   234  
   235  // AddCopilotUsers adds users to the Copilot for Business subscription for an organization
   236  //
   237  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-business#add-users-to-the-copilot-business-subscription-for-an-organization
   238  //
   239  //meta:operation POST /orgs/{org}/copilot/billing/selected_users
   240  func (s *CopilotService) AddCopilotUsers(ctx context.Context, org string, users []string) (*SeatAssignments, *Response, error) {
   241  	u := fmt.Sprintf("orgs/%v/copilot/billing/selected_users", org)
   242  
   243  	body := struct {
   244  		SelectedUsernames []string `json:"selected_usernames"`
   245  	}{
   246  		SelectedUsernames: users,
   247  	}
   248  
   249  	req, err := s.client.NewRequest("POST", u, body)
   250  	if err != nil {
   251  		return nil, nil, err
   252  	}
   253  
   254  	var seatAssignments *SeatAssignments
   255  	resp, err := s.client.Do(ctx, req, &seatAssignments)
   256  	if err != nil {
   257  		return nil, resp, err
   258  	}
   259  
   260  	return seatAssignments, resp, nil
   261  }
   262  
   263  // RemoveCopilotUsers removes users from the Copilot for Business subscription for an organization.
   264  //
   265  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-business#remove-users-from-the-copilot-business-subscription-for-an-organization
   266  //
   267  //meta:operation DELETE /orgs/{org}/copilot/billing/selected_users
   268  func (s *CopilotService) RemoveCopilotUsers(ctx context.Context, org string, users []string) (*SeatCancellations, *Response, error) {
   269  	u := fmt.Sprintf("orgs/%v/copilot/billing/selected_users", org)
   270  
   271  	body := struct {
   272  		SelectedUsernames []string `json:"selected_usernames"`
   273  	}{
   274  		SelectedUsernames: users,
   275  	}
   276  
   277  	req, err := s.client.NewRequest("DELETE", u, body)
   278  	if err != nil {
   279  		return nil, nil, err
   280  	}
   281  
   282  	var seatCancellations *SeatCancellations
   283  	resp, err := s.client.Do(ctx, req, &seatCancellations)
   284  	if err != nil {
   285  		return nil, resp, err
   286  	}
   287  
   288  	return seatCancellations, resp, nil
   289  }
   290  
   291  // GetSeatDetails gets Copilot for Business seat assignment details for a user.
   292  //
   293  // GitHub API docs: https://docs.github.com/rest/copilot/copilot-business#get-copilot-business-seat-assignment-details-for-a-user
   294  //
   295  //meta:operation GET /orgs/{org}/members/{username}/copilot
   296  func (s *CopilotService) GetSeatDetails(ctx context.Context, org, user string) (*CopilotSeatDetails, *Response, error) {
   297  	u := fmt.Sprintf("orgs/%v/members/%v/copilot", org, user)
   298  
   299  	req, err := s.client.NewRequest("GET", u, nil)
   300  	if err != nil {
   301  		return nil, nil, err
   302  	}
   303  
   304  	var seatDetails *CopilotSeatDetails
   305  	resp, err := s.client.Do(ctx, req, &seatDetails)
   306  	if err != nil {
   307  		return nil, resp, err
   308  	}
   309  
   310  	return seatDetails, resp, nil
   311  }