...

Source file src/github.com/google/go-github/v45/github/repos.go

Documentation: github.com/google/go-github/v45/github

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

View as plain text