Repository: google/go-github
File: github/copilot.go (Go)

Code before:
	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"`
}

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
		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" {
			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" {
			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" {
			organization := &Organization{}

Review comment (suggestion):
Not sure the documentation expectations here, but should this have a link to the GitHub API documentation? (I would have also mentioned the specific API version, but the Copilot API is technically in public preview and subject to change at any time)

Code after:
	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"`
}

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/en/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" {
			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" {
			team := &Team{}
			if err := json.Unmarshal(jsonData, team); err != nil {
				return err
			}
			cp.Assignee = team