Repository: google/go-github
Pull request #767 (2017-10-29 08:09:38)

Add RepositoriesService.GetCommitRaw method.
Follows the same high-level pattern as set out in PR #481 with `PullRequestsService.GetRaw` method. (/cc @huydx FYI.)

Improve documentation wording.

Improve style of `PullRequestsService.GetRaw` and its tests to be more consistent.

Fix minor typo in GitHub documentation URL.


Patch:
diff --git a/github/apps.go b/github/apps.go
index ff338938..a83ea7c2 100644
--- a/github/apps.go
+++ b/github/apps.go
@@ -5,7 +5,11 @@
 
 package github
 
-import "context"
+import (
+	"context"
+	"fmt"
+	"time"
+)
 
 // AppsService provides access to the installation related functions
 // in the GitHub API.
@@ -13,6 +17,57 @@ import "context"
 // GitHub API docs: https://developer.github.com/v3/apps/
 type AppsService service
 
+// App represents a GitHub App.
+type App struct {
+	ID          *int       `json:"id,omitempty"`
+	Owner       *User      `json:"owner,omitempty"`
+	Name        *string    `json:"name,omitempty"`
+	Description *string    `json:"description,omitempty"`
+	ExternalURL *string    `json:"external_url,omitempty"`
+	HTMLURL     *string    `json:"html_url,omitempty"`
+	CreatedAt   *time.Time `json:"created_at,omitempty"`
+	UpdatedAt   *time.Time `json:"updated_at,omitempty"`
+}
+
+// InstallationToken represents an installation token.
+type InstallationToken struct {
+	Token     *string    `json:"token,omitempty"`
+	ExpiresAt *time.Time `json:"expires_at,omitempty"`
+}
+
+// Get a single GitHub App. Passing the empty string will get
+// the authenticated GitHub App.
+//
+// Note: appSlug is just the URL-friendly name of your GitHub App.
+// You can find this on the settings page for your GitHub App
+// (e.g., https://github.com/settings/apps/:app_slug).
+//
+// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-github-app
+func (s *AppsService) Get(ctx context.Context, appSlug string) (*App, *Response, error) {
+	var u string
+	if appSlug != "" {
+		u = fmt.Sprintf("apps/%v", appSlug)
+	} else {
+		u = "app"
+	}
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// TODO: remove custom Accept header when this API fully launches.
+	req.Header.Set("Accept", mediaTypeIntegrationPreview)
+
+	app := new(App)
+	resp, err := s.client.Do(ctx, req, app)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return app, resp, nil
+}
+
 // ListInstallations lists the installations that the current GitHub App has.
 //
 // GitHub API docs: https://developer.github.com/v3/apps/#find-installations
@@ -38,3 +93,77 @@ func (s *AppsService) ListInstallations(ctx context.Context, opt *ListOptions) (
 
 	return i, resp, nil
 }
