Repository: google/go-github
Pull request #725 (2017-09-25 07:58:05)

Add admin stats
This adds support for "Admin Stats" part of the GitHub Enterprise API, as per https://developer.github.com/v3/enterprise-admin/admin_stats. It should implement part of #179 

At this point, only getting "all" stats is supported, thought it should be straightforward to add  others at some point. 

I'm really not sure about the naming here, the api prefixes for the GHE Admin API are all over the place with `/admin`, `/staff`, `/setup` and `/enterprise`. I see three options here:

- Stick to the pattern (In that case I'd need to move this implementation to `EnterpriseService`)
- Collect all of them in the existing `AdminService` 
- Collect all of them in a newly created `EnterpriseAdminService` (migration & deprecation fun)




  


googlebot: Thanks for your pull request.  It looks like this may be your first contribution to a Google open source project. 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, please reply here (e.g. `I signed it!`) and we'll verify.  Thanks.

---

- If you've already signed a CLA, it's possible we don't have your GitHub username or you're using a different email address.  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/).
- If your company signed a CLA, they designated a Point of Contact who decides which employees are authorized to participate. You may need to contact the Point of Contact for your company and ask to be added to the group of authorized contributors. If you don't know who your Point of Contact is, direct the project maintainer to go/cla#troubleshoot.
- In order to pass this check, please resolve this problem and have the pull request author add another comment and the bot will run again.

<!-- need_sender_cla -->
defsprite: I signed it!
googlebot: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for the commit author(s).  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 have the pull request author add another comment and the bot will run again.

<!-- need_author_cla -->
googlebot: CLAs look good, thanks!

<!-- ok -->
shurcooL: Thanks for the PR @defsprite.

As @e-beach mentioned, we'll definitely want the exported top-level identifiers to have documentation. See the other .go files for precedent and preferred format.

