Repository: google/go-github
Pull request #1602 (2020-08-14 13:57:54)

Update content type header for AppsService.CreateAttachment
While implementing the content attachment flow I found that the header needed to use this API has been changed. Included the link to the changes blog post referencing this.

codecov[bot]: # [Codecov](https://codecov.io/gh/google/go-github/pull/1602?src=pr&el=h1) Report
> Merging [#1602](https://codecov.io/gh/google/go-github/pull/1602?src=pr&el=desc) into [master](https://codecov.io/gh/google/go-github/commit/e19d4dd52119e904f326181ea091b575acf632c6&el=desc) will **increase** coverage by `5.15%`.
> The diff coverage is `100.00%`.

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

```diff
@@            Coverage Diff             @@
##           master    #1602      +/-   ##
==========================================
+ Coverage   67.98%   73.14%   +5.15%     
==========================================
  Files          96       96              
  Lines        8772     7057    -1715     
==========================================
- Hits         5964     5162     -802     
+ Misses       1898      985     -913     
  Partials      910      910              
```


| [Impacted Files](https://codecov.io/gh/google/go-github/pull/1602?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [github/github.go](https://codecov.io/gh/google/go-github/pull/1602/diff?src=pr&el=tree#diff-Z2l0aHViL2dpdGh1Yi5nbw==) | `89.77% <ø> (-0.14%)` | :arrow_down: |
| [github/apps.go](https://codecov.io/gh/google/go-github/pull/1602/diff?src=pr&el=tree#diff-Z2l0aHViL2FwcHMuZ28=) | `67.92% <100.00%> (+5.42%)` | :arrow_up: |
| [github/admin.go](https://codecov.io/gh/google/go-github/pull/1602/diff?src=pr&el=tree#diff-Z2l0aHViL2FkbWluLmdv) | `100.00% <0.00%> (ø)` | |
| [github/strings.go](https://codecov.io/gh/google/go-github/pull/1602/diff?src=pr&el=tree#diff-Z2l0aHViL3N0cmluZ3MuZ28=) | `100.00% <0.00%> (ø)` | |
| [github/activity.go](https://codecov.io/gh/google/go-github/pull/1602/diff?src=pr&el=tree#diff-Z2l0aHViL2FjdGl2aXR5Lmdv) | `100.00% <0.00%> (ø)` | |
| [github/timestamp.go](https://codecov.io/gh/google/go-github/pull/1602/diff?src=pr&el=tree#diff-Z2l0aHViL3RpbWVzdGFtcC5nbw==) | `100.00% <0.00%> (ø)` | |
| [github/admin\_stats.go](https://codecov.io/gh/google/go-github/pull/1602/diff?src=pr&el=tree#diff-Z2l0aHViL2FkbWluX3N0YXRzLmdv) | `100.00% <0.00%> (ø)` | |
| [github/repos\_traffic.go](https://codecov.io/gh/google/go-github/pull/1602/diff?src=pr&el=tree#diff-Z2l0aHViL3JlcG9zX3RyYWZmaWMuZ28=) | `100.00% <0.00%> (ø)` | |
| [github/pulls\_reviewers.go](https://codecov.io/gh/google/go-github/pull/1602/diff?src=pr&el=tree#diff-Z2l0aHViL3B1bGxzX3Jldmlld2Vycy5nbw==) | `100.00% <0.00%> (ø)` | |
| ... and [84 more](https://codecov.io/gh/google/go-github/pull/1602/diff?src=pr&el=tree-more) | |

------

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


Patch:
diff --git a/github/apps.go b/github/apps.go
index 45262c41..afbdd67f 100644
--- a/github/apps.go
+++ b/github/apps.go
@@ -291,7 +291,7 @@ func (s *AppsService) CreateAttachment(ctx context.Context, contentReferenceID i
 	}
 
 	// TODO: remove custom Accept headers when APIs fully launch.
-	req.Header.Set("Accept", mediaTypeReactionsPreview)
+	req.Header.Set("Accept", mediaTypeContentAttachmentsPreview)
 
 	m := &Attachment{}
 	resp, err := s.client.Do(ctx, req, m)
diff --git a/github/event.go b/github/event.go
index 3b96b029..6fcae541 100644
--- a/github/event.go
+++ b/github/event.go
@@ -118,6 +118,10 @@ func (e *Event) ParsePayload() (payload interface{}, err error) {
 		payload = &UserEvent{}
 	case "WatchEvent":
 		payload = &WatchEvent{}
+	case "WorkflowDispatchEvent":
+		payload = &WorkflowDispatchEvent{}
+	case "WorkflowRunEvent":
+		payload = &WorkflowRunEvent{}
 	}
 	err = json.Unmarshal(*e.RawPayload, &payload)
 	return payload, err
diff --git a/github/event_types.go b/github/event_types.go
index fe6991f5..171c8ea3 100644
--- a/github/event_types.go
+++ b/github/event_types.go
@@ -945,3 +945,30 @@ type WatchEvent struct {
 	Sender       *User         `json:"sender,omitempty"`
 	Installation *Installation `json:"installation,omitempty"`
 }
+
+// WorkflowDispatchEvent is triggered when someone triggers a workflow run on GitHub or
+// sends a POST request to the create a workflow dispatch event endpoint.
+//
+// GitHub API docs: https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#workflow_dispatch
+type WorkflowDispatchEvent struct {
+	Inputs   json.RawMessage `json:"inputs,omitempty"`
+	Ref      *string         `json:"ref,omitempty"`
+	Workflow *string         `json:"workflow,omitempty"`
+
+	// The following fields are only populated by Webhook events.
+	Repo   *Repository   `json:"repository,omitempty"`
+	Org    *Organization `json:"organization,omitempty"`
+	Sender *User         `json:"sender,omitempty"`
+}
+
+// WorkflowRunEvent is triggered when a GitHub Actions workflow run is requested or completed.
+//
+// GitHub API docs: https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#workflow_run
+type WorkflowRunEvent struct {
+	Action *string `json:"action,omitempty"`
+
+	// The following fields are only populated by Webhook events.
+	Org    *Organization `json:"organization,omitempty"`
+	Repo   *Repository   `json:"repository,omitempty"`
+	Sender *User         `json:"sender,omitempty"`
+}
diff --git a/github/github-accessors.go b/github/github-accessors.go
index 8e35c555..5e8fe2bf 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -1460,6 +1460,14 @@ func (c *CombinedStatus) GetTotalCount() int {
 	return *c.TotalCount
 }
 
+// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
+func (c *Comment) GetCreatedAt() time.Time {
+	if c == nil || c.CreatedAt == nil {
+		return time.Time{}
+	}
+	return *c.CreatedAt
+}
+
 // GetTotalCommitComments returns the TotalCommitComments field if it's non-nil, zero value otherwise.
 func (c *CommentStats) GetTotalCommitComments() int {
 	if c == nil || c.TotalCommitComments == nil {
@@ -5084,6 +5092,166 @@ func (i *IssueEvent) GetURL() string {
 	return *i.URL
 }
 
+// GetAssignee returns the Assignee field if it's non-nil, zero value otherwise.
+func (i *IssueImport) GetAssignee() string {
+	if i == nil || i.Assignee == nil {
+		return ""
+	}
+	return *i.Assignee
+}
+
+// GetClosed returns the Closed field if it's non-nil, zero value otherwise.
+func (i *IssueImport) GetClosed() bool {
+	if i == nil || i.Closed == nil {
+		return false
+	}
+	return *i.Closed
+}
+
+// GetClosedAt returns the ClosedAt field if it's non-nil, zero value otherwise.
+func (i *IssueImport) GetClosedAt() time.Time {
+	if i == nil || i.ClosedAt == nil {
+		return time.Time{}
+	}
+	return *i.ClosedAt
+}
+
+// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
+func (i *IssueImport) GetCreatedAt() time.Time {
+	if i == nil || i.CreatedAt == nil {
+		return time.Time{}
+	}
+	return *i.CreatedAt
+}
+
+// GetMilestone returns the Milestone field if it's non-nil, zero value otherwise.
+func (i *IssueImport) GetMilestone() int {
+	if i == nil || i.Milestone == nil {
+		return 0
+	}
+	return *i.Milestone
+}
+
+// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
+func (i *IssueImport) GetUpdatedAt() time.Time {
+	if i == nil || i.UpdatedAt == nil {
+		return time.Time{}
+	}
+	return *i.UpdatedAt
+}
+
+// GetCode returns the Code field if it's non-nil, zero value otherwise.
+func (i *IssueImportError) GetCode() string {
+	if i == nil || i.Code == nil {
+		return ""
+	}
+	return *i.Code
+}
+
+// GetField returns the Field field if it's non-nil, zero value otherwise.
+func (i *IssueImportError) GetField() string {
+	if i == nil || i.Field == nil {
+		return ""
+	}
+	return *i.Field
+}
+
+// GetLocation returns the Location field if it's non-nil, zero value otherwise.
+func (i *IssueImportError) GetLocation() string {
+	if i == nil || i.Location == nil {
+		return ""
+	}
+	return *i.Location
+}
+
+// GetResource returns the Resource field if it's non-nil, zero value otherwise.
+func (i *IssueImportError) GetResource() string {
+	if i == nil || i.Resource == nil {
+		return ""
+	}
+	return *i.Resource
+}
+
+// GetValue returns the Value field if it's non-nil, zero value otherwise.
+func (i *IssueImportError) GetValue() string {
+	if i == nil || i.Value == nil {
+		return ""
+	}
+	return *i.Value
+}
+
+// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
+func (i *IssueImportResponse) GetCreatedAt() time.Time {
+	if i == nil || i.CreatedAt == nil {
+		return time.Time{}
+	}
+	return *i.CreatedAt
+}
+
+// GetDocumentationURL returns the DocumentationURL field if it's non-nil, zero value otherwise.
+func (i *IssueImportResponse) GetDocumentationURL() string {
+	if i == nil || i.DocumentationURL == nil {
+		return ""
+	}
+	return *i.DocumentationURL
+}
+
+// GetID returns the ID field if it's non-nil, zero value otherwise.
+func (i *IssueImportResponse) GetID() int {
+	if i == nil || i.ID == nil {
+		return 0
+	}
+	return *i.ID
+}
+
+// GetImportIssuesURL returns the ImportIssuesURL field if it's non-nil, zero value otherwise.
+func (i *IssueImportResponse) GetImportIssuesURL() string {
+	if i == nil || i.ImportIssuesURL == nil {
+		return ""
+	}
+	return *i.ImportIssuesURL
+}
+
+// GetMessage returns the Message field if it's non-nil, zero value otherwise.
+func (i *IssueImportResponse) GetMessage() string {
+	if i == nil || i.Message == nil {
+		return ""
+	}
+	return *i.Message
+}
+
+// GetRepositoryURL returns the RepositoryURL field if it's non-nil, zero value otherwise.
+func (i *IssueImportResponse) GetRepositoryURL() string {
+	if i == nil || i.RepositoryURL == nil {
+		return ""
+	}
+	return *i.RepositoryURL
+}
+
+// GetStatus returns the Status field if it's non-nil, zero value otherwise.
+func (i *IssueImportResponse) GetStatus() string {
+	if i == nil || i.Status == nil {
+		return ""
+	}
+	return *i.Status
+}
+
+// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
+func (i *IssueImportResponse) GetUpdatedAt() time.Time {
+	if i == nil || i.UpdatedAt == nil {
+		return time.Time{}
+	}
+	return *i.UpdatedAt
+}
+
+// GetURL returns the URL field if it's non-nil, zero value otherwise.
+func (i *IssueImportResponse) GetURL() string {
+	if i == nil || i.URL == nil {
+		return ""
+	}
+	return *i.URL
+}
+
 // GetSince returns the Since field if it's non-nil, zero value otherwise.
 func (i *IssueListCommentsOptions) GetSince() time.Time {
 	if i == nil || i.Since == nil {
@@ -14892,6 +15060,46 @@ func (w *WorkflowBill) GetTotalMS() int64 {
 	return *w.TotalMS
 }
 
+// GetOrg returns the Org field.
+func (w *WorkflowDispatchEvent) GetOrg() *Organization {
+	if w == nil {
+		return nil
+	}
+	return w.Org
+}
+
+// GetRef returns the Ref field if it's non-nil, zero value otherwise.
+func (w *WorkflowDispatchEvent) GetRef() string {
+	if w == nil || w.Ref == nil {
+		return ""
+	}
+	return *w.Ref
+}
+
+// GetRepo returns the Repo field.
+func (w *WorkflowDispatchEvent) GetRepo() *Repository {
+	if w == nil {
+		return nil
+	}
+	return w.Repo
+}
+
+// GetSender returns the Sender field.
+func (w *WorkflowDispatchEvent) GetSender() *User {
+	if w == nil {
+		return nil
+	}
+	return w.Sender
+}
+
+// GetWorkflow returns the Workflow field if it's non-nil, zero value otherwise.
+func (w *WorkflowDispatchEvent) GetWorkflow() string {
+	if w == nil || w.Workflow == nil {
+		return ""
+	}
+	return *w.Workflow
+}
+
 // GetMacOS returns the MacOS field.
 func (w *WorkflowEnvironment) GetMacOS() *WorkflowBill {
 	if w == nil {
@@ -15244,6 +15452,38 @@ func (w *WorkflowRunEnvironment) GetWindows() *WorkflowRunBill {
 	return w.Windows
 }
 
+// GetAction returns the Action field if it's non-nil, zero value otherwise.
+func (w *WorkflowRunEvent) GetAction() string {
+	if w == nil || w.Action == nil {
+		return ""
+	}
+	return *w.Action
+}
+
+// GetOrg returns the Org field.
+func (w *WorkflowRunEvent) GetOrg() *Organization {
+	if w == nil {
+		return nil
+	}
+	return w.Org
+}
+
+// GetRepo returns the Repo field.
+func (w *WorkflowRunEvent) GetRepo() *Repository {
+	if w == nil {
+		return nil
+	}
+	return w.Repo
+}
+
+// GetSender returns the Sender field.
+func (w *WorkflowRunEvent) GetSender() *User {
+	if w == nil {
+		return nil
+	}
+	return w.Sender
+}
+
 // GetTotalCount returns the TotalCount field if it's non-nil, zero value otherwise.
 func (w *WorkflowRuns) GetTotalCount() int {
 	if w == nil || w.TotalCount == nil {
diff --git a/github/github.go b/github/github.go
index fc642dc9..5d20d6d3 100644
--- a/github/github.go
+++ b/github/github.go
@@ -43,6 +43,7 @@ const (
 	mediaTypeV3Diff            = "application/vnd.github.v3.diff"
 	mediaTypeV3Patch           = "application/vnd.github.v3.patch"
 	mediaTypeOrgPermissionRepo = "application/vnd.github.v3.repository+json"
+	mediaTypeIssueImportAPI    = "application/vnd.github.golden-comet-preview+json"
 
 	// Media Type values to access preview APIs
 
@@ -135,6 +136,9 @@ const (
 
 	// https://developer.github.com/changes/2019-12-03-internal-visibility-changes/
 	mediaTypeRepositoryVisibilityPreview = "application/vnd.github.nebula-preview+json"
+
+	// https://developer.github.com/changes/2018-12-10-content-attachments-api/
+	mediaTypeContentAttachmentsPreview = "application/vnd.github.corsair-preview+json"
 )
 
 // A Client manages communication with the GitHub API.
@@ -170,6 +174,7 @@ type Client struct {
 	Git            *GitService
 	Gitignores     *GitignoresService
 	Interactions   *InteractionsService
+	IssueImport    *IssueImportService
 	Issues         *IssuesService
 	Licenses       *LicensesService
 	Marketplace    *MarketplaceService
@@ -277,6 +282,7 @@ func NewClient(httpClient *http.Client) *Client {
 	c.Git = (*GitService)(&c.common)
 	c.Gitignores = (*GitignoresService)(&c.common)
 	c.Interactions = (*InteractionsService)(&c.common)
+	c.IssueImport = (*IssueImportService)(&c.common)
 	c.Issues = (*IssuesService)(&c.common)
 	c.Licenses = (*LicensesService)(&c.common)
 	c.Marketplace = &MarketplaceService{client: c}
diff --git a/github/issue_import.go b/github/issue_import.go
new file mode 100644
index 00000000..a9810407
--- /dev/null
+++ b/github/issue_import.go
@@ -0,0 +1,152 @@
+// Copyright 2020 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"time"
+)
+
+// IssueImportService handles communication with the issue import related
+// methods of the Issue Import GitHub API.
+type IssueImportService service
+
+// IssueImportRequest represents a request to create an issue.
+//
+// https://gist.github.com/jonmagic/5282384165e0f86ef105#supported-issue-and-comment-fields
+type IssueImportRequest struct {
+	IssueImport IssueImport `json:"issue"`
+	Comments    []*Comment  `json:"comments,omitempty"`
+}
+
+// IssueImport represents body of issue to import.
+type IssueImport struct {
+	Title     string     `json:"title"`
+	Body      string     `json:"body"`
+	CreatedAt *time.Time `json:"created_at,omitempty"`
+	ClosedAt  *time.Time `json:"closed_at,omitempty"`
+	UpdatedAt *time.Time `json:"updated_at,omitempty"`
+	Assignee  *string    `json:"assignee,omitempty"`
+	Milestone *int       `json:"milestone,omitempty"`
+	Closed    *bool      `json:"closed,omitempty"`
+	Labels    []string   `json:"labels,omitempty"`
+}
+
+// Comment represents comments of issue to import.
+type Comment struct {
+	CreatedAt *time.Time `json:"created_at,omitempty"`
+	Body      string     `json:"body"`
+}
+
+// IssueImportResponse represents the response of an issue import create request.
+//
+// https://gist.github.com/jonmagic/5282384165e0f86ef105#import-issue-response
+type IssueImportResponse struct {
+	ID               *int                `json:"id,omitempty"`
+	Status           *string             `json:"status,omitempty"`
+	URL              *string             `json:"url,omitempty"`
+	ImportIssuesURL  *string             `json:"import_issues_url,omitempty"`
+	RepositoryURL    *string             `json:"repository_url,omitempty"`
+	CreatedAt        *time.Time          `json:"created_at,omitempty"`
+	UpdatedAt        *time.Time          `json:"updated_at,omitempty"`
+	Message          *string             `json:"message,omitempty"`
+	DocumentationURL *string             `json:"documentation_url,omitempty"`
+	Errors           []*IssueImportError `json:"errors,omitempty"`
+}
+
+// IssueImportError represents errors of an issue import create request.
+type IssueImportError struct {
+	Location *string `json:"location,omitempty"`
+	Resource *string `json:"resource,omitempty"`
+	Field    *string `json:"field,omitempty"`
+	Value    *string `json:"value,omitempty"`
+	Code     *string `json:"code,omitempty"`
+}
+
+// Create a new imported issue on the specified repository.
+//
+// https://gist.github.com/jonmagic/5282384165e0f86ef105#start-an-issue-import
+func (s *IssueImportService) Create(ctx context.Context, owner, repo string, issue *IssueImportRequest) (*IssueImportResponse, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/import/issues", owner, repo)
+	req, err := s.client.NewRequest("POST", u, issue)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// TODO: remove custom Accept headers when APIs fully launch.
+	req.Header.Set("Accept", mediaTypeIssueImportAPI)
+
+	i := new(IssueImportResponse)
+	resp, err := s.client.Do(ctx, req, i)
+	if err != nil {
+		aerr, ok := err.(*AcceptedError)
+		if ok {
+			decErr := json.Unmarshal(aerr.Raw, i)
+			if decErr != nil {
+				err = decErr
+			}
+
+			return i, resp, nil
+		}
+
+		return nil, resp, err
+	}
+
+	return i, resp, nil
+}
+
+// CheckStatus checks the status of an imported issue.
+//
+// https://gist.github.com/jonmagic/5282384165e0f86ef105#import-status-request
+func (s *IssueImportService) CheckStatus(ctx context.Context, owner, repo string, issueID int64) (*IssueImportResponse, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/import/issues/%v", owner, repo, issueID)
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// TODO: remove custom Accept headers when APIs fully launch.
+	req.Header.Set("Accept", mediaTypeIssueImportAPI)
+
+	i := new(IssueImportResponse)
+	resp, err := s.client.Do(ctx, req, i)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return i, resp, nil
+}
+
+// CheckStatusSince checks the status of multiple imported issues since a given date.
+//
+// https://gist.github.com/jonmagic/5282384165e0f86ef105#check-status-of-multiple-issues
+func (s *IssueImportService) CheckStatusSince(ctx context.Context, owner, repo string, since time.Time) ([]*IssueImportResponse, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/import/issues?since=%v", owner, repo, since.Format("2006-01-02"))
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// TODO: remove custom Accept headers when APIs fully launch.
+	req.Header.Set("Accept", mediaTypeIssueImportAPI)
+
+	var b bytes.Buffer
+	resp, err := s.client.Do(ctx, req, &b)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	var i []*IssueImportResponse
+	err = json.Unmarshal(b.Bytes(), &i)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return i, resp, nil
+}
diff --git a/github/messages.go b/github/messages.go
index 2c1c7a7e..424a961c 100644
--- a/github/messages.go
+++ b/github/messages.go
@@ -85,6 +85,8 @@ var (
 		"team_add":                       "TeamAddEvent",
 		"user":                           "UserEvent",
 		"watch":                          "WatchEvent",
+		"workflow_dispatch":              "WorkflowDispatchEvent",
+		"workflow_run":                   "WorkflowRunEvent",
 	}
 )
 


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index bf3f173c..ef4830e9 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -7,7 +7,7 @@ jobs:
   test:
     strategy:
       matrix:
-        go-version: [1.x, 1.13.x]
+        go-version: [1.x, 1.14.x]
         platform: [ubuntu-latest, windows-latest]
     runs-on: ${{ matrix.platform }}
 
diff --git a/github/apps_test.go b/github/apps_test.go
index e80a2986..6610482f 100644
--- a/github/apps_test.go
+++ b/github/apps_test.go
@@ -328,7 +328,7 @@ func TestAppsService_CreateAttachement(t *testing.T) {
 
 	mux.HandleFunc("/content_references/11/attachments", func(w http.ResponseWriter, r *http.Request) {
 		testMethod(t, r, "POST")
-		testHeader(t, r, "Accept", mediaTypeReactionsPreview)
+		testHeader(t, r, "Accept", mediaTypeContentAttachmentsPreview)
 
 		w.WriteHeader(http.StatusOK)
 		w.Write([]byte(`{"id":1,"title":"title1","body":"body1"}`))
diff --git a/github/issue_import_test.go b/github/issue_import_test.go
new file mode 100644
index 00000000..5948ef44
--- /dev/null
+++ b/github/issue_import_test.go
@@ -0,0 +1,144 @@
+// Copyright 2020 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestIssueImportService_Create(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	createdAt := time.Date(2020, time.August, 11, 15, 30, 0, 0, time.UTC)
+	input := &IssueImportRequest{
+		IssueImport: IssueImport{
+			Assignee:  String("developer"),
+			Body:      "Dummy description",
+			CreatedAt: &createdAt,
+			Labels:    []string{"l1", "l2"},
+			Milestone: Int(1),
+			Title:     "Dummy Issue",
+		},
+		Comments: []*Comment{{
+			CreatedAt: &createdAt,
+			Body:      "Comment body",
+		}},
+	}
+
+	mux.HandleFunc("/repos/o/r/import/issues", func(w http.ResponseWriter, r *http.Request) {
+		v := new(IssueImportRequest)
+		json.NewDecoder(r.Body).Decode(v)
+		testMethod(t, r, "POST")
+		testHeader(t, r, "Accept", mediaTypeIssueImportAPI)
+		if !reflect.DeepEqual(v, input) {
+			t.Errorf("Request body = %+v, want %+v", v, input)
+		}
+
+		w.WriteHeader(http.StatusAccepted)
+		w.Write(issueImportResponseJSON)
+	})
+
+	got, _, err := client.IssueImport.Create(context.Background(), "o", "r", input)
+	if err != nil {
+		t.Errorf("Create returned error: %v", err)
+	}
+
+	want := wantIssueImportResponse
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("Create = %+v, want %+v", got, want)
+	}
+}
+
+func TestIssueImportService_Create_invalidOwner(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	_, _, err := client.IssueImport.Create(context.Background(), "%", "r", nil)
+	testURLParseError(t, err)
+}
+
+func TestIssueImportService_CheckStatus(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/import/issues/3", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeIssueImportAPI)
+		w.WriteHeader(http.StatusOK)
+		w.Write(issueImportResponseJSON)
+	})
+
+	got, _, err := client.IssueImport.CheckStatus(context.Background(), "o", "r", 3)
+	if err != nil {
+		t.Errorf("CheckStatus returned error: %v", err)
+	}
+
+	want := wantIssueImportResponse
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("CheckStatus = %+v, want %+v", got, want)
+	}
+}
+
+func TestIssueImportService_CheckStatus_invalidOwner(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	_, _, err := client.IssueImport.CheckStatus(context.Background(), "%", "r", 1)
+	testURLParseError(t, err)
+}
+
+func TestIssueImportService_CheckStatusSince(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/import/issues", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testHeader(t, r, "Accept", mediaTypeIssueImportAPI)
+		w.WriteHeader(http.StatusOK)
+		w.Write([]byte(fmt.Sprintf("[%s]", issueImportResponseJSON)))
+	})
+
+	got, _, err := client.IssueImport.CheckStatusSince(context.Background(), "o", "r", time.Now())
+	if err != nil {
+		t.Errorf("CheckStatusSince returned error: %v", err)
+	}
+
+	want := []*IssueImportResponse{wantIssueImportResponse}
+	if !reflect.DeepEqual(want, got) {
+		t.Errorf("CheckStatusSince = %v, want = %v", got, want)
+	}
+}
+
+func TestIssueImportService_CheckStatusSince_invalidOwner(t *testing.T) {
+	client, _, _, teardown := setup()
+	defer teardown()
+
+	_, _, err := client.IssueImport.CheckStatusSince(context.Background(), "%", "r", time.Now())
+	testURLParseError(t, err)
+}
+
+var issueImportResponseJSON = []byte(`{
+	"id": 3,
+	"status": "pending",
+	"url": "https://api.github.com/repos/o/r/import/issues/3",
+	"import_issues_url": "https://api.github.com/repos/o/r/import/issues",
+	"repository_url": "https://api.github.com/repos/o/r"
+}`)
+
+var wantIssueImportResponse = &IssueImportResponse{
+	ID:              Int(3),
+	Status:          String("pending"),
+	URL:             String("https://api.github.com/repos/o/r/import/issues/3"),
+	ImportIssuesURL: String("https://api.github.com/repos/o/r/import/issues"),
+	RepositoryURL:   String("https://api.github.com/repos/o/r"),
+}
diff --git a/github/licenses_test.go b/github/licenses_test.go
index a71f6a4e..5446ffd1 100644
--- a/github/licenses_test.go
+++ b/github/licenses_test.go
@@ -13,6 +13,100 @@ import (
 	"testing"
 )
 
+func TestRepositoryLicense_marshal(t *testing.T) {
+	testJSONMarshal(t, &RepositoryLicense{}, "{}")
+
+	rl := &RepositoryLicense{
+		Name:        String("n"),
+		Path:        String("p"),
+		SHA:         String("s"),
+		Size:        Int(1),
+		URL:         String("u"),
+		HTMLURL:     String("h"),
+		GitURL:      String("g"),
+		DownloadURL: String("d"),
+		Type:        String("t"),
+		Content:     String("c"),
+		Encoding:    String("e"),
+		License: &License{
+			Key:            String("k"),
+			Name:           String("n"),
+			URL:            String("u"),
+			SPDXID:         String("s"),
+			HTMLURL:        String("h"),
+			Featured:       Bool(true),
+			Description:    String("d"),
+			Implementation: String("i"),
+			Permissions:    &[]string{"p"},
+			Conditions:     &[]string{"c"},
+			Limitations:    &[]string{"l"},
+			Body:           String("b"),
+		},
+	}
+	want := `{
+		"name": "n",
+		"path": "p",
+		"sha": "s",
+		"size": 1,
+		"url": "u",
+		"html_url": "h",
+		"git_url": "g",
+		"download_url": "d",
+		"type": "t",
+		"content": "c",
+		"encoding": "e",
+		"license": {
+			"key": "k",
+			"name": "n",
+			"url": "u",
+			"spdx_id": "s",
+			"html_url": "h",
+			"featured": true,
+			"description": "d",
+			"implementation": "i",
+			"permissions": ["p"],
+			"conditions": ["c"],
+			"limitations": ["l"],
+			"body": "b"
+		}
+	}`
+	testJSONMarshal(t, rl, want)
+}
+
+func TestLicense_marshal(t *testing.T) {
+	testJSONMarshal(t, &License{}, "{}")
+
+	l := &License{
+		Key:            String("k"),
+		Name:           String("n"),
+		URL:            String("u"),
+		SPDXID:         String("s"),
+		HTMLURL:        String("h"),
+		Featured:       Bool(true),
+		Description:    String("d"),
+		Implementation: String("i"),
+		Permissions:    &[]string{"p"},
+		Conditions:     &[]string{"c"},
+		Limitations:    &[]string{"l"},
+		Body:           String("b"),
+	}
+	want := `{
+		"key": "k",
+		"name": "n",
+		"url": "u",
+		"spdx_id": "s",
+		"html_url": "h",
+		"featured": true,
+		"description": "d",
+		"implementation": "i",
+		"permissions": ["p"],
+		"conditions": ["c"],
+		"limitations": ["l"],
+		"body": "b"
+	}`
+	testJSONMarshal(t, l, want)
+}
+
 func TestLicensesService_List(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
diff --git a/github/messages_test.go b/github/messages_test.go
index 9a0fd74a..5f5a4c1b 100644
--- a/github/messages_test.go
+++ b/github/messages_test.go
@@ -359,6 +359,14 @@ func TestParseWebHook(t *testing.T) {
 			payload:     &RepositoryDispatchEvent{},
 			messageType: "repository_dispatch",
 		},
+		{
+			payload:     &WorkflowDispatchEvent{},
+			messageType: "workflow_dispatch",
+		},
+		{
+			payload:     &WorkflowRunEvent{},
+			messageType: "workflow_run",
+		},
 	}
 
 	for _, test := range tests {