+
+// GetInstallation returns the specified installation.
+//
+// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-installation
+func (s *AppsService) GetInstallation(ctx context.Context, id int) (*Installation, *Response, error) {
+	u := fmt.Sprintf("app/installations/%v", id)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// TODO: remove custom Accept header when this API fully launches.
+	req.Header.Set("Accept", mediaTypeIntegrationPreview)
+
+	i := new(Installation)
+	resp, err := s.client.Do(ctx, req, i)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return i, resp, nil
+}
+
+// ListUserInstallations lists installations that are accessible to the authenticated user.
+//
+// GitHub API docs: https://developer.github.com/v3/apps/#list-installations-for-user
+func (s *AppsService) ListUserInstallations(ctx context.Context, opt *ListOptions) ([]*Installation, *Response, error) {
+	u, err := addOptions("user/installations", opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// TODO: remove custom Accept header when this API fully launches.
+	req.Header.Set("Accept", mediaTypeIntegrationPreview)
+
+	var i struct {
+		Installations []*Installation `json:"installations"`
+	}
+	resp, err := s.client.Do(ctx, req, &i)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return i.Installations, resp, nil
+}
+
+// CreateInstallationToken creates a new installation token.
+//
+// GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token
+func (s *AppsService) CreateInstallationToken(ctx context.Context, id int) (*InstallationToken, *Response, error) {
+	u := fmt.Sprintf("installations/%v/access_tokens", id)
+
+	req, err := s.client.NewRequest("POST", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// TODO: remove custom Accept header when this API fully launches.
+	req.Header.Set("Accept", mediaTypeIntegrationPreview)
+
+	t := new(InstallationToken)
+	resp, err := s.client.Do(ctx, req, t)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return t, resp, nil
+}
diff --git a/github/apps_installation.go b/github/apps_installation.go
index 5c932919..ccac316c 100644
--- a/github/apps_installation.go
+++ b/github/apps_installation.go
@@ -51,6 +51,33 @@ func (s *AppsService) ListRepos(ctx context.Context, opt *ListOptions) ([]*Repos
 	return r.Repositories, resp, nil
 }
 
+// ListUserRepos lists repositories that are accessible
+// to the authenticated user for an installation.
+//
+// GitHub API docs: https://developer.github.com/v3/apps/installations/#list-repositories-accessible-to-the-user-for-an-installation
+func (s *AppsService) ListUserRepos(ctx context.Context, id int, opt *ListOptions) ([]*Repository, *Response, error) {
+	u := fmt.Sprintf("user/installations/%v/repositories", id)
+	u, err := addOptions(u, opt)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var r struct {
+		Repositories []*Repository `json:"repositories"`
+	}
+	resp, err := s.client.Do(ctx, req, &r)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return r.Repositories, resp, nil
+}
+
 // AddRepository adds a single repository to an installation.
 //
 // GitHub API docs: https://developer.github.com/v3/apps/installations/#add-repository-to-installation
diff --git a/github/github-accessors.go b/github/github-accessors.go
index 6da009ba..4e0ce600 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -36,6 +36,62 @@ func (a *APIMeta) GetVerifiablePasswordAuthentication() bool {
 	return *a.VerifiablePasswordAuthentication
 }
 
+// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
+func (a *App) GetCreatedAt() time.Time {
+	if a == nil || a.CreatedAt == nil {
+		return time.Time{}
+	}
+	return *a.CreatedAt
+}
+
+// GetDescription returns the Description field if it's non-nil, zero value otherwise.
+func (a *App) GetDescription() string {
+	if a == nil || a.Description == nil {
+		return ""
+	}
+	return *a.Description
+}
+
+// GetExternalURL returns the ExternalURL field if it's non-nil, zero value otherwise.
+func (a *App) GetExternalURL() string {
+	if a == nil || a.ExternalURL == nil {
+		return ""
+	}
+	return *a.ExternalURL
+}
+
+// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise.
+func (a *App) GetHTMLURL() string {
+	if a == nil || a.HTMLURL == nil {
+		return ""
+	}
+	return *a.HTMLURL
+}
+
+// GetID returns the ID field if it's non-nil, zero value otherwise.
+func (a *App) GetID() int {
+	if a == nil || a.ID == nil {
+		return 0
+	}
+	return *a.ID
+}
+
+// GetName returns the Name field if it's non-nil, zero value otherwise.
+func (a *App) GetName() string {
+	if a == nil || a.Name == nil {
+		return ""
+	}
+	return *a.Name
+}
+
+// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
+func (a *App) GetUpdatedAt() time.Time {
+	if a == nil || a.UpdatedAt == nil {
+		return time.Time{}
+	}
+	return *a.UpdatedAt
+}
+
 // GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
 func (a *Authorization) GetCreatedAt() Timestamp {
 	if a == nil || a.CreatedAt == nil {
@@ -2036,6 +2092,22 @@ func (i *InstallationRepositoriesEvent) GetRepositorySelection() string {
 	return *i.RepositorySelection
 }
 
+// GetExpiresAt returns the ExpiresAt field if it's non-nil, zero value otherwise.
+func (i *InstallationToken) GetExpiresAt() time.Time {
+	if i == nil || i.ExpiresAt == nil {
+		return time.Time{}
+	}
+	return *i.ExpiresAt
+}
+
+// GetToken returns the Token field if it's non-nil, zero value otherwise.
+func (i *InstallationToken) GetToken() string {
+	if i == nil || i.Token == nil {
+		return ""
+	}
+	return *i.Token
+}
+
 // GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
 func (i *Invitation) GetCreatedAt() time.Time {
 	if i == nil || i.CreatedAt == nil {
diff --git a/github/github.go b/github/github.go
index b33f70a4..87af91de 100644
--- a/github/github.go
+++ b/github/github.go
@@ -235,6 +235,37 @@ func NewClient(httpClient *http.Client) *Client {
 	return c
 }
 
+// NewEnterpriseClient returns a new GitHub API client with provided
+// base URL and upload URL (often the same URL).
+// If either URL does not have a trailing slash, one is added automatically.
+// If a nil httpClient is provided, http.DefaultClient will be used.
+//
+// Note that NewEnterpriseClient is a convenience helper only;
+// its behavior is equivalent to using NewClient, followed by setting
+// the BaseURL and UploadURL fields.
+func NewEnterpriseClient(baseURL, uploadURL string, httpClient *http.Client) (*Client, error) {
+	baseEndpoint, err := url.Parse(baseURL)
+	if err != nil {
+		return nil, err
+	}
+	if !strings.HasSuffix(baseEndpoint.Path, "/") {
+		baseEndpoint.Path += "/"
+	}
+
+	uploadEndpoint, err := url.Parse(uploadURL)
+	if err != nil {
+		return nil, err
+	}
+	if !strings.HasSuffix(uploadEndpoint.Path, "/") {
+		uploadEndpoint.Path += "/"
+	}
+
+	c := NewClient(httpClient)
+	c.BaseURL = baseEndpoint
+	c.UploadURL = uploadEndpoint
+	return c, nil
+}
+
 // NewRequest creates an API request. A relative URL can be provided in urlStr,
 // in which case it is resolved relative to the BaseURL of the Client.
 // Relative URLs should always be specified without a preceding slash. If
diff --git a/github/pulls.go b/github/pulls.go
index bc46081f..6681c8b2 100644
--- a/github/pulls.go
+++ b/github/pulls.go
@@ -138,7 +138,7 @@ func (s *PullRequestsService) Get(ctx context.Context, owner string, repo string
 	return pull, resp, nil
 }
 
-// GetRaw gets raw (diff or patch) format of a pull request.
+// GetRaw gets a single pull request in raw (diff or patch) format.
 func (s *PullRequestsService) GetRaw(ctx context.Context, owner string, repo string, number int, opt RawOptions) (string, *Response, error) {
 	u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number)
 	req, err := s.client.NewRequest("GET", u, nil)
@@ -155,13 +155,13 @@ func (s *PullRequestsService) GetRaw(ctx context.Context, owner string, repo str
 		return "", nil, fmt.Errorf("unsupported raw type %d", opt.Type)
 	}
 
-	ret := new(bytes.Buffer)
-	resp, err := s.client.Do(ctx, req, ret)
+	var buf bytes.Buffer
+	resp, err := s.client.Do(ctx, req, &buf)
 	if err != nil {
 		return "", resp, err
 	}
 
-	return ret.String(), resp, nil
+	return buf.String(), resp, nil
 }
 
 // NewPullRequest represents a new pull request to be created.
diff --git a/github/repos_commits.go b/github/repos_commits.go
index 4451b6bb..04847373 100644
--- a/github/repos_commits.go
+++ b/github/repos_commits.go
@@ -140,10 +140,9 @@ func (s *RepositoriesService) ListCommits(ctx context.Context, owner, repo strin
 }
 
 // GetCommit fetches the specified commit, including all details about it.
-// todo: support media formats - https://github.com/google/go-github/issues/6
 //
 // GitHub API docs: https://developer.github.com/v3/repos/commits/#get-a-single-commit
-// See also: https://developer.github.com//v3/git/commits/#get-a-single-commit provides the same functionality
+// See also: https://developer.github.com/v3/git/commits/#get-a-single-commit provides the same functionality
 func (s *RepositoriesService) GetCommit(ctx context.Context, owner, repo, sha string) (*RepositoryCommit, *Response, error) {
 	u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha)
 
@@ -164,6 +163,32 @@ func (s *RepositoriesService) GetCommit(ctx context.Context, owner, repo, sha st
 	return commit, resp, nil
 }
 
+// GetCommitRaw fetches the specified commit in raw (diff or patch) format.
+func (s *RepositoriesService) GetCommitRaw(ctx context.Context, owner string, repo string, sha string, opt RawOptions) (string, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return "", nil, err
+	}
+
+	switch opt.Type {
+	case Diff:
+		req.Header.Set("Accept", mediaTypeV3Diff)
+	case Patch:
+		req.Header.Set("Accept", mediaTypeV3Patch)
+	default:
+		return "", nil, fmt.Errorf("unsupported raw type %d", opt.Type)
+	}
+
+	var buf bytes.Buffer
+	resp, err := s.client.Do(ctx, req, &buf)
+	if err != nil {
+		return "", resp, err
+	}
+
+	return buf.String(), resp, nil
+}
+
 // GetCommitSHA1 gets the SHA-1 of a commit reference. If a last-known SHA1 is
 // supplied and no new commits have occurred, a 304 Unmodified response is returned.
 //


Test patch:
diff --git a/github/apps_installation_test.go b/github/apps_installation_test.go
index 69598cfe..ec796cd3 100644
--- a/github/apps_installation_test.go
+++ b/github/apps_installation_test.go
@@ -39,6 +39,31 @@ func TestAppsService_ListRepos(t *testing.T) {
 	}
 }
 
+func TestAppsService_ListUserRepos(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/user/installations/1/repositories", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testFormValues(t, r, values{
+			"page":     "1",
+			"per_page": "2",
+		})
+		fmt.Fprint(w, `{"repositories": [{"id":1}]}`)
+	})
+
+	opt := &ListOptions{Page: 1, PerPage: 2}
+	repositories, _, err := client.Apps.ListUserRepos(context.Background(), 1, opt)
+	if err != nil {
+		t.Errorf("Apps.ListUserRepos returned error: %v", err)
+	}
+
+	want := []*Repository{{ID: Int(1)}}
+	if !reflect.DeepEqual(repositories, want) {
+		t.Errorf("Apps.ListUserRepos returned %+v, want %+v", repositories, want)
+	}
+}
+
 func TestAppsService_AddRepository(t *testing.T) {
 	setup()
 	defer teardown()
diff --git a/github/apps_test.go b/github/apps_test.go
index f847b842..9ef1f468 100644
--- a/github/apps_test.go
+++ b/github/apps_test.go
@@ -13,6 +13,48 @@ import (
 	"testing"
 )
 
+func TestAppsService_Get_authenticatedApp(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/app", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
+		fmt.Fprint(w, `{"id":1}`)
+	})
+
+	app, _, err := client.Apps.Get(context.Background(), "")
+	if err != nil {
+		t.Errorf("Apps.Get returned error: %v", err)
+	}
+
+	want := &App{ID: Int(1)}
+	if !reflect.DeepEqual(app, want) {
+		t.Errorf("Apps.Get returned %+v, want %+v", app, want)
+	}
+}
+
+func TestAppsService_Get_specifiedApp(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/apps/a", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
+		fmt.Fprint(w, `{"html_url":"https://github.com/apps/a"}`)
+	})
+
+	app, _, err := client.Apps.Get(context.Background(), "a")
+	if err != nil {
+		t.Errorf("Apps.Get returned error: %v", err)
+	}
+
+	want := &App{HTMLURL: String("https://github.com/apps/a")}
+	if !reflect.DeepEqual(app, want) {
+		t.Errorf("Apps.Get returned %+v, want %+v", *app.HTMLURL, *want.HTMLURL)
+	}
+}
+
 func TestAppsService_ListInstallations(t *testing.T) {
 	setup()
 	defer teardown()
@@ -38,3 +80,71 @@ func TestAppsService_ListInstallations(t *testing.T) {
 		t.Errorf("Apps.ListInstallations returned %+v, want %+v", installations, want)
 	}
 }
