Repository: google/go-github
Pull request #1644 (2020-11-07 21:27:03)

Add Enterprise ListRunners/RegistrationToken APIs

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%2F1644) for more info**.

<!-- need_sender_cla -->
codecov[bot]: # [Codecov](https://codecov.io/gh/google/go-github/pull/1644?src=pr&el=h1) Report
> Merging [#1644](https://codecov.io/gh/google/go-github/pull/1644?src=pr&el=desc) (8f1389a) into [master](https://codecov.io/gh/google/go-github/commit/76c3c3d7c6e78e8c91e77d2e2578c4e0a7cf96ea?el=desc) (76c3c3d) will **increase** coverage by `2.09%`.
> The diff coverage is `54.54%`.

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

```diff
@@            Coverage Diff             @@
##           master    #1644      +/-   ##
==========================================
+ Coverage   67.87%   69.96%   +2.09%     
==========================================
  Files          97       98       +1     
  Lines        8802     6350    -2452     
==========================================
- Hits         5974     4443    -1531     
+ Misses       1912      986     -926     
- Partials      916      921       +5     
```


| [Impacted Files](https://codecov.io/gh/google/go-github/pull/1644?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [github/enterprise\_actions\_runners.go](https://codecov.io/gh/google/go-github/pull/1644/diff?src=pr&el=tree#diff-Z2l0aHViL2VudGVycHJpc2VfYWN0aW9uc19ydW5uZXJzLmdv) | `52.38% <52.38%> (ø)` | |
| [github/github.go](https://codecov.io/gh/google/go-github/pull/1644/diff?src=pr&el=tree#diff-Z2l0aHViL2dpdGh1Yi5nbw==) | `89.81% <100.00%> (-0.21%)` | :arrow_down: |
| [github/users\_administration.go](https://codecov.io/gh/google/go-github/pull/1644/diff?src=pr&el=tree#diff-Z2l0aHViL3VzZXJzX2FkbWluaXN0cmF0aW9uLmdv) | `60.00% <0.00%> (-2.50%)` | :arrow_down: |
| [github/interactions\_orgs.go](https://codecov.io/gh/google/go-github/pull/1644/diff?src=pr&el=tree#diff-Z2l0aHViL2ludGVyYWN0aW9uc19vcmdzLmdv) | `62.96% <0.00%> (-1.33%)` | :arrow_down: |
| [github/interactions\_repos.go](https://codecov.io/gh/google/go-github/pull/1644/diff?src=pr&el=tree#diff-Z2l0aHViL2ludGVyYWN0aW9uc19yZXBvcy5nbw==) | `62.96% <0.00%> (-1.33%)` | :arrow_down: |
| [github/admin\_users.go](https://codecov.io/gh/google/go-github/pull/1644/diff?src=pr&el=tree#diff-Z2l0aHViL2FkbWluX3VzZXJzLmdv) | `56.75% <0.00%> (-1.14%)` | :arrow_down: |
| [github/git\_trees.go](https://codecov.io/gh/google/go-github/pull/1644/diff?src=pr&el=tree#diff-Z2l0aHViL2dpdF90cmVlcy5nbw==) | `75.00% <0.00%> (-0.95%)` | :arrow_down: |
| [github/admin\_orgs.go](https://codecov.io/gh/google/go-github/pull/1644/diff?src=pr&el=tree#diff-Z2l0aHViL2FkbWluX29yZ3MuZ28=) | `66.66% <0.00%> (-0.91%)` | :arrow_down: |
| [github/users\_blocking.go](https://codecov.io/gh/google/go-github/pull/1644/diff?src=pr&el=tree#diff-Z2l0aHViL3VzZXJzX2Jsb2NraW5nLmdv) | `63.63% <0.00%> (-0.37%)` | :arrow_down: |
| [github/orgs\_users\_blocking.go](https://codecov.io/gh/google/go-github/pull/1644/diff?src=pr&el=tree#diff-Z2l0aHViL29yZ3NfdXNlcnNfYmxvY2tpbmcuZ28=) | `63.63% <0.00%> (-0.37%)` | :arrow_down: |
| ... and [90 more](https://codecov.io/gh/google/go-github/pull/1644/diff?src=pr&el=tree-more) | |

------

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

jamie-34254: @googlebot I signed it!
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%2F1644) for more info**.

<!-- need_sender_cla -->
jamie-34254: We just signed the corporate CLA, so I'm guessing there might be a delay on it?
gmlewis: @googlebot is usually very fast. There might be an issue. Let's see if it responds with an update.
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%2F1644) for more info**.

<!-- need_sender_cla -->
jamie-34254: @googlebot I signed it!
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%2F1644) for more info**.

<!-- need_sender_cla -->
gmlewis: > We just signed the corporate CLA, so I'm guessing there might be a delay on it?

Oh, I gotcha... I read that too quickly before.  Yes, there is a manual review process for brand new corporate CLAs... so we may have to wait a few days.

Thank you for your patience, @jamie-34254 !
jamie-34254: @googlebot I signed it! 
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

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

<!-- need_author_cla -->
jamie-34254: Thanks @gmlewis! This should be good for 2nd review now :) 

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/enterprise.go b/github/enterprise.go
new file mode 100644
index 00000000..225e3438
--- /dev/null
+++ b/github/enterprise.go
@@ -0,0 +1,12 @@
+// Copyright 2020 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+// EnterpriseService provides access to the enterprise related functions
+// in the GitHub API.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/enterprise-admin/
+type EnterpriseService service
diff --git a/github/enterprise_actions_runners.go b/github/enterprise_actions_runners.go
new file mode 100644
index 00000000..51fb793b
--- /dev/null
+++ b/github/enterprise_actions_runners.go
@@ -0,0 +1,55 @@
+// Copyright 2020 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"fmt"
+)
+
+// CreateRegistrationToken creates a token that can be used to add a self-hosted runner.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/enterprise-admin#create-a-registration-token-for-an-enterprise
+func (s *EnterpriseService) CreateRegistrationToken(ctx context.Context, enterprise string) (*RegistrationToken, *Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runners/registration-token", enterprise)
+
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	registrationToken := new(RegistrationToken)
+	resp, err := s.client.Do(ctx, req, registrationToken)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return registrationToken, resp, nil
+}
+
+// ListRunners lists all the self-hosted runners for a enterprise.
+//
+// GitHub API docs: https://docs.github.com/en/rest/reference/enterprise-admin/#list-self-hosted-runners-for-an-enterprise
+func (s *EnterpriseService) ListRunners(ctx context.Context, enterprise string, opts *ListOptions) (*Runners, *Response, error) {
+	u := fmt.Sprintf("enterprises/%v/actions/runners", enterprise)
+	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
+	}
+
+	runners := &Runners{}
+	resp, err := s.client.Do(ctx, req, &runners)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return runners, resp, nil
+}
diff --git a/github/github.go b/github/github.go
index 41702402..61c89e4d 100644
--- a/github/github.go
+++ b/github/github.go
@@ -161,6 +161,7 @@ type Client struct {
 	Authorizations *AuthorizationsService
 	Checks         *ChecksService
 	CodeScanning   *CodeScanningService
+	Enterprise     *EnterpriseService
 	Gists          *GistsService
 	Git            *GitService
 	Gitignores     *GitignoresService
@@ -269,6 +270,7 @@ func NewClient(httpClient *http.Client) *Client {
 	c.Authorizations = (*AuthorizationsService)(&c.common)
 	c.Checks = (*ChecksService)(&c.common)
 	c.CodeScanning = (*CodeScanningService)(&c.common)
+	c.Enterprise = (*EnterpriseService)(&c.common)
 	c.Gists = (*GistsService)(&c.common)
 	c.Git = (*GitService)(&c.common)
 	c.Gitignores = (*GitignoresService)(&c.common)
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/enterprise_actions_runners_test.go b/github/enterprise_actions_runners_test.go
new file mode 100644
index 00000000..eaafd46b
--- /dev/null
+++ b/github/enterprise_actions_runners_test.go
@@ -0,0 +1,65 @@
+// Copyright 2020 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestEnterpriseService_CreateRegistrationToken(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/e/actions/runners/registration-token", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "POST")
+		fmt.Fprint(w, `{"token":"LLBF3JGZDX3P5PMEXLND6TS6FCWO6","expires_at":"2020-01-22T12:13:35.123Z"}`)
+	})
+
+	token, _, err := client.Enterprise.CreateRegistrationToken(context.Background(), "e")
+	if err != nil {
+		t.Errorf("Enterprise.CreateRegistrationToken returned error: %v", err)
+	}
+
+	want := &RegistrationToken{Token: String("LLBF3JGZDX3P5PMEXLND6TS6FCWO6"),
+		ExpiresAt: &Timestamp{time.Date(2020, time.January, 22, 12, 13, 35,
+			123000000, time.UTC)}}
+	if !reflect.DeepEqual(token, want) {
+		t.Errorf("Enterprise.CreateRegistrationToken returned %+v, want %+v", token, want)
+	}
+}
+
+func TestEnterpriseService_ListRunners(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprises/e/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, `{"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}
+	runners, _, err := client.Enterprise.ListRunners(context.Background(), "e", opts)
+	if err != nil {
+		t.Errorf("Enterprise.ListRunners returned error: %v", err)
+	}
+
+	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/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) {