Repository: google/go-github
Pull request #1653 (2020-11-29 20:06:49)

[New Method] Actions/Runner: List enabled repos in organization for Actions
This PR implements the `List selected repositories enabled for GitHub Actions in an organization` method. The endpoint for this feature is `/orgs/{org}/actions/permissions/repositories`. More details around this can be found here: https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#list-selected-repositories-enabled-for-github-actions-in-an-organization

google-cla[bot]: 
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

:memo: **Please visit <https://cla.developers.google.com/> to sign.**

Once you've signed (or fixed any issues), please reply here with `@googlebot I signed it!` and we'll verify it.

----

#### What to do if you already signed the CLA

##### Individual signers

*   It's possible we don't have your GitHub username or you're using a different email address on your commit. Check [your existing CLA data](https://cla.developers.google.com/clas) and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).

##### Corporate signers

*   Your company has a Point of Contact who decides which employees are authorized to participate. Ask your POC to be added to the group of authorized contributors. If you don't know who your Point of Contact is, direct the Google project maintainer to [go/cla#troubleshoot](http://go/cla#troubleshoot) ([Public version](https://opensource.google/docs/cla/#troubleshoot)).
*   The email used to register you as an authorized contributor must be the email used for the Git commit. Check [your existing CLA data](https://cla.developers.google.com/clas) and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).
*   The email used to register you as an authorized contributor must also be [attached to your GitHub account](https://github.com/settings/emails).
		

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogle%2Fgo-github%2Fpull%2F1653) for more info**.

<!-- need_sender_cla -->
codecov[bot]: # [Codecov](https://codecov.io/gh/google/go-github/pull/1653?src=pr&el=h1) Report
> Merging [#1653](https://codecov.io/gh/google/go-github/pull/1653?src=pr&el=desc) (ab310e7) into [master](https://codecov.io/gh/google/go-github/commit/2aebd0d1a6c3abcf6d30fa50e1a833e1aa403655?el=desc) (2aebd0d) will **decrease** coverage by `0.12%`.
> The diff coverage is `0.00%`.

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

```diff
@@            Coverage Diff             @@
##           master    #1653      +/-   ##
==========================================
- Coverage   70.01%   69.89%   -0.13%     
==========================================
  Files          97       97              
  Lines        6340     6351      +11     
==========================================
  Hits         4439     4439              
- Misses        985      996      +11     
  Partials      916      916              
```


| [Impacted Files](https://codecov.io/gh/google/go-github/pull/1653?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [github/actions\_runners.go](https://codecov.io/gh/google/go-github/pull/1653/diff?src=pr&el=tree#diff-Z2l0aHViL2FjdGlvbnNfcnVubmVycy5nbw==) | `49.57% <0.00%> (-5.15%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/google/go-github/pull/1653?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/1653?src=pr&el=footer). Last update [2aebd0d...ab310e7](https://codecov.io/gh/google/go-github/pull/1653?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

erikkn: @googlebot I signed it! 
erikkn: Hi, @gmlewis thank you for your review, really appreciate it :)! Just added your requested changes. Will look into adding the necessary tests now
erikkn: @gmlewis may I ask you for another review, please :)? Cheers
erikkn: Hey, @wesleimp I know it is still early over there ;) and I obviously don't want to push, but do you have time to review this PR? Would be really great if we can get this in today :).

Patch:
diff --git a/github/actions_runners.go b/github/actions_runners.go
index 2f186026..e9a21992 100644
--- a/github/actions_runners.go
+++ b/github/actions_runners.go
@@ -18,6 +18,12 @@ type RunnerApplicationDownload struct {
 	Filename     *string `json:"filename,omitempty"`
 }
 
+// ActionsEnabledOnOrgRepos represents all the repositories in an organization for which Actions is enabled.
+type ActionsEnabledOnOrgRepos struct {
+	TotalCount   int           `json:"total_count"`
+	Repositories []*Repository `json:"repositories"`
+}
+
 // ListRunnerApplicationDownloads lists self-hosted runner application binaries that can be downloaded and run.
 //
 // GitHub API docs: https://docs.github.com/en/rest/reference/actions/#list-runner-applications-for-a-repository
@@ -232,6 +238,30 @@ func (s *ActionsService) ListOrganizationRunners(ctx context.Context, owner stri
 	return runners, resp, nil
 }
 