+
+func TestAppsService_GetInstallation(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/app/installations/1", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
+		fmt.Fprint(w, `{"id":1}`)
+	})
+
+	installation, _, err := client.Apps.GetInstallation(context.Background(), 1)
+	if err != nil {
+		t.Errorf("Apps.GetInstallation returned error: %v", err)
+	}
+
+	want := &Installation{ID: Int(1)}
+	if !reflect.DeepEqual(installation, want) {
+		t.Errorf("Apps.GetInstallation returned %+v, want %+v", installation, want)
+	}
+}
+
+func TestAppsService_ListUserInstallations(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/user/installations", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
+		testFormValues(t, r, values{
+			"page":     "1",
+			"per_page": "2",
+		})
+		fmt.Fprint(w, `{"installations":[{"id":1}]}`)
+	})
+
+	opt := &ListOptions{Page: 1, PerPage: 2}
+	installations, _, err := client.Apps.ListUserInstallations(context.Background(), opt)
+	if err != nil {
+		t.Errorf("Apps.ListUserInstallations returned error: %v", err)
+	}
+
+	want := []*Installation{{ID: Int(1)}}
+	if !reflect.DeepEqual(installations, want) {
+		t.Errorf("Apps.ListUserInstallations returned %+v, want %+v", installations, want)
+	}
+}
+
+func TestAppsService_CreateInstallationToken(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/installations/1/access_tokens", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "POST")
+		testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
+		fmt.Fprint(w, `{"token":"t"}`)
+	})
+
+	token, _, err := client.Apps.CreateInstallationToken(context.Background(), 1)
+	if err != nil {
+		t.Errorf("Apps.CreateInstallationToken returned error: %v", err)
+	}
+
+	want := &InstallationToken{Token: String("t")}
+	if !reflect.DeepEqual(token, want) {
+		t.Errorf("Apps.CreateInstallationToken returned %+v, want %+v", token, want)
+	}
+}
diff --git a/github/github_test.go b/github/github_test.go
index aff436a6..cc62fc6b 100644
--- a/github/github_test.go
+++ b/github/github_test.go
@@ -186,6 +186,41 @@ func TestNewClient(t *testing.T) {
 	}
 }
 
