Repository: google/go-github
Pull request #1473 (2020-03-25 12:31:02)

Update ListRunners with new response type - breaking change
Fixes: #1472.

Note to self: once this is merged, the next release to be built will need a semver major version bump, as this is a breaking change.

codecov[bot]: # [Codecov](https://codecov.io/gh/google/go-github/pull/1473?src=pr&el=h1) Report
> Merging [#1473](https://codecov.io/gh/google/go-github/pull/1473?src=pr&el=desc) into [master](https://codecov.io/gh/google/go-github/commit/7726a3e3e3b67ab86c97198c8d682b09108a27b7&el=desc) will **increase** coverage by `5.09%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/google/go-github/pull/1473/graphs/tree.svg?width=650&height=150&src=pr&token=EgYjGjZlI0)](https://codecov.io/gh/google/go-github/pull/1473?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #1473      +/-   ##
==========================================
+ Coverage   68.16%   73.26%   +5.09%     
==========================================
  Files          94       94              
  Lines        8419     6781    -1638     
==========================================
- Hits         5739     4968     -771     
+ Misses       1819      952     -867     
  Partials      861      861              
```


| [Impacted Files](https://codecov.io/gh/google/go-github/pull/1473?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [github/actions\_runners.go](https://codecov.io/gh/google/go-github/pull/1473/diff?src=pr&el=tree#diff-Z2l0aHViL2FjdGlvbnNfcnVubmVycy5nbw==) | `59.32% <100.00%> (+7.97%)` | :arrow_up: |
| [github/github.go](https://codecov.io/gh/google/go-github/pull/1473/diff?src=pr&el=tree#diff-Z2l0aHViL2dpdGh1Yi5nbw==) | `89.74% <0.00%> (-0.03%)` | :arrow_down: |
| [github/admin.go](https://codecov.io/gh/google/go-github/pull/1473/diff?src=pr&el=tree#diff-Z2l0aHViL2FkbWluLmdv) | `100.00% <0.00%> (ø)` | |
| [github/strings.go](https://codecov.io/gh/google/go-github/pull/1473/diff?src=pr&el=tree#diff-Z2l0aHViL3N0cmluZ3MuZ28=) | `100.00% <0.00%> (ø)` | |
| [github/activity.go](https://codecov.io/gh/google/go-github/pull/1473/diff?src=pr&el=tree#diff-Z2l0aHViL2FjdGl2aXR5Lmdv) | `100.00% <0.00%> (ø)` | |
| [github/timestamp.go](https://codecov.io/gh/google/go-github/pull/1473/diff?src=pr&el=tree#diff-Z2l0aHViL3RpbWVzdGFtcC5nbw==) | `100.00% <0.00%> (ø)` | |
| [github/admin\_stats.go](https://codecov.io/gh/google/go-github/pull/1473/diff?src=pr&el=tree#diff-Z2l0aHViL2FkbWluX3N0YXRzLmdv) | `100.00% <0.00%> (ø)` | |
| [github/repos\_traffic.go](https://codecov.io/gh/google/go-github/pull/1473/diff?src=pr&el=tree#diff-Z2l0aHViL3JlcG9zX3RyYWZmaWMuZ28=) | `100.00% <0.00%> (ø)` | |
| [github/pulls\_reviewers.go](https://codecov.io/gh/google/go-github/pull/1473/diff?src=pr&el=tree#diff-Z2l0aHViL3B1bGxzX3Jldmlld2Vycy5nbw==) | `100.00% <0.00%> (ø)` | |
| [github/git\_commits.go](https://codecov.io/gh/google/go-github/pull/1473/diff?src=pr&el=tree#diff-Z2l0aHViL2dpdF9jb21taXRzLmdv) | `91.30% <0.00%> (+1.30%)` | :arrow_up: |
| ... and [82 more](https://codecov.io/gh/google/go-github/pull/1473/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/google/go-github/pull/1473?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/google/go-github/pull/1473?src=pr&el=footer). Last update [7726a3e...05ad97b](https://codecov.io/gh/google/go-github/pull/1473?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

gmlewis: Awaiting two LGTMs before merging.

Patch:
diff --git a/github/actions_runners.go b/github/actions_runners.go
index bab39631..24f88f0f 100644
--- a/github/actions_runners.go
+++ b/github/actions_runners.go
@@ -71,10 +71,16 @@ type Runner struct {
 	Status *string `json:"status,omitempty"`
 }
 
+// Runners represents a collection of self-hosted runners for a repository.
+type Runners struct {
+	TotalCount int       `json:"total_count"`
+	Runners    []*Runner `json:"runners"`
+}
+
 // ListRunners lists all the self-hosted runners for a repository.
 //
 // GitHub API docs: https://developer.github.com/v3/actions/self_hosted_runners/#list-self-hosted-runners-for-a-repository
-func (s *ActionsService) ListRunners(ctx context.Context, owner, repo string, opts *ListOptions) ([]*Runner, *Response, error) {
+func (s *ActionsService) ListRunners(ctx context.Context, owner, repo string, opts *ListOptions) (*Runners, *Response, error) {
 	u := fmt.Sprintf("repos/%v/%v/actions/runners", owner, repo)
 	u, err := addOptions(u, opts)
 	if err != nil {
@@ -86,7 +92,7 @@ func (s *ActionsService) ListRunners(ctx context.Context, owner, repo string, op
 		return nil, nil, err
 	}
 
-	var runners []*Runner
+	runners := &Runners{}
 	resp, err := s.client.Do(ctx, req, &runners)
 	if err != nil {
 		return nil, resp, err
diff --git a/github/github-accessors.go b/github/github-accessors.go
index 519123cd..27e8b136 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -10708,6 +10708,14 @@ func (r *Repository) GetURL() string {
 	return *r.URL
 }
 
+// GetVisibility returns the Visibility field if it's non-nil, zero value otherwise.
+func (r *Repository) GetVisibility() string {
+	if r == nil || r.Visibility == nil {
+		return ""
+	}
+	return *r.Visibility
+}
+
 // GetWatchersCount returns the WatchersCount field if it's non-nil, zero value otherwise.
 func (r *Repository) GetWatchersCount() int {
 	if r == nil || r.WatchersCount == nil {
diff --git a/github/github.go b/github/github.go
index 15715cf0..c9bdff55 100644
--- a/github/github.go
+++ b/github/github.go
@@ -138,6 +138,9 @@ const (
 
 	// https://developer.github.com/changes/2019-11-05-deprecated-passwords-and-authorizations-api/
 	mediaTypeOAuthAppPreview = "application/vnd.github.doctor-strange-preview+json"
+
+	// https://developer.github.com/changes/2019-12-03-internal-visibility-changes/
+	mediaTypeRepositoryVisibilityPreview = "application/vnd.github.nebula-preview+json"
 )
 
 // A Client manages communication with the GitHub API.
diff --git a/github/repos.go b/github/repos.go
index bce3c942..41249226 100644
--- a/github/repos.go
+++ b/github/repos.go
@@ -121,6 +121,11 @@ type Repository struct {
 	// TextMatches is only populated from search results that request text matches
 	// See: search.go and https://developer.github.com/v3/search/#text-match-metadata
 	TextMatches []*TextMatch `json:"text_matches,omitempty"`
+
+	// Visibility is only used for Create and Edit endpoints. The visibility field
+	// overrides the field parameter when both are used.
+	// Can be one of public, private or internal.
+	Visibility *string `json:"visibility,omitempty"`
 }
 
 func (r Repository) String() string {
@@ -295,11 +300,12 @@ type createRepoRequest struct {
 	Description *string `json:"description,omitempty"`
 	Homepage    *string `json:"homepage,omitempty"`
 
-	Private     *bool `json:"private,omitempty"`
-	HasIssues   *bool `json:"has_issues,omitempty"`
-	HasProjects *bool `json:"has_projects,omitempty"`
-	HasWiki     *bool `json:"has_wiki,omitempty"`
-	IsTemplate  *bool `json:"is_template,omitempty"`
+	Private     *bool   `json:"private,omitempty"`
+	Visibility  *string `json:"visibility,omitempty"`
+	HasIssues   *bool   `json:"has_issues,omitempty"`
+	HasProjects *bool   `json:"has_projects,omitempty"`
+	HasWiki     *bool   `json:"has_wiki,omitempty"`
+	IsTemplate  *bool   `json:"is_template,omitempty"`
 
 	// Creating an organization repository. Required for non-owners.
 	TeamID *int64 `json:"team_id,omitempty"`
@@ -334,6 +340,7 @@ func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repo
 		Description:         repo.Description,
 		Homepage:            repo.Homepage,
 		Private:             repo.Private,
+		Visibility:          repo.Visibility,
 		HasIssues:           repo.HasIssues,
 		HasProjects:         repo.HasProjects,
 		HasWiki:             repo.HasWiki,
@@ -353,7 +360,8 @@ func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repo
 		return nil, nil, err
 	}
 
-	req.Header.Set("Accept", mediaTypeRepositoryTemplatePreview)
+	acceptHeaders := []string{mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview}
+	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
 	r := new(Repository)
 	resp, err := s.client.Do(ctx, req, r)
 	if err != nil {
@@ -469,7 +477,8 @@ func (s *RepositoriesService) Edit(ctx context.Context, owner, repo string, repo
 		return nil, nil, err
 	}
 
-	req.Header.Set("Accept", mediaTypeRepositoryTemplatePreview)
+	acceptHeaders := []string{mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview}
+	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
 	r := new(Repository)
 	resp, err := s.client.Do(ctx, req, r)
 	if err != nil {


Test patch:
diff --git a/github/actions_runners_test.go b/github/actions_runners_test.go
index 6739b28a..13ceeea6 100644
--- a/github/actions_runners_test.go
+++ b/github/actions_runners_test.go
@@ -69,7 +69,7 @@ func TestActionsService_ListRunners(t *testing.T) {
 	mux.HandleFunc("/repos/o/r/actions/runners", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
 		testFormValues(t, r, values{"per_page": "2", "page": "2"})
-		fmt.Fprint(w, `[{"id":23,"name":"MBP","os":"macos","status":"online"},{"id":24,"name":"iMac","os":"macos","status":"offline"}]`)
+		fmt.Fprint(w, `{"total_count":2,"runners":[{"id":23,"name":"MBP","os":"macos","status":"online"},{"id":24,"name":"iMac","os":"macos","status":"offline"}]}`)
 	})
 
 	opts := &ListOptions{Page: 2, PerPage: 2}
@@ -78,9 +78,12 @@ func TestActionsService_ListRunners(t *testing.T) {
 		t.Errorf("Actions.ListRunners returned error: %v", err)
 	}
 
-	want := []*Runner{
-		{ID: Int64(23), Name: String("MBP"), OS: String("macos"), Status: String("online")},
-		{ID: Int64(24), Name: String("iMac"), OS: String("macos"), Status: String("offline")},
+	want := &Runners{
+		TotalCount: 2,
+		Runners: []*Runner{
+			{ID: Int64(23), Name: String("MBP"), OS: String("macos"), Status: String("online")},
+			{ID: Int64(24), Name: String("iMac"), OS: String("macos"), Status: String("offline")},
+		},
 	}
 	if !reflect.DeepEqual(runners, want) {
 		t.Errorf("Actions.ListRunners returned %+v, want %+v", runners, want)
diff --git a/github/github-stringify_test.go b/github/github-stringify_test.go
index b85d3a62..df474203 100644
--- a/github/github-stringify_test.go
+++ b/github/github-stringify_test.go
@@ -1301,8 +1301,9 @@ func TestRepository_String(t *testing.T) {
 		TagsURL:             String(""),
 		TreesURL:            String(""),
 		TeamsURL:            String(""),
+		Visibility:          String(""),
 	}
-	want := `github.Repository{ID:0, NodeID:"", Owner:github.User{}, Name:"", FullName:"", Description:"", Homepage:"", CodeOfConduct:github.CodeOfConduct{}, DefaultBranch:"", MasterBranch:"", CreatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, PushedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, UpdatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, HTMLURL:"", CloneURL:"", GitURL:"", MirrorURL:"", SSHURL:"", SVNURL:"", Language:"", Fork:false, ForksCount:0, NetworkCount:0, OpenIssuesCount:0, StargazersCount:0, SubscribersCount:0, WatchersCount:0, Size:0, AutoInit:false, Parent:github.Repository{}, Source:github.Repository{}, TemplateRepository:github.Repository{}, Organization:github.Organization{}, AllowRebaseMerge:false, AllowSquashMerge:false, AllowMergeCommit:false, DeleteBranchOnMerge:false, Archived:false, Disabled:false, License:github.License{}, Private:false, HasIssues:false, HasWiki:false, HasPages:false, HasProjects:false, HasDownloads:false, IsTemplate:false, LicenseTemplate:"", GitignoreTemplate:"", TeamID:0, URL:"", ArchiveURL:"", AssigneesURL:"", BlobsURL:"", BranchesURL:"", CollaboratorsURL:"", CommentsURL:"", CommitsURL:"", CompareURL:"", ContentsURL:"", ContributorsURL:"", DeploymentsURL:"", DownloadsURL:"", EventsURL:"", ForksURL:"", GitCommitsURL:"", GitRefsURL:"", GitTagsURL:"", HooksURL:"", IssueCommentURL:"", IssueEventsURL:"", IssuesURL:"", KeysURL:"", LabelsURL:"", LanguagesURL:"", MergesURL:"", MilestonesURL:"", NotificationsURL:"", PullsURL:"", ReleasesURL:"", StargazersURL:"", StatusesURL:"", SubscribersURL:"", SubscriptionURL:"", TagsURL:"", TreesURL:"", TeamsURL:""}`
+	want := `github.Repository{ID:0, NodeID:"", Owner:github.User{}, Name:"", FullName:"", Description:"", Homepage:"", CodeOfConduct:github.CodeOfConduct{}, DefaultBranch:"", MasterBranch:"", CreatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, PushedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, UpdatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, HTMLURL:"", CloneURL:"", GitURL:"", MirrorURL:"", SSHURL:"", SVNURL:"", Language:"", Fork:false, ForksCount:0, NetworkCount:0, OpenIssuesCount:0, StargazersCount:0, SubscribersCount:0, WatchersCount:0, Size:0, AutoInit:false, Parent:github.Repository{}, Source:github.Repository{}, TemplateRepository:github.Repository{}, Organization:github.Organization{}, AllowRebaseMerge:false, AllowSquashMerge:false, AllowMergeCommit:false, DeleteBranchOnMerge:false, Archived:false, Disabled:false, License:github.License{}, Private:false, HasIssues:false, HasWiki:false, HasPages:false, HasProjects:false, HasDownloads:false, IsTemplate:false, LicenseTemplate:"", GitignoreTemplate:"", TeamID:0, URL:"", ArchiveURL:"", AssigneesURL:"", BlobsURL:"", BranchesURL:"", CollaboratorsURL:"", CommentsURL:"", CommitsURL:"", CompareURL:"", ContentsURL:"", ContributorsURL:"", DeploymentsURL:"", DownloadsURL:"", EventsURL:"", ForksURL:"", GitCommitsURL:"", GitRefsURL:"", GitTagsURL:"", HooksURL:"", IssueCommentURL:"", IssueEventsURL:"", IssuesURL:"", KeysURL:"", LabelsURL:"", LanguagesURL:"", MergesURL:"", MilestonesURL:"", NotificationsURL:"", PullsURL:"", ReleasesURL:"", StargazersURL:"", StatusesURL:"", SubscribersURL:"", SubscriptionURL:"", TagsURL:"", TreesURL:"", TeamsURL:"", Visibility:""}`
 	if got := v.String(); got != want {
 		t.Errorf("Repository.String = %v, want %v", got, want)
 	}
diff --git a/github/repos_test.go b/github/repos_test.go
index d1c60cb0..889a8fc8 100644
--- a/github/repos_test.go
+++ b/github/repos_test.go
@@ -251,12 +251,13 @@ func TestRepositoriesService_Create_user(t *testing.T) {
 		Archived: Bool(true), // not passed along.
 	}
 
+	wantAcceptHeaders := []string{mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview}
 	mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
 		v := new(createRepoRequest)
 		json.NewDecoder(r.Body).Decode(v)
 
 		testMethod(t, r, "POST")
-		testHeader(t, r, "Accept", mediaTypeRepositoryTemplatePreview)
+		testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", "))
 		want := &createRepoRequest{Name: String("n")}
 		if !reflect.DeepEqual(v, want) {
 			t.Errorf("Request body = %+v, want %+v", v, want)
@@ -313,12 +314,13 @@ func TestRepositoriesService_Create_org(t *testing.T) {
 		Archived: Bool(true), // not passed along.
 	}
 
+	wantAcceptHeaders := []string{mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview}
 	mux.HandleFunc("/orgs/o/repos", func(w http.ResponseWriter, r *http.Request) {
 		v := new(createRepoRequest)
 		json.NewDecoder(r.Body).Decode(v)
 
 		testMethod(t, r, "POST")
-		testHeader(t, r, "Accept", mediaTypeRepositoryTemplatePreview)
+		testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", "))
 		want := &createRepoRequest{Name: String("n")}
 		if !reflect.DeepEqual(v, want) {
 			t.Errorf("Request body = %+v, want %+v", v, want)
@@ -551,12 +553,13 @@ func TestRepositoriesService_Edit(t *testing.T) {
 	i := true
 	input := &Repository{HasIssues: &i}
 
+	wantAcceptHeaders := []string{mediaTypeRepositoryTemplatePreview, mediaTypeRepositoryVisibilityPreview}
 	mux.HandleFunc("/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
 		v := new(Repository)
 		json.NewDecoder(r.Body).Decode(v)
 
 		testMethod(t, r, "PATCH")
-		testHeader(t, r, "Accept", mediaTypeRepositoryTemplatePreview)
+		testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", "))
 		if !reflect.DeepEqual(v, input) {
 			t.Errorf("Request body = %+v, want %+v", v, input)
 		}