+// ListEnabledReposInOrg lists the selected repositories that are enabled for GitHub Actions in an organization.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/actions#list-selected-repositories-enabled-for-github-actions-in-an-organization
+func (s *ActionsService) ListEnabledReposInOrg(ctx context.Context, owner string, opts *ListOptions) (*ActionsEnabledOnOrgRepos, *Response, error) {
+	u := fmt.Sprintf("orgs/%v/actions/permissions/repositories", owner)
+	u, err := addOptions(u, opts)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	repos := &ActionsEnabledOnOrgRepos{}
+	resp, err := s.client.Do(ctx, req, repos)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return repos, resp, nil
+}
+
 // GetOrganizationRunner gets a specific self-hosted runner for an organization using its runner ID.
 //
 // GitHub API docs: https://docs.github.com/en/rest/reference/actions/#get-a-self-hosted-runner-for-an-organization
diff --git a/github/repos_commits.go b/github/repos_commits.go
index 06210c57..5d3784a3 100644
--- a/github/repos_commits.go
+++ b/github/repos_commits.go
@@ -9,7 +9,6 @@ import (
 	"bytes"
 	"context"
 	"fmt"
-	"net/url"
 	"time"
 )
 
@@ -223,11 +222,9 @@ func (s *RepositoriesService) GetCommitSHA1(ctx context.Context, owner, repo, re
 
 // CompareCommits compares a range of commits with each other.
 //
-// The url query string is escaped before making the request.
-//
 // GitHub API docs: https://docs.github.com/en/rest/reference/repos/#compare-two-commits
-func (s *RepositoriesService) CompareCommits(ctx context.Context, owner, repo, base, head string) (*CommitsComparison, *Response, error) {
-	u := url.QueryEscape(fmt.Sprintf("repos/%v/%v/compare/%v...%v", owner, repo, base, head))
+func (s *RepositoriesService) CompareCommits(ctx context.Context, owner, repo string, base, head string) (*CommitsComparison, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/compare/%v...%v", owner, repo, base, head)
 
 	req, err := s.client.NewRequest("GET", u, nil)
 	if err != nil {


Test patch:
diff --git a/github/actions_runners_test.go b/github/actions_runners_test.go
index 86bec240..02184072 100644
--- a/github/actions_runners_test.go
+++ b/github/actions_runners_test.go
@@ -225,6 +225,56 @@ func TestActionsService_ListOrganizationRunners(t *testing.T) {
 	}
 }
 
+func TestActionsService_ListEnabledReposInOrg(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/orgs/o/actions/permissions/repositories", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testFormValues(t, r, values{
+			"page": "1",
+		})
+		fmt.Fprint(w, `{"total_count":2,"repositories":[{"id":2}, {"id": 3}]}`)
+	})
+
+	ctx := context.Background()
+	opt := &ListOptions{
+		Page: 1,
+	}
+	got, _, err := client.Actions.ListEnabledReposInOrg(ctx, "o", opt)
+	if err != nil {
+		t.Errorf("Actions.ListEnabledReposInOrg returned error: %v", err)
+	}
+
+	want := &ActionsEnabledOnOrgRepos{TotalCount: int(2), Repositories: []*Repository{
+		{ID: Int64(2)},
+		{ID: Int64(3)},
+	}}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("Actions.ListEnabledReposInOrg returned %+v, want %+v", got, want)
+	}
+
+	// Test addOptions failure
+	_, _, err = client.Actions.ListEnabledReposInOrg(ctx, "\n", opt)
+	if err == nil {
+		t.Error("bad options ListEnabledReposInOrg err = nil, want error")
+	}
+
+	// Test s.client.Do failure
+	client.BaseURL.Path = "/api-v3/"
+	client.rateLimits[0].Reset.Time = time.Now().Add(10 * time.Minute)
+	got, resp, err := client.Actions.ListEnabledReposInOrg(ctx, "o", opt)
+	if got != nil {
+		t.Errorf("rate.Reset.Time > now ListEnabledReposInOrg = %#v, want nil", got)
+	}
+	if want := http.StatusForbidden; resp == nil || resp.Response.StatusCode != want {
+		t.Errorf("rate.Reset.Time > now ListEnabledReposInOrg resp = %#v, want StatusCode=%v", resp.Response, want)
+	}
+	if err == nil {
+		t.Error("rate.Reset.Time > now ListEnabledReposInOrg err = nil, want error")
+	}
+}
+
 func TestActionsService_GetOrganizationRunner(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
diff --git a/github/repos_commits_test.go b/github/repos_commits_test.go
index 489092ae..6da964fe 100644
--- a/github/repos_commits_test.go
+++ b/github/repos_commits_test.go
@@ -9,7 +9,6 @@ import (
 	"context"
 	"fmt"
 	"net/http"
-	"net/url"
 	"reflect"
 	"strings"
 	"testing"
@@ -306,118 +305,99 @@ func TestRepositoriesService_CompareCommits(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
 
-	cases := []struct {
-		name string
-		b    string
-		h    string
-	}{
-		{name: "case 1", b: "b", h: "h"},
-		{name: "case 2", b: "#b#", h: "#h#"},
-	}
-
-	for _, c := range cases {
-		t.Run(c.name, func(t *testing.T) {
-			b := url.QueryEscape(c.b)
-			h := url.QueryEscape(c.h)
-
-			u := fmt.Sprintf("/repos/o/r/compare/%v...%v", c.b, c.h)
-
-			mux.HandleFunc(u, func(w http.ResponseWriter, r *http.Request) {
-				testMethod(t, r, "GET")
-				fmt.Fprintf(w, `{
-				  "base_commit": {
-					"sha": "s",
-					"commit": {
-					  "author": { "name": "n" },
-					  "committer": { "name": "n" },
-					  "message": "m",
-					  "tree": { "sha": "t" }
-					},
-					"author": { "login": "l" },
-					"committer": { "login": "l" },
-					"parents": [ { "sha": "s" } ]
-				  },
-				  "status": "s",
-				  "ahead_by": 1,
-				  "behind_by": 2,
-				  "total_commits": 1,
-				  "commits": [
-					{
-					  "sha": "s",
-					  "commit": { "author": { "name": "n" } },
-					  "author": { "login": "l" },
-					  "committer": { "login": "l" },
-					  "parents": [ { "sha": "s" } ]
-					}
-				  ],
-				  "files": [ { "filename": "f" } ],
-				  "html_url":      "https://github.com/o/r/compare/%[1]v...%[2]v",
-				  "permalink_url": "https://github.com/o/r/compare/o:bbcd538c8e72b8c175046e27cc8f907076331401...o:0328041d1152db8ae77652d1618a02e57f745f17",
-				  "diff_url":      "https://github.com/o/r/compare/%[1]v...%[2]v.diff",
-				  "patch_url":     "https://github.com/o/r/compare/%[1]v...%[2]v.patch",
-				  "url":           "https://api.github.com/repos/o/r/compare/%[1]v...%[2]v"
-				}`, b, h)
-			})
+	mux.HandleFunc("/repos/o/r/compare/b...h", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprintf(w, `{
+		  "base_commit": {
+		    "sha": "s",
+		    "commit": {
+		      "author": { "name": "n" },
+		      "committer": { "name": "n" },
+		      "message": "m",
+		      "tree": { "sha": "t" }
+		    },
+		    "author": { "login": "l" },
+		    "committer": { "login": "l" },
+		    "parents": [ { "sha": "s" } ]
+		  },
+		  "status": "s",
+		  "ahead_by": 1,
+		  "behind_by": 2,
+		  "total_commits": 1,
+		  "commits": [
+		    {
+		      "sha": "s",
+		      "commit": { "author": { "name": "n" } },
+		      "author": { "login": "l" },
+		      "committer": { "login": "l" },
+		      "parents": [ { "sha": "s" } ]
+		    }
+		  ],
+		  "files": [ { "filename": "f" } ],
+		  "html_url":      "https://github.com/o/r/compare/b...h",
+		  "permalink_url": "https://github.com/o/r/compare/o:bbcd538c8e72b8c175046e27cc8f907076331401...o:0328041d1152db8ae77652d1618a02e57f745f17",
+		  "diff_url":      "https://github.com/o/r/compare/b...h.diff",
+		  "patch_url":     "https://github.com/o/r/compare/b...h.patch",
+		  "url":           "https://api.github.com/repos/o/r/compare/b...h"
+		}`)
+	})
 
-			got, _, err := client.Repositories.CompareCommits(context.Background(), "o", "r", c.b, c.h)
-			if err != nil {
-				t.Errorf("Repositories.CompareCommits returned error: %v", err)
-			}
+	got, _, err := client.Repositories.CompareCommits(context.Background(), "o", "r", "b", "h")
+	if err != nil {
+		t.Errorf("Repositories.CompareCommits returned error: %v", err)
+	}
 
-			want := &CommitsComparison{
-				BaseCommit: &RepositoryCommit{
+	want := &CommitsComparison{
+		BaseCommit: &RepositoryCommit{
+			SHA: String("s"),
+			Commit: &Commit{
+				Author:    &CommitAuthor{Name: String("n")},
+				Committer: &CommitAuthor{Name: String("n")},
+				Message:   String("m"),
+				Tree:      &Tree{SHA: String("t")},
+			},
+			Author:    &User{Login: String("l")},
+			Committer: &User{Login: String("l")},
+			Parents: []*Commit{
+				{
 					SHA: String("s"),
-					Commit: &Commit{
-						Author:    &CommitAuthor{Name: String("n")},
-						Committer: &CommitAuthor{Name: String("n")},
-						Message:   String("m"),
-						Tree:      &Tree{SHA: String("t")},
-					},
-					Author:    &User{Login: String("l")},
-					Committer: &User{Login: String("l")},
-					Parents: []*Commit{
-						{
-							SHA: String("s"),
-						},
-					},
 				},
-				Status:       String("s"),
-				AheadBy:      Int(1),
-				BehindBy:     Int(2),
-				TotalCommits: Int(1),
-				Commits: []*RepositoryCommit{
-					{
-						SHA: String("s"),
-						Commit: &Commit{
-							Author: &CommitAuthor{Name: String("n")},
-						},
-						Author:    &User{Login: String("l")},
-						Committer: &User{Login: String("l")},
-						Parents: []*Commit{
-							{
-								SHA: String("s"),
-							},
-						},
-					},
+			},
+		},
+		Status:       String("s"),
+		AheadBy:      Int(1),
+		BehindBy:     Int(2),
+		TotalCommits: Int(1),
+		Commits: []*RepositoryCommit{
+			{
+				SHA: String("s"),
+				Commit: &Commit{
+					Author: &CommitAuthor{Name: String("n")},
 				},
-				Files: []*CommitFile{
+				Author:    &User{Login: String("l")},
+				Committer: &User{Login: String("l")},
+				Parents: []*Commit{
 					{
-						Filename: String("f"),
+						SHA: String("s"),
 					},
 				},
-				HTMLURL:      String(fmt.Sprintf("https://github.com/o/r/compare/%v...%v", b, h)),
-				PermalinkURL: String("https://github.com/o/r/compare/o:bbcd538c8e72b8c175046e27cc8f907076331401...o:0328041d1152db8ae77652d1618a02e57f745f17"),
-				DiffURL:      String(fmt.Sprintf("https://github.com/o/r/compare/%v...%v.diff", b, h)),
-				PatchURL:     String(fmt.Sprintf("https://github.com/o/r/compare/%v...%v.patch", b, h)),
-				URL:          String(fmt.Sprintf("https://api.github.com/repos/o/r/compare/%v...%v", b, h)),
-			}
-
-			if !reflect.DeepEqual(got, want) {
-				t.Errorf("Repositories.CompareCommits returned \n%+v, want \n%+v", got, want)
-			}
-		})
+			},
+		},
+		Files: []*CommitFile{
+			{
+				Filename: String("f"),
+			},
+		},
+		HTMLURL:      String("https://github.com/o/r/compare/b...h"),
+		PermalinkURL: String("https://github.com/o/r/compare/o:bbcd538c8e72b8c175046e27cc8f907076331401...o:0328041d1152db8ae77652d1618a02e57f745f17"),
+		DiffURL:      String("https://github.com/o/r/compare/b...h.diff"),
+		PatchURL:     String("https://github.com/o/r/compare/b...h.patch"),
+		URL:          String("https://api.github.com/repos/o/r/compare/b...h"),
 	}
 
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("Repositories.CompareCommits returned \n%+v, want \n%+v", got, want)
+	}
 }
 
 func TestRepositoriesService_CompareCommitsRaw_diff(t *testing.T) {