Repository: google/go-github
Pull request #1236 (2019-07-23 05:00:34)

Add support for creating repos from template repos
Add API for `POST /repos/:template_owner/:template_repo/generate` endpoint which creates a repository from a template repository.
Developer Blog: https://developer.github.com/changes/2019-07-16-repository-templates-api/
API Reference: https://developer.github.com/v3/repos/#create-repository-using-a-repository-template

Issue: https://github.com/google/go-github/issues/1235

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

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

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

----

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

##### Individual signers

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

##### Corporate signers

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

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

<!-- need_sender_cla -->
shanempope: I signed it!
googlebot: CLAs look good, thanks!

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

<!-- ok -->
codecov[bot]: # [Codecov](https://codecov.io/gh/google/go-github/pull/1236?src=pr&el=h1) Report
> Merging [#1236](https://codecov.io/gh/google/go-github/pull/1236?src=pr&el=desc) into [master](https://codecov.io/gh/google/go-github/commit/c756c329c19dbbadba0675b42af693093c3f2c45?src=pr&el=desc) will **decrease** coverage by `0.01%`.
> The diff coverage is `63.63%`.

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

```diff
@@            Coverage Diff             @@
##           master    #1236      +/-   ##
==========================================
- Coverage   73.36%   73.34%   -0.02%     
==========================================
  Files          86       86              
  Lines        6026     6037      +11     
==========================================
+ Hits         4421     4428       +7     
- Misses        836      838       +2     
- Partials      769      771       +2
```


| [Impacted Files](https://codecov.io/gh/google/go-github/pull/1236?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [github/repos.go](https://codecov.io/gh/google/go-github/pull/1236/diff?src=pr&el=tree#diff-Z2l0aHViL3JlcG9zLmdv) | `74.1% <63.63%> (-0.27%)` | :arrow_down: |

------

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

shanempope: > Note: Creating and using repository templates is currently available for developers to preview. To access this new endpoint during the preview period, you must provide a custom media type in the Accept header:
> 
> `application/vnd.github.baptiste-preview+json`

And

> Warning: The API may change without advance notice during the preview period. Preview features are not supported for production use. If you experience any issues, contact GitHub Support.

shanempope: I will add the custom headers to the other two endpoints later today.
shanempope: Alright, I manually tested all of the endpoints. It's ready for a second review. Thanks @gmlewis 
shanempope: Thanks @gauntface and @gmlewis. I've squashed the commits
gmlewis: Thank you, @shanempope, but we prefer that you don't use force-push in this repo, as it makes it more difficult for other contributors to see the change history in case they wish to make comments during the PR review period.  Additionally, we always "Squash and merge" in this repo, so it ends up being a single commit anyway, so the force-push is unnecessary. 

Thank you, @gauntface.

Merging.

Patch:
diff --git a/github/github-accessors.go b/github/github-accessors.go
index b4ca033d..13e60abb 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -9612,6 +9612,14 @@ func (r *Repository) GetIssuesURL() string {
 	return *r.IssuesURL
 }
 
+// GetIsTemplate returns the IsTemplate field if it's non-nil, zero value otherwise.
+func (r *Repository) GetIsTemplate() bool {
+	if r == nil || r.IsTemplate == nil {
+		return false
+	}
+	return *r.IsTemplate
+}
+
 // GetKeysURL returns the KeysURL field if it's non-nil, zero value otherwise.
 func (r *Repository) GetKeysURL() string {
 	if r == nil || r.KeysURL == nil {
@@ -9900,6 +9908,14 @@ func (r *Repository) GetTeamsURL() string {
 	return *r.TeamsURL
 }
 
+// GetTemplateRepository returns the TemplateRepository field.
+func (r *Repository) GetTemplateRepository() *Repository {
+	if r == nil {
+		return nil
+	}
+	return r.TemplateRepository
+}
+
 // GetTreesURL returns the TreesURL field if it's non-nil, zero value otherwise.
 func (r *Repository) GetTreesURL() string {
 	if r == nil || r.TreesURL == nil {
@@ -11668,6 +11684,38 @@ func (t *TeamProjectOptions) GetPermission() string {
 	return *t.Permission
 }
 
+// GetDescription returns the Description field if it's non-nil, zero value otherwise.
+func (t *TemplateRepoRequest) GetDescription() string {
+	if t == nil || t.Description == nil {
+		return ""
+	}
+	return *t.Description
+}
+
+// GetName returns the Name field if it's non-nil, zero value otherwise.
+func (t *TemplateRepoRequest) GetName() string {
+	if t == nil || t.Name == nil {
+		return ""
+	}
+	return *t.Name
+}
+
+// GetOwner returns the Owner field if it's non-nil, zero value otherwise.
+func (t *TemplateRepoRequest) GetOwner() string {
+	if t == nil || t.Owner == nil {
+		return ""
+	}
+	return *t.Owner
+}
+
+// GetPrivate returns the Private field if it's non-nil, zero value otherwise.
+func (t *TemplateRepoRequest) GetPrivate() bool {
+	if t == nil || t.Private == nil {
+		return false
+	}
+	return *t.Private
+}
+
 // GetFragment returns the Fragment field if it's non-nil, zero value otherwise.
 func (t *TextMatch) GetFragment() string {
 	if t == nil || t.Fragment == nil {
diff --git a/github/github.go b/github/github.go
index 7a82677c..d348a7b6 100644
--- a/github/github.go
+++ b/github/github.go
@@ -153,6 +153,9 @@ const (
 
 	// https://developer.github.com/v3/previews/#repository-creation-permissions
 	mediaTypeMemberAllowedRepoCreationTypePreview = "application/vnd.github.surtur-preview+json"
+
+	// https://developer.github.com/v3/previews/#create-and-use-repository-templates
+	mediaTypeRepositoryTemplatePreview = "application/vnd.github.baptiste-preview+json"
 )
 
 // A Client manages communication with the GitHub API.
diff --git a/github/repos.go b/github/repos.go
index 5f44c6d8..a380f302 100644
--- a/github/repos.go
+++ b/github/repos.go
@@ -19,45 +19,46 @@ type RepositoriesService service
 
 // Repository represents a GitHub repository.
 type Repository struct {
-	ID               *int64           `json:"id,omitempty"`
-	NodeID           *string          `json:"node_id,omitempty"`
-	Owner            *User            `json:"owner,omitempty"`
-	Name             *string          `json:"name,omitempty"`
-	FullName         *string          `json:"full_name,omitempty"`
-	Description      *string          `json:"description,omitempty"`
-	Homepage         *string          `json:"homepage,omitempty"`
-	CodeOfConduct    *CodeOfConduct   `json:"code_of_conduct,omitempty"`
-	DefaultBranch    *string          `json:"default_branch,omitempty"`
-	MasterBranch     *string          `json:"master_branch,omitempty"`
-	CreatedAt        *Timestamp       `json:"created_at,omitempty"`
-	PushedAt         *Timestamp       `json:"pushed_at,omitempty"`
-	UpdatedAt        *Timestamp       `json:"updated_at,omitempty"`
-	HTMLURL          *string          `json:"html_url,omitempty"`
-	CloneURL         *string          `json:"clone_url,omitempty"`
-	GitURL           *string          `json:"git_url,omitempty"`
-	MirrorURL        *string          `json:"mirror_url,omitempty"`
-	SSHURL           *string          `json:"ssh_url,omitempty"`
-	SVNURL           *string          `json:"svn_url,omitempty"`
-	Language         *string          `json:"language,omitempty"`
-	Fork             *bool            `json:"fork,omitempty"`
-	ForksCount       *int             `json:"forks_count,omitempty"`
-	NetworkCount     *int             `json:"network_count,omitempty"`
-	OpenIssuesCount  *int             `json:"open_issues_count,omitempty"`
-	StargazersCount  *int             `json:"stargazers_count,omitempty"`
-	SubscribersCount *int             `json:"subscribers_count,omitempty"`
-	WatchersCount    *int             `json:"watchers_count,omitempty"`
-	Size             *int             `json:"size,omitempty"`
-	AutoInit         *bool            `json:"auto_init,omitempty"`
-	Parent           *Repository      `json:"parent,omitempty"`
-	Source           *Repository      `json:"source,omitempty"`
-	Organization     *Organization    `json:"organization,omitempty"`
-	Permissions      *map[string]bool `json:"permissions,omitempty"`
-	AllowRebaseMerge *bool            `json:"allow_rebase_merge,omitempty"`
-	AllowSquashMerge *bool            `json:"allow_squash_merge,omitempty"`
-	AllowMergeCommit *bool            `json:"allow_merge_commit,omitempty"`
-	Topics           []string         `json:"topics,omitempty"`
-	Archived         *bool            `json:"archived,omitempty"`
-	Disabled         *bool            `json:"disabled,omitempty"`
+	ID                 *int64           `json:"id,omitempty"`
+	NodeID             *string          `json:"node_id,omitempty"`
+	Owner              *User            `json:"owner,omitempty"`
+	Name               *string          `json:"name,omitempty"`
+	FullName           *string          `json:"full_name,omitempty"`
+	Description        *string          `json:"description,omitempty"`
+	Homepage           *string          `json:"homepage,omitempty"`
+	CodeOfConduct      *CodeOfConduct   `json:"code_of_conduct,omitempty"`
+	DefaultBranch      *string          `json:"default_branch,omitempty"`
+	MasterBranch       *string          `json:"master_branch,omitempty"`
+	CreatedAt          *Timestamp       `json:"created_at,omitempty"`
+	PushedAt           *Timestamp       `json:"pushed_at,omitempty"`
+	UpdatedAt          *Timestamp       `json:"updated_at,omitempty"`
+	HTMLURL            *string          `json:"html_url,omitempty"`
+	CloneURL           *string          `json:"clone_url,omitempty"`
+	GitURL             *string          `json:"git_url,omitempty"`
+	MirrorURL          *string          `json:"mirror_url,omitempty"`
+	SSHURL             *string          `json:"ssh_url,omitempty"`
+	SVNURL             *string          `json:"svn_url,omitempty"`
+	Language           *string          `json:"language,omitempty"`
+	Fork               *bool            `json:"fork,omitempty"`
+	ForksCount         *int             `json:"forks_count,omitempty"`
+	NetworkCount       *int             `json:"network_count,omitempty"`
+	OpenIssuesCount    *int             `json:"open_issues_count,omitempty"`
+	StargazersCount    *int             `json:"stargazers_count,omitempty"`
+	SubscribersCount   *int             `json:"subscribers_count,omitempty"`
+	WatchersCount      *int             `json:"watchers_count,omitempty"`
+	Size               *int             `json:"size,omitempty"`
+	AutoInit           *bool            `json:"auto_init,omitempty"`
+	Parent             *Repository      `json:"parent,omitempty"`
+	Source             *Repository      `json:"source,omitempty"`
+	TemplateRepository *Repository      `json:"template_repository,omitempty"`
+	Organization       *Organization    `json:"organization,omitempty"`
+	Permissions        *map[string]bool `json:"permissions,omitempty"`
+	AllowRebaseMerge   *bool            `json:"allow_rebase_merge,omitempty"`
+	AllowSquashMerge   *bool            `json:"allow_squash_merge,omitempty"`
+	AllowMergeCommit   *bool            `json:"allow_merge_commit,omitempty"`
+	Topics             []string         `json:"topics,omitempty"`
+	Archived           *bool            `json:"archived,omitempty"`
+	Disabled           *bool            `json:"disabled,omitempty"`
 
 	// Only provided when using RepositoriesService.Get while in preview
 	License *License `json:"license,omitempty"`
@@ -69,6 +70,7 @@ type Repository struct {
 	HasPages          *bool   `json:"has_pages,omitempty"`
 	HasProjects       *bool   `json:"has_projects,omitempty"`
 	HasDownloads      *bool   `json:"has_downloads,omitempty"`
+	IsTemplate        *bool   `json:"is_template,omitempty"`
 	LicenseTemplate   *string `json:"license_template,omitempty"`
 	GitignoreTemplate *string `json:"gitignore_template,omitempty"`
 
@@ -275,6 +277,7 @@ type createRepoRequest struct {
 	HasIssues   *bool `json:"has_issues,omitempty"`
 	HasProjects *bool `json:"has_projects,omitempty"`
 	HasWiki     *bool `json:"has_wiki,omitempty"`
+	IsTemplate  *bool `json:"is_template,omitempty"`
 
 	// Creating an organization repository. Required for non-owners.
 	TeamID *int64 `json:"team_id,omitempty"`
@@ -311,6 +314,7 @@ func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repo
 		HasIssues:         repo.HasIssues,
 		HasProjects:       repo.HasProjects,
 		HasWiki:           repo.HasWiki,
+		IsTemplate:        repo.IsTemplate,
 		TeamID:            repo.TeamID,
 		AutoInit:          repo.AutoInit,
 		GitignoreTemplate: repo.GitignoreTemplate,
@@ -325,6 +329,38 @@ func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repo
 		return nil, nil, err
 	}
 
+	req.Header.Set("Accept", mediaTypeRepositoryTemplatePreview)
+	r := new(Repository)
+	resp, err := s.client.Do(ctx, req, r)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return r, resp, nil
+}
+
+// TemplateRepoRequest represents a request to create a repository from a template.
+type TemplateRepoRequest struct {
+	// Name is required when creating a repo.
+	Name        *string `json:"name,omitempty"`
+	Owner       *string `json:"owner,omitempty"`
+	Description *string `json:"description,omitempty"`
+
+	Private *bool `json:"private,omitempty"`
+}
+
+// CreateFromTemplate generates a repository from a template.
+//
+// GitHub API docs: https://developer.github.com/v3/repos/#create-repository-using-a-repository-template
+func (s *RepositoriesService) CreateFromTemplate(ctx context.Context, templateOwner, templateRepo string, templateRepoReq *TemplateRepoRequest) (*Repository, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/generate", templateOwner, templateRepo)
+
+	req, err := s.client.NewRequest("POST", u, templateRepoReq)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req.Header.Set("Accept", mediaTypeRepositoryTemplatePreview)
 	r := new(Repository)
 	resp, err := s.client.Do(ctx, req, r)
 	if err != nil {
@@ -346,7 +382,7 @@ func (s *RepositoriesService) Get(ctx context.Context, owner, repo string) (*Rep
 
 	// TODO: remove custom Accept header when the license support fully launches
 	// https://developer.github.com/v3/licenses/#get-a-repositorys-license
-	acceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
+	acceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview, mediaTypeRepositoryTemplatePreview}
 	req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
 
 	repository := new(Repository)
@@ -409,6 +445,7 @@ func (s *RepositoriesService) Edit(ctx context.Context, owner, repo string, repo
 		return nil, nil, err
 	}
 
+	req.Header.Set("Accept", mediaTypeRepositoryTemplatePreview)
 	r := new(Repository)
 	resp, err := s.client.Do(ctx, req, r)
 	if err != nil {


Test patch:
diff --git a/github/github-stringify_test.go b/github/github-stringify_test.go
index f424531e..c91f7b5a 100644
--- a/github/github-stringify_test.go
+++ b/github/github-stringify_test.go
@@ -1167,92 +1167,94 @@ func TestRepoStatus_String(t *testing.T) {
 
 func TestRepository_String(t *testing.T) {
 	v := Repository{
-		ID:                Int64(0),
-		NodeID:            String(""),
-		Owner:             &User{},
-		Name:              String(""),
-		FullName:          String(""),
-		Description:       String(""),
-		Homepage:          String(""),
-		CodeOfConduct:     &CodeOfConduct{},
-		DefaultBranch:     String(""),
-		MasterBranch:      String(""),
-		CreatedAt:         &Timestamp{},
-		PushedAt:          &Timestamp{},
-		UpdatedAt:         &Timestamp{},
-		HTMLURL:           String(""),
-		CloneURL:          String(""),
-		GitURL:            String(""),
-		MirrorURL:         String(""),
-		SSHURL:            String(""),
-		SVNURL:            String(""),
-		Language:          String(""),
-		Fork:              Bool(false),
-		ForksCount:        Int(0),
-		NetworkCount:      Int(0),
-		OpenIssuesCount:   Int(0),
-		StargazersCount:   Int(0),
-		SubscribersCount:  Int(0),
-		WatchersCount:     Int(0),
-		Size:              Int(0),
-		AutoInit:          Bool(false),
-		Parent:            &Repository{},
-		Source:            &Repository{},
-		Organization:      &Organization{},
-		AllowRebaseMerge:  Bool(false),
-		AllowSquashMerge:  Bool(false),
-		AllowMergeCommit:  Bool(false),
-		Archived:          Bool(false),
-		Disabled:          Bool(false),
-		License:           &License{},
-		Private:           Bool(false),
-		HasIssues:         Bool(false),
-		HasWiki:           Bool(false),
-		HasPages:          Bool(false),
-		HasProjects:       Bool(false),
-		HasDownloads:      Bool(false),
-		LicenseTemplate:   String(""),
-		GitignoreTemplate: String(""),
-		TeamID:            Int64(0),
-		URL:               String(""),
-		ArchiveURL:        String(""),
-		AssigneesURL:      String(""),
-		BlobsURL:          String(""),
-		BranchesURL:       String(""),
-		CollaboratorsURL:  String(""),
-		CommentsURL:       String(""),
-		CommitsURL:        String(""),
-		CompareURL:        String(""),
-		ContentsURL:       String(""),
-		ContributorsURL:   String(""),
-		DeploymentsURL:    String(""),
-		DownloadsURL:      String(""),
-		EventsURL:         String(""),
-		ForksURL:          String(""),
-		GitCommitsURL:     String(""),
-		GitRefsURL:        String(""),
-		GitTagsURL:        String(""),
-		HooksURL:          String(""),
-		IssueCommentURL:   String(""),
-		IssueEventsURL:    String(""),
-		IssuesURL:         String(""),
-		KeysURL:           String(""),
-		LabelsURL:         String(""),
-		LanguagesURL:      String(""),
-		MergesURL:         String(""),
-		MilestonesURL:     String(""),
-		NotificationsURL:  String(""),
-		PullsURL:          String(""),
-		ReleasesURL:       String(""),
-		StargazersURL:     String(""),
-		StatusesURL:       String(""),
-		SubscribersURL:    String(""),
-		SubscriptionURL:   String(""),
-		TagsURL:           String(""),
-		TreesURL:          String(""),
-		TeamsURL:          String(""),
-	}
-	want := `github.Repository{ID:0, NodeID:"", Owner:github.User{}, Name:"", FullName:"", Description:"", Homepage:"", CodeOfConduct:github.CodeOfConduct{}, DefaultBranch:"", MasterBranch:"", CreatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, PushedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, UpdatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, HTMLURL:"", CloneURL:"", GitURL:"", MirrorURL:"", SSHURL:"", SVNURL:"", Language:"", Fork:false, ForksCount:0, NetworkCount:0, OpenIssuesCount:0, StargazersCount:0, SubscribersCount:0, WatchersCount:0, Size:0, AutoInit:false, Parent:github.Repository{}, Source:github.Repository{}, Organization:github.Organization{}, AllowRebaseMerge:false, AllowSquashMerge:false, AllowMergeCommit:false, Archived:false, Disabled:false, License:github.License{}, Private:false, HasIssues:false, HasWiki:false, HasPages:false, HasProjects:false, HasDownloads:false, LicenseTemplate:"", GitignoreTemplate:"", TeamID:0, URL:"", ArchiveURL:"", AssigneesURL:"", BlobsURL:"", BranchesURL:"", CollaboratorsURL:"", CommentsURL:"", CommitsURL:"", CompareURL:"", ContentsURL:"", ContributorsURL:"", DeploymentsURL:"", DownloadsURL:"", EventsURL:"", ForksURL:"", GitCommitsURL:"", GitRefsURL:"", GitTagsURL:"", HooksURL:"", IssueCommentURL:"", IssueEventsURL:"", IssuesURL:"", KeysURL:"", LabelsURL:"", LanguagesURL:"", MergesURL:"", MilestonesURL:"", NotificationsURL:"", PullsURL:"", ReleasesURL:"", StargazersURL:"", StatusesURL:"", SubscribersURL:"", SubscriptionURL:"", TagsURL:"", TreesURL:"", TeamsURL:""}`
+		ID:                 Int64(0),
+		NodeID:             String(""),
+		Owner:              &User{},
+		Name:               String(""),
+		FullName:           String(""),
+		Description:        String(""),
+		Homepage:           String(""),
+		CodeOfConduct:      &CodeOfConduct{},
+		DefaultBranch:      String(""),
+		MasterBranch:       String(""),
+		CreatedAt:          &Timestamp{},
+		PushedAt:           &Timestamp{},
+		UpdatedAt:          &Timestamp{},
+		HTMLURL:            String(""),
+		CloneURL:           String(""),
+		GitURL:             String(""),
+		MirrorURL:          String(""),
+		SSHURL:             String(""),
+		SVNURL:             String(""),
+		Language:           String(""),
+		Fork:               Bool(false),
+		ForksCount:         Int(0),
+		NetworkCount:       Int(0),
+		OpenIssuesCount:    Int(0),
+		StargazersCount:    Int(0),
+		SubscribersCount:   Int(0),
+		WatchersCount:      Int(0),
+		Size:               Int(0),
+		AutoInit:           Bool(false),
+		Parent:             &Repository{},
+		Source:             &Repository{},
+		TemplateRepository: &Repository{},
+		Organization:       &Organization{},
+		AllowRebaseMerge:   Bool(false),
+		AllowSquashMerge:   Bool(false),
+		AllowMergeCommit:   Bool(false),
+		Archived:           Bool(false),
+		Disabled:           Bool(false),
+		License:            &License{},
+		Private:            Bool(false),
+		HasIssues:          Bool(false),
+		HasWiki:            Bool(false),
+		HasPages:           Bool(false),
+		HasProjects:        Bool(false),
+		HasDownloads:       Bool(false),
+		IsTemplate:         Bool(false),
+		LicenseTemplate:    String(""),
+		GitignoreTemplate:  String(""),
+		TeamID:             Int64(0),
+		URL:                String(""),
+		ArchiveURL:         String(""),
+		AssigneesURL:       String(""),
+		BlobsURL:           String(""),
+		BranchesURL:        String(""),
+		CollaboratorsURL:   String(""),
+		CommentsURL:        String(""),
+		CommitsURL:         String(""),
+		CompareURL:         String(""),
+		ContentsURL:        String(""),
+		ContributorsURL:    String(""),
+		DeploymentsURL:     String(""),
+		DownloadsURL:       String(""),
+		EventsURL:          String(""),
+		ForksURL:           String(""),
+		GitCommitsURL:      String(""),
+		GitRefsURL:         String(""),
+		GitTagsURL:         String(""),
+		HooksURL:           String(""),
+		IssueCommentURL:    String(""),
+		IssueEventsURL:     String(""),
+		IssuesURL:          String(""),
+		KeysURL:            String(""),
+		LabelsURL:          String(""),
+		LanguagesURL:       String(""),
+		MergesURL:          String(""),
+		MilestonesURL:      String(""),
+		NotificationsURL:   String(""),
+		PullsURL:           String(""),
+		ReleasesURL:        String(""),
+		StargazersURL:      String(""),
+		StatusesURL:        String(""),
+		SubscribersURL:     String(""),
+		SubscriptionURL:    String(""),
+		TagsURL:            String(""),
+		TreesURL:           String(""),
+		TeamsURL:           String(""),
+	}
+	want := `github.Repository{ID:0, NodeID:"", Owner:github.User{}, Name:"", FullName:"", Description:"", Homepage:"", CodeOfConduct:github.CodeOfConduct{}, DefaultBranch:"", MasterBranch:"", CreatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, PushedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, UpdatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, HTMLURL:"", CloneURL:"", GitURL:"", MirrorURL:"", SSHURL:"", SVNURL:"", Language:"", Fork:false, ForksCount:0, NetworkCount:0, OpenIssuesCount:0, StargazersCount:0, SubscribersCount:0, WatchersCount:0, Size:0, AutoInit:false, Parent:github.Repository{}, Source:github.Repository{}, TemplateRepository:github.Repository{}, Organization:github.Organization{}, AllowRebaseMerge:false, AllowSquashMerge:false, AllowMergeCommit:false, Archived:false, Disabled:false, License:github.License{}, Private:false, HasIssues:false, HasWiki:false, HasPages:false, HasProjects:false, HasDownloads:false, IsTemplate:false, LicenseTemplate:"", GitignoreTemplate:"", TeamID:0, URL:"", ArchiveURL:"", AssigneesURL:"", BlobsURL:"", BranchesURL:"", CollaboratorsURL:"", CommentsURL:"", CommitsURL:"", CompareURL:"", ContentsURL:"", ContributorsURL:"", DeploymentsURL:"", DownloadsURL:"", EventsURL:"", ForksURL:"", GitCommitsURL:"", GitRefsURL:"", GitTagsURL:"", HooksURL:"", IssueCommentURL:"", IssueEventsURL:"", IssuesURL:"", KeysURL:"", LabelsURL:"", LanguagesURL:"", MergesURL:"", MilestonesURL:"", NotificationsURL:"", PullsURL:"", ReleasesURL:"", StargazersURL:"", StatusesURL:"", SubscribersURL:"", SubscriptionURL:"", TagsURL:"", TreesURL:"", TeamsURL:""}`
 	if got := v.String(); got != want {
 		t.Errorf("Repository.String = %v, want %v", got, want)
 	}
diff --git a/github/repos_test.go b/github/repos_test.go
index 75e09a83..75ccbb0d 100644
--- a/github/repos_test.go
+++ b/github/repos_test.go
@@ -253,6 +253,7 @@ func TestRepositoriesService_Create_user(t *testing.T) {
 		json.NewDecoder(r.Body).Decode(v)
 
 		testMethod(t, r, "POST")
+		testHeader(t, r, "Accept", mediaTypeRepositoryTemplatePreview)
 		want := &createRepoRequest{Name: String("n")}
 		if !reflect.DeepEqual(v, want) {
 			t.Errorf("Request body = %+v, want %+v", v, want)
@@ -314,6 +315,7 @@ func TestRepositoriesService_Create_org(t *testing.T) {
 		json.NewDecoder(r.Body).Decode(v)
 
 		testMethod(t, r, "POST")
+		testHeader(t, r, "Accept", mediaTypeRepositoryTemplatePreview)
 		want := &createRepoRequest{Name: String("n")}
 		if !reflect.DeepEqual(v, want) {
 			t.Errorf("Request body = %+v, want %+v", v, want)
@@ -333,11 +335,72 @@ func TestRepositoriesService_Create_org(t *testing.T) {
 	}
 }
 
+func TestRepositoriesService_CreateFromTemplate(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	templateRepoReq := &TemplateRepoRequest{
+		Name: String("n"),
+	}
+
+	mux.HandleFunc("/repos/to/tr/generate", func(w http.ResponseWriter, r *http.Request) {
+		v := new(TemplateRepoRequest)
+		json.NewDecoder(r.Body).Decode(v)
+
+		testMethod(t, r, "POST")
+		testHeader(t, r, "Accept", mediaTypeRepositoryTemplatePreview)
+		want := &TemplateRepoRequest{Name: String("n")}
+		if !reflect.DeepEqual(v, want) {
+			t.Errorf("Request body = %+v, want %+v", v, want)
+		}
+
+		fmt.Fprint(w, `{"id":1,"name":"n"}`)
+	})
+
+	ctx := context.Background()
+	got, _, err := client.Repositories.CreateFromTemplate(ctx, "to", "tr", templateRepoReq)
+	if err != nil {
+		t.Errorf("Repositories.CreateFromTemplate returned error: %v", err)
+	}
+
+	want := &Repository{ID: Int64(1), Name: String("n")}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("Repositories.CreateFromTemplate returned %+v, want %+v", got, want)
+	}
+
+	// Test s.client.NewRequest failure
+	client.BaseURL.Path = ""
+	got, resp, err := client.Repositories.CreateFromTemplate(ctx, "to", "tr", templateRepoReq)
+	if got != nil {
+		t.Errorf("client.BaseURL.Path='' CreateFromTemplate = %#v, want nil", got)
+	}
+	if resp != nil {
+		t.Errorf("client.BaseURL.Path='' CreateFromTemplate resp = %#v, want nil", resp)
+	}
+	if err == nil {
+		t.Error("client.BaseURL.Path='' CreateFromTemplate err = nil, want error")
+	}
+
+	// Test s.client.Do failure
+	client.BaseURL.Path = "/api-v3/"
+	client.rateLimits[0].Reset.Time = time.Now().Add(10 * time.Minute)
+	got, resp, err = client.Repositories.CreateFromTemplate(ctx, "to", "tr", templateRepoReq)
+	if got != nil {
+		t.Errorf("rate.Reset.Time > now CreateFromTemplate = %#v, want nil", got)
+	}
+	if want := http.StatusForbidden; resp == nil || resp.Response.StatusCode != want {
+		t.Errorf("rate.Reset.Time > now CreateFromTemplate resp = %#v, want StatusCode=%v", resp.Response, want)
+	}
+	if err == nil {
+		t.Error("rate.Reset.Time > now CreateFromTemplate err = nil, want error")
+	}
+}
+
 func TestRepositoriesService_Get(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
 
-	wantAcceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
+	wantAcceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview, mediaTypeRepositoryTemplatePreview}
 	mux.HandleFunc("/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "GET")
 		testHeader(t, r, "Accept", strings.Join(wantAcceptHeaders, ", "))
@@ -490,6 +553,7 @@ func TestRepositoriesService_Edit(t *testing.T) {
 		json.NewDecoder(r.Body).Decode(v)
 
 		testMethod(t, r, "PATCH")
+		testHeader(t, r, "Accept", mediaTypeRepositoryTemplatePreview)
 		if !reflect.DeepEqual(v, input) {
 			t.Errorf("Request body = %+v, want %+v", v, input)
 		}