Repository: google/go-github
Pull request #1545 (2020-05-30 17:40:11)

Add support for Code Scanning API
Adds a Code Scanning service with functions for getting code scanning alerts.

Docs: https://developer.github.com/v3/code-scanning/

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

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

```diff
@@            Coverage Diff             @@
##           master    #1545      +/-   ##
==========================================
+ Coverage   67.92%   73.05%   +5.12%     
==========================================
  Files          94       95       +1     
  Lines        8670     7002    -1668     
==========================================
- Hits         5889     5115     -774     
+ Misses       1880      981     -899     
- Partials      901      906       +5     
```


| [Impacted Files](https://codecov.io/gh/google/go-github/pull/1545?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [github/authorizations.go](https://codecov.io/gh/google/go-github/pull/1545/diff?src=pr&el=tree#diff-Z2l0aHViL2F1dGhvcml6YXRpb25zLmdv) | `75.67% <ø> (+4.09%)` | :arrow_up: |
| [github/code-scanning.go](https://codecov.io/gh/google/go-github/pull/1545/diff?src=pr&el=tree#diff-Z2l0aHViL2NvZGUtc2Nhbm5pbmcuZ28=) | `56.52% <56.52%> (ø)` | |
| [github/github.go](https://codecov.io/gh/google/go-github/pull/1545/diff?src=pr&el=tree#diff-Z2l0aHViL2dpdGh1Yi5nbw==) | `89.65% <100.00%> (ø)` | |
| [github/admin.go](https://codecov.io/gh/google/go-github/pull/1545/diff?src=pr&el=tree#diff-Z2l0aHViL2FkbWluLmdv) | `100.00% <0.00%> (ø)` | |
| [github/strings.go](https://codecov.io/gh/google/go-github/pull/1545/diff?src=pr&el=tree#diff-Z2l0aHViL3N0cmluZ3MuZ28=) | `100.00% <0.00%> (ø)` | |
| [github/activity.go](https://codecov.io/gh/google/go-github/pull/1545/diff?src=pr&el=tree#diff-Z2l0aHViL2FjdGl2aXR5Lmdv) | `100.00% <0.00%> (ø)` | |
| [github/timestamp.go](https://codecov.io/gh/google/go-github/pull/1545/diff?src=pr&el=tree#diff-Z2l0aHViL3RpbWVzdGFtcC5nbw==) | `100.00% <0.00%> (ø)` | |
| [github/admin\_stats.go](https://codecov.io/gh/google/go-github/pull/1545/diff?src=pr&el=tree#diff-Z2l0aHViL2FkbWluX3N0YXRzLmdv) | `100.00% <0.00%> (ø)` | |
| [github/repos\_traffic.go](https://codecov.io/gh/google/go-github/pull/1545/diff?src=pr&el=tree#diff-Z2l0aHViL3JlcG9zX3RyYWZmaWMuZ28=) | `100.00% <0.00%> (ø)` | |
| ... and [85 more](https://codecov.io/gh/google/go-github/pull/1545/diff?src=pr&el=tree-more) | |

------

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

nightlark: Should we wait until GitHub support responds with an answer for the `closed_by` field format, leave it as is for now, or switch it to `*User`?
gmlewis: Hmmm... good question.  We already have a breaking change in the queue, unfortunately, immediately after the release of `v32.0.0`, so we could proceed with what we have here and then update it (if necessary) when we hear back from GitHub tech support... all before the release of `v33.0.0`.  I'm fine with that if you are OK with that.  But if you would prefer to wait, I'm totally fine with that too.
nightlark: Updating when we hear back if needed would be okay. If I hear back before the next LGTM I'll update the PR.

Patch:
diff --git a/example/basicauth/main.go b/example/basicauth/main.go
index 021c1d20..0bf7e674 100644
--- a/example/basicauth/main.go
+++ b/example/basicauth/main.go
@@ -6,6 +6,12 @@
 // The basicauth command demonstrates using the github.BasicAuthTransport,
 // including handling two-factor authentication. This won't currently work for
 // accounts that use SMS to receive one-time passwords.
+//
+// Deprecation Notice: GitHub will discontinue password authentication to the API.
+// You must now authenticate to the GitHub API with an API token, such as an OAuth access token,
+// GitHub App installation access token, or personal access token, depending on what you need to do with the token.
+// Password authentication to the API will be removed on November 13, 2020.
+// See the tokenauth example for details.
 package main
 
 import (
diff --git a/example/commitpr/main.go b/example/commitpr/main.go
index 2c7ff213..13f9dc35 100644
--- a/example/commitpr/main.go
+++ b/example/commitpr/main.go
@@ -122,7 +122,7 @@ func getFileContent(fileArg string) (targetName string, b []byte, err error) {
 	return targetName, b, err
 }
 
-// createCommit creates the commit in the given reference using the given tree.
+// pushCommit creates the commit in the given reference using the given tree.
 func pushCommit(ref *github.Reference, tree *github.Tree) (err error) {
 	// Get the parent commit to attach the commit to.
 	parent, _, err := client.Repositories.GetCommit(ctx, *sourceOwner, *sourceRepo, *ref.Object.SHA)
diff --git a/example/tokenauth/main.go b/example/tokenauth/main.go
new file mode 100644
index 00000000..92280262
--- /dev/null
+++ b/example/tokenauth/main.go
@@ -0,0 +1,40 @@
+// 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.
+
+// The tokenauth command demonstrates using the oauth2.StaticTokenSource.
+package main
+
+import (
+	"context"
+	"fmt"
+	"syscall"
+
+	"github.com/google/go-github/v32/github"
+	"golang.org/x/crypto/ssh/terminal"
+	"golang.org/x/oauth2"
+)
+
+func main() {
+	fmt.Print("GitHub Token: ")
+	byteToken, _ := terminal.ReadPassword(int(syscall.Stdin))
+	token := string(byteToken)
+
+	ctx := context.Background()
+	ts := oauth2.StaticTokenSource(
+		&oauth2.Token{AccessToken: token},
+	)
+	tc := oauth2.NewClient(ctx, ts)
+
+	client := github.NewClient(tc)
+
+	user, _, err := client.Users.Get(ctx, "")
+
+	if err != nil {
+		fmt.Printf("\nerror: %v\n", err)
+		return
+	}
+
+	fmt.Printf("\n%v\n", github.Stringify(user))
+}
diff --git a/github/actions_workflow_runs.go b/github/actions_workflow_runs.go
index 14d6cd34..47305797 100644
--- a/github/actions_workflow_runs.go
+++ b/github/actions_workflow_runs.go
@@ -22,6 +22,7 @@ type WorkflowRun struct {
 	Event          *string        `json:"event,omitempty"`
 	Status         *string        `json:"status,omitempty"`
 	Conclusion     *string        `json:"conclusion,omitempty"`
+	WorkflowID     *int64         `json:"workflow_id,omitempty"`
 	URL            *string        `json:"url,omitempty"`
 	HTMLURL        *string        `json:"html_url,omitempty"`
 	PullRequests   []*PullRequest `json:"pull_requests,omitempty"`
diff --git a/github/authorizations.go b/github/authorizations.go
index 7447e2fb..ad31ebf2 100644
--- a/github/authorizations.go
+++ b/github/authorizations.go
@@ -41,6 +41,7 @@ const (
 	ScopeReadGPGKey     Scope = "read:gpg_key"
 	ScopeWriteGPGKey    Scope = "write:gpg_key"
 	ScopeAdminGPGKey    Scope = "admin:gpg_key"
+	ScopeSecurityEvents Scope = "security_events"
 )
 
 // AuthorizationsService handles communication with the authorization related
diff --git a/github/code-scanning.go b/github/code-scanning.go
new file mode 100644
index 00000000..dc57a890
--- /dev/null
+++ b/github/code-scanning.go
@@ -0,0 +1,117 @@
+// Copyright 2020 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// CodeScanningService handles communication with the code scanning related
+// methods of the GitHub API.
+//
+// GitHub API docs: https://developer.github.com/v3/code-scanning/
+type CodeScanningService service
+
+type Alert struct {
+	RuleID          *string    `json:"rule_id,omitempty"`
+	RuleSeverity    *string    `json:"rule_severity,omitempty"`
+	RuleDescription *string    `json:"rule_description,omitempty"`
+	Tool            *string    `json:"tool,omitempty"`
+	CreatedAt       *Timestamp `json:"created_at,omitempty"`
+	Open            *bool      `json:"open,omitempty"`
+	ClosedBy        *User      `json:"closed_by,omitempty"`
+	ClosedAt        *Timestamp `json:"closed_at,omitempty"`
+	URL             *string    `json:"url,omitempty"`
+	HTMLURL         *string    `json:"html_url,omitempty"`
+}
+
+// ID returns the ID associated with an alert. It is the number at the end of the security alert's URL.
+func (a *Alert) ID() int64 {
+	if a == nil {
+		return 0
+	}
+
+	s := a.GetHTMLURL()
+
+	// Check for an ID to parse at the end of the url
+	if i := strings.LastIndex(s, "/"); i >= 0 {
+		s = s[i+1:]
+	}
+
+	// Return the alert ID as a 64-bit integer. Unable to convert or out of range returns 0.
+	id, err := strconv.ParseInt(s, 10, 64)
+	if err != nil {
+		return 0
+	}
+
+	return id
+}
+
+// AlertListOptions specifies optional parameters to the CodeScanningService.ListAlerts
+// method.
+type AlertListOptions struct {
+	// State of the code scanning alerts to list. Set to closed to list only closed code scanning alerts. Default: open
+	State string `url:"state,omitempty"`
+
+	// Return code scanning alerts for a specific branch reference. The ref must be formatted as heads/<branch name>.
+	Ref string `url:"ref,omitempty"`
+}
+
+// ListAlertsForRepo lists code scanning alerts for a repository.
+//
+// Lists all open code scanning alerts for the default branch (usually master) and protected branches in a repository.
+// You must use an access token with the security_events scope to use this endpoint. GitHub Apps must have the security_events
+// read permission to use this endpoint.
+//
+// GitHub API docs: https://developer.github.com/v3/code-scanning/#list-code-scanning-alerts-for-a-repository
+func (s *CodeScanningService) ListAlertsForRepo(ctx context.Context, owner, repo string, opts *AlertListOptions) ([]*Alert, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/code-scanning/alerts", owner, repo)
+	u, err := addOptions(u, opts)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var alerts []*Alert
+	resp, err := s.client.Do(ctx, req, &alerts)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return alerts, resp, nil
+}
+
+// GetAlert gets a single code scanning alert for a repository.
+//
+// You must use an access token with the security_events scope to use this endpoint.
+// GitHub Apps must have the security_events read permission to use this endpoint.
+//
+// The security alert_id is the number at the end of the security alert's URL.
+//
+// GitHub API docs: https://developer.github.com/v3/code-scanning/#get-a-code-scanning-alert
+func (s *CodeScanningService) GetAlert(ctx context.Context, owner, repo string, id int64) (*Alert, *Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/code-scanning/alerts/%v", owner, repo, id)
+
+	req, err := s.client.NewRequest("GET", u, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	a := new(Alert)
+	resp, err := s.client.Do(ctx, req, a)
+	if err != nil {
+		return nil, resp, err
+	}
+
+	return a, resp, nil
+}
diff --git a/github/github-accessors.go b/github/github-accessors.go
index 4489e4dc..c2a158f1 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -108,6 +108,86 @@ func (a *AdminStats) GetUsers() *UserStats {
 	return a.Users
 }
 
+// GetClosedAt returns the ClosedAt field if it's non-nil, zero value otherwise.
+func (a *Alert) GetClosedAt() Timestamp {
+	if a == nil || a.ClosedAt == nil {
+		return Timestamp{}
+	}
+	return *a.ClosedAt
+}
+
+// GetClosedBy returns the ClosedBy field.
+func (a *Alert) GetClosedBy() *User {
+	if a == nil {
+		return nil
+	}
+	return a.ClosedBy
+}
+
+// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
+func (a *Alert) GetCreatedAt() Timestamp {
+	if a == nil || a.CreatedAt == nil {
+		return Timestamp{}
+	}
+	return *a.CreatedAt
+}
+
+// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise.
+func (a *Alert) GetHTMLURL() string {
+	if a == nil || a.HTMLURL == nil {
+		return ""
+	}
+	return *a.HTMLURL
+}
+
+// GetOpen returns the Open field if it's non-nil, zero value otherwise.
+func (a *Alert) GetOpen() bool {
+	if a == nil || a.Open == nil {
+		return false
+	}
+	return *a.Open
+}
+
+// GetRuleDescription returns the RuleDescription field if it's non-nil, zero value otherwise.
+func (a *Alert) GetRuleDescription() string {
+	if a == nil || a.RuleDescription == nil {
+		return ""
+	}
+	return *a.RuleDescription
+}
+
+// GetRuleID returns the RuleID field if it's non-nil, zero value otherwise.
+func (a *Alert) GetRuleID() string {
+	if a == nil || a.RuleID == nil {
+		return ""
+	}
+	return *a.RuleID
+}
+
+// GetRuleSeverity returns the RuleSeverity field if it's non-nil, zero value otherwise.
+func (a *Alert) GetRuleSeverity() string {
+	if a == nil || a.RuleSeverity == nil {
+		return ""
+	}
+	return *a.RuleSeverity
+}
+
+// GetTool returns the Tool field if it's non-nil, zero value otherwise.
+func (a *Alert) GetTool() string {
+	if a == nil || a.Tool == nil {
+		return ""
+	}
+	return *a.Tool
+}
+
+// GetURL returns the URL field if it's non-nil, zero value otherwise.
+func (a *Alert) GetURL() string {
+	if a == nil || a.URL == nil {
+		return ""
+	}
+	return *a.URL
+}
+
 // GetVerifiablePasswordAuthentication returns the VerifiablePasswordAuthentication field if it's non-nil, zero value otherwise.
 func (a *APIMeta) GetVerifiablePasswordAuthentication() bool {
 	if a == nil || a.VerifiablePasswordAuthentication == nil {
@@ -6692,6 +6772,22 @@ func (o *Organization) GetFollowing() int {
 	return *o.Following
 }
 
+// GetHasOrganizationProjects returns the HasOrganizationProjects field if it's non-nil, zero value otherwise.
+func (o *Organization) GetHasOrganizationProjects() bool {
+	if o == nil || o.HasOrganizationProjects == nil {
+		return false
+	}
+	return *o.HasOrganizationProjects
+}
+
+// GetHasRepositoryProjects returns the HasRepositoryProjects field if it's non-nil, zero value otherwise.
+func (o *Organization) GetHasRepositoryProjects() bool {
+	if o == nil || o.HasRepositoryProjects == nil {
+		return false
+	}
+	return *o.HasRepositoryProjects
+}
+
 // GetHooksURL returns the HooksURL field if it's non-nil, zero value otherwise.
 func (o *Organization) GetHooksURL() string {
 	if o == nil || o.HooksURL == nil {
@@ -6724,6 +6820,14 @@ func (o *Organization) GetIssuesURL() string {
 	return *o.IssuesURL
 }
 
+// GetIsVerified returns the IsVerified field if it's non-nil, zero value otherwise.
+func (o *Organization) GetIsVerified() bool {
+	if o == nil || o.IsVerified == nil {
+		return false
+	}
+	return *o.IsVerified
+}
+
 // GetLocation returns the Location field if it's non-nil, zero value otherwise.
 func (o *Organization) GetLocation() string {
 	if o == nil || o.Location == nil {
@@ -6868,6 +6972,14 @@ func (o *Organization) GetTotalPrivateRepos() int {
 	return *o.TotalPrivateRepos
 }
 
+// GetTwitterUsername returns the TwitterUsername field if it's non-nil, zero value otherwise.
+func (o *Organization) GetTwitterUsername() string {
+	if o == nil || o.TwitterUsername == nil {
+		return ""
+	}
+	return *o.TwitterUsername
+}
+
 // GetTwoFactorRequirementEnabled returns the TwoFactorRequirementEnabled field if it's non-nil, zero value otherwise.
 func (o *Organization) GetTwoFactorRequirementEnabled() bool {
 	if o == nil || o.TwoFactorRequirementEnabled == nil {
@@ -13484,6 +13596,14 @@ func (u *User) GetTotalPrivateRepos() int {
 	return *u.TotalPrivateRepos
 }
 
+// GetTwitterUsername returns the TwitterUsername field if it's non-nil, zero value otherwise.
+func (u *User) GetTwitterUsername() string {
+	if u == nil || u.TwitterUsername == nil {
+		return ""
+	}
+	return *u.TwitterUsername
+}
+
 // GetTwoFactorAuthentication returns the TwoFactorAuthentication field if it's non-nil, zero value otherwise.
 func (u *User) GetTwoFactorAuthentication() bool {
 	if u == nil || u.TwoFactorAuthentication == nil {
@@ -14556,6 +14676,14 @@ func (w *WorkflowRun) GetURL() string {
 	return *w.URL
 }
 
+// GetWorkflowID returns the WorkflowID field if it's non-nil, zero value otherwise.
+func (w *WorkflowRun) GetWorkflowID() int64 {
+	if w == nil || w.WorkflowID == nil {
+		return 0
+	}
+	return *w.WorkflowID
+}
+
 // GetWorkflowURL returns the WorkflowURL field if it's non-nil, zero value otherwise.
 func (w *WorkflowRun) GetWorkflowURL() string {
 	if w == nil || w.WorkflowURL == nil {
diff --git a/github/github.go b/github/github.go
index 888da212..d876e98b 100644
--- a/github/github.go
+++ b/github/github.go
@@ -165,6 +165,7 @@ type Client struct {
 	Apps           *AppsService
 	Authorizations *AuthorizationsService
 	Checks         *ChecksService
+	CodeScanning   *CodeScanningService
 	Gists          *GistsService
 	Git            *GitService
 	Gitignores     *GitignoresService
@@ -271,6 +272,7 @@ func NewClient(httpClient *http.Client) *Client {
 	c.Apps = (*AppsService)(&c.common)
 	c.Authorizations = (*AuthorizationsService)(&c.common)
 	c.Checks = (*ChecksService)(&c.common)
+	c.CodeScanning = (*CodeScanningService)(&c.common)
 	c.Gists = (*GistsService)(&c.common)
 	c.Git = (*GitService)(&c.common)
 	c.Gitignores = (*GitignoresService)(&c.common)
diff --git a/github/orgs.go b/github/orgs.go
index 564231bc..4065b014 100644
--- a/github/orgs.go
+++ b/github/orgs.go
@@ -29,6 +29,7 @@ type Organization struct {
 	Blog                        *string    `json:"blog,omitempty"`
 	Location                    *string    `json:"location,omitempty"`
 	Email                       *string    `json:"email,omitempty"`
+	TwitterUsername             *string    `json:"twitter_username,omitempty"`
 	Description                 *string    `json:"description,omitempty"`
 	PublicRepos                 *int       `json:"public_repos,omitempty"`
 	PublicGists                 *int       `json:"public_gists,omitempty"`
@@ -45,6 +46,9 @@ type Organization struct {
 	Type                        *string    `json:"type,omitempty"`
 	Plan                        *Plan      `json:"plan,omitempty"`
 	TwoFactorRequirementEnabled *bool      `json:"two_factor_requirement_enabled,omitempty"`
+	IsVerified                  *bool      `json:"is_verified,omitempty"`
+	HasOrganizationProjects     *bool      `json:"has_organization_projects,omitempty"`
+	HasRepositoryProjects       *bool      `json:"has_repository_projects,omitempty"`
 
 	// DefaultRepoPermission can be one of: "read", "write", "admin", or "none". (Default: "read").
 	// It is only used in OrganizationsService.Edit.
diff --git a/github/pulls.go b/github/pulls.go
index 685493f1..ad372d45 100644
--- a/github/pulls.go
+++ b/github/pulls.go
@@ -439,7 +439,7 @@ type PullRequestMergeResult struct {
 
 // PullRequestOptions lets you define how a pull request will be merged.
 type PullRequestOptions struct {
-	CommitTitle string // Extra detail to append to automatic commit message. (Optional.)
+	CommitTitle string // Title for the automatic commit message. (Optional.)
 	SHA         string // SHA that pull request head must match to allow merge. (Optional.)
 
 	// The merge method to use. Possible values include: "merge", "squash", and "rebase" with the default being merge. (Optional.)
@@ -453,10 +453,10 @@ type pullRequestMergeRequest struct {
 	SHA           string `json:"sha,omitempty"`
 }
 
-// Merge a pull request (Merge Button™).
-// commitMessage is the title for the automatic commit message.
+// Merge a pull request.
+// commitMessage is an extra detail to append to automatic commit message.
 //
-// GitHub API docs: https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button
+// GitHub API docs: https://developer.github.com/v3/pulls/#merge-a-pull-request
 func (s *PullRequestsService) Merge(ctx context.Context, owner string, repo string, number int, commitMessage string, options *PullRequestOptions) (*PullRequestMergeResult, *Response, error) {
 	u := fmt.Sprintf("repos/%v/%v/pulls/%d/merge", owner, repo, number)
 
diff --git a/github/repos_deployments.go b/github/repos_deployments.go
index 57de0a22..3caa9730 100644
--- a/github/repos_deployments.go
+++ b/github/repos_deployments.go
@@ -129,6 +129,18 @@ func (s *RepositoriesService) CreateDeployment(ctx context.Context, owner, repo
 	return d, resp, nil
 }
 
+// DeleteDeployment deletes an existing deployment for a repository.
+//
+// GitHub API docs: https://developer.github.com/v3/repos/deployments/#delete-a-deployment
+func (s *RepositoriesService) DeleteDeployment(ctx context.Context, owner, repo string, deploymentID int64) (*Response, error) {
+	u := fmt.Sprintf("repos/%v/%v/deployments/%v", owner, repo, deploymentID)
+	req, err := s.client.NewRequest("DELETE", u, nil)
+	if err != nil {
+		return nil, err
+	}
+	return s.client.Do(ctx, req, nil)
+}
+
 // DeploymentStatus represents the status of a
 // particular deployment.
 type DeploymentStatus struct {
diff --git a/github/users.go b/github/users.go
index 97747f71..1db2d323 100644
--- a/github/users.go
+++ b/github/users.go
@@ -31,6 +31,7 @@ type User struct {
 	Email                   *string    `json:"email,omitempty"`
 	Hireable                *bool      `json:"hireable,omitempty"`
 	Bio                     *string    `json:"bio,omitempty"`
+	TwitterUsername         *string    `json:"twitter_username,omitempty"`
 	PublicRepos             *int       `json:"public_repos,omitempty"`
 	PublicGists             *int       `json:"public_gists,omitempty"`
 	Followers               *int       `json:"followers,omitempty"`


Test patch:
diff --git a/github/code-scanning_test.go b/github/code-scanning_test.go
new file mode 100644
index 00000000..2e0c2282
--- /dev/null
+++ b/github/code-scanning_test.go
@@ -0,0 +1,165 @@
+// Copyright 2020 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package github
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestActionsService_Alert_ID(t *testing.T) {
+	// Test: nil Alert ID == 0
+	var a *Alert
+	id := a.ID()
+	var want int64
+	if id != want {
+		t.Errorf("Alert.ID error returned %+v, want %+v", id, want)
+	}
+
+	// Test: Valid HTMLURL
+	a = &Alert{
+		HTMLURL: String("https://github.com/o/r/security/code-scanning/88"),
+	}
+	id = a.ID()
+	want = 88
+	if !reflect.DeepEqual(id, want) {
+		t.Errorf("Alert.ID error returned %+v, want %+v", id, want)
+	}
+
+	// Test: HTMLURL is nil
+	a = &Alert{}
+	id = a.ID()
+	want = 0
+	if !reflect.DeepEqual(id, want) {
+		t.Errorf("Alert.ID error returned %+v, want %+v", id, want)
+	}
+
+	// Test: ID can't be parsed as an int
+	a = &Alert{
+		HTMLURL: String("https://github.com/o/r/security/code-scanning/bad88"),
+	}
+	id = a.ID()
+	want = 0
+	if !reflect.DeepEqual(id, want) {
+		t.Errorf("Alert.ID error returned %+v, want %+v", id, want)
+	}
+}
+
+func TestActionsService_ListAlertsForRepo(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/code-scanning/alerts", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		testFormValues(t, r, values{"state": "open", "ref": "heads/master"})
+		fmt.Fprint(w, `[{
+				"rule_id":"js/trivial-conditional",
+				"rule_severity":"warning",
+				"rule_description":"Useless conditional",
+				"tool":"CodeQL",
+				"created_at":"2020-05-06T12:00:00Z",
+				"open":true,
+				"closed_by":null,
+				"closed_at":null,
+				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/25",
+				"html_url":"https://github.com/o/r/security/code-scanning/25"
+				},
+				{
+				"rule_id":"js/useless-expression",
+				"rule_severity":"warning",
+				"rule_description":"Expression has no effect",
+				"tool":"CodeQL",
+				"created_at":"2020-05-06T12:00:00Z",
+				"open":true,
+				"closed_by":null,
+				"closed_at":null,
+				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/88",
+				"html_url":"https://github.com/o/r/security/code-scanning/88"
+				}]`)
+	})
+
+	opts := &AlertListOptions{State: "open", Ref: "heads/master"}
+	alerts, _, err := client.CodeScanning.ListAlertsForRepo(context.Background(), "o", "r", opts)
+	if err != nil {
+		t.Errorf("CodeScanning.ListAlertsForRepo returned error: %v", err)
+	}
+
+	date := Timestamp{time.Date(2020, time.May, 06, 12, 00, 00, 0, time.UTC)}
+	want := []*Alert{
+		{
+			RuleID:          String("js/trivial-conditional"),
+			RuleSeverity:    String("warning"),
+			RuleDescription: String("Useless conditional"),
+			Tool:            String("CodeQL"),
+			CreatedAt:       &date,
+			Open:            Bool(true),
+			ClosedBy:        nil,
+			ClosedAt:        nil,
+			URL:             String("https://api.github.com/repos/o/r/code-scanning/alerts/25"),
+			HTMLURL:         String("https://github.com/o/r/security/code-scanning/25"),
+		},
+		{
+			RuleID:          String("js/useless-expression"),
+			RuleSeverity:    String("warning"),
+			RuleDescription: String("Expression has no effect"),
+			Tool:            String("CodeQL"),
+			CreatedAt:       &date,
+			Open:            Bool(true),
+			ClosedBy:        nil,
+			ClosedAt:        nil,
+			URL:             String("https://api.github.com/repos/o/r/code-scanning/alerts/88"),
+			HTMLURL:         String("https://github.com/o/r/security/code-scanning/88"),
+		},
+	}
+	if !reflect.DeepEqual(alerts, want) {
+		t.Errorf("CodeScanning.ListAlertsForRepo returned %+v, want %+v", alerts, want)
+	}
+}
+
+func TestActionsService_GetAlert(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/code-scanning/alerts/88", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		fmt.Fprint(w, `{"rule_id":"js/useless-expression",
+				"rule_severity":"warning",
+				"rule_description":"Expression has no effect",
+				"tool":"CodeQL",
+				"created_at":"2019-01-02T15:04:05Z",
+				"open":true,
+				"closed_by":null,
+				"closed_at":null,
+				"url":"https://api.github.com/repos/o/r/code-scanning/alerts/88",
+				"html_url":"https://github.com/o/r/security/code-scanning/88"}`)
+	})
+
+	alert, _, err := client.CodeScanning.GetAlert(context.Background(), "o", "r", 88)
+	if err != nil {
+		t.Errorf("CodeScanning.GetAlert returned error: %v", err)
+	}
+
+	date := Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}
+	want := &Alert{
+		RuleID:          String("js/useless-expression"),
+		RuleSeverity:    String("warning"),
+		RuleDescription: String("Expression has no effect"),
+		Tool:            String("CodeQL"),
+		CreatedAt:       &date,
+		Open:            Bool(true),
+		ClosedBy:        nil,
+		ClosedAt:        nil,
+		URL:             String("https://api.github.com/repos/o/r/code-scanning/alerts/88"),
+		HTMLURL:         String("https://github.com/o/r/security/code-scanning/88"),
+	}
+	if !reflect.DeepEqual(alert, want) {
+		t.Errorf("CodeScanning.GetAlert returned %+v, want %+v", alert, want)
+	}
+}
diff --git a/github/github-stringify_test.go b/github/github-stringify_test.go
index df474203..96d2baf2 100644
--- a/github/github-stringify_test.go
+++ b/github/github-stringify_test.go
@@ -854,6 +854,7 @@ func TestOrganization_String(t *testing.T) {
 		Blog:                                 String(""),
 		Location:                             String(""),
 		Email:                                String(""),
+		TwitterUsername:                      String(""),
 		Description:                          String(""),
 		PublicRepos:                          Int(0),
 		PublicGists:                          Int(0),
@@ -868,6 +869,9 @@ func TestOrganization_String(t *testing.T) {
 		Type:                                 String(""),
 		Plan:                                 &Plan{},
 		TwoFactorRequirementEnabled:          Bool(false),
+		IsVerified:                           Bool(false),
+		HasOrganizationProjects:              Bool(false),
+		HasRepositoryProjects:                Bool(false),
 		DefaultRepoPermission:                String(""),
 		DefaultRepoSettings:                  String(""),
 		MembersCanCreateRepos:                Bool(false),
@@ -883,7 +887,7 @@ func TestOrganization_String(t *testing.T) {
 		PublicMembersURL:                     String(""),
 		ReposURL:                             String(""),
 	}
-	want := `github.Organization{Login:"", ID:0, NodeID:"", AvatarURL:"", HTMLURL:"", Name:"", Company:"", Blog:"", Location:"", Email:"", Description:"", PublicRepos:0, PublicGists:0, Followers:0, Following:0, TotalPrivateRepos:0, OwnedPrivateRepos:0, PrivateGists:0, DiskUsage:0, Collaborators:0, BillingEmail:"", Type:"", Plan:github.Plan{}, TwoFactorRequirementEnabled:false, DefaultRepoPermission:"", DefaultRepoSettings:"", MembersCanCreateRepos:false, MembersCanCreatePublicRepos:false, MembersCanCreatePrivateRepos:false, MembersCanCreateInternalRepos:false, MembersAllowedRepositoryCreationType:"", URL:"", EventsURL:"", HooksURL:"", IssuesURL:"", MembersURL:"", PublicMembersURL:"", ReposURL:""}`
+	want := `github.Organization{Login:"", ID:0, NodeID:"", AvatarURL:"", HTMLURL:"", Name:"", Company:"", Blog:"", Location:"", Email:"", TwitterUsername:"", Description:"", PublicRepos:0, PublicGists:0, Followers:0, Following:0, TotalPrivateRepos:0, OwnedPrivateRepos:0, PrivateGists:0, DiskUsage:0, Collaborators:0, BillingEmail:"", Type:"", Plan:github.Plan{}, TwoFactorRequirementEnabled:false, IsVerified:false, HasOrganizationProjects:false, HasRepositoryProjects:false, DefaultRepoPermission:"", DefaultRepoSettings:"", MembersCanCreateRepos:false, MembersCanCreatePublicRepos:false, MembersCanCreatePrivateRepos:false, MembersCanCreateInternalRepos:false, MembersAllowedRepositoryCreationType:"", URL:"", EventsURL:"", HooksURL:"", IssuesURL:"", MembersURL:"", PublicMembersURL:"", ReposURL:""}`
 	if got := v.String(); got != want {
 		t.Errorf("Organization.String = %v, want %v", got, want)
 	}
@@ -1555,6 +1559,7 @@ func TestUser_String(t *testing.T) {
 		Email:                   String(""),
 		Hireable:                Bool(false),
 		Bio:                     String(""),
+		TwitterUsername:         String(""),
 		PublicRepos:             Int(0),
 		PublicGists:             Int(0),
 		Followers:               Int(0),
@@ -1583,7 +1588,7 @@ func TestUser_String(t *testing.T) {
 		StarredURL:              String(""),
 		SubscriptionsURL:        String(""),
 	}
-	want := `github.User{Login:"", ID:0, NodeID:"", AvatarURL:"", HTMLURL:"", GravatarID:"", Name:"", Company:"", Blog:"", Location:"", Email:"", Hireable:false, Bio:"", PublicRepos:0, PublicGists:0, Followers:0, Following:0, CreatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, UpdatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, SuspendedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, Type:"", SiteAdmin:false, TotalPrivateRepos:0, OwnedPrivateRepos:0, PrivateGists:0, DiskUsage:0, Collaborators:0, TwoFactorAuthentication:false, Plan:github.Plan{}, LdapDn:"", URL:"", EventsURL:"", FollowingURL:"", FollowersURL:"", GistsURL:"", OrganizationsURL:"", ReceivedEventsURL:"", ReposURL:"", StarredURL:"", SubscriptionsURL:""}`
+	want := `github.User{Login:"", ID:0, NodeID:"", AvatarURL:"", HTMLURL:"", GravatarID:"", Name:"", Company:"", Blog:"", Location:"", Email:"", Hireable:false, Bio:"", TwitterUsername:"", PublicRepos:0, PublicGists:0, Followers:0, Following:0, CreatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, UpdatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, SuspendedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, Type:"", SiteAdmin:false, TotalPrivateRepos:0, OwnedPrivateRepos:0, PrivateGists:0, DiskUsage:0, Collaborators:0, TwoFactorAuthentication:false, Plan:github.Plan{}, LdapDn:"", URL:"", EventsURL:"", FollowingURL:"", FollowersURL:"", GistsURL:"", OrganizationsURL:"", ReceivedEventsURL:"", ReposURL:"", StarredURL:"", SubscriptionsURL:""}`
 	if got := v.String(); got != want {
 		t.Errorf("User.String = %v, want %v", got, want)
 	}
diff --git a/github/orgs_test.go b/github/orgs_test.go
index cf69453c..e60a01f6 100644
--- a/github/orgs_test.go
+++ b/github/orgs_test.go
@@ -22,9 +22,13 @@ func TestOrganization_marshal(t *testing.T) {
 		Blog:                                 String("https://github.com/blog"),
 		Company:                              String("GitHub"),
 		Email:                                String("support@github.com"),
+		TwitterUsername:                      String("github"),
 		Location:                             String("San Francisco"),
 		Name:                                 String("github"),
 		Description:                          String("GitHub, the company."),
+		IsVerified:                           Bool(true),
+		HasOrganizationProjects:              Bool(true),
+		HasRepositoryProjects:                Bool(true),
 		DefaultRepoPermission:                String("read"),
 		MembersCanCreateRepos:                Bool(true),
 		MembersCanCreateInternalRepos:        Bool(true),
@@ -38,9 +42,13 @@ func TestOrganization_marshal(t *testing.T) {
 			"blog": "https://github.com/blog",
 			"company": "GitHub",
 			"email": "support@github.com",
+			"twitter_username": "github",
 			"location": "San Francisco",
 			"name": "github",
 			"description": "GitHub, the company.",
+			"is_verified": true,
+			"has_organization_projects": true,
+			"has_repository_projects": true,
 			"default_repository_permission": "read",
 			"members_can_create_repositories": true,
 			"members_can_create_public_repositories": false,
diff --git a/github/repos_deployments_test.go b/github/repos_deployments_test.go
index fdbfdd3a..53f8cec5 100644
--- a/github/repos_deployments_test.go
+++ b/github/repos_deployments_test.go
@@ -89,6 +89,32 @@ func TestRepositoriesService_CreateDeployment(t *testing.T) {
 	}
 }
 
+func TestRepositoriesService_DeleteDeployment(t *testing.T) {
+	client, mux, _, teardown := setup()
+	defer teardown()
+
+	mux.HandleFunc("/repos/o/r/deployments/1", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "DELETE")
+		w.WriteHeader(http.StatusNoContent)
+	})
+
+	resp, err := client.Repositories.DeleteDeployment(context.Background(), "o", "r", 1)
+	if err != nil {
+		t.Errorf("Repositories.DeleteDeployment returned error: %v", err)
+	}
+	if resp.StatusCode != http.StatusNoContent {
+		t.Error("Repositories.DeleteDeployment should return a 204 status")
+	}
+
+	resp, err = client.Repositories.DeleteDeployment(context.Background(), "o", "r", 2)
+	if err == nil {
+		t.Error("Repositories.DeleteDeployment should return an error")
+	}
+	if resp.StatusCode != http.StatusNotFound {
+		t.Error("Repositories.DeleteDeployment should return a 404 status")
+	}
+}
+
 func TestRepositoriesService_ListDeploymentStatuses(t *testing.T) {
 	client, mux, _, teardown := setup()
 	defer teardown()
diff --git a/github/users_test.go b/github/users_test.go
index d1ce7e39..e97e8e1b 100644
--- a/github/users_test.go
+++ b/github/users_test.go
@@ -18,22 +18,24 @@ func TestUser_marshall(t *testing.T) {
 	testJSONMarshal(t, &User{}, "{}")
 
 	u := &User{
-		Login:       String("l"),
-		ID:          Int64(1),
-		URL:         String("u"),
-		AvatarURL:   String("a"),
-		GravatarID:  String("g"),
-		Name:        String("n"),
-		Company:     String("c"),
-		Blog:        String("b"),
-		Location:    String("l"),
-		Email:       String("e"),
-		Hireable:    Bool(true),
-		PublicRepos: Int(1),
-		Followers:   Int(1),
-		Following:   Int(1),
-		CreatedAt:   &Timestamp{referenceTime},
-		SuspendedAt: &Timestamp{referenceTime},
+		Login:           String("l"),
+		ID:              Int64(1),
+		URL:             String("u"),
+		AvatarURL:       String("a"),
+		GravatarID:      String("g"),
+		Name:            String("n"),
+		Company:         String("c"),
+		Blog:            String("b"),
+		Location:        String("l"),
+		Email:           String("e"),
+		Hireable:        Bool(true),
+		Bio:             String("b"),
+		TwitterUsername: String("t"),
+		PublicRepos:     Int(1),
+		Followers:       Int(1),
+		Following:       Int(1),
+		CreatedAt:       &Timestamp{referenceTime},
+		SuspendedAt:     &Timestamp{referenceTime},
 	}
 	want := `{
 		"login": "l",
@@ -46,6 +48,8 @@ func TestUser_marshall(t *testing.T) {
 		"location": "l",
 		"email": "e",
 		"hireable": true,
+		"bio": "b",
+		"twitter_username": "t",
 		"public_repos": 1,
 		"followers": 1,
 		"following": 1,