> I'm really not sure about the naming here, the api prefixes for the GHE Admin API are all over the place with `/admin`, `/staff`, `/setup` and `/enterprise`. I see three options here:
>
> - Stick to the pattern (In that case I'd need to move this implementation to `EnterpriseService`)
> - Collect all of them in the existing `AdminService` 
> - Collect all of them in a newly created `EnterpriseAdminService` (migration & deprecation fun)

Good question.

I think in this case there's an easy answer. Since we already have an existing `AdminService`, this feels like it would fit nicely there.

If there was no equivalent non-GHE service for a GHE endpoint, we might want to create an `EnterpriseService` and put all the stragglers there. I definitely don't think we ever need to go down the `EnterpriseAdminService`, there's just not that many GHE-only endpoints to justify it.

Thanks!

Patch:
diff --git a/.travis.yml b/.travis.yml
index 60ce6cae..f575d459 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,7 @@
 sudo: false
 language: go
 go:
+  - 1.9.x
   - 1.8.x
   - 1.7.x
   - master
diff --git a/AUTHORS b/AUTHORS
index c15c465a..e97e992e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -77,6 +77,7 @@ i2bskn <i2bskn@gmail.com>
 Isao Jonas <isao.jonas@gmail.com>
 isqua <isqua@isqua.ru>
 Jameel Haffejee <RC1140@republiccommandos.co.za>
+Jeremy Morris <jeremylevanmorris@gmail.com>
 Jan Kosecki <jan.kosecki91@gmail.com>
 Jihoon Chung <j.c@navercorp.com>
 Jimmi Dyson <jimmidyson@gmail.com>
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 68a23f00..8da635a6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -55,7 +55,7 @@ again.
 
 [forking]: https://help.github.com/articles/fork-a-repo
 [golint]: https://github.com/golang/lint
-[golint readme]: https://github.com/golang/lint/blob/master/README
+[golint readme]: https://github.com/golang/lint/blob/master/README.md
 [gocov]: https://github.com/axw/gocov
 [gocov-html]: https://github.com/matm/gocov-html
 [well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
diff --git a/README.md b/README.md
index d751b8cd..f416c81d 100644
--- a/README.md
+++ b/README.md
@@ -210,6 +210,17 @@ For complete usage of go-github, see the full [package docs][].
 [GraphQL API v4]: https://developer.github.com/v4/
 [shurcooL/githubql]: https://github.com/shurcooL/githubql
 
+### Google App Engine ###
+
+Go on App Engine Classic (which as of this writing uses Go 1.6) can not use
+the `"context"` import and still relies on `"golang.org/x/net/context"`.
+As a result, if you wish to continue to use `go-github` on App Engine Classic,
+you will need to rewrite all the `"context"` imports using the following command:
+
+	gofmt -w -r '"context" -> "golang.org/x/net/context"' *.go
+
+See `with_appengine.go` for more details.
+
 ### Integration Tests ###
 
 You can run integration tests from the `test` directory. See the integration tests [README](test/README.md).
@@ -227,18 +238,6 @@ straightforward.
 [roadmap]: https://docs.google.com/spreadsheet/ccc?key=0ApoVX4GOiXr-dGNKN1pObFh6ek1DR2FKUjBNZ1FmaEE&usp=sharing
 [contributing]: CONTRIBUTING.md
 
-
-## Google App Engine ##
-
-Go on App Engine Classic (which as of this writing uses Go 1.6) can not use
-the `"context"` import and still relies on `"golang.org/x/net/context"`.
-As a result, if you wish to continue to use `go-github` on App Engine Classic,
-you will need to rewrite all the `"context"` imports using the following command:
-
-	gofmt -w -r '"context" -> "golang.org/x/net/context"' *.go
-
-See `with_appengine.go` for more details.
-
 ## License ##
 
 This library is distributed under the BSD-style license found in the [LICENSE](./LICENSE)
diff --git a/github/admin_stats.go b/github/admin_stats.go
new file mode 100644
index 00000000..1550d250
--- /dev/null
+++ b/github/admin_stats.go
@@ -0,0 +1,171 @@
+// Copyright 2017 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"
+)
+
+// AdminStats represents a variety of stats of a Github Enterprise
+// installation.
+type AdminStats struct {
+	Issues     *IssueStats     `json:"issues,omitempty"`
+	Hooks      *HookStats      `json:"hooks,omitempty"`
+	Milestones *MilestoneStats `json:"milestones,omitempty"`
+	Orgs       *OrgStats       `json:"orgs,omitempty"`
+	Comments   *CommentStats   `json:"comments,omitempty"`
+	Pages      *PageStats      `json:"pages,omitempty"`
+	Users      *UserStats      `json:"users,omitempty"`
+	Gists      *GistStats      `json:"gists,omitempty"`
+	Pulls      *PullStats      `json:"pulls,omitempty"`
+	Repos      *RepoStats      `json:"repos,omitempty"`
+}
+
+func (s AdminStats) String() string {
+	return Stringify(s)
+}
+
+// IssueStats represents the number of total, open and closed issues.
+type IssueStats struct {
+	TotalIssues  *int `json:"total_issues,omitempty"`
+	OpenIssues   *int `json:"open_issues,omitempty"`
+	ClosedIssues *int `json:"closed_issues,omitempty"`
+}
+
+func (s IssueStats) String() string {
+	return Stringify(s)
+}
+
+// HookStats represents the number of total, active and inactive hooks.
+type HookStats struct {
+	TotalHooks    *int `json:"total_hooks,omitempty"`
+	ActiveHooks   *int `json:"active_hooks,omitempty"`
+	InactiveHooks *int `json:"inactive_hooks,omitempty"`
+}
+
+func (s HookStats) String() string {
+	return Stringify(s)
+}
+
+// MilestoneStats represents the number of total, open and close milestones.
+type MilestoneStats struct {
+	TotalMilestones  *int `json:"total_milestones,omitempty"`
+	OpenMilestones   *int `json:"open_milestones,omitempty"`
+	ClosedMilestones *int `json:"closed_milestones,omitempty"`
+}
+
+func (s MilestoneStats) String() string {
+	return Stringify(s)
+}
+
+// OrgStats represents the number of total, disabled organizations and the team
+// and team member count.
+type OrgStats struct {
+	TotalOrgs        *int `json:"total_orgs,omitempty"`
+	DisabledOrgs     *int `json:"disabled_orgs,omitempty"`
+	TotalTeams       *int `json:"total_teams,omitempty"`
+	TotalTeamMembers *int `json:"total_team_members,omitempty"`
+}
+
+func (s OrgStats) String() string {
+	return Stringify(s)
+}
+
+// CommentStats represents the number of total comments on commits, gists, issues
+// and pull requests.
+type CommentStats struct {
+	TotalCommitComments      *int `json:"total_commit_comments,omitempty"`
+	TotalGistComments        *int `json:"total_gist_comments,omitempty"`
+	TotalIssueComments       *int `json:"total_issue_comments,omitempty"`
+	TotalPullRequestComments *int `json:"total_pull_request_comments,omitempty"`
+}
+
+func (s CommentStats) String() string {
+	return Stringify(s)
+}
+
+// PageStats represents the total number of github pages.
+type PageStats struct {
+	TotalPages *int `json:"total_pages,omitempty"`
+}
+
+func (s PageStats) String() string {
+	return Stringify(s)
+}
+
+// UserStats represents the number of total, admin and suspended users.
+type UserStats struct {
+	TotalUsers     *int `json:"total_users,omitempty"`
+	AdminUsers     *int `json:"admin_users,omitempty"`
+	SuspendedUsers *int `json:"suspended_users,omitempty"`
+}
+
+func (s UserStats) String() string {
+	return Stringify(s)
+}
+
+//GistStats represents the number of total, private and public gists.
+type GistStats struct {
+	TotalGists   *int `json:"total_gists,omitempty"`
+	PrivateGists *int `json:"private_gists,omitempty"`
+	PublicGists  *int `json:"public_gists,omitempty"`
+}
+
+func (s GistStats) String() string {
+	return Stringify(s)
+}
+
+// PullStats represents the number of total, merged, mergable and unmergeable
+// pull-requests.
+type PullStats struct {
+	TotalPulls      *int `json:"total_pulls,omitempty"`
+	MergedPulls     *int `json:"merged_pulls,omitempty"`
+	MergablePulls   *int `json:"mergeable_pulls,omitempty"`
+	UnmergablePulls *int `json:"unmergeable_pulls,omitempty"`
+}
+
+func (s PullStats) String() string {
+	return Stringify(s)
+}
+
+// RepoStats represents the number of total, root, fork, organization repositories
+// together with the total number of pushes and wikis.
+type RepoStats struct {
+	TotalRepos  *int `json:"total_repos,omitempty"`
+	RootRepos   *int `json:"root_repos,omitempty"`
+	ForkRepos   *int `json:"fork_repos,omitempty"`
+	OrgRepos    *int `json:"org_repos,omitempty"`
+	TotalPushes *int `json:"total_pushes,omitempty"`
+	TotalWikis  *int `json:"total_wikis,omitempty"`
+}
+
+func (s RepoStats) String() string {
+	return Stringify(s)
+}
+
+// GetAdminStats returns a variety of metrics about a Github Enterprise
+// installation.
+//
+// Please note that this is only available to site administrators,
+// otherwise it will error with a 404 not found (instead of 401 or 403).
+//
+// GitHub API docs: https://developer.github.com/v3/enterprise-admin/admin_stats/
+func (s *AdminService) GetAdminStats(ctx context.Context) (*AdminStats, *Response, error) {
+	u := fmt.Sprintf("enterprise/stats/all")
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	m := new(AdminStats)
+	resp, err := s.client.Do(ctx, req, m)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return m, resp, nil
+}
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 6a277995..ccac316c 100644
--- a/github/apps_installation.go
+++ b/github/apps_installation.go
@@ -5,7 +5,10 @@
 
 package github
 
-import "context"
+import (
+	"context"
+	"fmt"
+)
 
 // Installation represents a GitHub Apps installation.
 type Installation struct {
@@ -47,3 +50,62 @@ 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
+func (s *AppsService) AddRepository(ctx context.Context, instID, repoID int) (*Repository, *Response, error) {
+	u := fmt.Sprintf("apps/installations/%v/repositories/%v", instID, repoID)
+	req, err := s.client.NewRequest("PUT", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	r := new(Repository)
+	resp, err := s.client.Do(ctx, req, r)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return r, resp, nil
+}
+
+// RemoveRepository removes a single repository from an installation.
+//
+// GitHub docs: https://developer.github.com/v3/apps/installations/#remove-repository-from-installation
+func (s *AppsService) RemoveRepository(ctx context.Context, instID, repoID int) (*Response, error) {
+	u := fmt.Sprintf("apps/installations/%v/repositories/%v", instID, repoID)
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return s.client.Do(ctx, req, nil)
+}
diff --git a/github/github-accessors.go b/github/github-accessors.go
index 4fed8e50..92cd1b0b 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 {
@@ -388,6 +444,38 @@ func (c *CombinedStatus) GetTotalCount() int {
 	return *c.TotalCount
 }
 
+// GetTotalCommitComments returns the TotalCommitComments field if it's non-nil, zero value otherwise.
+func (c *CommentStats) GetTotalCommitComments() int {
+	if c == nil || c.TotalCommitComments == nil {
+		return 0
+	}
+	return *c.TotalCommitComments
+}
+
+// GetTotalGistComments returns the TotalGistComments field if it's non-nil, zero value otherwise.
+func (c *CommentStats) GetTotalGistComments() int {
+	if c == nil || c.TotalGistComments == nil {
+		return 0
+	}
+	return *c.TotalGistComments
+}
+
+// GetTotalIssueComments returns the TotalIssueComments field if it's non-nil, zero value otherwise.
+func (c *CommentStats) GetTotalIssueComments() int {
+	if c == nil || c.TotalIssueComments == nil {
+		return 0
+	}
+	return *c.TotalIssueComments
+}
+
+// GetTotalPullRequestComments returns the TotalPullRequestComments field if it's non-nil, zero value otherwise.
+func (c *CommentStats) GetTotalPullRequestComments() int {
+	if c == nil || c.TotalPullRequestComments == nil {
+		return 0
+	}
+	return *c.TotalPullRequestComments
+}
+
 // GetCommentCount returns the CommentCount field if it's non-nil, zero value otherwise.
 func (c *Commit) GetCommentCount() int {
 	if c == nil || c.CommentCount == nil {
@@ -1588,6 +1676,30 @@ func (g *GistFork) GetURL() string {
 	return *g.URL
 }
 
+// GetPrivateGists returns the PrivateGists field if it's non-nil, zero value otherwise.
+func (g *GistStats) GetPrivateGists() int {
+	if g == nil || g.PrivateGists == nil {
+		return 0
+	}
+	return *g.PrivateGists
+}
+
+// GetPublicGists returns the PublicGists field if it's non-nil, zero value otherwise.
+func (g *GistStats) GetPublicGists() int {
+	if g == nil || g.PublicGists == nil {
+		return 0
+	}
+	return *g.PublicGists
+}
+
+// GetTotalGists returns the TotalGists field if it's non-nil, zero value otherwise.
+func (g *GistStats) GetTotalGists() int {
+	if g == nil || g.TotalGists == nil {
+		return 0
+	}
+	return *g.TotalGists
+}
+
 // GetName returns the Name field if it's non-nil, zero value otherwise.
 func (g *Gitignore) GetName() string {
 	if g == nil || g.Name == nil {
@@ -1804,6 +1916,30 @@ func (h *Hook) GetURL() string {
 	return *h.URL
 }
 
+// GetActiveHooks returns the ActiveHooks field if it's non-nil, zero value otherwise.
+func (h *HookStats) GetActiveHooks() int {
+	if h == nil || h.ActiveHooks == nil {
+		return 0
+	}
+	return *h.ActiveHooks
+}
+
+// GetInactiveHooks returns the InactiveHooks field if it's non-nil, zero value otherwise.
+func (h *HookStats) GetInactiveHooks() int {
+	if h == nil || h.InactiveHooks == nil {
+		return 0
+	}
+	return *h.InactiveHooks
+}
+
+// GetTotalHooks returns the TotalHooks field if it's non-nil, zero value otherwise.
+func (h *HookStats) GetTotalHooks() int {
+	if h == nil || h.TotalHooks == nil {
+		return 0
+	}
+	return *h.TotalHooks
+}
+
 // GetAuthorsCount returns the AuthorsCount field if it's non-nil, zero value otherwise.
 func (i *Import) GetAuthorsCount() int {
 	if i == nil || i.AuthorsCount == nil {
@@ -2036,6 +2172,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 {
@@ -2100,6 +2252,14 @@ func (i *Issue) GetComments() int {
 	return *i.Comments
 }
 
+// GetCommentsURL returns the CommentsURL field if it's non-nil, zero value otherwise.
+func (i *Issue) GetCommentsURL() string {
+	if i == nil || i.CommentsURL == nil {
+		return ""
+	}
+	return *i.CommentsURL
+}
+
 // GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
 func (i *Issue) GetCreatedAt() time.Time {
 	if i == nil || i.CreatedAt == nil {
@@ -2108,6 +2268,14 @@ func (i *Issue) GetCreatedAt() time.Time {
 	return *i.CreatedAt
 }
 
+// GetEventsURL returns the EventsURL field if it's non-nil, zero value otherwise.
+func (i *Issue) GetEventsURL() string {
+	if i == nil || i.EventsURL == nil {
+		return ""
+	}
+	return *i.EventsURL
+}
+
 // GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise.
 func (i *Issue) GetHTMLURL() string {
 	if i == nil || i.HTMLURL == nil {
@@ -2124,6 +2292,14 @@ func (i *Issue) GetID() int {
 	return *i.ID
 }
 
+// GetLabelsURL returns the LabelsURL field if it's non-nil, zero value otherwise.
+func (i *Issue) GetLabelsURL() string {
+	if i == nil || i.LabelsURL == nil {
+		return ""
+	}
+	return *i.LabelsURL
+}
+
 // GetLocked returns the Locked field if it's non-nil, zero value otherwise.
 func (i *Issue) GetLocked() bool {
 	if i == nil || i.Locked == nil {
@@ -2140,6 +2316,14 @@ func (i *Issue) GetNumber() int {
 	return *i.Number
 }
 
+// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise.
+func (i *Issue) GetRepositoryURL() string {
+	if i == nil || i.RepositoryURL == nil {
+		return ""
+	}
+	return *i.RepositoryURL
+}
+
 // GetState returns the State field if it's non-nil, zero value otherwise.
 func (i *Issue) GetState() string {
 	if i == nil || i.State == nil {
@@ -2356,6 +2540,30 @@ func (i *IssuesSearchResult) GetTotal() int {
 	return *i.Total
 }
 
+// GetClosedIssues returns the ClosedIssues field if it's non-nil, zero value otherwise.
+func (i *IssueStats) GetClosedIssues() int {
+	if i == nil || i.ClosedIssues == nil {
+		return 0
+	}
+	return *i.ClosedIssues
+}
+
+// GetOpenIssues returns the OpenIssues field if it's non-nil, zero value otherwise.
+func (i *IssueStats) GetOpenIssues() int {
+	if i == nil || i.OpenIssues == nil {
+		return 0
+	}
+	return *i.OpenIssues
+}
+
+// GetTotalIssues returns the TotalIssues field if it's non-nil, zero value otherwise.
+func (i *IssueStats) GetTotalIssues() int {
+	if i == nil || i.TotalIssues == nil {
+		return 0
+	}
+	return *i.TotalIssues
+}
+
 // GetID returns the ID field if it's non-nil, zero value otherwise.
 func (k *Key) GetID() int {
 	if k == nil || k.ID == nil {
@@ -2868,6 +3076,30 @@ func (m *MilestoneEvent) GetAction() string {
 	return *m.Action
 }
 
+// GetClosedMilestones returns the ClosedMilestones field if it's non-nil, zero value otherwise.
+func (m *MilestoneStats) GetClosedMilestones() int {
+	if m == nil || m.ClosedMilestones == nil {
+		return 0
+	}
+	return *m.ClosedMilestones
+}
+
+// GetOpenMilestones returns the OpenMilestones field if it's non-nil, zero value otherwise.
+func (m *MilestoneStats) GetOpenMilestones() int {
+	if m == nil || m.OpenMilestones == nil {
+		return 0
+	}
+	return *m.OpenMilestones
+}
+
+// GetTotalMilestones returns the TotalMilestones field if it's non-nil, zero value otherwise.
+func (m *MilestoneStats) GetTotalMilestones() int {
+	if m == nil || m.TotalMilestones == nil {
+		return 0
+	}
+	return *m.TotalMilestones
+}
+
 // GetBase returns the Base field if it's non-nil, zero value otherwise.
 func (n *NewPullRequest) GetBase() string {
 	if n == nil || n.Base == nil {
@@ -2916,6 +3148,46 @@ func (n *NewPullRequest) GetTitle() string {
 	return *n.Title
 }
 
+// GetDescription returns the Description field if it's non-nil, zero value otherwise.
+func (n *NewTeam) GetDescription() string {
+	if n == nil || n.Description == nil {
+		return ""
+	}
+	return *n.Description
+}
+
+// GetLDAPDN returns the LDAPDN field if it's non-nil, zero value otherwise.
+func (n *NewTeam) GetLDAPDN() string {
+	if n == nil || n.LDAPDN == nil {
+		return ""
+	}
+	return *n.LDAPDN
+}
+
+// GetParentTeamID returns the ParentTeamID field if it's non-nil, zero value otherwise.
+func (n *NewTeam) GetParentTeamID() int {
+	if n == nil || n.ParentTeamID == nil {
+		return 0
+	}
+	return *n.ParentTeamID
+}
+
+// GetPermission returns the Permission field if it's non-nil, zero value otherwise.
+func (n *NewTeam) GetPermission() string {
+	if n == nil || n.Permission == nil {
+		return ""
+	}
+	return *n.Permission
+}
+
+// GetPrivacy returns the Privacy field if it's non-nil, zero value otherwise.
+func (n *NewTeam) GetPrivacy() string {
+	if n == nil || n.Privacy == nil {
+		return ""
+	}
+	return *n.Privacy
+}
+
 // GetID returns the ID field if it's non-nil, zero value otherwise.
 func (n *Notification) GetID() string {
 	if n == nil || n.ID == nil {
@@ -3252,6 +3524,38 @@ func (o *OrgBlockEvent) GetAction() string {
 	return *o.Action
 }
 
+// GetDisabledOrgs returns the DisabledOrgs field if it's non-nil, zero value otherwise.
+func (o *OrgStats) GetDisabledOrgs() int {
+	if o == nil || o.DisabledOrgs == nil {
+		return 0
+	}
+	return *o.DisabledOrgs
+}
+
+// GetTotalOrgs returns the TotalOrgs field if it's non-nil, zero value otherwise.
+func (o *OrgStats) GetTotalOrgs() int {
+	if o == nil || o.TotalOrgs == nil {
+		return 0
+	}
+	return *o.TotalOrgs
+}
+
+// GetTotalTeamMembers returns the TotalTeamMembers field if it's non-nil, zero value otherwise.
+func (o *OrgStats) GetTotalTeamMembers() int {
+	if o == nil || o.TotalTeamMembers == nil {
+		return 0
+	}
+	return *o.TotalTeamMembers
+}
+
+// GetTotalTeams returns the TotalTeams field if it's non-nil, zero value otherwise.
+func (o *OrgStats) GetTotalTeams() int {
+	if o == nil || o.TotalTeams == nil {
+		return 0
+	}
+	return *o.TotalTeams
+}
+
 // GetAction returns the Action field if it's non-nil, zero value otherwise.
 func (p *Page) GetAction() string {
 	if p == nil || p.Action == nil {
@@ -3404,6 +3708,14 @@ func (p *PagesError) GetMessage() string {
 	return *p.Message
 }
 
+// GetTotalPages returns the TotalPages field if it's non-nil, zero value otherwise.
+func (p *PageStats) GetTotalPages() int {
+	if p == nil || p.TotalPages == nil {
+		return 0
+	}
+	return *p.TotalPages
+}
+
 // GetHookID returns the HookID field if it's non-nil, zero value otherwise.
 func (p *PingEvent) GetHookID() int {
 	if p == nil || p.HookID == nil {
@@ -4228,6 +4540,38 @@ func (p *pullRequestUpdate) GetTitle() string {
 	return *p.Title
 }
 
+// GetMergablePulls returns the MergablePulls field if it's non-nil, zero value otherwise.
+func (p *PullStats) GetMergablePulls() int {
+	if p == nil || p.MergablePulls == nil {
+		return 0
+	}
+	return *p.MergablePulls
+}
+
+// GetMergedPulls returns the MergedPulls field if it's non-nil, zero value otherwise.
+func (p *PullStats) GetMergedPulls() int {
+	if p == nil || p.MergedPulls == nil {
+		return 0
+	}
+	return *p.MergedPulls
+}
+
+// GetTotalPulls returns the TotalPulls field if it's non-nil, zero value otherwise.
+func (p *PullStats) GetTotalPulls() int {
+	if p == nil || p.TotalPulls == nil {
+		return 0
+	}
+	return *p.TotalPulls
+}
+
+// GetUnmergablePulls returns the UnmergablePulls field if it's non-nil, zero value otherwise.
+func (p *PullStats) GetUnmergablePulls() int {
+	if p == nil || p.UnmergablePulls == nil {
+		return 0
+	}
+	return *p.UnmergablePulls
+}
+
 // GetCommits returns the Commits field if it's non-nil, zero value otherwise.
 func (p *PunchCard) GetCommits() int {
 	if p == nil || p.Commits == nil {
@@ -6012,6 +6356,54 @@ func (r *RepositoryTag) GetZipballURL() string {
 	return *r.ZipballURL
 }
 
+// GetForkRepos returns the ForkRepos field if it's non-nil, zero value otherwise.
+func (r *RepoStats) GetForkRepos() int {
+	if r == nil || r.ForkRepos == nil {
+		return 0
+	}
+	return *r.ForkRepos
+}
+
+// GetOrgRepos returns the OrgRepos field if it's non-nil, zero value otherwise.
+func (r *RepoStats) GetOrgRepos() int {
+	if r == nil || r.OrgRepos == nil {
+		return 0
+	}
+	return *r.OrgRepos
+}
+
+// GetRootRepos returns the RootRepos field if it's non-nil, zero value otherwise.
+func (r *RepoStats) GetRootRepos() int {
+	if r == nil || r.RootRepos == nil {
+		return 0
+	}
+	return *r.RootRepos
+}
+
+// GetTotalPushes returns the TotalPushes field if it's non-nil, zero value otherwise.
+func (r *RepoStats) GetTotalPushes() int {
+	if r == nil || r.TotalPushes == nil {
+		return 0
+	}
+	return *r.TotalPushes
+}
+
+// GetTotalRepos returns the TotalRepos field if it's non-nil, zero value otherwise.
+func (r *RepoStats) GetTotalRepos() int {
+	if r == nil || r.TotalRepos == nil {
+		return 0
+	}
+	return *r.TotalRepos
+}
+
+// GetTotalWikis returns the TotalWikis field if it's non-nil, zero value otherwise.
+func (r *RepoStats) GetTotalWikis() int {
+	if r == nil || r.TotalWikis == nil {
+		return 0
+	}
+	return *r.TotalWikis
+}
+
 // GetContext returns the Context field if it's non-nil, zero value otherwise.
 func (r *RepoStatus) GetContext() string {
 	if r == nil || r.Context == nil {
@@ -7308,6 +7700,30 @@ func (u *UsersSearchResult) GetTotal() int {
 	return *u.Total
 }
 
+// GetAdminUsers returns the AdminUsers field if it's non-nil, zero value otherwise.
+func (u *UserStats) GetAdminUsers() int {
+	if u == nil || u.AdminUsers == nil {
+		return 0
+	}
+	return *u.AdminUsers
+}
+
+// GetSuspendedUsers returns the SuspendedUsers field if it's non-nil, zero value otherwise.
+func (u *UserStats) GetSuspendedUsers() int {
+	if u == nil || u.SuspendedUsers == nil {
+		return 0
+	}
+	return *u.SuspendedUsers
+}
+
+// GetTotalUsers returns the TotalUsers field if it's non-nil, zero value otherwise.
+func (u *UserStats) GetTotalUsers() int {
+	if u == nil || u.TotalUsers == nil {
+		return 0
+	}
+	return *u.TotalUsers
+}
+
 // GetAction returns the Action field if it's non-nil, zero value otherwise.
 func (w *WatchEvent) GetAction() string {
 	if w == nil || w.Action == nil {
diff --git a/github/github.go b/github/github.go
index 99ad8d07..db06cfb4 100644
--- a/github/github.go
+++ b/github/github.go
@@ -27,7 +27,7 @@ import (
 )
 
 const (
-	libraryVersion = "11"
+	libraryVersion = "14"
 	defaultBaseURL = "https://api.github.com/"
 	uploadBaseURL  = "https://uploads.github.com/"
 	userAgent      = "go-github/" + libraryVersion
@@ -102,6 +102,9 @@ const (
 
 	// https://developer.github.com/changes/2017-07-26-team-review-request-thor-preview/
 	mediaTypeTeamReviewPreview = "application/vnd.github.thor-preview+json"
+
+	// https://developer.github.com/changes/2017-08-30-preview-nested-teams/
+	mediaTypeNestedTeamsPreview = "application/vnd.github.hellcat-preview+json"
 )
 
 // A Client manages communication with the GitHub API.
@@ -235,6 +238,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
@@ -252,7 +286,9 @@ func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Requ
 	var buf io.ReadWriter
 	if body != nil {
 		buf = new(bytes.Buffer)
-		err := json.NewEncoder(buf).Encode(body)
+		enc := json.NewEncoder(buf)
+		enc.SetEscapeHTML(false)
+		err := enc.Encode(body)
 		if err != nil {
 			return nil, err
 		}
diff --git a/github/issues.go b/github/issues.go
index b437d506..9b7a9d68 100644
--- a/github/issues.go
+++ b/github/issues.go
@@ -23,6 +23,7 @@ type IssuesService service
 // but not every issue is a pull request. Some endpoints, events, and webhooks
 // may also return pull requests via this struct. If PullRequestLinks is nil,
 // this is an issue, and if PullRequestLinks is not nil, this is a pull request.
+// The IsPullRequest helper method can be used to check that.
 type Issue struct {
 	ID               *int              `json:"id,omitempty"`
 	Number           *int              `json:"number,omitempty"`
@@ -40,6 +41,10 @@ type Issue struct {
 	ClosedBy         *User             `json:"closed_by,omitempty"`
 	URL              *string           `json:"url,omitempty"`
 	HTMLURL          *string           `json:"html_url,omitempty"`
+	CommentsURL      *string           `json:"comments_url,omitempty"`
+	EventsURL        *string           `json:"events_url,omitempty"`
+	LabelsURL        *string           `json:"labels_url,omitempty"`
+	RepositoryURL    *string           `json:"repository_url,omitempty"`
 	Milestone        *Milestone        `json:"milestone,omitempty"`
 	PullRequestLinks *PullRequestLinks `json:"pull_request,omitempty"`
 	Repository       *Repository       `json:"repository,omitempty"`
@@ -55,6 +60,13 @@ func (i Issue) String() string {
 	return Stringify(i)
 }
 
+// IsPullRequest reports whether the issue is also a pull request. It uses the
+// method recommended by GitHub's API documentation, which is to check whether
+// PullRequestLinks is non-nil.
+func (i Issue) IsPullRequest() bool {
+	return i.PullRequestLinks != nil
+}
+
 // IssueRequest represents a request to create/edit an issue.
 // It is separate from Issue above because otherwise Labels
 // and Assignee fail to serialize to the correct JSON.
@@ -97,7 +109,7 @@ type IssueListOptions struct {
 }
 
 // PullRequestLinks object is added to the Issue object when it's an issue included
-// in the IssueCommentEvent webhook payload, if the webhooks is fired by a comment on a PR
+// in the IssueCommentEvent webhook payload, if the webhook is fired by a comment on a PR.
 type PullRequestLinks struct {
 	URL      *string `json:"url,omitempty"`
 	HTMLURL  *string `json:"html_url,omitempty"`
diff --git a/github/messages.go b/github/messages.go
index c0f315a7..3a4d4644 100644
--- a/github/messages.go
+++ b/github/messages.go
@@ -20,6 +20,7 @@ import (
 	"hash"
 	"io/ioutil"
 	"net/http"
+	"net/url"
 	"strings"
 )
 
@@ -122,6 +123,8 @@ func messageMAC(signature string) ([]byte, func() hash.Hash, error) {
 
 // ValidatePayload validates an incoming GitHub Webhook event request
 // and returns the (JSON) payload.
+// The Content-Type header of the payload can be "application/json" or "application/x-www-form-urlencoded".
+// If the Content-Type is neither then an error is returned.
 // secretKey is the GitHub Webhook secret message.
 //
 // Example usage:
@@ -133,13 +136,43 @@ func messageMAC(signature string) ([]byte, func() hash.Hash, error) {
 //     }
 //
 func ValidatePayload(r *http.Request, secretKey []byte) (payload []byte, err error) {
-	payload, err = ioutil.ReadAll(r.Body)
-	if err != nil {
-		return nil, err
+	var body []byte // Raw body that GitHub uses to calculate the signature.
+
+	switch ct := r.Header.Get("Content-Type"); ct {
+	case "application/json":
+		var err error
+		if body, err = ioutil.ReadAll(r.Body); err != nil {
+			return nil, err
+		}
+
+		// If the content type is application/json,
+		// the JSON payload is just the original body.
+		payload = body
+
+	case "application/x-www-form-urlencoded":
+		// payloadFormParam is the name of the form parameter that the JSON payload
+		// will be in if a webhook has its content type set to application/x-www-form-urlencoded.
+		const payloadFormParam = "payload"
+
+		var err error
+		if body, err = ioutil.ReadAll(r.Body); err != nil {
+			return nil, err
+		}
+
+		// If the content type is application/x-www-form-urlencoded,
+		// the JSON payload will be under the "payload" form param.
+		form, err := url.ParseQuery(string(body))
+		if err != nil {
+			return nil, err
+		}
+		payload = []byte(form.Get(payloadFormParam))
+
+	default:
+		return nil, fmt.Errorf("Webhook request has unsupported Content-Type %q", ct)
 	}
 
 	sig := r.Header.Get(signatureHeader)
-	if err := validateSignature(sig, payload, secretKey); err != nil {
+	if err := validateSignature(sig, body, secretKey); err != nil {
 		return nil, err
 	}
 	return payload, nil
diff --git a/github/orgs_members.go b/github/orgs_members.go
index f1209c7c..d0ea6a98 100644
--- a/github/orgs_members.go
+++ b/github/orgs_members.go
@@ -278,7 +278,7 @@ func (s *OrganizationsService) RemoveOrgMembership(ctx context.Context, user, or
 // ListPendingOrgInvitations returns a list of pending invitations.
 //
 // GitHub API docs: https://developer.github.com/v3/orgs/members/#list-pending-organization-invitations
-func (s *OrganizationsService) ListPendingOrgInvitations(ctx context.Context, org int, opt *ListOptions) ([]*Invitation, *Response, error) {
+func (s *OrganizationsService) ListPendingOrgInvitations(ctx context.Context, org string, opt *ListOptions) ([]*Invitation, *Response, error) {
 	u := fmt.Sprintf("orgs/%v/invitations", org)
 	u, err := addOptions(u, opt)
 	if err != nil {
diff --git a/github/orgs_teams.go b/github/orgs_teams.go
index 684e2daf..8a209d93 100644
--- a/github/orgs_teams.go
+++ b/github/orgs_teams.go
@@ -8,6 +8,7 @@ package github
 import (
 	"context"
 	"fmt"
+	"strings"
 	"time"
 )
 
@@ -20,11 +21,7 @@ type Team struct {
 	URL         *string `json:"url,omitempty"`
 	Slug        *string `json:"slug,omitempty"`
 
-	// Permission is deprecated when creating or editing a team in an org
-	// using the new GitHub permission model. It no longer identifies the
-	// permission a team has on its repos, but only specifies the default
-	// permission a repo is initially added with. Avoid confusion by
-	// specifying a permission value when calling AddTeamRepo.
+	// Permission specifies the default permission for repositories owned by the team.
 	Permission *string `json:"permission,omitempty"`
 
 	// Privacy identifies the level of privacy this team should have.
@@ -39,6 +36,7 @@ type Team struct {
 	Organization    *Organization `json:"organization,omitempty"`
 	MembersURL      *string       `json:"members_url,omitempty"`
 	RepositoriesURL *string       `json:"repositories_url,omitempty"`
+	Parent          *Team         `json:"parent,omitempty"`
 
 	// LDAPDN is only available in GitHub Enterprise and when the team
 	// membership is synchronized with LDAP.
@@ -79,6 +77,9 @@ func (s *OrganizationsService) ListTeams(ctx context.Context, org string, opt *L
 		return nil, nil, err
 	}
 
+	// TODO: remove custom Accept header when this API fully launches.
+	req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
+
 	var teams []*Team
 	resp, err := s.client.Do(ctx, req, &teams)
 	if err != nil {
@@ -98,6 +99,9 @@ func (s *OrganizationsService) GetTeam(ctx context.Context, team int) (*Team, *R
 		return nil, nil, err
 	}
 
+	// TODO: remove custom Accept header when this API fully launches.
+	req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
+
 	t := new(Team)
 	resp, err := s.client.Do(ctx, req, t)
 	if err != nil {
@@ -107,16 +111,50 @@ func (s *OrganizationsService) GetTeam(ctx context.Context, team int) (*Team, *R
 	return t, resp, nil
 }
 
+// NewTeam represents a team to be created or modified.
+type NewTeam struct {
+	Name         string   `json:"name"` // Name of the team. (Required.)
+	Description  *string  `json:"description,omitempty"`
+	Maintainers  []string `json:"maintainers,omitempty"`
+	RepoNames    []string `json:"repo_names,omitempty"`
+	ParentTeamID *int     `json:"parent_team_id,omitempty"`
+
+	// Deprecated: Permission is deprecated when creating or editing a team in an org
+	// using the new GitHub permission model. It no longer identifies the
+	// permission a team has on its repos, but only specifies the default
+	// permission a repo is initially added with. Avoid confusion by
+	// specifying a permission value when calling AddTeamRepo.
+	Permission *string `json:"permission,omitempty"`
+
+	// Privacy identifies the level of privacy this team should have.
+	// Possible values are:
+	//     secret - only visible to organization owners and members of this team
+	//     closed - visible to all members of this organization
+	// Default is "secret".
+	Privacy *string `json:"privacy,omitempty"`
+
+	// LDAPDN may be used in GitHub Enterprise when the team membership
+	// is synchronized with LDAP.
+	LDAPDN *string `json:"ldap_dn,omitempty"`
+}
+
+func (s NewTeam) String() string {
+	return Stringify(s)
+}
+
 // CreateTeam creates a new team within an organization.
 //
 // GitHub API docs: https://developer.github.com/v3/orgs/teams/#create-team
-func (s *OrganizationsService) CreateTeam(ctx context.Context, org string, team *Team) (*Team, *Response, error) {
+func (s *OrganizationsService) CreateTeam(ctx context.Context, org string, team *NewTeam) (*Team, *Response, error) {
 	u := fmt.Sprintf("orgs/%v/teams", org)
 	req, err := s.client.NewRequest("POST", u, team)
 	if err != nil {
 		return nil, nil, err
 	}
 
+	// TODO: remove custom Accept header when this API fully launches.
+	req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
+
 	t := new(Team)
 	resp, err := s.client.Do(ctx, req, t)
 	if err != nil {
@@ -129,13 +167,16 @@ func (s *OrganizationsService) CreateTeam(ctx context.Context, org string, team
 // EditTeam edits a team.
 //
 // GitHub API docs: https://developer.github.com/v3/orgs/teams/#edit-team
-func (s *OrganizationsService) EditTeam(ctx context.Context, id int, team *Team) (*Team, *Response, error) {
+func (s *OrganizationsService) EditTeam(ctx context.Context, id int, team *NewTeam) (*Team, *Response, error) {
 	u := fmt.Sprintf("teams/%v", id)
 	req, err := s.client.NewRequest("PATCH", u, team)
 	if err != nil {
 		return nil, nil, err
 	}
 
+	// TODO: remove custom Accept header when this API fully launches.
+	req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
+
 	t := new(Team)
 	resp, err := s.client.Do(ctx, req, t)
 	if err != nil {
@@ -155,6 +196,8 @@ func (s *OrganizationsService) DeleteTeam(ctx context.Context, team int) (*Respo
 		return nil, err
 	}
 
+	req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
+
 	return s.client.Do(ctx, req, nil)
 }
 
@@ -168,6 +211,32 @@ type OrganizationListTeamMembersOptions struct {
 	ListOptions
 }
 
+// ListChildTeams lists child teams for a team.
+//
+// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-child-teams
+func (s *OrganizationsService) ListChildTeams(ctx context.Context, teamID int, opt *ListOptions) ([]*Team, *Response, error) {
+	u := fmt.Sprintf("teams/%v/teams", teamID)
+	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
+	}
+
+	req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
+
+	var teams []*Team
+	resp, err := s.client.Do(ctx, req, &teams)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return teams, resp, nil
+}
+
 // ListTeamMembers lists all of the users who are members of the specified
 // team.
 //
@@ -184,6 +253,8 @@ func (s *OrganizationsService) ListTeamMembers(ctx context.Context, team int, op
 		return nil, nil, err
 	}
 
+	req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
+
 	var members []*User
 	resp, err := s.client.Do(ctx, req, &members)
 	if err != nil {
@@ -196,6 +267,9 @@ func (s *OrganizationsService) ListTeamMembers(ctx context.Context, team int, op
 // IsTeamMember checks if a user is a member of the specified team.
 //
 // GitHub API docs: https://developer.github.com/v3/orgs/teams/#get-team-member
+//
+// Deprecated: This API has been marked as deprecated in the Github API docs,
+// OrganizationsService.GetTeamMembership method should be used instead.
 func (s *OrganizationsService) IsTeamMember(ctx context.Context, team int, user string) (bool, *Response, error) {
 	u := fmt.Sprintf("teams/%v/members/%v", team, user)
 	req, err := s.client.NewRequest("GET", u, nil)
@@ -224,7 +298,8 @@ func (s *OrganizationsService) ListTeamRepos(ctx context.Context, team int, opt
 	}
 
 	// TODO: remove custom Accept header when topics API fully launches.
-	req.Header.Set("Accept", mediaTypeTopicsPreview)
+	headers := []string{mediaTypeTopicsPreview, mediaTypeNestedTeamsPreview}
+	req.Header.Set("Accept", strings.Join(headers, ", "))
 
 	var repos []*Repository
 	resp, err := s.client.Do(ctx, req, &repos)
@@ -247,7 +322,8 @@ func (s *OrganizationsService) IsTeamRepo(ctx context.Context, team int, owner s
 		return nil, nil, err
 	}
 
-	req.Header.Set("Accept", mediaTypeOrgPermissionRepo)
+	headers := []string{mediaTypeOrgPermissionRepo, mediaTypeNestedTeamsPreview}
+	req.Header.Set("Accept", strings.Join(headers, ", "))
 
 	repository := new(Repository)
 	resp, err := s.client.Do(ctx, req, repository)
@@ -315,6 +391,9 @@ func (s *OrganizationsService) ListUserTeams(ctx context.Context, opt *ListOptio
 		return nil, nil, err
 	}
 
+	// TODO: remove custom Accept header when this API fully launches.
+	req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
+
 	var teams []*Team
 	resp, err := s.client.Do(ctx, req, &teams)
 	if err != nil {
@@ -334,6 +413,8 @@ func (s *OrganizationsService) GetTeamMembership(ctx context.Context, team int,
 		return nil, nil, err
 	}
 
+	req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
+
 	t := new(Membership)
 	resp, err := s.client.Do(ctx, req, t)
 	if err != nil {
diff --git a/github/projects.go b/github/projects.go
index 89685c9d..a9b143df 100644
--- a/github/projects.go
+++ b/github/projects.go
@@ -65,6 +65,12 @@ type ProjectOptions struct {
 	Name string `json:"name,omitempty"`
 	// The body of the project. (Optional.)
 	Body string `json:"body,omitempty"`
+
+	// The following field(s) are only applicable for update.
+	// They should be left with zero values for creation.
+
+	// State of the project. Either "open" or "closed". (Optional.)
+	State string `json:"state,omitempty"`
 }
 
 // UpdateProject updates a repository project.
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.go b/github/repos.go
index b6d98cc1..13daa7e9 100644
--- a/github/repos.go
+++ b/github/repos.go
@@ -232,8 +232,6 @@ func (s *RepositoriesService) ListByOrg(ctx context.Context, org string, opt *Re
 type RepositoryListAllOptions struct {
 	// ID of the last repository seen
 	Since int `url:"since,omitempty"`
-
-	ListOptions
 }
 
 // ListAll lists all GitHub repositories in the order that they were created.
@@ -483,6 +481,8 @@ func (s *RepositoriesService) ListTeams(ctx context.Context, owner string, repo
 		return nil, nil, err
 	}
 
+	req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
+
 	var teams []*Team
 	resp, err := s.client.Do(ctx, req, &teams)
 	if err != nil {
@@ -562,6 +562,8 @@ type PullRequestReviewsEnforcement struct {
 	DismissalRestrictions DismissalRestrictions `json:"dismissal_restrictions"`
 	// Specifies if approved reviews are dismissed automatically, when a new commit is pushed.
 	DismissStaleReviews bool `json:"dismiss_stale_reviews"`
+	// RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner.
+	RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"`
 }
 
 // PullRequestReviewsEnforcementRequest represents request to set the pull request review
@@ -572,6 +574,8 @@ type PullRequestReviewsEnforcementRequest struct {
 	DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions"`
 	// Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. (Required)
 	DismissStaleReviews bool `json:"dismiss_stale_reviews"`
+	// RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner.
+	RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"`
 }
 
 // MarshalJSON implements the json.Marshaler interface.
@@ -581,18 +585,22 @@ func (req PullRequestReviewsEnforcementRequest) MarshalJSON() ([]byte, error) {
 		newReq := struct {
 			R []interface{} `json:"dismissal_restrictions"`
 			D bool          `json:"dismiss_stale_reviews"`
+			O bool          `json:"require_code_owner_reviews"`
 		}{
 			R: []interface{}{},
 			D: req.DismissStaleReviews,
+			O: req.RequireCodeOwnerReviews,
 		}
 		return json.Marshal(newReq)
 	}
 	newReq := struct {
 		R *DismissalRestrictionsRequest `json:"dismissal_restrictions"`
 		D bool                          `json:"dismiss_stale_reviews"`
+		O bool                          `json:"require_code_owner_reviews"`
 	}{
 		R: req.DismissalRestrictionsRequest,
 		D: req.DismissStaleReviews,
+		O: req.RequireCodeOwnerReviews,
 	}
 	return json.Marshal(newReq)
 }
@@ -605,6 +613,8 @@ type PullRequestReviewsEnforcementUpdate struct {
 	DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions,omitempty"`
 	// Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. Can be omitted.
 	DismissStaleReviews *bool `json:"dismiss_stale_reviews,omitempty"`
+	// RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner.
+	RequireCodeOwnerReviews bool `json:"require_code_owner_reviews,omitempty"`
 }
 
 // AdminEnforcement represents the configuration to enforce required status checks for repository administrators.
diff --git a/github/repos_collaborators.go b/github/repos_collaborators.go
index 100a9257..61ee9d39 100644
--- a/github/repos_collaborators.go
+++ b/github/repos_collaborators.go
@@ -41,6 +41,8 @@ func (s *RepositoriesService) ListCollaborators(ctx context.Context, owner, repo
 		return nil, nil, err
 	}
 
+	req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
+
 	var users []*User
 	resp, err := s.client.Do(ctx, req, &users)
 	if err != nil {
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/admin_stats_test.go b/github/admin_stats_test.go
new file mode 100644
index 00000000..d2d979a1
--- /dev/null
+++ b/github/admin_stats_test.go
@@ -0,0 +1,142 @@
+package github
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+)
+
+func TestAdminService_GetAdminStats(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/enterprise/stats/all", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+
+		fmt.Fprint(w, `
+{
+  "repos": {
+    "total_repos": 212,
+    "root_repos": 194,
+    "fork_repos": 18,
+    "org_repos": 51,
+    "total_pushes": 3082,
+    "total_wikis": 15
+  },
+  "hooks": {
+    "total_hooks": 27,
+    "active_hooks": 23,
+    "inactive_hooks": 4
+  },
+  "pages": {
+    "total_pages": 36
+  },
+  "orgs": {
+    "total_orgs": 33,
+    "disabled_orgs": 0,
+    "total_teams": 60,
+    "total_team_members": 314
+  },
+  "users": {
+    "total_users": 254,
+    "admin_users": 45,
+    "suspended_users": 21
+  },
+  "pulls": {
+    "total_pulls": 86,
+    "merged_pulls": 60,
+    "mergeable_pulls": 21,
+    "unmergeable_pulls": 3
+  },
+  "issues": {
+    "total_issues": 179,
+    "open_issues": 83,
+    "closed_issues": 96
+  },
+  "milestones": {
+    "total_milestones": 7,
+    "open_milestones": 6,
+    "closed_milestones": 1
+  },
+  "gists": {
+    "total_gists": 178,
+    "private_gists": 151,
+    "public_gists": 25
+  },
+  "comments": {
+    "total_commit_comments": 6,
+    "total_gist_comments": 28,
+    "total_issue_comments": 366,
+    "total_pull_request_comments": 30
+  }
+}
+`)
+	})
+
+	stats, _, err := client.Admin.GetAdminStats(context.Background())
+	if err != nil {
+		t.Errorf("AdminService.GetAdminStats returned error: %v", err)
+	}
+
+	want := &AdminStats{
+		Repos: &RepoStats{
+			TotalRepos:  Int(212),
+			RootRepos:   Int(194),
+			ForkRepos:   Int(18),
+			OrgRepos:    Int(51),
+			TotalPushes: Int(3082),
+			TotalWikis:  Int(15),
+		},
+		Hooks: &HookStats{
+			TotalHooks:    Int(27),
+			ActiveHooks:   Int(23),
+			InactiveHooks: Int(4),
+		},
+		Pages: &PageStats{
+			TotalPages: Int(36),
+		},
+		Orgs: &OrgStats{
+			TotalOrgs:        Int(33),
+			DisabledOrgs:     Int(0),
+			TotalTeams:       Int(60),
+			TotalTeamMembers: Int(314),
+		},
+		Users: &UserStats{
+			TotalUsers:     Int(254),
+			AdminUsers:     Int(45),
+			SuspendedUsers: Int(21),
+		},
+		Pulls: &PullStats{
+			TotalPulls:      Int(86),
+			MergedPulls:     Int(60),
+			MergablePulls:   Int(21),
+			UnmergablePulls: Int(3),
+		},
+		Issues: &IssueStats{
+			TotalIssues:  Int(179),
+			OpenIssues:   Int(83),
+			ClosedIssues: Int(96),
+		},
+		Milestones: &MilestoneStats{
+			TotalMilestones:  Int(7),
+			OpenMilestones:   Int(6),
+			ClosedMilestones: Int(1),
+		},
+		Gists: &GistStats{
+			TotalGists:   Int(178),
+			PrivateGists: Int(151),
+			PublicGists:  Int(25),
+		},
+		Comments: &CommentStats{
+			TotalCommitComments:      Int(6),
+			TotalGistComments:        Int(28),
+			TotalIssueComments:       Int(366),
+			TotalPullRequestComments: Int(30),
+		},
+	}
+	if !reflect.DeepEqual(stats, want) {
+		t.Errorf("AdminService.GetAdminStats returned %+v, want %+v", stats, want)
+	}
+}
diff --git a/github/apps_installation_test.go b/github/apps_installation_test.go
index 462d15a3..ec796cd3 100644
--- a/github/apps_installation_test.go
+++ b/github/apps_installation_test.go
@@ -38,3 +38,63 @@ func TestAppsService_ListRepos(t *testing.T) {
 		t.Errorf("Apps.ListRepos returned %+v, want %+v", repositories, want)
 	}
 }
+
+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()
+
+	mux.HandleFunc("/apps/installations/1/repositories/1", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PUT")
+		fmt.Fprint(w, `{"id":1,"name":"n","description":"d","owner":{"login":"l"},"license":{"key":"mit"}}`)
+	})
+
+	repo, _, err := client.Apps.AddRepository(context.Background(), 1, 1)
+	if err != nil {
+		t.Errorf("Apps.AddRepository returned error: %v", err)
+	}
+
+	want := &Repository{ID: Int(1), Name: String("n"), Description: String("d"), Owner: &User{Login: String("l")}, License: &License{Key: String("mit")}}
+	if !reflect.DeepEqual(repo, want) {
+		t.Errorf("AddRepository returned %+v, want %+v", repo, want)
+	}
+}
+
+func TestAppsService_RemoveRepository(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/apps/installations/1/repositories/1", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+		w.WriteHeader(http.StatusNoContent)
+	})
+
+	_, err := client.Apps.RemoveRepository(context.Background(), 1, 1)
+	if err != nil {
+		t.Errorf("Apps.RemoveRepository returned error: %v", err)
+	}
+}
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 74d14759..cc62fc6b 100644
--- a/github/github_test.go
+++ b/github/github_test.go
@@ -33,17 +33,39 @@ var (
 	server *httptest.Server
 )
 
+const (
+	// baseURLPath is a non-empty Client.BaseURL path to use during tests,
+	// to ensure relative URLs are used for all endpoints. See issue #752.
+	baseURLPath = "/api-v3"
+)
+
 // setup sets up a test HTTP server along with a github.Client that is
 // configured to talk to that test server. Tests should register handlers on
 // mux which provide mock responses for the API method being tested.
 func setup() {
 	// test server
 	mux = http.NewServeMux()
-	server = httptest.NewServer(mux)
+
+	// We want to ensure that tests catch mistakes where the endpoint URL is
+	// specified as absolute rather than relative. It only makes a difference
+	// when there's a non-empty base URL path. So, use that. See issue #752.
+	apiHandler := http.NewServeMux()
+	apiHandler.Handle(baseURLPath+"/", http.StripPrefix(baseURLPath, mux))
+	apiHandler.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
+		fmt.Fprintln(os.Stderr, "FAIL: Client.BaseURL path prefix is not preserved in the request URL:")
+		fmt.Fprintln(os.Stderr)
+		fmt.Fprintln(os.Stderr, "\t"+req.URL.String())
+		fmt.Fprintln(os.Stderr)
+		fmt.Fprintln(os.Stderr, "\tDid you accidentally use an absolute endpoint URL rather than relative?")
+		fmt.Fprintln(os.Stderr, "\tSee https://github.com/google/go-github/issues/752 for information.")
+		http.Error(w, "Client.BaseURL path prefix is not preserved in the request URL.", http.StatusInternalServerError)
+	})
+
+	server = httptest.NewServer(apiHandler)
 
 	// github client configured to use test server
 	client = NewClient(nil)
-	url, _ := url.Parse(server.URL + "/")
+	url, _ := url.Parse(server.URL + baseURLPath + "/")
 	client.BaseURL = url
 	client.UploadURL = url
 }
@@ -164,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 {
@@ -201,7 +258,7 @@ func TestNewRequest_invalidJSON(t *testing.T) {
 	type T struct {
 		A map[interface{}]interface{}
 	}
-	_, err := c.NewRequest("GET", "/", &T{})
+	_, err := c.NewRequest("GET", ".", &T{})
 
 	if err == nil {
 		t.Error("Expected error to be returned.")
@@ -222,7 +279,7 @@ func TestNewRequest_badURL(t *testing.T) {
 func TestNewRequest_emptyUserAgent(t *testing.T) {
 	c := NewClient(nil)
 	c.UserAgent = ""
-	req, err := c.NewRequest("GET", "/", nil)
+	req, err := c.NewRequest("GET", ".", nil)
 	if err != nil {
 		t.Fatalf("NewRequest returned unexpected error: %v", err)
 	}
@@ -239,7 +296,7 @@ func TestNewRequest_emptyUserAgent(t *testing.T) {
 // subtle errors.
 func TestNewRequest_emptyBody(t *testing.T) {
 	c := NewClient(nil)
-	req, err := c.NewRequest("GET", "/", nil)
+	req, err := c.NewRequest("GET", ".", nil)
 	if err != nil {
 		t.Fatalf("NewRequest returned unexpected error: %v", err)
 	}
@@ -374,7 +431,7 @@ func TestDo(t *testing.T) {
 		fmt.Fprint(w, `{"A":"a"}`)
 	})
 
-	req, _ := client.NewRequest("GET", "/", nil)
+	req, _ := client.NewRequest("GET", ".", nil)
 	body := new(foo)
 	client.Do(context.Background(), req, body)
 
@@ -392,11 +449,14 @@ func TestDo_httpError(t *testing.T) {
 		http.Error(w, "Bad Request", 400)
 	})
 
-	req, _ := client.NewRequest("GET", "/", nil)
-	_, err := client.Do(context.Background(), req, nil)
+	req, _ := client.NewRequest("GET", ".", nil)
+	resp, err := client.Do(context.Background(), req, nil)
 
 	if err == nil {
-		t.Error("Expected HTTP 400 error.")
+		t.Fatal("Expected HTTP 400 error, got no error.")
+	}
+	if resp.StatusCode != 400 {
+		t.Errorf("Expected HTTP 400 error, got %d status code.", resp.StatusCode)
 	}
 }
 
@@ -408,10 +468,10 @@ func TestDo_redirectLoop(t *testing.T) {
 	defer teardown()
 
 	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
-		http.Redirect(w, r, "/", http.StatusFound)
+		http.Redirect(w, r, baseURLPath, http.StatusFound)
 	})
 
-	req, _ := client.NewRequest("GET", "/", nil)
+	req, _ := client.NewRequest("GET", ".", nil)
 	_, err := client.Do(context.Background(), req, nil)
 
 	if err == nil {
@@ -431,7 +491,7 @@ func TestDo_sanitizeURL(t *testing.T) {
 	}
 	unauthedClient := NewClient(tp.Client())
 	unauthedClient.BaseURL = &url.URL{Scheme: "http", Host: "127.0.0.1:0", Path: "/"} // Use port 0 on purpose to trigger a dial TCP error, expect to get "dial tcp 127.0.0.1:0: connect: can't assign requested address".
-	req, err := unauthedClient.NewRequest("GET", "/", nil)
+	req, err := unauthedClient.NewRequest("GET", ".", nil)
 	if err != nil {
 		t.Fatalf("NewRequest returned unexpected error: %v", err)
 	}
@@ -454,7 +514,7 @@ func TestDo_rateLimit(t *testing.T) {
 		w.Header().Set(headerRateReset, "1372700873")
 	})
 
-	req, _ := client.NewRequest("GET", "/", nil)
+	req, _ := client.NewRequest("GET", ".", nil)
 	resp, err := client.Do(context.Background(), req, nil)
 	if err != nil {
 		t.Errorf("Do returned unexpected error: %v", err)
@@ -483,7 +543,7 @@ func TestDo_rateLimit_errorResponse(t *testing.T) {
 		http.Error(w, "Bad Request", 400)
 	})
 
-	req, _ := client.NewRequest("GET", "/", nil)
+	req, _ := client.NewRequest("GET", ".", nil)
 	resp, err := client.Do(context.Background(), req, nil)
 	if err == nil {
 		t.Error("Expected error to be returned.")
@@ -520,7 +580,7 @@ func TestDo_rateLimit_rateLimitError(t *testing.T) {
 }`)
 	})
 
-	req, _ := client.NewRequest("GET", "/", nil)
+	req, _ := client.NewRequest("GET", ".", nil)
 	_, err := client.Do(context.Background(), req, nil)
 
 	if err == nil {
@@ -567,11 +627,11 @@ func TestDo_rateLimit_noNetworkCall(t *testing.T) {
 	})
 
 	// First request is made, and it makes the client aware of rate reset time being in the future.
-	req, _ := client.NewRequest("GET", "/first", nil)
+	req, _ := client.NewRequest("GET", "first", nil)
 	client.Do(context.Background(), req, nil)
 
 	// Second request should not cause a network call to be made, since client can predict a rate limit error.
-	req, _ = client.NewRequest("GET", "/second", nil)
+	req, _ = client.NewRequest("GET", "second", nil)
 	_, err := client.Do(context.Background(), req, nil)
 
 	if madeNetworkCall {
@@ -613,7 +673,7 @@ func TestDo_rateLimit_abuseRateLimitError(t *testing.T) {
 }`)
 	})
 
-	req, _ := client.NewRequest("GET", "/", nil)
+	req, _ := client.NewRequest("GET", ".", nil)
 	_, err := client.Do(context.Background(), req, nil)
 
 	if err == nil {
@@ -643,7 +703,7 @@ func TestDo_rateLimit_abuseRateLimitError_retryAfter(t *testing.T) {
 }`)
 	})
 
-	req, _ := client.NewRequest("GET", "/", nil)
+	req, _ := client.NewRequest("GET", ".", nil)
 	_, err := client.Do(context.Background(), req, nil)
 
 	if err == nil {
@@ -671,7 +731,7 @@ func TestDo_noContent(t *testing.T) {
 
 	var body json.RawMessage
 
-	req, _ := client.NewRequest("GET", "/", nil)
+	req, _ := client.NewRequest("GET", ".", nil)
 	_, err := client.Do(context.Background(), req, &body)
 	if err != nil {
 		t.Fatalf("Do returned unexpected error: %v", err)
@@ -864,7 +924,7 @@ func TestUnauthenticatedRateLimitedTransport(t *testing.T) {
 	}
 	unauthedClient := NewClient(tp.Client())
 	unauthedClient.BaseURL = client.BaseURL
-	req, _ := unauthedClient.NewRequest("GET", "/", nil)
+	req, _ := unauthedClient.NewRequest("GET", ".", nil)
 	unauthedClient.Do(context.Background(), req, nil)
 }
 
@@ -938,7 +998,7 @@ func TestBasicAuthTransport(t *testing.T) {
 	}
 	basicAuthClient := NewClient(tp.Client())
 	basicAuthClient.BaseURL = client.BaseURL
-	req, _ := basicAuthClient.NewRequest("GET", "/", nil)
+	req, _ := basicAuthClient.NewRequest("GET", ".", nil)
 	basicAuthClient.Do(context.Background(), req, nil)
 }
 
diff --git a/github/issues_test.go b/github/issues_test.go
index dadee755..da60740f 100644
--- a/github/issues_test.go
+++ b/github/issues_test.go
@@ -275,3 +275,14 @@ func TestIssuesService_Unlock(t *testing.T) {
 		t.Errorf("Issues.Unlock returned error: %v", err)
 	}
 }
+
+func TestIsPullRequest(t *testing.T) {
+	i := new(Issue)
+	if i.IsPullRequest() == true {
+		t.Errorf("expected i.IsPullRequest (%v) to return false, got true", i)
+	}
+	i.PullRequestLinks = &PullRequestLinks{URL: String("http://example.com")}
+	if i.IsPullRequest() == false {
+		t.Errorf("expected i.IsPullRequest (%v) to return true, got false", i)
+	}
+}
diff --git a/github/messages_test.go b/github/messages_test.go
index 5f348f2a..eebfa10d 100644
--- a/github/messages_test.go
+++ b/github/messages_test.go
@@ -9,7 +9,9 @@ import (
 	"bytes"
 	"encoding/json"
 	"net/http"
+	"net/url"
 	"reflect"
+	"strings"
 	"testing"
 )
 
@@ -68,6 +70,7 @@ func TestValidatePayload(t *testing.T) {
 		if test.signature != "" {
 			req.Header.Set(signatureHeader, test.signature)
 		}
+		req.Header.Set("Content-Type", "application/json")
 
 		got, err := ValidatePayload(req, secretKey)
 		if err != nil {
@@ -82,6 +85,77 @@ func TestValidatePayload(t *testing.T) {
 	}
 }
 
+func TestValidatePayload_FormGet(t *testing.T) {
+	payload := `{"yo":true}`
+	signature := "sha1=3374ef144403e8035423b23b02e2c9d7a4c50368"
+	secretKey := []byte("0123456789abcdef")
+
+	form := url.Values{}
+	form.Add("payload", payload)
+	req, err := http.NewRequest("POST", "http://localhost/event", strings.NewReader(form.Encode()))
+	if err != nil {
+		t.Fatalf("NewRequest: %v", err)
+	}
+	req.PostForm = form
+	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+	req.Header.Set(signatureHeader, signature)
+
+	got, err := ValidatePayload(req, secretKey)
+	if err != nil {
+		t.Errorf("ValidatePayload(%#v): err = %v, want nil", payload, err)
+	}
+	if string(got) != payload {
+		t.Errorf("ValidatePayload = %q, want %q", got, payload)
+	}
+
+	// check that if payload is invalid we get error
+	req.Header.Set(signatureHeader, "invalid signature")
+	if _, err = ValidatePayload(req, nil); err == nil {
+		t.Error("ValidatePayload = nil, want err")
+	}
+}
+
+func TestValidatePayload_FormPost(t *testing.T) {
+	payload := `{"yo":true}`
+	signature := "sha1=3374ef144403e8035423b23b02e2c9d7a4c50368"
+	secretKey := []byte("0123456789abcdef")
+
+	form := url.Values{}
+	form.Set("payload", payload)
+	buf := bytes.NewBufferString(form.Encode())
+	req, err := http.NewRequest("POST", "http://localhost/event", buf)
+	if err != nil {
+		t.Fatalf("NewRequest: %v", err)
+	}
+	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+	req.Header.Set(signatureHeader, signature)
+
+	got, err := ValidatePayload(req, secretKey)
+	if err != nil {
+		t.Errorf("ValidatePayload(%#v): err = %v, want nil", payload, err)
+	}
+	if string(got) != payload {
+		t.Errorf("ValidatePayload = %q, want %q", got, payload)
+	}
+
+	// check that if payload is invalid we get error
+	req.Header.Set(signatureHeader, "invalid signature")
+	if _, err = ValidatePayload(req, nil); err == nil {
+		t.Error("ValidatePayload = nil, want err")
+	}
+}
+
+func TestValidatePayload_InvalidContentType(t *testing.T) {
+	req, err := http.NewRequest("POST", "http://localhost/event", nil)
+	if err != nil {
+		t.Fatalf("NewRequest: %v", err)
+	}
+	req.Header.Set("Content-Type", "invalid content type")
+	if _, err = ValidatePayload(req, nil); err == nil {
+		t.Error("ValidatePayload = nil, want err")
+	}
+}
+
 func TestParseWebHook(t *testing.T) {
 	tests := []struct {
 		payload     interface{}
diff --git a/github/orgs_members_test.go b/github/orgs_members_test.go
index a17c5186..21fbeeaf 100644
--- a/github/orgs_members_test.go
+++ b/github/orgs_members_test.go
@@ -360,7 +360,7 @@ func TestOrganizationsService_ListPendingOrgInvitations(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/orgs/1/invitations", func(w http.ResponseWriter, r *http.Request) {
+	mux.HandleFunc("/orgs/o/invitations", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
 		testFormValues(t, r, values{"page": "1"})
 		fmt.Fprint(w, `[
@@ -394,7 +394,7 @@ func TestOrganizationsService_ListPendingOrgInvitations(t *testing.T) {
 	})
 
 	opt := &ListOptions{Page: 1}
-	invitations, _, err := client.Organizations.ListPendingOrgInvitations(context.Background(), 1, opt)
+	invitations, _, err := client.Organizations.ListPendingOrgInvitations(context.Background(), "o", opt)
 	if err != nil {
 		t.Errorf("Organizations.ListPendingOrgInvitations returned error: %v", err)
 	}
diff --git a/github/orgs_teams_test.go b/github/orgs_teams_test.go
index ff1101dc..04669866 100644
--- a/github/orgs_teams_test.go
+++ b/github/orgs_teams_test.go
@@ -11,6 +11,7 @@ import (
 	"fmt"
 	"net/http"
 	"reflect"
+	"strings"
 	"testing"
 	"time"
 )
@@ -21,6 +22,7 @@ func TestOrganizationsService_ListTeams(t *testing.T) {
 
 	mux.HandleFunc("/orgs/o/teams", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
 		testFormValues(t, r, values{"page": "2"})
 		fmt.Fprint(w, `[{"id":1}]`)
 	})
@@ -48,7 +50,8 @@ func TestOrganizationsService_GetTeam(t *testing.T) {
 
 	mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
-		fmt.Fprint(w, `{"id":1, "name":"n", "description": "d", "url":"u", "slug": "s", "permission":"p", "ldap_dn":"cn=n,ou=groups,dc=example,dc=com"}`)
+		testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
+		fmt.Fprint(w, `{"id":1, "name":"n", "description": "d", "url":"u", "slug": "s", "permission":"p", "ldap_dn":"cn=n,ou=groups,dc=example,dc=com", "parent":null}`)
 	})
 
 	team, _, err := client.Organizations.GetTeam(context.Background(), 1)
@@ -62,17 +65,42 @@ func TestOrganizationsService_GetTeam(t *testing.T) {
 	}
 }
 
+func TestOrganizationService_GetTeam_nestedTeams(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
+		fmt.Fprint(w, `{"id":1, "name":"n", "description": "d", "url":"u", "slug": "s", "permission":"p",
+		"parent": {"id":2, "name":"n", "description": "d", "parent": null}}`)
+	})
+
+	team, _, err := client.Organizations.GetTeam(context.Background(), 1)
+	if err != nil {
+		t.Errorf("Organizations.GetTeam returned error: %v", err)
+	}
+
+	want := &Team{ID: Int(1), Name: String("n"), Description: String("d"), URL: String("u"), Slug: String("s"), Permission: String("p"),
+		Parent: &Team{ID: Int(2), Name: String("n"), Description: String("d")},
+	}
+	if !reflect.DeepEqual(team, want) {
+		t.Errorf("Organizations.GetTeam returned %+v, want %+v", team, want)
+	}
+}
+
 func TestOrganizationsService_CreateTeam(t *testing.T) {
 	setup()
 	defer teardown()
 
-	input := &Team{Name: String("n"), Privacy: String("closed")}
+	input := &NewTeam{Name: "n", Privacy: String("closed"), RepoNames: []string{"r"}}
 
 	mux.HandleFunc("/orgs/o/teams", func(w http.ResponseWriter, r *http.Request) {
-		v := new(Team)
+		v := new(NewTeam)
 		json.NewDecoder(r.Body).Decode(v)
 
 		testMethod(t, r, "POST")
+		testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
 		if !reflect.DeepEqual(v, input) {
 			t.Errorf("Request body = %+v, want %+v", v, input)
 		}
@@ -100,12 +128,13 @@ func TestOrganizationsService_EditTeam(t *testing.T) {
 	setup()
 	defer teardown()
 
-	input := &Team{Name: String("n"), Privacy: String("closed")}
+	input := &NewTeam{Name: "n", Privacy: String("closed")}
 
 	mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) {
-		v := new(Team)
+		v := new(NewTeam)
 		json.NewDecoder(r.Body).Decode(v)
 
+		testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
 		testMethod(t, r, "PATCH")
 		if !reflect.DeepEqual(v, input) {
 			t.Errorf("Request body = %+v, want %+v", v, input)
@@ -131,6 +160,7 @@ func TestOrganizationsService_DeleteTeam(t *testing.T) {
 
 	mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "DELETE")
+		testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
 	})
 
 	_, err := client.Organizations.DeleteTeam(context.Background(), 1)
@@ -139,12 +169,36 @@ func TestOrganizationsService_DeleteTeam(t *testing.T) {
 	}
 }
 
+func TestOrganizationsService_ListChildTeams(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/teams/1/teams", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
+		testFormValues(t, r, values{"page": "2"})
+		fmt.Fprint(w, `[{"id":2}]`)
+	})
+
+	opt := &ListOptions{Page: 2}
+	teams, _, err := client.Organizations.ListChildTeams(context.Background(), 1, opt)
+	if err != nil {
+		t.Errorf("Organizations.ListTeams returned error: %v", err)
+	}
+
+	want := []*Team{{ID: Int(2)}}
+	if !reflect.DeepEqual(teams, want) {
+		t.Errorf("Organizations.ListTeams returned %+v, want %+v", teams, want)
+	}
+}
+
 func TestOrganizationsService_ListTeamMembers(t *testing.T) {
 	setup()
 	defer teardown()
 
 	mux.HandleFunc("/teams/1/members", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
 		testFormValues(t, r, values{"role": "member", "page": "2"})
 		fmt.Fprint(w, `[{"id":1}]`)
 	})
@@ -268,7 +322,8 @@ func TestOrganizationsService_ListTeamRepos(t *testing.T) {
 
 	mux.HandleFunc("/teams/1/repos", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
-		testHeader(t, r, "Accept", mediaTypeTopicsPreview)
+		acceptHeaders := []string{mediaTypeTopicsPreview, mediaTypeNestedTeamsPreview}
+		testHeader(t, r, "Accept", strings.Join(acceptHeaders, ", "))
 		testFormValues(t, r, values{"page": "2"})
 		fmt.Fprint(w, `[{"id":1}]`)
 	})
@@ -291,7 +346,8 @@ func TestOrganizationsService_IsTeamRepo_true(t *testing.T) {
 
 	mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
-		testHeader(t, r, "Accept", mediaTypeOrgPermissionRepo)
+		acceptHeaders := []string{mediaTypeOrgPermissionRepo, mediaTypeNestedTeamsPreview}
+		testHeader(t, r, "Accept", strings.Join(acceptHeaders, ", "))
 		fmt.Fprint(w, `{"id":1}`)
 	})
 
@@ -423,6 +479,7 @@ func TestOrganizationsService_GetTeamMembership(t *testing.T) {
 
 	mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
 		fmt.Fprint(w, `{"url":"u", "state":"active"}`)
 	})
 
@@ -487,6 +544,7 @@ func TestOrganizationsService_ListUserTeams(t *testing.T) {
 
 	mux.HandleFunc("/user/teams", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
 		testFormValues(t, r, values{"page": "1"})
 		fmt.Fprint(w, `[{"id":1}]`)
 	})
diff --git a/github/projects_test.go b/github/projects_test.go
index 1045ca9b..bf287e02 100644
--- a/github/projects_test.go
+++ b/github/projects_test.go
@@ -18,7 +18,7 @@ func TestProjectsService_UpdateProject(t *testing.T) {
 	setup()
 	defer teardown()
 
-	input := &ProjectOptions{Name: "Project Name", Body: "Project body."}
+	input := &ProjectOptions{Name: "Project Name", Body: "Project body.", State: "open"}
 
 	mux.HandleFunc("/projects/1", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "PATCH")
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_collaborators_test.go b/github/repos_collaborators_test.go
index 4ac23934..4f3d4770 100644
--- a/github/repos_collaborators_test.go
+++ b/github/repos_collaborators_test.go
@@ -20,6 +20,7 @@ func TestRepositoriesService_ListCollaborators(t *testing.T) {
 
 	mux.HandleFunc("/repos/o/r/collaborators", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
 		testFormValues(t, r, values{"page": "2"})
 		fmt.Fprintf(w, `[{"id":1}, {"id":2}]`)
 	})
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()
diff --git a/github/repos_contents_test.go b/github/repos_contents_test.go
index 498dfc81..770098e8 100644
--- a/github/repos_contents_test.go
+++ b/github/repos_contents_test.go
@@ -98,7 +98,7 @@ func TestRepositoriesService_DownloadContents_Success(t *testing.T) {
 		fmt.Fprint(w, `[{
 		  "type": "file",
 		  "name": "f",
-		  "download_url": "`+server.URL+`/download/f"
+		  "download_url": "`+server.URL+baseURLPath+`/download/f"
 		}]`)
 	})
 	mux.HandleFunc("/download/f", func(w http.ResponseWriter, r *http.Request) {
diff --git a/github/repos_test.go b/github/repos_test.go
index 1f7b424f..9e522c82 100644
--- a/github/repos_test.go
+++ b/github/repos_test.go
@@ -145,14 +145,12 @@ func TestRepositoriesService_ListAll(t *testing.T) {
 	mux.HandleFunc("/repositories", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
 		testFormValues(t, r, values{
-			"since":    "1",
-			"page":     "2",
-			"per_page": "3",
+			"since": "1",
 		})
 		fmt.Fprint(w, `[{"id":1}]`)
 	})
 
-	opt := &RepositoryListAllOptions{1, ListOptions{2, 3}}
+	opt := &RepositoryListAllOptions{1}
 	repos, _, err := client.Repositories.ListAll(context.Background(), opt)
 	if err != nil {
 		t.Errorf("Repositories.ListAll returned error: %v", err)
@@ -406,6 +404,7 @@ func TestRepositoriesService_ListTeams(t *testing.T) {
 
 	mux.HandleFunc("/repos/o/r/teams", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
 		testFormValues(t, r, values{"page": "2"})
 		fmt.Fprint(w, `[{"id":1}]`)
 	})
@@ -518,7 +517,7 @@ func TestRepositoriesService_GetBranchProtection(t *testing.T) {
 
 		testMethod(t, r, "GET")
 		testHeader(t, r, "Accept", mediaTypeProtectedBranchesPreview)
-		fmt.Fprintf(w, `{"required_status_checks":{"strict":true,"contexts":["continuous-integration"]},"required_pull_request_reviews":{"dismissal_restrictions":{"users":[{"id":3,"login":"u"}],"teams":[{"id":4,"slug":"t"}]},"dismiss_stale_reviews":true},"enforce_admins":{"url":"/repos/o/r/branches/b/protection/enforce_admins","enabled":true},"restrictions":{"users":[{"id":1,"login":"u"}],"teams":[{"id":2,"slug":"t"}]}}`)
+		fmt.Fprintf(w, `{"required_status_checks":{"strict":true,"contexts":["continuous-integration"]},"required_pull_request_reviews":{"dismissal_restrictions":{"users":[{"id":3,"login":"u"}],"teams":[{"id":4,"slug":"t"}]},"dismiss_stale_reviews":true,"require_code_owner_reviews":true},"enforce_admins":{"url":"/repos/o/r/branches/b/protection/enforce_admins","enabled":true},"restrictions":{"users":[{"id":1,"login":"u"}],"teams":[{"id":2,"slug":"t"}]}}`)
 	})
 
 	protection, _, err := client.Repositories.GetBranchProtection(context.Background(), "o", "r", "b")
@@ -541,6 +540,7 @@ func TestRepositoriesService_GetBranchProtection(t *testing.T) {
 					{Slug: String("t"), ID: Int(4)},
 				},
 			},
+			RequireCodeOwnerReviews: true,
 		},
 		EnforceAdmins: &AdminEnforcement{
 			URL:     String("/repos/o/r/branches/b/protection/enforce_admins"),
@@ -591,7 +591,7 @@ func TestRepositoriesService_UpdateBranchProtection(t *testing.T) {
 			t.Errorf("Request body = %+v, want %+v", v, input)
 		}
 		testHeader(t, r, "Accept", mediaTypeProtectedBranchesPreview)
-		fmt.Fprintf(w, `{"required_status_checks":{"strict":true,"contexts":["continuous-integration"]},"required_pull_request_reviews":{"dismissal_restrictions":{"users":[{"id":3,"login":"uu"}],"teams":[{"id":4,"slug":"tt"}]},"dismiss_stale_reviews":true},"restrictions":{"users":[{"id":1,"login":"u"}],"teams":[{"id":2,"slug":"t"}]}}`)
+		fmt.Fprintf(w, `{"required_status_checks":{"strict":true,"contexts":["continuous-integration"]},"required_pull_request_reviews":{"dismissal_restrictions":{"users":[{"id":3,"login":"uu"}],"teams":[{"id":4,"slug":"tt"}]},"dismiss_stale_reviews":true,"require_code_owner_reviews":true},"restrictions":{"users":[{"id":1,"login":"u"}],"teams":[{"id":2,"slug":"t"}]}}`)
 	})
 
 	protection, _, err := client.Repositories.UpdateBranchProtection(context.Background(), "o", "r", "b", input)
@@ -614,6 +614,7 @@ func TestRepositoriesService_UpdateBranchProtection(t *testing.T) {
 					{Slug: String("tt"), ID: Int(4)},
 				},
 			},
+			RequireCodeOwnerReviews: true,
 		},
 		Restrictions: &BranchRestrictions{
 			Users: []*User{
@@ -739,7 +740,7 @@ func TestRepositoriesService_GetPullRequestReviewEnforcement(t *testing.T) {
 	mux.HandleFunc("/repos/o/r/branches/b/protection/required_pull_request_reviews", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
 		testHeader(t, r, "Accept", mediaTypeProtectedBranchesPreview)
-		fmt.Fprintf(w, `{"dismissal_restrictions":{"users":[{"id":1,"login":"u"}],"teams":[{"id":2,"slug":"t"}]},"dismiss_stale_reviews":true}`)
+		fmt.Fprintf(w, `{"dismissal_restrictions":{"users":[{"id":1,"login":"u"}],"teams":[{"id":2,"slug":"t"}]},"dismiss_stale_reviews":true,"require_code_owner_reviews":true}`)
 	})
 
 	enforcement, _, err := client.Repositories.GetPullRequestReviewEnforcement(context.Background(), "o", "r", "b")
@@ -757,6 +758,7 @@ func TestRepositoriesService_GetPullRequestReviewEnforcement(t *testing.T) {
 				{Slug: String("t"), ID: Int(2)},
 			},
 		},
+		RequireCodeOwnerReviews: true,
 	}
 
 	if !reflect.DeepEqual(enforcement, want) {
@@ -784,7 +786,7 @@ func TestRepositoriesService_UpdatePullRequestReviewEnforcement(t *testing.T) {
 			t.Errorf("Request body = %+v, want %+v", v, input)
 		}
 		testHeader(t, r, "Accept", mediaTypeProtectedBranchesPreview)
-		fmt.Fprintf(w, `{"dismissal_restrictions":{"users":[{"id":1,"login":"u"}],"teams":[{"id":2,"slug":"t"}]},"dismiss_stale_reviews":true}`)
+		fmt.Fprintf(w, `{"dismissal_restrictions":{"users":[{"id":1,"login":"u"}],"teams":[{"id":2,"slug":"t"}]},"dismiss_stale_reviews":true,"require_code_owner_reviews":true}`)
 	})
 
 	enforcement, _, err := client.Repositories.UpdatePullRequestReviewEnforcement(context.Background(), "o", "r", "b", input)
@@ -802,6 +804,7 @@ func TestRepositoriesService_UpdatePullRequestReviewEnforcement(t *testing.T) {
 				{Slug: String("t"), ID: Int(2)},
 			},
 		},
+		RequireCodeOwnerReviews: true,
 	}
 	if !reflect.DeepEqual(enforcement, want) {
 		t.Errorf("Repositories.UpdatePullRequestReviewEnforcement returned %+v, want %+v", enforcement, want)
@@ -816,7 +819,7 @@ func TestRepositoriesService_DisableDismissalRestrictions(t *testing.T) {
 		testMethod(t, r, "PATCH")
 		testHeader(t, r, "Accept", mediaTypeProtectedBranchesPreview)
 		testBody(t, r, `{"dismissal_restrictions":[]}`+"\n")
-		fmt.Fprintf(w, `{"dismissal_restrictions":{"users":[],"teams":[]},"dismiss_stale_reviews":true}`)
+		fmt.Fprintf(w, `{"dismissal_restrictions":{"users":[],"teams":[]},"dismiss_stale_reviews":true,"require_code_owner_reviews":true}`)
 	})
 
 	enforcement, _, err := client.Repositories.DisableDismissalRestrictions(context.Background(), "o", "r", "b")
@@ -830,6 +833,7 @@ func TestRepositoriesService_DisableDismissalRestrictions(t *testing.T) {
 			Users: []*User{},
 			Teams: []*Team{},
 		},
+		RequireCodeOwnerReviews: true,
 	}
 	if !reflect.DeepEqual(enforcement, want) {
 		t.Errorf("Repositories.DisableDismissalRestrictions returned %+v, want %+v", enforcement, want)
@@ -925,7 +929,7 @@ func TestPullRequestReviewsEnforcementRequest_MarshalJSON_nilDismissalRestirctio
 		t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned error: %v", err)
 	}
 
-	want := `{"dismissal_restrictions":[],"dismiss_stale_reviews":false}`
+	want := `{"dismissal_restrictions":[],"dismiss_stale_reviews":false,"require_code_owner_reviews":false}`
 	if want != string(json) {
 		t.Errorf("PullRequestReviewsEnforcementRequest.MarshalJSON returned %+v, want %+v", string(json), want)
 	}