+func TestNewEnterpriseClient(t *testing.T) {
+	baseURL := "https://custom-url/"
+	uploadURL := "https://custom-upload-url/"
+	c, err := NewEnterpriseClient(baseURL, uploadURL, nil)
+	if err != nil {
+		t.Fatalf("NewEnterpriseClient returned unexpected error: %v", err)
+	}
+
+	if got, want := c.BaseURL.String(), baseURL; got != want {
+		t.Errorf("NewClient BaseURL is %v, want %v", got, want)
+	}
+	if got, want := c.UploadURL.String(), uploadURL; got != want {
+		t.Errorf("NewClient UploadURL is %v, want %v", got, want)
+	}
+}
+
+func TestNewEnterpriseClient_addsTrailingSlashToURLs(t *testing.T) {
+	baseURL := "https://custom-url"
+	uploadURL := "https://custom-upload-url"
+	formattedBaseURL := baseURL + "/"
+	formattedUploadURL := uploadURL + "/"
+
+	c, err := NewEnterpriseClient(baseURL, uploadURL, nil)
+	if err != nil {
+		t.Fatalf("NewEnterpriseClient returned unexpected error: %v", err)
+	}
+
+	if got, want := c.BaseURL.String(), formattedBaseURL; got != want {
+		t.Errorf("NewClient BaseURL is %v, want %v", got, want)
+	}
+	if got, want := c.UploadURL.String(), formattedUploadURL; got != want {
+		t.Errorf("NewClient UploadURL is %v, want %v", got, want)
+	}
+}
+
 // Ensure that length of Client.rateLimits is the same as number of fields in RateLimits struct.
 func TestClient_rateLimits(t *testing.T) {
 	if got, want := len(Client{}.rateLimits), reflect.TypeOf(RateLimits{}).NumField(); got != want {
diff --git a/github/pulls_test.go b/github/pulls_test.go
index ea31e521..89adf239 100644
--- a/github/pulls_test.go
+++ b/github/pulls_test.go
@@ -70,9 +70,10 @@ func TestPullRequestsService_Get(t *testing.T) {
 	}
 }
 
-func TestPullRequestsService_GetRawDiff(t *testing.T) {
+func TestPullRequestsService_GetRaw_diff(t *testing.T) {
 	setup()
 	defer teardown()
+
 	const rawStr = "@@diff content"
 
 	mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
@@ -81,19 +82,20 @@ func TestPullRequestsService_GetRawDiff(t *testing.T) {
 		fmt.Fprint(w, rawStr)
 	})
 
-	ret, _, err := client.PullRequests.GetRaw(context.Background(), "o", "r", 1, RawOptions{Diff})
+	got, _, err := client.PullRequests.GetRaw(context.Background(), "o", "r", 1, RawOptions{Diff})
 	if err != nil {
 		t.Fatalf("PullRequests.GetRaw returned error: %v", err)
 	}
-
-	if ret != rawStr {
-		t.Errorf("PullRequests.GetRaw returned %s want %s", ret, rawStr)
+	want := rawStr
+	if got != want {
+		t.Errorf("PullRequests.GetRaw returned %s want %s", got, want)
 	}
 }
 
-func TestPullRequestsService_GetRawPatch(t *testing.T) {
+func TestPullRequestsService_GetRaw_patch(t *testing.T) {
 	setup()
 	defer teardown()
+
 	const rawStr = "@@patch content"
 
 	mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
@@ -102,17 +104,17 @@ func TestPullRequestsService_GetRawPatch(t *testing.T) {
 		fmt.Fprint(w, rawStr)
 	})
 
-	ret, _, err := client.PullRequests.GetRaw(context.Background(), "o", "r", 1, RawOptions{Patch})
+	got, _, err := client.PullRequests.GetRaw(context.Background(), "o", "r", 1, RawOptions{Patch})
 	if err != nil {
 		t.Fatalf("PullRequests.GetRaw returned error: %v", err)
 	}
-
-	if ret != rawStr {
-		t.Errorf("PullRequests.GetRaw returned %s want %s", ret, rawStr)
+	want := rawStr
+	if got != want {
+		t.Errorf("PullRequests.GetRaw returned %s want %s", got, want)
 	}
 }
 
-func TestPullRequestsService_GetRawInvalid(t *testing.T) {
+func TestPullRequestsService_GetRaw_invalid(t *testing.T) {
 	setup()
 	defer teardown()
 
diff --git a/github/repos_commits_test.go b/github/repos_commits_test.go
index 98eadabb..1d5f5ec9 100644
--- a/github/repos_commits_test.go
+++ b/github/repos_commits_test.go
@@ -10,6 +10,7 @@ import (
 	"fmt"
 	"net/http"
 	"reflect"
+	"strings"
 	"testing"
 	"time"
 )
@@ -126,6 +127,63 @@ func TestRepositoriesService_GetCommit(t *testing.T) {
 	}
 }
 
+func TestRepositoriesService_GetCommitRaw_diff(t *testing.T) {
+	setup()
+	defer teardown()
+
+	const rawStr = "@@diff content"
+
+	mux.HandleFunc("/repos/o/r/commits/s", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeV3Diff)
+		fmt.Fprint(w, rawStr)
+	})
+
+	got, _, err := client.Repositories.GetCommitRaw(context.Background(), "o", "r", "s", RawOptions{Type: Diff})
+	if err != nil {
+		t.Fatalf("Repositories.GetCommitRaw returned error: %v", err)
+	}
+	want := rawStr
+	if got != want {
+		t.Errorf("Repositories.GetCommitRaw returned %s want %s", got, want)
+	}
+}
+
+func TestRepositoriesService_GetCommitRaw_patch(t *testing.T) {
+	setup()
+	defer teardown()
+
+	const rawStr = "@@patch content"
+
+	mux.HandleFunc("/repos/o/r/commits/s", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeV3Patch)
+		fmt.Fprint(w, rawStr)
+	})
+
+	got, _, err := client.Repositories.GetCommitRaw(context.Background(), "o", "r", "s", RawOptions{Type: Patch})
+	if err != nil {
+		t.Fatalf("Repositories.GetCommitRaw returned error: %v", err)
+	}
+	want := rawStr
+	if got != want {
+		t.Errorf("Repositories.GetCommitRaw returned %s want %s", got, want)
+	}
+}
+
+func TestRepositoriesService_GetCommitRaw_invalid(t *testing.T) {
+	setup()
+	defer teardown()
+
+	_, _, err := client.Repositories.GetCommitRaw(context.Background(), "o", "r", "s", RawOptions{100})
+	if err == nil {
+		t.Fatal("Repositories.GetCommitRaw should return error")
+	}
+	if !strings.Contains(err.Error(), "unsupported raw type") {
+		t.Error("Repositories.GetCommitRaw should return unsupported raw type error")
+	}
+}
+
 func TestRepositoriesService_GetCommitSHA1(t *testing.T) {
 	setup()
 	defer teardown()