github.com/google/go-github/v42@v42.0.0/github/repos.go (about)

     1  // Copyright 2013 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  	"errors"
    12  	"fmt"
    13  	"net/http"
    14  	"strings"
    15  )
    16  
    17  const githubBranchNotProtected string = "Branch not protected"
    18  
    19  var ErrBranchNotProtected = errors.New("branch is not protected")
    20  
    21  // RepositoriesService handles communication with the repository related
    22  // methods of the GitHub API.
    23  //
    24  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/
    25  type RepositoriesService service
    26  
    27  // Repository represents a GitHub repository.
    28  type Repository struct {
    29  	ID                  *int64          `json:"id,omitempty"`
    30  	NodeID              *string         `json:"node_id,omitempty"`
    31  	Owner               *User           `json:"owner,omitempty"`
    32  	Name                *string         `json:"name,omitempty"`
    33  	FullName            *string         `json:"full_name,omitempty"`
    34  	Description         *string         `json:"description,omitempty"`
    35  	Homepage            *string         `json:"homepage,omitempty"`
    36  	CodeOfConduct       *CodeOfConduct  `json:"code_of_conduct,omitempty"`
    37  	DefaultBranch       *string         `json:"default_branch,omitempty"`
    38  	MasterBranch        *string         `json:"master_branch,omitempty"`
    39  	CreatedAt           *Timestamp      `json:"created_at,omitempty"`
    40  	PushedAt            *Timestamp      `json:"pushed_at,omitempty"`
    41  	UpdatedAt           *Timestamp      `json:"updated_at,omitempty"`
    42  	HTMLURL             *string         `json:"html_url,omitempty"`
    43  	CloneURL            *string         `json:"clone_url,omitempty"`
    44  	GitURL              *string         `json:"git_url,omitempty"`
    45  	MirrorURL           *string         `json:"mirror_url,omitempty"`
    46  	SSHURL              *string         `json:"ssh_url,omitempty"`
    47  	SVNURL              *string         `json:"svn_url,omitempty"`
    48  	Language            *string         `json:"language,omitempty"`
    49  	Fork                *bool           `json:"fork,omitempty"`
    50  	ForksCount          *int            `json:"forks_count,omitempty"`
    51  	NetworkCount        *int            `json:"network_count,omitempty"`
    52  	OpenIssuesCount     *int            `json:"open_issues_count,omitempty"`
    53  	OpenIssues          *int            `json:"open_issues,omitempty"` // Deprecated: Replaced by OpenIssuesCount. For backward compatibility OpenIssues is still populated.
    54  	StargazersCount     *int            `json:"stargazers_count,omitempty"`
    55  	SubscribersCount    *int            `json:"subscribers_count,omitempty"`
    56  	WatchersCount       *int            `json:"watchers_count,omitempty"` // Deprecated: Replaced by StargazersCount. For backward compatibility WatchersCount is still populated.
    57  	Watchers            *int            `json:"watchers,omitempty"`       // Deprecated: Replaced by StargazersCount. For backward compatibility Watchers is still populated.
    58  	Size                *int            `json:"size,omitempty"`
    59  	AutoInit            *bool           `json:"auto_init,omitempty"`
    60  	Parent              *Repository     `json:"parent,omitempty"`
    61  	Source              *Repository     `json:"source,omitempty"`
    62  	TemplateRepository  *Repository     `json:"template_repository,omitempty"`
    63  	Organization        *Organization   `json:"organization,omitempty"`
    64  	Permissions         map[string]bool `json:"permissions,omitempty"`
    65  	AllowRebaseMerge    *bool           `json:"allow_rebase_merge,omitempty"`
    66  	AllowSquashMerge    *bool           `json:"allow_squash_merge,omitempty"`
    67  	AllowMergeCommit    *bool           `json:"allow_merge_commit,omitempty"`
    68  	AllowAutoMerge      *bool           `json:"allow_auto_merge,omitempty"`
    69  	DeleteBranchOnMerge *bool           `json:"delete_branch_on_merge,omitempty"`
    70  	Topics              []string        `json:"topics,omitempty"`
    71  	Archived            *bool           `json:"archived,omitempty"`
    72  	Disabled            *bool           `json:"disabled,omitempty"`
    73  
    74  	// Only provided when using RepositoriesService.Get while in preview
    75  	License *License `json:"license,omitempty"`
    76  
    77  	// Additional mutable fields when creating and editing a repository
    78  	Private           *bool   `json:"private,omitempty"`
    79  	HasIssues         *bool   `json:"has_issues,omitempty"`
    80  	HasWiki           *bool   `json:"has_wiki,omitempty"`
    81  	HasPages          *bool   `json:"has_pages,omitempty"`
    82  	HasProjects       *bool   `json:"has_projects,omitempty"`
    83  	HasDownloads      *bool   `json:"has_downloads,omitempty"`
    84  	IsTemplate        *bool   `json:"is_template,omitempty"`
    85  	LicenseTemplate   *string `json:"license_template,omitempty"`
    86  	GitignoreTemplate *string `json:"gitignore_template,omitempty"`
    87  
    88  	// Options for configuring Advanced Security and Secret Scanning
    89  	SecurityAndAnalysis *SecurityAndAnalysis `json:"security_and_analysis,omitempty"`
    90  
    91  	// Creating an organization repository. Required for non-owners.
    92  	TeamID *int64 `json:"team_id,omitempty"`
    93  
    94  	// API URLs
    95  	URL              *string `json:"url,omitempty"`
    96  	ArchiveURL       *string `json:"archive_url,omitempty"`
    97  	AssigneesURL     *string `json:"assignees_url,omitempty"`
    98  	BlobsURL         *string `json:"blobs_url,omitempty"`
    99  	BranchesURL      *string `json:"branches_url,omitempty"`
   100  	CollaboratorsURL *string `json:"collaborators_url,omitempty"`
   101  	CommentsURL      *string `json:"comments_url,omitempty"`
   102  	CommitsURL       *string `json:"commits_url,omitempty"`
   103  	CompareURL       *string `json:"compare_url,omitempty"`
   104  	ContentsURL      *string `json:"contents_url,omitempty"`
   105  	ContributorsURL  *string `json:"contributors_url,omitempty"`
   106  	DeploymentsURL   *string `json:"deployments_url,omitempty"`
   107  	DownloadsURL     *string `json:"downloads_url,omitempty"`
   108  	EventsURL        *string `json:"events_url,omitempty"`
   109  	ForksURL         *string `json:"forks_url,omitempty"`
   110  	GitCommitsURL    *string `json:"git_commits_url,omitempty"`
   111  	GitRefsURL       *string `json:"git_refs_url,omitempty"`
   112  	GitTagsURL       *string `json:"git_tags_url,omitempty"`
   113  	HooksURL         *string `json:"hooks_url,omitempty"`
   114  	IssueCommentURL  *string `json:"issue_comment_url,omitempty"`
   115  	IssueEventsURL   *string `json:"issue_events_url,omitempty"`
   116  	IssuesURL        *string `json:"issues_url,omitempty"`
   117  	KeysURL          *string `json:"keys_url,omitempty"`
   118  	LabelsURL        *string `json:"labels_url,omitempty"`
   119  	LanguagesURL     *string `json:"languages_url,omitempty"`
   120  	MergesURL        *string `json:"merges_url,omitempty"`
   121  	MilestonesURL    *string `json:"milestones_url,omitempty"`
   122  	NotificationsURL *string `json:"notifications_url,omitempty"`
   123  	PullsURL         *string `json:"pulls_url,omitempty"`
   124  	ReleasesURL      *string `json:"releases_url,omitempty"`
   125  	StargazersURL    *string `json:"stargazers_url,omitempty"`
   126  	StatusesURL      *string `json:"statuses_url,omitempty"`
   127  	SubscribersURL   *string `json:"subscribers_url,omitempty"`
   128  	SubscriptionURL  *string `json:"subscription_url,omitempty"`
   129  	TagsURL          *string `json:"tags_url,omitempty"`
   130  	TreesURL         *string `json:"trees_url,omitempty"`
   131  	TeamsURL         *string `json:"teams_url,omitempty"`
   132  
   133  	// TextMatches is only populated from search results that request text matches
   134  	// See: search.go and https://docs.github.com/en/free-pro-team@latest/rest/reference/search/#text-match-metadata
   135  	TextMatches []*TextMatch `json:"text_matches,omitempty"`
   136  
   137  	// Visibility is only used for Create and Edit endpoints. The visibility field
   138  	// overrides the field parameter when both are used.
   139  	// Can be one of public, private or internal.
   140  	Visibility *string `json:"visibility,omitempty"`
   141  }
   142  
   143  func (r Repository) String() string {
   144  	return Stringify(r)
   145  }
   146  
   147  // BranchListOptions specifies the optional parameters to the
   148  // RepositoriesService.ListBranches method.
   149  type BranchListOptions struct {
   150  	// Setting to true returns only protected branches.
   151  	// When set to false, only unprotected branches are returned.
   152  	// Omitting this parameter returns all branches.
   153  	// Default: nil
   154  	Protected *bool `url:"protected,omitempty"`
   155  
   156  	ListOptions
   157  }
   158  
   159  // RepositoryListOptions specifies the optional parameters to the
   160  // RepositoriesService.List method.
   161  type RepositoryListOptions struct {
   162  	// Visibility of repositories to list. Can be one of all, public, or private.
   163  	// Default: all
   164  	Visibility string `url:"visibility,omitempty"`
   165  
   166  	// List repos of given affiliation[s].
   167  	// Comma-separated list of values. Can include:
   168  	// * owner: Repositories that are owned by the authenticated user.
   169  	// * collaborator: Repositories that the user has been added to as a
   170  	//   collaborator.
   171  	// * organization_member: Repositories that the user has access to through
   172  	//   being a member of an organization. This includes every repository on
   173  	//   every team that the user is on.
   174  	// Default: owner,collaborator,organization_member
   175  	Affiliation string `url:"affiliation,omitempty"`
   176  
   177  	// Type of repositories to list.
   178  	// Can be one of all, owner, public, private, member. Default: all
   179  	// Will cause a 422 error if used in the same request as visibility or
   180  	// affiliation.
   181  	Type string `url:"type,omitempty"`
   182  
   183  	// How to sort the repository list. Can be one of created, updated, pushed,
   184  	// full_name. Default: full_name
   185  	Sort string `url:"sort,omitempty"`
   186  
   187  	// Direction in which to sort repositories. Can be one of asc or desc.
   188  	// Default: when using full_name: asc; otherwise desc
   189  	Direction string `url:"direction,omitempty"`
   190  
   191  	ListOptions
   192  }
   193  
   194  // SecurityAndAnalysis specifies the optional advanced security features
   195  // that are enabled on a given repository.
   196  type SecurityAndAnalysis struct {
   197  	AdvancedSecurity *AdvancedSecurity `json:"advanced_security,omitempty"`
   198  	SecretScanning   *SecretScanning   `json:"secret_scanning,omitempty"`
   199  }
   200  
   201  func (s SecurityAndAnalysis) String() string {
   202  	return Stringify(s)
   203  }
   204  
   205  // AdvancedSecurity specifies the state of advanced security on a repository.
   206  //
   207  // GitHub API docs: https://docs.github.com/en/github/getting-started-with-github/learning-about-github/about-github-advanced-security
   208  type AdvancedSecurity struct {
   209  	Status *string `json:"status,omitempty"`
   210  }
   211  
   212  func (a AdvancedSecurity) String() string {
   213  	return Stringify(a)
   214  }
   215  
   216  // SecretScanning specifies the state of secret scanning on a repository.
   217  //
   218  // GitHub API docs: https://docs.github.com/en/code-security/secret-security/about-secret-scanning
   219  type SecretScanning struct {
   220  	Status *string `json:"status,omitempty"`
   221  }
   222  
   223  func (s SecretScanning) String() string {
   224  	return Stringify(s)
   225  }
   226  
   227  // List the repositories for a user. Passing the empty string will list
   228  // repositories for the authenticated user.
   229  //
   230  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#list-repositories-for-the-authenticated-user
   231  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#list-repositories-for-a-user
   232  func (s *RepositoriesService) List(ctx context.Context, user string, opts *RepositoryListOptions) ([]*Repository, *Response, error) {
   233  	var u string
   234  	if user != "" {
   235  		u = fmt.Sprintf("users/%v/repos", user)
   236  	} else {
   237  		u = "user/repos"
   238  	}
   239  	u, err := addOptions(u, opts)
   240  	if err != nil {
   241  		return nil, nil, err
   242  	}
   243  
   244  	req, err := s.client.NewRequest("GET", u, nil)
   245  	if err != nil {
   246  		return nil, nil, err
   247  	}
   248  
   249  	// TODO: remove custom Accept headers when APIs fully launch.
   250  	acceptHeaders := []string{mediaTypeTopicsPreview, mediaTypeRepositoryVisibilityPreview}
   251  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   252  
   253  	var repos []*Repository
   254  	resp, err := s.client.Do(ctx, req, &repos)
   255  	if err != nil {
   256  		return nil, resp, err
   257  	}
   258  
   259  	return repos, resp, nil
   260  }
   261  
   262  // RepositoryListByOrgOptions specifies the optional parameters to the
   263  // RepositoriesService.ListByOrg method.
   264  type RepositoryListByOrgOptions struct {
   265  	// Type of repositories to list. Possible values are: all, public, private,
   266  	// forks, sources, member. Default is "all".
   267  	Type string `url:"type,omitempty"`
   268  
   269  	// How to sort the repository list. Can be one of created, updated, pushed,
   270  	// full_name. Default is "created".
   271  	Sort string `url:"sort,omitempty"`
   272  
   273  	// Direction in which to sort repositories. Can be one of asc or desc.
   274  	// Default when using full_name: asc; otherwise desc.
   275  	Direction string `url:"direction,omitempty"`
   276  
   277  	ListOptions
   278  }
   279  
   280  // ListByOrg lists the repositories for an organization.
   281  //
   282  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#list-organization-repositories
   283  func (s *RepositoriesService) ListByOrg(ctx context.Context, org string, opts *RepositoryListByOrgOptions) ([]*Repository, *Response, error) {
   284  	u := fmt.Sprintf("orgs/%v/repos", org)
   285  	u, err := addOptions(u, opts)
   286  	if err != nil {
   287  		return nil, nil, err
   288  	}
   289  
   290  	req, err := s.client.NewRequest("GET", u, nil)
   291  	if err != nil {
   292  		return nil, nil, err
   293  	}
   294  
   295  	// TODO: remove custom Accept headers when APIs fully launch.
   296  	acceptHeaders := []string{mediaTypeTopicsPreview, mediaTypeRepositoryVisibilityPreview}
   297  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   298  
   299  	var repos []*Repository
   300  	resp, err := s.client.Do(ctx, req, &repos)
   301  	if err != nil {
   302  		return nil, resp, err
   303  	}
   304  
   305  	return repos, resp, nil
   306  }
   307  
   308  // RepositoryListAllOptions specifies the optional parameters to the
   309  // RepositoriesService.ListAll method.
   310  type RepositoryListAllOptions struct {
   311  	// ID of the last repository seen
   312  	Since int64 `url:"since,omitempty"`
   313  }
   314  
   315  // ListAll lists all GitHub repositories in the order that they were created.
   316  //
   317  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#list-public-repositories
   318  func (s *RepositoriesService) ListAll(ctx context.Context, opts *RepositoryListAllOptions) ([]*Repository, *Response, error) {
   319  	u, err := addOptions("repositories", opts)
   320  	if err != nil {
   321  		return nil, nil, err
   322  	}
   323  
   324  	req, err := s.client.NewRequest("GET", u, nil)
   325  	if err != nil {
   326  		return nil, nil, err
   327  	}
   328  
   329  	var repos []*Repository
   330  	resp, err := s.client.Do(ctx, req, &repos)
   331  	if err != nil {
   332  		return nil, resp, err
   333  	}
   334  
   335  	return repos, resp, nil
   336  }
   337  
   338  // createRepoRequest is a subset of Repository and is used internally
   339  // by Create to pass only the known fields for the endpoint.
   340  //
   341  // See https://github.com/google/go-github/issues/1014 for more
   342  // information.
   343  type createRepoRequest struct {
   344  	// Name is required when creating a repo.
   345  	Name        *string `json:"name,omitempty"`
   346  	Description *string `json:"description,omitempty"`
   347  	Homepage    *string `json:"homepage,omitempty"`
   348  
   349  	Private     *bool   `json:"private,omitempty"`
   350  	Visibility  *string `json:"visibility,omitempty"`
   351  	HasIssues   *bool   `json:"has_issues,omitempty"`
   352  	HasProjects *bool   `json:"has_projects,omitempty"`
   353  	HasWiki     *bool   `json:"has_wiki,omitempty"`
   354  	IsTemplate  *bool   `json:"is_template,omitempty"`
   355  
   356  	// Creating an organization repository. Required for non-owners.
   357  	TeamID *int64 `json:"team_id,omitempty"`
   358  
   359  	AutoInit            *bool   `json:"auto_init,omitempty"`
   360  	GitignoreTemplate   *string `json:"gitignore_template,omitempty"`
   361  	LicenseTemplate     *string `json:"license_template,omitempty"`
   362  	AllowSquashMerge    *bool   `json:"allow_squash_merge,omitempty"`
   363  	AllowMergeCommit    *bool   `json:"allow_merge_commit,omitempty"`
   364  	AllowRebaseMerge    *bool   `json:"allow_rebase_merge,omitempty"`
   365  	AllowAutoMerge      *bool   `json:"allow_auto_merge,omitempty"`
   366  	DeleteBranchOnMerge *bool   `json:"delete_branch_on_merge,omitempty"`
   367  }
   368  
   369  // Create a new repository. If an organization is specified, the new
   370  // repository will be created under that org. If the empty string is
   371  // specified, it will be created for the authenticated user.
   372  //
   373  // Note that only a subset of the repo fields are used and repo must
   374  // not be nil.
   375  //
   376  // Also note that this method will return the response without actually
   377  // waiting for GitHub to finish creating the repository and letting the
   378  // changes propagate throughout its servers. You may set up a loop with
   379  // exponential back-off to verify repository's creation.
   380  //
   381  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#create-a-repository-for-the-authenticated-user
   382  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#create-an-organization-repository
   383  func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repository) (*Repository, *Response, error) {
   384  	var u string
   385  	if org != "" {
   386  		u = fmt.Sprintf("orgs/%v/repos", org)
   387  	} else {
   388  		u = "user/repos"
   389  	}
   390  
   391  	repoReq := &createRepoRequest{
   392  		Name:                repo.Name,
   393  		Description:         repo.Description,
   394  		Homepage:            repo.Homepage,
   395  		Private:             repo.Private,
   396  		Visibility:          repo.Visibility,
   397  		HasIssues:           repo.HasIssues,
   398  		HasProjects:         repo.HasProjects,
   399  		HasWiki:             repo.HasWiki,
   400  		IsTemplate:          repo.IsTemplate,
   401  		TeamID:              repo.TeamID,
   402  		AutoInit:            repo.AutoInit,
   403  		GitignoreTemplate:   repo.GitignoreTemplate,
   404  		LicenseTemplate:     repo.LicenseTemplate,
   405  		AllowSquashMerge:    repo.AllowSquashMerge,
   406  		AllowMergeCommit:    repo.AllowMergeCommit,
   407  		AllowRebaseMerge:    repo.AllowRebaseMerge,
   408  		AllowAutoMerge:      repo.AllowAutoMerge,
   409  		DeleteBranchOnMerge: repo.DeleteBranchOnMerge,
   410  	}
   411  
   412  	req, err := s.client.NewRequest("POST", u, repoReq)
   413  	if err != nil {
   414  		return nil, nil, err
   415  	}
   416  
   417  	acceptHeaders := []string{mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview}
   418  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   419  	r := new(Repository)
   420  	resp, err := s.client.Do(ctx, req, r)
   421  	if err != nil {
   422  		return nil, resp, err
   423  	}
   424  
   425  	return r, resp, nil
   426  }
   427  
   428  // TemplateRepoRequest represents a request to create a repository from a template.
   429  type TemplateRepoRequest struct {
   430  	// Name is required when creating a repo.
   431  	Name        *string `json:"name,omitempty"`
   432  	Owner       *string `json:"owner,omitempty"`
   433  	Description *string `json:"description,omitempty"`
   434  
   435  	IncludeAllBranches *bool `json:"include_all_branches,omitempty"`
   436  	Private            *bool `json:"private,omitempty"`
   437  }
   438  
   439  // CreateFromTemplate generates a repository from a template.
   440  //
   441  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#create-a-repository-using-a-template
   442  func (s *RepositoriesService) CreateFromTemplate(ctx context.Context, templateOwner, templateRepo string, templateRepoReq *TemplateRepoRequest) (*Repository, *Response, error) {
   443  	u := fmt.Sprintf("repos/%v/%v/generate", templateOwner, templateRepo)
   444  
   445  	req, err := s.client.NewRequest("POST", u, templateRepoReq)
   446  	if err != nil {
   447  		return nil, nil, err
   448  	}
   449  
   450  	req.Header.Set("Accept", mediaTypeRepositoryTemplatePreview)
   451  	r := new(Repository)
   452  	resp, err := s.client.Do(ctx, req, r)
   453  	if err != nil {
   454  		return nil, resp, err
   455  	}
   456  
   457  	return r, resp, nil
   458  }
   459  
   460  // Get fetches a repository.
   461  //
   462  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#get-a-repository
   463  func (s *RepositoriesService) Get(ctx context.Context, owner, repo string) (*Repository, *Response, error) {
   464  	u := fmt.Sprintf("repos/%v/%v", owner, repo)
   465  	req, err := s.client.NewRequest("GET", u, nil)
   466  	if err != nil {
   467  		return nil, nil, err
   468  	}
   469  
   470  	// TODO: remove custom Accept header when the license support fully launches
   471  	// https://docs.github.com/en/free-pro-team@latest/rest/reference/licenses/#get-a-repositorys-license
   472  	acceptHeaders := []string{
   473  		mediaTypeCodesOfConductPreview,
   474  		mediaTypeTopicsPreview,
   475  		mediaTypeRepositoryTemplatePreview,
   476  		mediaTypeRepositoryVisibilityPreview,
   477  	}
   478  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   479  
   480  	repository := new(Repository)
   481  	resp, err := s.client.Do(ctx, req, repository)
   482  	if err != nil {
   483  		return nil, resp, err
   484  	}
   485  
   486  	return repository, resp, nil
   487  }
   488  
   489  // GetCodeOfConduct gets the contents of a repository's code of conduct.
   490  //
   491  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/codes-of-conduct/#get-the-code-of-conduct-for-a-repository
   492  func (s *RepositoriesService) GetCodeOfConduct(ctx context.Context, owner, repo string) (*CodeOfConduct, *Response, error) {
   493  	u := fmt.Sprintf("repos/%v/%v/community/code_of_conduct", owner, repo)
   494  	req, err := s.client.NewRequest("GET", u, nil)
   495  	if err != nil {
   496  		return nil, nil, err
   497  	}
   498  
   499  	// TODO: remove custom Accept header when this API fully launches.
   500  	req.Header.Set("Accept", mediaTypeCodesOfConductPreview)
   501  
   502  	coc := new(CodeOfConduct)
   503  	resp, err := s.client.Do(ctx, req, coc)
   504  	if err != nil {
   505  		return nil, resp, err
   506  	}
   507  
   508  	return coc, resp, nil
   509  }
   510  
   511  // GetByID fetches a repository.
   512  //
   513  // Note: GetByID uses the undocumented GitHub API endpoint /repositories/:id.
   514  func (s *RepositoriesService) GetByID(ctx context.Context, id int64) (*Repository, *Response, error) {
   515  	u := fmt.Sprintf("repositories/%d", id)
   516  	req, err := s.client.NewRequest("GET", u, nil)
   517  	if err != nil {
   518  		return nil, nil, err
   519  	}
   520  
   521  	repository := new(Repository)
   522  	resp, err := s.client.Do(ctx, req, repository)
   523  	if err != nil {
   524  		return nil, resp, err
   525  	}
   526  
   527  	return repository, resp, nil
   528  }
   529  
   530  // Edit updates a repository.
   531  //
   532  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#update-a-repository
   533  func (s *RepositoriesService) Edit(ctx context.Context, owner, repo string, repository *Repository) (*Repository, *Response, error) {
   534  	u := fmt.Sprintf("repos/%v/%v", owner, repo)
   535  	req, err := s.client.NewRequest("PATCH", u, repository)
   536  	if err != nil {
   537  		return nil, nil, err
   538  	}
   539  
   540  	acceptHeaders := []string{mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview}
   541  	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
   542  	r := new(Repository)
   543  	resp, err := s.client.Do(ctx, req, r)
   544  	if err != nil {
   545  		return nil, resp, err
   546  	}
   547  
   548  	return r, resp, nil
   549  }
   550  
   551  // Delete a repository.
   552  //
   553  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#delete-a-repository
   554  func (s *RepositoriesService) Delete(ctx context.Context, owner, repo string) (*Response, error) {
   555  	u := fmt.Sprintf("repos/%v/%v", owner, repo)
   556  	req, err := s.client.NewRequest("DELETE", u, nil)
   557  	if err != nil {
   558  		return nil, err
   559  	}
   560  
   561  	return s.client.Do(ctx, req, nil)
   562  }
   563  
   564  // Contributor represents a repository contributor
   565  type Contributor struct {
   566  	Login             *string `json:"login,omitempty"`
   567  	ID                *int64  `json:"id,omitempty"`
   568  	NodeID            *string `json:"node_id,omitempty"`
   569  	AvatarURL         *string `json:"avatar_url,omitempty"`
   570  	GravatarID        *string `json:"gravatar_id,omitempty"`
   571  	URL               *string `json:"url,omitempty"`
   572  	HTMLURL           *string `json:"html_url,omitempty"`
   573  	FollowersURL      *string `json:"followers_url,omitempty"`
   574  	FollowingURL      *string `json:"following_url,omitempty"`
   575  	GistsURL          *string `json:"gists_url,omitempty"`
   576  	StarredURL        *string `json:"starred_url,omitempty"`
   577  	SubscriptionsURL  *string `json:"subscriptions_url,omitempty"`
   578  	OrganizationsURL  *string `json:"organizations_url,omitempty"`
   579  	ReposURL          *string `json:"repos_url,omitempty"`
   580  	EventsURL         *string `json:"events_url,omitempty"`
   581  	ReceivedEventsURL *string `json:"received_events_url,omitempty"`
   582  	Type              *string `json:"type,omitempty"`
   583  	SiteAdmin         *bool   `json:"site_admin,omitempty"`
   584  	Contributions     *int    `json:"contributions,omitempty"`
   585  	Name              *string `json:"name,omitempty"`
   586  	Email             *string `json:"email,omitempty"`
   587  }
   588  
   589  // ListContributorsOptions specifies the optional parameters to the
   590  // RepositoriesService.ListContributors method.
   591  type ListContributorsOptions struct {
   592  	// Include anonymous contributors in results or not
   593  	Anon string `url:"anon,omitempty"`
   594  
   595  	ListOptions
   596  }
   597  
   598  // GetVulnerabilityAlerts checks if vulnerability alerts are enabled for a repository.
   599  //
   600  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#check-if-vulnerability-alerts-are-enabled-for-a-repository
   601  func (s *RepositoriesService) GetVulnerabilityAlerts(ctx context.Context, owner, repository string) (bool, *Response, error) {
   602  	u := fmt.Sprintf("repos/%v/%v/vulnerability-alerts", owner, repository)
   603  
   604  	req, err := s.client.NewRequest("GET", u, nil)
   605  	if err != nil {
   606  		return false, nil, err
   607  	}
   608  
   609  	// TODO: remove custom Accept header when this API fully launches
   610  	req.Header.Set("Accept", mediaTypeRequiredVulnerabilityAlertsPreview)
   611  
   612  	resp, err := s.client.Do(ctx, req, nil)
   613  	vulnerabilityAlertsEnabled, err := parseBoolResponse(err)
   614  
   615  	return vulnerabilityAlertsEnabled, resp, err
   616  }
   617  
   618  // EnableVulnerabilityAlerts enables vulnerability alerts and the dependency graph for a repository.
   619  //
   620  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#enable-vulnerability-alerts
   621  func (s *RepositoriesService) EnableVulnerabilityAlerts(ctx context.Context, owner, repository string) (*Response, error) {
   622  	u := fmt.Sprintf("repos/%v/%v/vulnerability-alerts", owner, repository)
   623  
   624  	req, err := s.client.NewRequest("PUT", u, nil)
   625  	if err != nil {
   626  		return nil, err
   627  	}
   628  
   629  	// TODO: remove custom Accept header when this API fully launches
   630  	req.Header.Set("Accept", mediaTypeRequiredVulnerabilityAlertsPreview)
   631  
   632  	return s.client.Do(ctx, req, nil)
   633  }
   634  
   635  // DisableVulnerabilityAlerts disables vulnerability alerts and the dependency graph for a repository.
   636  //
   637  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#disable-vulnerability-alerts
   638  func (s *RepositoriesService) DisableVulnerabilityAlerts(ctx context.Context, owner, repository string) (*Response, error) {
   639  	u := fmt.Sprintf("repos/%v/%v/vulnerability-alerts", owner, repository)
   640  
   641  	req, err := s.client.NewRequest("DELETE", u, nil)
   642  	if err != nil {
   643  		return nil, err
   644  	}
   645  
   646  	// TODO: remove custom Accept header when this API fully launches
   647  	req.Header.Set("Accept", mediaTypeRequiredVulnerabilityAlertsPreview)
   648  
   649  	return s.client.Do(ctx, req, nil)
   650  }
   651  
   652  // EnableAutomatedSecurityFixes enables the automated security fixes for a repository.
   653  //
   654  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#enable-automated-security-fixes
   655  func (s *RepositoriesService) EnableAutomatedSecurityFixes(ctx context.Context, owner, repository string) (*Response, error) {
   656  	u := fmt.Sprintf("repos/%v/%v/automated-security-fixes", owner, repository)
   657  
   658  	req, err := s.client.NewRequest("PUT", u, nil)
   659  	if err != nil {
   660  		return nil, err
   661  	}
   662  
   663  	// TODO: remove custom Accept header when this API fully launches
   664  	req.Header.Set("Accept", mediaTypeRequiredAutomatedSecurityFixesPreview)
   665  
   666  	return s.client.Do(ctx, req, nil)
   667  }
   668  
   669  // DisableAutomatedSecurityFixes disables vulnerability alerts and the dependency graph for a repository.
   670  //
   671  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#disable-automated-security-fixes
   672  func (s *RepositoriesService) DisableAutomatedSecurityFixes(ctx context.Context, owner, repository string) (*Response, error) {
   673  	u := fmt.Sprintf("repos/%v/%v/automated-security-fixes", owner, repository)
   674  
   675  	req, err := s.client.NewRequest("DELETE", u, nil)
   676  	if err != nil {
   677  		return nil, err
   678  	}
   679  
   680  	// TODO: remove custom Accept header when this API fully launches
   681  	req.Header.Set("Accept", mediaTypeRequiredAutomatedSecurityFixesPreview)
   682  
   683  	return s.client.Do(ctx, req, nil)
   684  }
   685  
   686  // ListContributors lists contributors for a repository.
   687  //
   688  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#list-repository-contributors
   689  func (s *RepositoriesService) ListContributors(ctx context.Context, owner string, repository string, opts *ListContributorsOptions) ([]*Contributor, *Response, error) {
   690  	u := fmt.Sprintf("repos/%v/%v/contributors", owner, repository)
   691  	u, err := addOptions(u, opts)
   692  	if err != nil {
   693  		return nil, nil, err
   694  	}
   695  
   696  	req, err := s.client.NewRequest("GET", u, nil)
   697  	if err != nil {
   698  		return nil, nil, err
   699  	}
   700  
   701  	var contributor []*Contributor
   702  	resp, err := s.client.Do(ctx, req, &contributor)
   703  	if err != nil {
   704  		return nil, resp, err
   705  	}
   706  
   707  	return contributor, resp, nil
   708  }
   709  
   710  // ListLanguages lists languages for the specified repository. The returned map
   711  // specifies the languages and the number of bytes of code written in that
   712  // language. For example:
   713  //
   714  //     {
   715  //       "C": 78769,
   716  //       "Python": 7769
   717  //     }
   718  //
   719  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#list-repository-languages
   720  func (s *RepositoriesService) ListLanguages(ctx context.Context, owner string, repo string) (map[string]int, *Response, error) {
   721  	u := fmt.Sprintf("repos/%v/%v/languages", owner, repo)
   722  	req, err := s.client.NewRequest("GET", u, nil)
   723  	if err != nil {
   724  		return nil, nil, err
   725  	}
   726  
   727  	languages := make(map[string]int)
   728  	resp, err := s.client.Do(ctx, req, &languages)
   729  	if err != nil {
   730  		return nil, resp, err
   731  	}
   732  
   733  	return languages, resp, nil
   734  }
   735  
   736  // ListTeams lists the teams for the specified repository.
   737  //
   738  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#list-repository-teams
   739  func (s *RepositoriesService) ListTeams(ctx context.Context, owner string, repo string, opts *ListOptions) ([]*Team, *Response, error) {
   740  	u := fmt.Sprintf("repos/%v/%v/teams", owner, repo)
   741  	u, err := addOptions(u, opts)
   742  	if err != nil {
   743  		return nil, nil, err
   744  	}
   745  
   746  	req, err := s.client.NewRequest("GET", u, nil)
   747  	if err != nil {
   748  		return nil, nil, err
   749  	}
   750  
   751  	var teams []*Team
   752  	resp, err := s.client.Do(ctx, req, &teams)
   753  	if err != nil {
   754  		return nil, resp, err
   755  	}
   756  
   757  	return teams, resp, nil
   758  }
   759  
   760  // RepositoryTag represents a repository tag.
   761  type RepositoryTag struct {
   762  	Name       *string `json:"name,omitempty"`
   763  	Commit     *Commit `json:"commit,omitempty"`
   764  	ZipballURL *string `json:"zipball_url,omitempty"`
   765  	TarballURL *string `json:"tarball_url,omitempty"`
   766  }
   767  
   768  // ListTags lists tags for the specified repository.
   769  //
   770  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#list-repository-tags
   771  func (s *RepositoriesService) ListTags(ctx context.Context, owner string, repo string, opts *ListOptions) ([]*RepositoryTag, *Response, error) {
   772  	u := fmt.Sprintf("repos/%v/%v/tags", owner, repo)
   773  	u, err := addOptions(u, opts)
   774  	if err != nil {
   775  		return nil, nil, err
   776  	}
   777  
   778  	req, err := s.client.NewRequest("GET", u, nil)
   779  	if err != nil {
   780  		return nil, nil, err
   781  	}
   782  
   783  	var tags []*RepositoryTag
   784  	resp, err := s.client.Do(ctx, req, &tags)
   785  	if err != nil {
   786  		return nil, resp, err
   787  	}
   788  
   789  	return tags, resp, nil
   790  }
   791  
   792  // Branch represents a repository branch
   793  type Branch struct {
   794  	Name      *string           `json:"name,omitempty"`
   795  	Commit    *RepositoryCommit `json:"commit,omitempty"`
   796  	Protected *bool             `json:"protected,omitempty"`
   797  }
   798  
   799  // Protection represents a repository branch's protection.
   800  type Protection struct {
   801  	RequiredStatusChecks           *RequiredStatusChecks           `json:"required_status_checks"`
   802  	RequiredPullRequestReviews     *PullRequestReviewsEnforcement  `json:"required_pull_request_reviews"`
   803  	EnforceAdmins                  *AdminEnforcement               `json:"enforce_admins"`
   804  	Restrictions                   *BranchRestrictions             `json:"restrictions"`
   805  	RequireLinearHistory           *RequireLinearHistory           `json:"required_linear_history"`
   806  	AllowForcePushes               *AllowForcePushes               `json:"allow_force_pushes"`
   807  	AllowDeletions                 *AllowDeletions                 `json:"allow_deletions"`
   808  	RequiredConversationResolution *RequiredConversationResolution `json:"required_conversation_resolution"`
   809  }
   810  
   811  // BranchProtectionRule represents the rule applied to a repositories branch.
   812  type BranchProtectionRule struct {
   813  	ID                                       *int64     `json:"id,omitempty"`
   814  	RepositoryID                             *int64     `json:"repository_id,omitempty"`
   815  	Name                                     *string    `json:"name,omitempty"`
   816  	CreatedAt                                *Timestamp `json:"created_at,omitempty"`
   817  	UpdatedAt                                *Timestamp `json:"updated_at,omitempty"`
   818  	PullRequestReviewsEnforcementLevel       *string    `json:"pull_request_reviews_enforcement_level,omitempty"`
   819  	RequiredApprovingReviewCount             *int       `json:"required_approving_review_count,omitempty"`
   820  	DismissStaleReviewsOnPush                *bool      `json:"dismiss_stale_reviews_on_push,omitempty"`
   821  	AuthorizedDismissalActorsOnly            *bool      `json:"authorized_dismissal_actors_only,omitempty"`
   822  	IgnoreApprovalsFromContributors          *bool      `json:"ignore_approvals_from_contributors,omitempty"`
   823  	RequireCodeOwnerReview                   *bool      `json:"require_code_owner_review,omitempty"`
   824  	RequiredStatusChecks                     []string   `json:"required_status_checks,omitempty"`
   825  	RequiredStatusChecksEnforcementLevel     *string    `json:"required_status_checks_enforcement_level,omitempty"`
   826  	StrictRequiredStatusChecksPolicy         *bool      `json:"strict_required_status_checks_policy,omitempty"`
   827  	SignatureRequirementEnforcementLevel     *string    `json:"signature_requirement_enforcement_level,omitempty"`
   828  	LinearHistoryRequirementEnforcementLevel *string    `json:"linear_history_requirement_enforcement_level,omitempty"`
   829  	AdminEnforced                            *bool      `json:"admin_enforced,omitempty"`
   830  	AllowForcePushesEnforcementLevel         *string    `json:"allow_force_pushes_enforcement_level,omitempty"`
   831  	AllowDeletionsEnforcementLevel           *string    `json:"allow_deletions_enforcement_level,omitempty"`
   832  	MergeQueueEnforcementLevel               *string    `json:"merge_queue_enforcement_level,omitempty"`
   833  	RequiredDeploymentsEnforcementLevel      *string    `json:"required_deployments_enforcement_level,omitempty"`
   834  	RequiredConversationResolutionLevel      *string    `json:"required_conversation_resolution_level,omitempty"`
   835  	AuthorizedActorsOnly                     *bool      `json:"authorized_actors_only,omitempty"`
   836  	AuthorizedActorNames                     []string   `json:"authorized_actor_names,omitempty"`
   837  }
   838  
   839  // ProtectionChanges represents the changes to the rule if the BranchProtection was edited.
   840  type ProtectionChanges struct {
   841  	AuthorizedActorsOnly *AuthorizedActorsOnly `json:"authorized_actors_only,omitempty"`
   842  	AuthorizedActorNames *AuthorizedActorNames `json:"authorized_actor_names,omitempty"`
   843  }
   844  
   845  // AuthorizedActorNames represents who are authorized to edit the branch protection rules.
   846  type AuthorizedActorNames struct {
   847  	From []string `json:"from,omitempty"`
   848  }
   849  
   850  // AuthorizedActorsOnly represents if the branche rule can be edited by authorized actors only.
   851  type AuthorizedActorsOnly struct {
   852  	From *bool `json:"from,omitempty"`
   853  }
   854  
   855  // ProtectionRequest represents a request to create/edit a branch's protection.
   856  type ProtectionRequest struct {
   857  	RequiredStatusChecks       *RequiredStatusChecks                 `json:"required_status_checks"`
   858  	RequiredPullRequestReviews *PullRequestReviewsEnforcementRequest `json:"required_pull_request_reviews"`
   859  	EnforceAdmins              bool                                  `json:"enforce_admins"`
   860  	Restrictions               *BranchRestrictionsRequest            `json:"restrictions"`
   861  	// Enforces a linear commit Git history, which prevents anyone from pushing merge commits to a branch.
   862  	RequireLinearHistory *bool `json:"required_linear_history,omitempty"`
   863  	// Permits force pushes to the protected branch by anyone with write access to the repository.
   864  	AllowForcePushes *bool `json:"allow_force_pushes,omitempty"`
   865  	// Allows deletion of the protected branch by anyone with write access to the repository.
   866  	AllowDeletions *bool `json:"allow_deletions,omitempty"`
   867  	// RequiredConversationResolution, if set to true, requires all comments
   868  	// on the pull request to be resolved before it can be merged to a protected branch.
   869  	RequiredConversationResolution *bool `json:"required_conversation_resolution,omitempty"`
   870  }
   871  
   872  // RequiredStatusChecks represents the protection status of a individual branch.
   873  type RequiredStatusChecks struct {
   874  	// Require branches to be up to date before merging. (Required.)
   875  	Strict bool `json:"strict"`
   876  	// The list of status checks to require in order to merge into this
   877  	// branch. (Required; use []string{} instead of nil for empty list.)
   878  	Contexts []string `json:"contexts"`
   879  }
   880  
   881  // RequiredStatusChecksRequest represents a request to edit a protected branch's status checks.
   882  type RequiredStatusChecksRequest struct {
   883  	Strict   *bool    `json:"strict,omitempty"`
   884  	Contexts []string `json:"contexts,omitempty"`
   885  }
   886  
   887  // PullRequestReviewsEnforcement represents the pull request reviews enforcement of a protected branch.
   888  type PullRequestReviewsEnforcement struct {
   889  	// Specifies which users and teams can dismiss pull request reviews.
   890  	DismissalRestrictions *DismissalRestrictions `json:"dismissal_restrictions,omitempty"`
   891  	// Specifies if approved reviews are dismissed automatically, when a new commit is pushed.
   892  	DismissStaleReviews bool `json:"dismiss_stale_reviews"`
   893  	// RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner.
   894  	RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"`
   895  	// RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged.
   896  	// Valid values are 1-6.
   897  	RequiredApprovingReviewCount int `json:"required_approving_review_count"`
   898  }
   899  
   900  // PullRequestReviewsEnforcementRequest represents request to set the pull request review
   901  // enforcement of a protected branch. It is separate from PullRequestReviewsEnforcement above
   902  // because the request structure is different from the response structure.
   903  type PullRequestReviewsEnforcementRequest struct {
   904  	// Specifies which users and teams should be allowed to dismiss pull request reviews.
   905  	// User and team dismissal restrictions are only available for
   906  	// organization-owned repositories. Must be nil for personal repositories.
   907  	DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions,omitempty"`
   908  	// Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. (Required)
   909  	DismissStaleReviews bool `json:"dismiss_stale_reviews"`
   910  	// RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner.
   911  	RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"`
   912  	// RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged.
   913  	// Valid values are 1-6.
   914  	RequiredApprovingReviewCount int `json:"required_approving_review_count"`
   915  }
   916  
   917  // PullRequestReviewsEnforcementUpdate represents request to patch the pull request review
   918  // enforcement of a protected branch. It is separate from PullRequestReviewsEnforcementRequest above
   919  // because the patch request does not require all fields to be initialized.
   920  type PullRequestReviewsEnforcementUpdate struct {
   921  	// Specifies which users and teams can dismiss pull request reviews. Can be omitted.
   922  	DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions,omitempty"`
   923  	// Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. Can be omitted.
   924  	DismissStaleReviews *bool `json:"dismiss_stale_reviews,omitempty"`
   925  	// RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner.
   926  	RequireCodeOwnerReviews bool `json:"require_code_owner_reviews,omitempty"`
   927  	// RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged.
   928  	// Valid values are 1 - 6.
   929  	RequiredApprovingReviewCount int `json:"required_approving_review_count"`
   930  }
   931  
   932  // RequireLinearHistory represents the configuration to enforce branches with no merge commit.
   933  type RequireLinearHistory struct {
   934  	Enabled bool `json:"enabled"`
   935  }
   936  
   937  // AllowDeletions represents the configuration to accept deletion of protected branches.
   938  type AllowDeletions struct {
   939  	Enabled bool `json:"enabled"`
   940  }
   941  
   942  // AllowForcePushes represents the configuration to accept forced pushes on protected branches.
   943  type AllowForcePushes struct {
   944  	Enabled bool `json:"enabled"`
   945  }
   946  
   947  // RequiredConversationResolution, if enabled, requires all comments on the pull request to be resolved before it can be merged to a protected branch.
   948  type RequiredConversationResolution struct {
   949  	Enabled bool `json:"enabled"`
   950  }
   951  
   952  // AdminEnforcement represents the configuration to enforce required status checks for repository administrators.
   953  type AdminEnforcement struct {
   954  	URL     *string `json:"url,omitempty"`
   955  	Enabled bool    `json:"enabled"`
   956  }
   957  
   958  // BranchRestrictions represents the restriction that only certain users or
   959  // teams may push to a branch.
   960  type BranchRestrictions struct {
   961  	// The list of user logins with push access.
   962  	Users []*User `json:"users"`
   963  	// The list of team slugs with push access.
   964  	Teams []*Team `json:"teams"`
   965  	// The list of app slugs with push access.
   966  	Apps []*App `json:"apps"`
   967  }
   968  
   969  // BranchRestrictionsRequest represents the request to create/edit the
   970  // restriction that only certain users or teams may push to a branch. It is
   971  // separate from BranchRestrictions above because the request structure is
   972  // different from the response structure.
   973  type BranchRestrictionsRequest struct {
   974  	// The list of user logins with push access. (Required; use []string{} instead of nil for empty list.)
   975  	Users []string `json:"users"`
   976  	// The list of team slugs with push access. (Required; use []string{} instead of nil for empty list.)
   977  	Teams []string `json:"teams"`
   978  	// The list of app slugs with push access.
   979  	Apps []string `json:"apps,omitempty"`
   980  }
   981  
   982  // DismissalRestrictions specifies which users and teams can dismiss pull request reviews.
   983  type DismissalRestrictions struct {
   984  	// The list of users who can dimiss pull request reviews.
   985  	Users []*User `json:"users"`
   986  	// The list of teams which can dismiss pull request reviews.
   987  	Teams []*Team `json:"teams"`
   988  }
   989  
   990  // DismissalRestrictionsRequest represents the request to create/edit the
   991  // restriction to allows only specific users or teams to dimiss pull request reviews. It is
   992  // separate from DismissalRestrictions above because the request structure is
   993  // different from the response structure.
   994  // Note: Both Users and Teams must be nil, or both must be non-nil.
   995  type DismissalRestrictionsRequest struct {
   996  	// The list of user logins who can dismiss pull request reviews. (Required; use nil to disable dismissal_restrictions or &[]string{} otherwise.)
   997  	Users *[]string `json:"users,omitempty"`
   998  	// The list of team slugs which can dismiss pull request reviews. (Required; use nil to disable dismissal_restrictions or &[]string{} otherwise.)
   999  	Teams *[]string `json:"teams,omitempty"`
  1000  }
  1001  
  1002  // SignaturesProtectedBranch represents the protection status of an individual branch.
  1003  type SignaturesProtectedBranch struct {
  1004  	URL *string `json:"url,omitempty"`
  1005  	// Commits pushed to matching branches must have verified signatures.
  1006  	Enabled *bool `json:"enabled,omitempty"`
  1007  }
  1008  
  1009  // ListBranches lists branches for the specified repository.
  1010  //
  1011  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#list-branches
  1012  func (s *RepositoriesService) ListBranches(ctx context.Context, owner string, repo string, opts *BranchListOptions) ([]*Branch, *Response, error) {
  1013  	u := fmt.Sprintf("repos/%v/%v/branches", owner, repo)
  1014  	u, err := addOptions(u, opts)
  1015  	if err != nil {
  1016  		return nil, nil, err
  1017  	}
  1018  
  1019  	req, err := s.client.NewRequest("GET", u, nil)
  1020  	if err != nil {
  1021  		return nil, nil, err
  1022  	}
  1023  
  1024  	var branches []*Branch
  1025  	resp, err := s.client.Do(ctx, req, &branches)
  1026  	if err != nil {
  1027  		return nil, resp, err
  1028  	}
  1029  
  1030  	return branches, resp, nil
  1031  }
  1032  
  1033  // GetBranch gets the specified branch for a repository.
  1034  //
  1035  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#get-a-branch
  1036  func (s *RepositoriesService) GetBranch(ctx context.Context, owner, repo, branch string, followRedirects bool) (*Branch, *Response, error) {
  1037  	u := fmt.Sprintf("repos/%v/%v/branches/%v", owner, repo, branch)
  1038  
  1039  	resp, err := s.getBranchFromURL(ctx, u, followRedirects)
  1040  	if err != nil {
  1041  		return nil, nil, err
  1042  	}
  1043  	defer resp.Body.Close()
  1044  
  1045  	if resp.StatusCode != http.StatusOK {
  1046  		return nil, newResponse(resp), fmt.Errorf("unexpected status code: %s", resp.Status)
  1047  	}
  1048  
  1049  	b := new(Branch)
  1050  	err = json.NewDecoder(resp.Body).Decode(b)
  1051  	return b, newResponse(resp), err
  1052  }
  1053  
  1054  func (s *RepositoriesService) getBranchFromURL(ctx context.Context, u string, followRedirects bool) (*http.Response, error) {
  1055  	req, err := s.client.NewRequest("GET", u, nil)
  1056  	if err != nil {
  1057  		return nil, err
  1058  	}
  1059  
  1060  	var resp *http.Response
  1061  	// Use http.DefaultTransport if no custom Transport is configured
  1062  	req = withContext(ctx, req)
  1063  	if s.client.client.Transport == nil {
  1064  		resp, err = http.DefaultTransport.RoundTrip(req)
  1065  	} else {
  1066  		resp, err = s.client.client.Transport.RoundTrip(req)
  1067  	}
  1068  	if err != nil {
  1069  		return nil, err
  1070  	}
  1071  
  1072  	// If redirect response is returned, follow it
  1073  	if followRedirects && resp.StatusCode == http.StatusMovedPermanently {
  1074  		resp.Body.Close()
  1075  		u = resp.Header.Get("Location")
  1076  		resp, err = s.getBranchFromURL(ctx, u, false)
  1077  	}
  1078  	return resp, err
  1079  }
  1080  
  1081  // renameBranchRequest represents a request to rename a branch.
  1082  type renameBranchRequest struct {
  1083  	NewName string `json:"new_name"`
  1084  }
  1085  
  1086  // RenameBranch renames a branch in a repository.
  1087  //
  1088  // To rename a non-default branch: Users must have push access. GitHub Apps must have the `contents:write` repository permission.
  1089  // To rename the default branch: Users must have admin or owner permissions. GitHub Apps must have the `administration:write` repository permission.
  1090  //
  1091  // GitHub API docs: https://docs.github.com/en/rest/reference/repos#rename-a-branch
  1092  func (s *RepositoriesService) RenameBranch(ctx context.Context, owner, repo, branch, newName string) (*Branch, *Response, error) {
  1093  	u := fmt.Sprintf("repos/%v/%v/branches/%v/rename", owner, repo, branch)
  1094  	r := &renameBranchRequest{NewName: newName}
  1095  	req, err := s.client.NewRequest("POST", u, r)
  1096  	if err != nil {
  1097  		return nil, nil, err
  1098  	}
  1099  
  1100  	b := new(Branch)
  1101  	resp, err := s.client.Do(ctx, req, b)
  1102  	if err != nil {
  1103  		return nil, resp, err
  1104  	}
  1105  
  1106  	return b, resp, nil
  1107  }
  1108  
  1109  // GetBranchProtection gets the protection of a given branch.
  1110  //
  1111  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#get-branch-protection
  1112  func (s *RepositoriesService) GetBranchProtection(ctx context.Context, owner, repo, branch string) (*Protection, *Response, error) {
  1113  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch)
  1114  	req, err := s.client.NewRequest("GET", u, nil)
  1115  	if err != nil {
  1116  		return nil, nil, err
  1117  	}
  1118  
  1119  	// TODO: remove custom Accept header when this API fully launches
  1120  	req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
  1121  
  1122  	p := new(Protection)
  1123  	resp, err := s.client.Do(ctx, req, p)
  1124  	if err != nil {
  1125  		if isBranchNotProtected(err) {
  1126  			err = ErrBranchNotProtected
  1127  		}
  1128  		return nil, resp, err
  1129  	}
  1130  
  1131  	return p, resp, nil
  1132  }
  1133  
  1134  // GetRequiredStatusChecks gets the required status checks for a given protected branch.
  1135  //
  1136  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#get-status-checks-protection
  1137  func (s *RepositoriesService) GetRequiredStatusChecks(ctx context.Context, owner, repo, branch string) (*RequiredStatusChecks, *Response, error) {
  1138  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch)
  1139  	req, err := s.client.NewRequest("GET", u, nil)
  1140  	if err != nil {
  1141  		return nil, nil, err
  1142  	}
  1143  
  1144  	p := new(RequiredStatusChecks)
  1145  	resp, err := s.client.Do(ctx, req, p)
  1146  	if err != nil {
  1147  		if isBranchNotProtected(err) {
  1148  			err = ErrBranchNotProtected
  1149  		}
  1150  		return nil, resp, err
  1151  	}
  1152  
  1153  	return p, resp, nil
  1154  }
  1155  
  1156  // ListRequiredStatusChecksContexts lists the required status checks contexts for a given protected branch.
  1157  //
  1158  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#get-all-status-check-contexts
  1159  func (s *RepositoriesService) ListRequiredStatusChecksContexts(ctx context.Context, owner, repo, branch string) (contexts []string, resp *Response, err error) {
  1160  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks/contexts", owner, repo, branch)
  1161  	req, err := s.client.NewRequest("GET", u, nil)
  1162  	if err != nil {
  1163  		return nil, nil, err
  1164  	}
  1165  
  1166  	resp, err = s.client.Do(ctx, req, &contexts)
  1167  	if err != nil {
  1168  		if isBranchNotProtected(err) {
  1169  			err = ErrBranchNotProtected
  1170  		}
  1171  		return nil, resp, err
  1172  	}
  1173  
  1174  	return contexts, resp, nil
  1175  }
  1176  
  1177  // UpdateBranchProtection updates the protection of a given branch.
  1178  //
  1179  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#update-branch-protection
  1180  func (s *RepositoriesService) UpdateBranchProtection(ctx context.Context, owner, repo, branch string, preq *ProtectionRequest) (*Protection, *Response, error) {
  1181  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch)
  1182  	req, err := s.client.NewRequest("PUT", u, preq)
  1183  	if err != nil {
  1184  		return nil, nil, err
  1185  	}
  1186  
  1187  	// TODO: remove custom Accept header when this API fully launches
  1188  	req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
  1189  
  1190  	p := new(Protection)
  1191  	resp, err := s.client.Do(ctx, req, p)
  1192  	if err != nil {
  1193  		return nil, resp, err
  1194  	}
  1195  
  1196  	return p, resp, nil
  1197  }
  1198  
  1199  // RemoveBranchProtection removes the protection of a given branch.
  1200  //
  1201  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#delete-branch-protection
  1202  func (s *RepositoriesService) RemoveBranchProtection(ctx context.Context, owner, repo, branch string) (*Response, error) {
  1203  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection", owner, repo, branch)
  1204  	req, err := s.client.NewRequest("DELETE", u, nil)
  1205  	if err != nil {
  1206  		return nil, err
  1207  	}
  1208  
  1209  	return s.client.Do(ctx, req, nil)
  1210  }
  1211  
  1212  // GetSignaturesProtectedBranch gets required signatures of protected branch.
  1213  //
  1214  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#get-commit-signature-protection
  1215  func (s *RepositoriesService) GetSignaturesProtectedBranch(ctx context.Context, owner, repo, branch string) (*SignaturesProtectedBranch, *Response, error) {
  1216  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch)
  1217  	req, err := s.client.NewRequest("GET", u, nil)
  1218  	if err != nil {
  1219  		return nil, nil, err
  1220  	}
  1221  
  1222  	// TODO: remove custom Accept header when this API fully launches
  1223  	req.Header.Set("Accept", mediaTypeSignaturePreview)
  1224  
  1225  	p := new(SignaturesProtectedBranch)
  1226  	resp, err := s.client.Do(ctx, req, p)
  1227  	if err != nil {
  1228  		return nil, resp, err
  1229  	}
  1230  
  1231  	return p, resp, nil
  1232  }
  1233  
  1234  // RequireSignaturesOnProtectedBranch makes signed commits required on a protected branch.
  1235  // It requires admin access and branch protection to be enabled.
  1236  //
  1237  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#create-commit-signature-protection
  1238  func (s *RepositoriesService) RequireSignaturesOnProtectedBranch(ctx context.Context, owner, repo, branch string) (*SignaturesProtectedBranch, *Response, error) {
  1239  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch)
  1240  	req, err := s.client.NewRequest("POST", u, nil)
  1241  	if err != nil {
  1242  		return nil, nil, err
  1243  	}
  1244  
  1245  	// TODO: remove custom Accept header when this API fully launches
  1246  	req.Header.Set("Accept", mediaTypeSignaturePreview)
  1247  
  1248  	r := new(SignaturesProtectedBranch)
  1249  	resp, err := s.client.Do(ctx, req, r)
  1250  	if err != nil {
  1251  		return nil, resp, err
  1252  	}
  1253  
  1254  	return r, resp, err
  1255  }
  1256  
  1257  // OptionalSignaturesOnProtectedBranch removes required signed commits on a given branch.
  1258  //
  1259  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#delete-commit-signature-protection
  1260  func (s *RepositoriesService) OptionalSignaturesOnProtectedBranch(ctx context.Context, owner, repo, branch string) (*Response, error) {
  1261  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch)
  1262  	req, err := s.client.NewRequest("DELETE", u, nil)
  1263  	if err != nil {
  1264  		return nil, err
  1265  	}
  1266  
  1267  	// TODO: remove custom Accept header when this API fully launches
  1268  	req.Header.Set("Accept", mediaTypeSignaturePreview)
  1269  
  1270  	return s.client.Do(ctx, req, nil)
  1271  }
  1272  
  1273  // UpdateRequiredStatusChecks updates the required status checks for a given protected branch.
  1274  //
  1275  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#update-status-check-protection
  1276  func (s *RepositoriesService) UpdateRequiredStatusChecks(ctx context.Context, owner, repo, branch string, sreq *RequiredStatusChecksRequest) (*RequiredStatusChecks, *Response, error) {
  1277  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch)
  1278  	req, err := s.client.NewRequest("PATCH", u, sreq)
  1279  	if err != nil {
  1280  		return nil, nil, err
  1281  	}
  1282  
  1283  	sc := new(RequiredStatusChecks)
  1284  	resp, err := s.client.Do(ctx, req, sc)
  1285  	if err != nil {
  1286  		return nil, resp, err
  1287  	}
  1288  
  1289  	return sc, resp, nil
  1290  }
  1291  
  1292  // RemoveRequiredStatusChecks removes the required status checks for a given protected branch.
  1293  //
  1294  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos#remove-status-check-protection
  1295  func (s *RepositoriesService) RemoveRequiredStatusChecks(ctx context.Context, owner, repo, branch string) (*Response, error) {
  1296  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch)
  1297  	req, err := s.client.NewRequest("DELETE", u, nil)
  1298  	if err != nil {
  1299  		return nil, err
  1300  	}
  1301  
  1302  	return s.client.Do(ctx, req, nil)
  1303  }
  1304  
  1305  // License gets the contents of a repository's license if one is detected.
  1306  //
  1307  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/licenses/#get-the-license-for-a-repository
  1308  func (s *RepositoriesService) License(ctx context.Context, owner, repo string) (*RepositoryLicense, *Response, error) {
  1309  	u := fmt.Sprintf("repos/%v/%v/license", owner, repo)
  1310  	req, err := s.client.NewRequest("GET", u, nil)
  1311  	if err != nil {
  1312  		return nil, nil, err
  1313  	}
  1314  
  1315  	r := &RepositoryLicense{}
  1316  	resp, err := s.client.Do(ctx, req, r)
  1317  	if err != nil {
  1318  		return nil, resp, err
  1319  	}
  1320  
  1321  	return r, resp, nil
  1322  }
  1323  
  1324  // GetPullRequestReviewEnforcement gets pull request review enforcement of a protected branch.
  1325  //
  1326  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#get-pull-request-review-protection
  1327  func (s *RepositoriesService) GetPullRequestReviewEnforcement(ctx context.Context, owner, repo, branch string) (*PullRequestReviewsEnforcement, *Response, error) {
  1328  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch)
  1329  	req, err := s.client.NewRequest("GET", u, nil)
  1330  	if err != nil {
  1331  		return nil, nil, err
  1332  	}
  1333  
  1334  	// TODO: remove custom Accept header when this API fully launches
  1335  	req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
  1336  
  1337  	r := new(PullRequestReviewsEnforcement)
  1338  	resp, err := s.client.Do(ctx, req, r)
  1339  	if err != nil {
  1340  		return nil, resp, err
  1341  	}
  1342  
  1343  	return r, resp, nil
  1344  }
  1345  
  1346  // UpdatePullRequestReviewEnforcement patches pull request review enforcement of a protected branch.
  1347  // It requires admin access and branch protection to be enabled.
  1348  //
  1349  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#update-pull-request-review-protection
  1350  func (s *RepositoriesService) UpdatePullRequestReviewEnforcement(ctx context.Context, owner, repo, branch string, patch *PullRequestReviewsEnforcementUpdate) (*PullRequestReviewsEnforcement, *Response, error) {
  1351  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch)
  1352  	req, err := s.client.NewRequest("PATCH", u, patch)
  1353  	if err != nil {
  1354  		return nil, nil, err
  1355  	}
  1356  
  1357  	// TODO: remove custom Accept header when this API fully launches
  1358  	req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
  1359  
  1360  	r := new(PullRequestReviewsEnforcement)
  1361  	resp, err := s.client.Do(ctx, req, r)
  1362  	if err != nil {
  1363  		return nil, resp, err
  1364  	}
  1365  
  1366  	return r, resp, err
  1367  }
  1368  
  1369  // DisableDismissalRestrictions disables dismissal restrictions of a protected branch.
  1370  // It requires admin access and branch protection to be enabled.
  1371  //
  1372  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#update-pull-request-review-protection
  1373  func (s *RepositoriesService) DisableDismissalRestrictions(ctx context.Context, owner, repo, branch string) (*PullRequestReviewsEnforcement, *Response, error) {
  1374  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch)
  1375  
  1376  	data := new(struct {
  1377  		DismissalRestrictionsRequest `json:"dismissal_restrictions"`
  1378  	})
  1379  
  1380  	req, err := s.client.NewRequest("PATCH", u, data)
  1381  	if err != nil {
  1382  		return nil, nil, err
  1383  	}
  1384  
  1385  	// TODO: remove custom Accept header when this API fully launches
  1386  	req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
  1387  
  1388  	r := new(PullRequestReviewsEnforcement)
  1389  	resp, err := s.client.Do(ctx, req, r)
  1390  	if err != nil {
  1391  		return nil, resp, err
  1392  	}
  1393  
  1394  	return r, resp, err
  1395  }
  1396  
  1397  // RemovePullRequestReviewEnforcement removes pull request enforcement of a protected branch.
  1398  //
  1399  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#delete-pull-request-review-protection
  1400  func (s *RepositoriesService) RemovePullRequestReviewEnforcement(ctx context.Context, owner, repo, branch string) (*Response, error) {
  1401  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_pull_request_reviews", owner, repo, branch)
  1402  	req, err := s.client.NewRequest("DELETE", u, nil)
  1403  	if err != nil {
  1404  		return nil, err
  1405  	}
  1406  
  1407  	return s.client.Do(ctx, req, nil)
  1408  }
  1409  
  1410  // GetAdminEnforcement gets admin enforcement information of a protected branch.
  1411  //
  1412  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#get-admin-branch-protection
  1413  func (s *RepositoriesService) GetAdminEnforcement(ctx context.Context, owner, repo, branch string) (*AdminEnforcement, *Response, error) {
  1414  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, branch)
  1415  	req, err := s.client.NewRequest("GET", u, nil)
  1416  	if err != nil {
  1417  		return nil, nil, err
  1418  	}
  1419  
  1420  	r := new(AdminEnforcement)
  1421  	resp, err := s.client.Do(ctx, req, r)
  1422  	if err != nil {
  1423  		return nil, resp, err
  1424  	}
  1425  
  1426  	return r, resp, nil
  1427  }
  1428  
  1429  // AddAdminEnforcement adds admin enforcement to a protected branch.
  1430  // It requires admin access and branch protection to be enabled.
  1431  //
  1432  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#set-admin-branch-protection
  1433  func (s *RepositoriesService) AddAdminEnforcement(ctx context.Context, owner, repo, branch string) (*AdminEnforcement, *Response, error) {
  1434  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, branch)
  1435  	req, err := s.client.NewRequest("POST", u, nil)
  1436  	if err != nil {
  1437  		return nil, nil, err
  1438  	}
  1439  
  1440  	r := new(AdminEnforcement)
  1441  	resp, err := s.client.Do(ctx, req, r)
  1442  	if err != nil {
  1443  		return nil, resp, err
  1444  	}
  1445  
  1446  	return r, resp, err
  1447  }
  1448  
  1449  // RemoveAdminEnforcement removes admin enforcement from a protected branch.
  1450  //
  1451  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#delete-admin-branch-protection
  1452  func (s *RepositoriesService) RemoveAdminEnforcement(ctx context.Context, owner, repo, branch string) (*Response, error) {
  1453  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/enforce_admins", owner, repo, branch)
  1454  	req, err := s.client.NewRequest("DELETE", u, nil)
  1455  	if err != nil {
  1456  		return nil, err
  1457  	}
  1458  
  1459  	return s.client.Do(ctx, req, nil)
  1460  }
  1461  
  1462  // repositoryTopics represents a collection of repository topics.
  1463  type repositoryTopics struct {
  1464  	Names []string `json:"names"`
  1465  }
  1466  
  1467  // ListAllTopics lists topics for a repository.
  1468  //
  1469  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#get-all-repository-topics
  1470  func (s *RepositoriesService) ListAllTopics(ctx context.Context, owner, repo string) ([]string, *Response, error) {
  1471  	u := fmt.Sprintf("repos/%v/%v/topics", owner, repo)
  1472  	req, err := s.client.NewRequest("GET", u, nil)
  1473  	if err != nil {
  1474  		return nil, nil, err
  1475  	}
  1476  
  1477  	// TODO: remove custom Accept header when this API fully launches.
  1478  	req.Header.Set("Accept", mediaTypeTopicsPreview)
  1479  
  1480  	topics := new(repositoryTopics)
  1481  	resp, err := s.client.Do(ctx, req, topics)
  1482  	if err != nil {
  1483  		return nil, resp, err
  1484  	}
  1485  
  1486  	return topics.Names, resp, nil
  1487  }
  1488  
  1489  // ReplaceAllTopics replaces topics for a repository.
  1490  //
  1491  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#replace-all-repository-topics
  1492  func (s *RepositoriesService) ReplaceAllTopics(ctx context.Context, owner, repo string, topics []string) ([]string, *Response, error) {
  1493  	u := fmt.Sprintf("repos/%v/%v/topics", owner, repo)
  1494  	t := &repositoryTopics{
  1495  		Names: topics,
  1496  	}
  1497  	if t.Names == nil {
  1498  		t.Names = []string{}
  1499  	}
  1500  	req, err := s.client.NewRequest("PUT", u, t)
  1501  	if err != nil {
  1502  		return nil, nil, err
  1503  	}
  1504  
  1505  	// TODO: remove custom Accept header when this API fully launches.
  1506  	req.Header.Set("Accept", mediaTypeTopicsPreview)
  1507  
  1508  	t = new(repositoryTopics)
  1509  	resp, err := s.client.Do(ctx, req, t)
  1510  	if err != nil {
  1511  		return nil, resp, err
  1512  	}
  1513  
  1514  	return t.Names, resp, nil
  1515  }
  1516  
  1517  // ListApps lists the GitHub apps that have push access to a given protected branch.
  1518  // It requires the GitHub apps to have `write` access to the `content` permission.
  1519  //
  1520  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#get-apps-with-access-to-the-protected-branch
  1521  func (s *RepositoriesService) ListApps(ctx context.Context, owner, repo, branch string) ([]*App, *Response, error) {
  1522  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch)
  1523  	req, err := s.client.NewRequest("GET", u, nil)
  1524  	if err != nil {
  1525  		return nil, nil, err
  1526  	}
  1527  
  1528  	var apps []*App
  1529  	resp, err := s.client.Do(ctx, req, &apps)
  1530  	if err != nil {
  1531  		return nil, resp, err
  1532  	}
  1533  
  1534  	return apps, resp, nil
  1535  }
  1536  
  1537  // ReplaceAppRestrictions replaces the apps that have push access to a given protected branch.
  1538  // It removes all apps that previously had push access and grants push access to the new list of apps.
  1539  // It requires the GitHub apps to have `write` access to the `content` permission.
  1540  //
  1541  // Note: The list of users, apps, and teams in total is limited to 100 items.
  1542  //
  1543  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#set-app-access-restrictions
  1544  func (s *RepositoriesService) ReplaceAppRestrictions(ctx context.Context, owner, repo, branch string, slug []string) ([]*App, *Response, error) {
  1545  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch)
  1546  	req, err := s.client.NewRequest("PUT", u, slug)
  1547  	if err != nil {
  1548  		return nil, nil, err
  1549  	}
  1550  
  1551  	var apps []*App
  1552  	resp, err := s.client.Do(ctx, req, &apps)
  1553  	if err != nil {
  1554  		return nil, resp, err
  1555  	}
  1556  
  1557  	return apps, resp, nil
  1558  }
  1559  
  1560  // AddAppRestrictions grants the specified apps push access to a given protected branch.
  1561  // It requires the GitHub apps to have `write` access to the `content` permission.
  1562  //
  1563  // Note: The list of users, apps, and teams in total is limited to 100 items.
  1564  //
  1565  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#add-app-access-restrictions
  1566  func (s *RepositoriesService) AddAppRestrictions(ctx context.Context, owner, repo, branch string, slug []string) ([]*App, *Response, error) {
  1567  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch)
  1568  	req, err := s.client.NewRequest("POST", u, slug)
  1569  	if err != nil {
  1570  		return nil, nil, err
  1571  	}
  1572  
  1573  	var apps []*App
  1574  	resp, err := s.client.Do(ctx, req, &apps)
  1575  	if err != nil {
  1576  		return nil, resp, err
  1577  	}
  1578  
  1579  	return apps, resp, nil
  1580  }
  1581  
  1582  // RemoveAppRestrictions removes the ability of an app to push to this branch.
  1583  // It requires the GitHub apps to have `write` access to the `content` permission.
  1584  //
  1585  // Note: The list of users, apps, and teams in total is limited to 100 items.
  1586  //
  1587  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#remove-app-access-restrictions
  1588  func (s *RepositoriesService) RemoveAppRestrictions(ctx context.Context, owner, repo, branch string, slug []string) ([]*App, *Response, error) {
  1589  	u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/restrictions/apps", owner, repo, branch)
  1590  	req, err := s.client.NewRequest("DELETE", u, slug)
  1591  	if err != nil {
  1592  		return nil, nil, err
  1593  	}
  1594  
  1595  	var apps []*App
  1596  	resp, err := s.client.Do(ctx, req, &apps)
  1597  	if err != nil {
  1598  		return nil, resp, err
  1599  	}
  1600  
  1601  	return apps, resp, nil
  1602  }
  1603  
  1604  // TransferRequest represents a request to transfer a repository.
  1605  type TransferRequest struct {
  1606  	NewOwner string  `json:"new_owner"`
  1607  	TeamID   []int64 `json:"team_ids,omitempty"`
  1608  }
  1609  
  1610  // Transfer transfers a repository from one account or organization to another.
  1611  //
  1612  // This method might return an *AcceptedError and a status code of
  1613  // 202. This is because this is the status that GitHub returns to signify that
  1614  // it has now scheduled the transfer of the repository in a background task.
  1615  // A follow up request, after a delay of a second or so, should result
  1616  // in a successful request.
  1617  //
  1618  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#transfer-a-repository
  1619  func (s *RepositoriesService) Transfer(ctx context.Context, owner, repo string, transfer TransferRequest) (*Repository, *Response, error) {
  1620  	u := fmt.Sprintf("repos/%v/%v/transfer", owner, repo)
  1621  
  1622  	req, err := s.client.NewRequest("POST", u, &transfer)
  1623  	if err != nil {
  1624  		return nil, nil, err
  1625  	}
  1626  
  1627  	r := new(Repository)
  1628  	resp, err := s.client.Do(ctx, req, r)
  1629  	if err != nil {
  1630  		return nil, resp, err
  1631  	}
  1632  
  1633  	return r, resp, nil
  1634  }
  1635  
  1636  // DispatchRequestOptions represents a request to trigger a repository_dispatch event.
  1637  type DispatchRequestOptions struct {
  1638  	// EventType is a custom webhook event name. (Required.)
  1639  	EventType string `json:"event_type"`
  1640  	// ClientPayload is a custom JSON payload with extra information about the webhook event.
  1641  	// Defaults to an empty JSON object.
  1642  	ClientPayload *json.RawMessage `json:"client_payload,omitempty"`
  1643  }
  1644  
  1645  // Dispatch triggers a repository_dispatch event in a GitHub Actions workflow.
  1646  //
  1647  // GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/repos/#create-a-repository-dispatch-event
  1648  func (s *RepositoriesService) Dispatch(ctx context.Context, owner, repo string, opts DispatchRequestOptions) (*Repository, *Response, error) {
  1649  	u := fmt.Sprintf("repos/%v/%v/dispatches", owner, repo)
  1650  
  1651  	req, err := s.client.NewRequest("POST", u, &opts)
  1652  	if err != nil {
  1653  		return nil, nil, err
  1654  	}
  1655  
  1656  	r := new(Repository)
  1657  	resp, err := s.client.Do(ctx, req, r)
  1658  	if err != nil {
  1659  		return nil, resp, err
  1660  	}
  1661  
  1662  	return r, resp, nil
  1663  }
  1664  
  1665  // isBranchNotProtected determines whether a branch is not protected
  1666  // based on the error message returned by GitHub API.
  1667  func isBranchNotProtected(err error) bool {
  1668  	errorResponse, ok := err.(*ErrorResponse)
  1669  	return ok && errorResponse.Message == githubBranchNotProtected
  1670  }