Repository: google/go-github
Pull request #1569 (2020-07-06 07:49:30)

Handle package webhook
Addresses https://github.com/google/go-github/issues/1550

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

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

```diff
@@            Coverage Diff             @@
##           master    #1569      +/-   ##
==========================================
+ Coverage   67.90%   73.13%   +5.22%     
==========================================
  Files          95       96       +1     
  Lines        8750     7053    -1697     
==========================================
- Hits         5942     5158     -784     
+ Misses       1898      985     -913     
  Partials      910      910              
```


| [Impacted Files](https://codecov.io/gh/google/go-github/pull/1569?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [github/event\_types.go](https://codecov.io/gh/google/go-github/pull/1569/diff?src=pr&el=tree#diff-Z2l0aHViL2V2ZW50X3R5cGVzLmdv) | `100.00% <ø> (ø)` | |
| [github/messages.go](https://codecov.io/gh/google/go-github/pull/1569/diff?src=pr&el=tree#diff-Z2l0aHViL21lc3NhZ2VzLmdv) | `82.85% <ø> (+1.68%)` | :arrow_up: |
| [github/event.go](https://codecov.io/gh/google/go-github/pull/1569/diff?src=pr&el=tree#diff-Z2l0aHViL2V2ZW50Lmdv) | `94.00% <100.00%> (+0.12%)` | :arrow_up: |
| [github/packages.go](https://codecov.io/gh/google/go-github/pull/1569/diff?src=pr&el=tree#diff-Z2l0aHViL3BhY2thZ2VzLmdv) | `100.00% <100.00%> (ø)` | |
| [github/github.go](https://codecov.io/gh/google/go-github/pull/1569/diff?src=pr&el=tree#diff-Z2l0aHViL2dpdGh1Yi5nbw==) | `89.65% <0.00%> (-0.03%)` | :arrow_down: |
| [github/admin.go](https://codecov.io/gh/google/go-github/pull/1569/diff?src=pr&el=tree#diff-Z2l0aHViL2FkbWluLmdv) | `100.00% <0.00%> (ø)` | |
| [github/strings.go](https://codecov.io/gh/google/go-github/pull/1569/diff?src=pr&el=tree#diff-Z2l0aHViL3N0cmluZ3MuZ28=) | `100.00% <0.00%> (ø)` | |
| [github/activity.go](https://codecov.io/gh/google/go-github/pull/1569/diff?src=pr&el=tree#diff-Z2l0aHViL2FjdGl2aXR5Lmdv) | `100.00% <0.00%> (ø)` | |
| [github/timestamp.go](https://codecov.io/gh/google/go-github/pull/1569/diff?src=pr&el=tree#diff-Z2l0aHViL3RpbWVzdGFtcC5nbw==) | `100.00% <0.00%> (ø)` | |
| [github/admin\_stats.go](https://codecov.io/gh/google/go-github/pull/1569/diff?src=pr&el=tree#diff-Z2l0aHViL2FkbWluX3N0YXRzLmdv) | `100.00% <0.00%> (ø)` | |
| ... and [87 more](https://codecov.io/gh/google/go-github/pull/1569/diff?src=pr&el=tree-more) | |

------

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

gmlewis: Thank you, @wesleimp!
Merging.

Patch:
diff --git a/github/event.go b/github/event.go
index 848fa6da..3b96b029 100644
--- a/github/event.go
+++ b/github/event.go
@@ -76,6 +76,8 @@ func (e *Event) ParsePayload() (payload interface{}, err error) {
 		payload = &OrganizationEvent{}
 	case "OrgBlockEvent":
 		payload = &OrgBlockEvent{}
+	case "PackageEvent":
+		payload = &PackageEvent{}
 	case "PageBuildEvent":
 		payload = &PageBuildEvent{}
 	case "PingEvent":
diff --git a/github/event_types.go b/github/event_types.go
index bbb25af2..fe6991f5 100644
--- a/github/event_types.go
+++ b/github/event_types.go
@@ -468,6 +468,22 @@ type OrgBlockEvent struct {
 	Installation *Installation `json:"installation,omitempty"`
 }
 
+// PackageEvent represents activity related to GitHub Packages.
+// The Webhook event name is "package".
+//
+// This event is triggered when a GitHub Package is published or updated.
+//
+// GitHub API docs: https://developer.github.com/webhooks/event-payloads/#package
+type PackageEvent struct {
+	// Action is the action that was performed.
+	// Can be "published" or "updated".
+	Action  *string       `json:"action,omitempty"`
+	Package *Package      `json:"package,omitempty"`
+	Repo    *Repository   `json:"repository,omitempty"`
+	Org     *Organization `json:"organization,omitempty"`
+	Sender  *User         `json:"sender,omitempty"`
+}
+
 // PageBuildEvent represents an attempted build of a GitHub Pages site, whether
 // successful or not.
 // The Webhook event name is "page_build".
diff --git a/github/github-accessors.go b/github/github-accessors.go
index 3e2e0340..8c591ce8 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -7172,6 +7172,478 @@ func (o *OrgStats) GetTotalTeams() int {
 	return *o.TotalTeams
 }
 
+// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
+func (p *Package) GetCreatedAt() Timestamp {
+	if p == nil || p.CreatedAt == nil {
+		return Timestamp{}
+	}
+	return *p.CreatedAt
+}
+
+// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise.
+func (p *Package) GetHTMLURL() string {
+	if p == nil || p.HTMLURL == nil {
+		return ""
+	}
+	return *p.HTMLURL
+}
+
+// GetID returns the ID field if it's non-nil, zero value otherwise.
+func (p *Package) GetID() int64 {
+	if p == nil || p.ID == nil {
+		return 0
+	}
+	return *p.ID
+}
+
+// GetName returns the Name field if it's non-nil, zero value otherwise.
+func (p *Package) GetName() string {
+	if p == nil || p.Name == nil {
+		return ""
+	}
+	return *p.Name
+}
+
+// GetOwner returns the Owner field.
+func (p *Package) GetOwner() *User {
+	if p == nil {
+		return nil
+	}
+	return p.Owner
+}
+
+// GetPackageType returns the PackageType field if it's non-nil, zero value otherwise.
+func (p *Package) GetPackageType() string {
+	if p == nil || p.PackageType == nil {
+		return ""
+	}
+	return *p.PackageType
+}
+
+// GetPackageVersion returns the PackageVersion field.
+func (p *Package) GetPackageVersion() *PackageVersion {
+	if p == nil {
+		return nil
+	}
+	return p.PackageVersion
+}
+
+// GetRegistry returns the Registry field.
+func (p *Package) GetRegistry() *PackageRegistry {
+	if p == nil {
+		return nil
+	}
+	return p.Registry
+}
+
+// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
+func (p *Package) GetUpdatedAt() Timestamp {
+	if p == nil || p.UpdatedAt == nil {
+		return Timestamp{}
+	}
+	return *p.UpdatedAt
+}
+
+// GetAction returns the Action field if it's non-nil, zero value otherwise.
+func (p *PackageEvent) GetAction() string {
+	if p == nil || p.Action == nil {
+		return ""
+	}
+	return *p.Action
+}
+
+// GetOrg returns the Org field.
+func (p *PackageEvent) GetOrg() *Organization {
+	if p == nil {
+		return nil
+	}
+	return p.Org
+}
+
+// GetPackage returns the Package field.
+func (p *PackageEvent) GetPackage() *Package {
+	if p == nil {
+		return nil
+	}
+	return p.Package
+}
+
+// GetRepo returns the Repo field.
+func (p *PackageEvent) GetRepo() *Repository {
+	if p == nil {
+		return nil
+	}
+	return p.Repo
+}
+
+// GetSender returns the Sender field.
+func (p *PackageEvent) GetSender() *User {
+	if p == nil {
+		return nil
+	}
+	return p.Sender
+}
+
+// GetAuthor returns the Author field.
+func (p *PackageFile) GetAuthor() *User {
+	if p == nil {
+		return nil
+	}
+	return p.Author
+}
+
+// GetContentType returns the ContentType field if it's non-nil, zero value otherwise.
+func (p *PackageFile) GetContentType() string {
+	if p == nil || p.ContentType == nil {
+		return ""
+	}
+	return *p.ContentType
+}
+
+// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
+func (p *PackageFile) GetCreatedAt() Timestamp {
+	if p == nil || p.CreatedAt == nil {
+		return Timestamp{}
+	}
+	return *p.CreatedAt
+}
+
+// GetDownloadURL returns the DownloadURL field if it's non-nil, zero value otherwise.
+func (p *PackageFile) GetDownloadURL() string {
+	if p == nil || p.DownloadURL == nil {
+		return ""
+	}
+	return *p.DownloadURL
+}
+
+// GetID returns the ID field if it's non-nil, zero value otherwise.
+func (p *PackageFile) GetID() int64 {
+	if p == nil || p.ID == nil {
+		return 0
+	}
+	return *p.ID
+}
+
+// GetMD5 returns the MD5 field if it's non-nil, zero value otherwise.
+func (p *PackageFile) GetMD5() string {
+	if p == nil || p.MD5 == nil {
+		return ""
+	}
+	return *p.MD5
+}
+
+// GetName returns the Name field if it's non-nil, zero value otherwise.
+func (p *PackageFile) GetName() string {
+	if p == nil || p.Name == nil {
+		return ""
+	}
+	return *p.Name
+}
+
+// GetSHA1 returns the SHA1 field if it's non-nil, zero value otherwise.
+func (p *PackageFile) GetSHA1() string {
+	if p == nil || p.SHA1 == nil {
+		return ""
+	}
+	return *p.SHA1
+}
+
+// GetSHA256 returns the SHA256 field if it's non-nil, zero value otherwise.
+func (p *PackageFile) GetSHA256() string {
+	if p == nil || p.SHA256 == nil {
+		return ""
+	}
+	return *p.SHA256
+}
+
+// GetSize returns the Size field if it's non-nil, zero value otherwise.
+func (p *PackageFile) GetSize() int64 {
+	if p == nil || p.Size == nil {
+		return 0
+	}
+	return *p.Size
+}
+
+// GetState returns the State field if it's non-nil, zero value otherwise.
+func (p *PackageFile) GetState() string {
+	if p == nil || p.State == nil {
+		return ""
+	}
+	return *p.State
+}
+
+// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
+func (p *PackageFile) GetUpdatedAt() Timestamp {
+	if p == nil || p.UpdatedAt == nil {
+		return Timestamp{}
+	}
+	return *p.UpdatedAt
+}
+
+// GetAboutURL returns the AboutURL field if it's non-nil, zero value otherwise.
+func (p *PackageRegistry) GetAboutURL() string {
+	if p == nil || p.AboutURL == nil {
+		return ""
+	}
+	return *p.AboutURL
+}
+
+// GetName returns the Name field if it's non-nil, zero value otherwise.
+func (p *PackageRegistry) GetName() string {
+	if p == nil || p.Name == nil {
+		return ""
+	}
+	return *p.Name
+}
+
+// GetType returns the Type field if it's non-nil, zero value otherwise.
+func (p *PackageRegistry) GetType() string {
+	if p == nil || p.Type == nil {
+		return ""
+	}
+	return *p.Type
+}
+
+// GetURL returns the URL field if it's non-nil, zero value otherwise.
+func (p *PackageRegistry) GetURL() string {
+	if p == nil || p.URL == nil {
+		return ""
+	}
+	return *p.URL
+}
+
+// GetVendor returns the Vendor field if it's non-nil, zero value otherwise.
+func (p *PackageRegistry) GetVendor() string {
+	if p == nil || p.Vendor == nil {
+		return ""
+	}
+	return *p.Vendor
+}
+
+// GetAuthor returns the Author field.
+func (p *PackageRelease) GetAuthor() *User {
+	if p == nil {
+		return nil
+	}
+	return p.Author
+}
+
+// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
+func (p *PackageRelease) GetCreatedAt() Timestamp {
+	if p == nil || p.CreatedAt == nil {
+		return Timestamp{}
+	}
+	return *p.CreatedAt
+}
+
+// GetDraft returns the Draft field if it's non-nil, zero value otherwise.
+func (p *PackageRelease) GetDraft() bool {
+	if p == nil || p.Draft == nil {
+		return false
+	}
+	return *p.Draft
+}
+
+// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise.
+func (p *PackageRelease) GetHTMLURL() string {
+	if p == nil || p.HTMLURL == nil {
+		return ""
+	}
+	return *p.HTMLURL
+}
+
+// GetID returns the ID field if it's non-nil, zero value otherwise.
+func (p *PackageRelease) GetID() int64 {
+	if p == nil || p.ID == nil {
+		return 0
+	}
+	return *p.ID
+}
+
+// GetName returns the Name field if it's non-nil, zero value otherwise.
+func (p *PackageRelease) GetName() string {
+	if p == nil || p.Name == nil {
+		return ""
+	}
+	return *p.Name
+}
+
+// GetPrerelease returns the Prerelease field if it's non-nil, zero value otherwise.
+func (p *PackageRelease) GetPrerelease() bool {
+	if p == nil || p.Prerelease == nil {
+		return false
+	}
+	return *p.Prerelease
+}
+
+// GetPublishedAt returns the PublishedAt field if it's non-nil, zero value otherwise.
+func (p *PackageRelease) GetPublishedAt() Timestamp {
+	if p == nil || p.PublishedAt == nil {
+		return Timestamp{}
+	}
+	return *p.PublishedAt
+}
+
+// GetTagName returns the TagName field if it's non-nil, zero value otherwise.
+func (p *PackageRelease) GetTagName() string {
+	if p == nil || p.TagName == nil {
+		return ""
+	}
+	return *p.TagName
+}
+
+// GetTargetCommitish returns the TargetCommitish field if it's non-nil, zero value otherwise.
+func (p *PackageRelease) GetTargetCommitish() string {
+	if p == nil || p.TargetCommitish == nil {
+		return ""
+	}
+	return *p.TargetCommitish
+}
+
+// GetURL returns the URL field if it's non-nil, zero value otherwise.
+func (p *PackageRelease) GetURL() string {
+	if p == nil || p.URL == nil {
+		return ""
+	}
+	return *p.URL
+}
+
+// GetAuthor returns the Author field.
+func (p *PackageVersion) GetAuthor() *User {
+	if p == nil {
+		return nil
+	}
+	return p.Author
+}
+
+// GetBody returns the Body field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetBody() string {
+	if p == nil || p.Body == nil {
+		return ""
+	}
+	return *p.Body
+}
+
+// GetBodyHTML returns the BodyHTML field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetBodyHTML() string {
+	if p == nil || p.BodyHTML == nil {
+		return ""
+	}
+	return *p.BodyHTML
+}
+
+// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetCreatedAt() Timestamp {
+	if p == nil || p.CreatedAt == nil {
+		return Timestamp{}
+	}
+	return *p.CreatedAt
+}
+
+// GetDraft returns the Draft field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetDraft() bool {
+	if p == nil || p.Draft == nil {
+		return false
+	}
+	return *p.Draft
+}
+
+// GetHTMLURL returns the HTMLURL field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetHTMLURL() string {
+	if p == nil || p.HTMLURL == nil {
+		return ""
+	}
+	return *p.HTMLURL
+}
+
+// GetID returns the ID field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetID() int64 {
+	if p == nil || p.ID == nil {
+		return 0
+	}
+	return *p.ID
+}
+
+// GetInstallationCommand returns the InstallationCommand field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetInstallationCommand() string {
+	if p == nil || p.InstallationCommand == nil {
+		return ""
+	}
+	return *p.InstallationCommand
+}
+
+// GetManifest returns the Manifest field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetManifest() string {
+	if p == nil || p.Manifest == nil {
+		return ""
+	}
+	return *p.Manifest
+}
+
+// GetPrerelease returns the Prerelease field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetPrerelease() bool {
+	if p == nil || p.Prerelease == nil {
+		return false
+	}
+	return *p.Prerelease
+}
+
+// GetRelease returns the Release field.
+func (p *PackageVersion) GetRelease() *PackageRelease {
+	if p == nil {
+		return nil
+	}
+	return p.Release
+}
+
+// GetSummary returns the Summary field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetSummary() string {
+	if p == nil || p.Summary == nil {
+		return ""
+	}
+	return *p.Summary
+}
+
+// GetTagName returns the TagName field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetTagName() string {
+	if p == nil || p.TagName == nil {
+		return ""
+	}
+	return *p.TagName
+}
+
+// GetTargetCommitish returns the TargetCommitish field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetTargetCommitish() string {
+	if p == nil || p.TargetCommitish == nil {
+		return ""
+	}
+	return *p.TargetCommitish
+}
+
+// GetTargetOID returns the TargetOID field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetTargetOID() string {
+	if p == nil || p.TargetOID == nil {
+		return ""
+	}
+	return *p.TargetOID
+}
+
+// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetUpdatedAt() Timestamp {
+	if p == nil || p.UpdatedAt == nil {
+		return Timestamp{}
+	}
+	return *p.UpdatedAt
+}
+
+// GetVersion returns the Version field if it's non-nil, zero value otherwise.
+func (p *PackageVersion) GetVersion() string {
+	if p == nil || p.Version == nil {
+		return ""
+	}
+	return *p.Version
+}
+
 // GetAction returns the Action field if it's non-nil, zero value otherwise.
 func (p *Page) GetAction() string {
 	if p == nil || p.Action == nil {
diff --git a/github/messages.go b/github/messages.go
index 8ae80452..2c1c7a7e 100644
--- a/github/messages.go
+++ b/github/messages.go
@@ -64,6 +64,7 @@ var (
 		"milestone":                      "MilestoneEvent",
 		"organization":                   "OrganizationEvent",
 		"org_block":                      "OrgBlockEvent",
+		"package":                        "PackageEvent",
 		"page_build":                     "PageBuildEvent",
 		"ping":                           "PingEvent",
 		"project":                        "ProjectEvent",
diff --git a/github/packages.go b/github/packages.go
new file mode 100644
index 00000000..446e4faa
--- /dev/null
+++ b/github/packages.go
@@ -0,0 +1,101 @@
+// 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
+
+// Package represents a GitHub package.
+type Package struct {
+	ID             *int64           `json:"id,omitempty"`
+	Name           *string          `json:"name,omitempty"`
+	PackageType    *string          `json:"package_type,omitempty"`
+	HTMLURL        *string          `json:"html_url,omitempty"`
+	CreatedAt      *Timestamp       `json:"created_at,omitempty"`
+	UpdatedAt      *Timestamp       `json:"updated_at,omitempty"`
+	Owner          *User            `json:"owner,omitempty"`
+	PackageVersion *PackageVersion  `json:"package_version,omitempty"`
+	Registry       *PackageRegistry `json:"registry,omitempty"`
+}
+
+func (p Package) String() string {
+	return Stringify(p)
+}
+
+// PackageVersion represents a GitHub package version.
+type PackageVersion struct {
+	ID                  *int64          `json:"id,omitempty"`
+	Version             *string         `json:"version,omitempty"`
+	Summary             *string         `json:"summary,omitempty"`
+	Body                *string         `json:"body,omitempty"`
+	BodyHTML            *string         `json:"body_html,omitempty"`
+	Release             *PackageRelease `json:"release,omitempty"`
+	Manifest            *string         `json:"manifest,omitempty"`
+	HTMLURL             *string         `json:"html_url,omitempty"`
+	TagName             *string         `json:"tag_name,omitempty"`
+	TargetCommitish     *string         `json:"target_commitish,omitempty"`
+	TargetOID           *string         `json:"target_oid,omitempty"`
+	Draft               *bool           `json:"draft,omitempty"`
+	Prerelease          *bool           `json:"prerelease,omitempty"`
+	CreatedAt           *Timestamp      `json:"created_at,omitempty"`
+	UpdatedAt           *Timestamp      `json:"updated_at,omitempty"`
+	PackageFiles        []*PackageFile  `json:"package_files,omitempty"`
+	Author              *User           `json:"author,omitempty"`
+	InstallationCommand *string         `json:"installation_command,omitempty"`
+}
+
+func (pv PackageVersion) String() string {
+	return Stringify(pv)
+}
+
+// PackageRelease represents a GitHub package version release.
+type PackageRelease struct {
+	URL             *string    `json:"url,omitempty"`
+	HTMLURL         *string    `json:"html_url,omitempty"`
+	ID              *int64     `json:"id,omitempty"`
+	TagName         *string    `json:"tag_name,omitempty"`
+	TargetCommitish *string    `json:"target_commitish,omitempty"`
+	Name            *string    `json:"name,omitempty"`
+	Draft           *bool      `json:"draft,omitempty"`
+	Author          *User      `json:"author,omitempty"`
+	Prerelease      *bool      `json:"prerelease,omitempty"`
+	CreatedAt       *Timestamp `json:"created_at,omitempty"`
+	PublishedAt     *Timestamp `json:"published_at,omitempty"`
+}
+
+func (r PackageRelease) String() string {
+	return Stringify(r)
+}
+
+// PackageFile represents a GitHub package version release file.
+type PackageFile struct {
+	DownloadURL *string    `json:"download_url,omitempty"`
+	ID          *int64     `json:"id,omitempty"`
+	Name        *string    `json:"name,omitempty"`
+	SHA256      *string    `json:"sha256,omitempty"`
+	SHA1        *string    `json:"sha1,omitempty"`
+	MD5         *string    `json:"md5,omitempty"`
+	ContentType *string    `json:"content_type,omitempty"`
+	State       *string    `json:"state,omitempty"`
+	Author      *User      `json:"author,omitempty"`
+	Size        *int64     `json:"size,omitempty"`
+	CreatedAt   *Timestamp `json:"created_at,omitempty"`
+	UpdatedAt   *Timestamp `json:"updated_at,omitempty"`
+}
+
+func (pf PackageFile) String() string {
+	return Stringify(pf)
+}
+
+// PackageRegistry represents a GitHub package registry.
+type PackageRegistry struct {
+	AboutURL *string `json:"about_url,omitempty"`
+	Name     *string `json:"name,omitempty"`
+	Type     *string `json:"type,omitempty"`
+	URL      *string `json:"url,omitempty"`
+	Vendor   *string `json:"vendor,omitempty"`
+}
+
+func (r PackageRegistry) String() string {
+	return Stringify(r)
+}


Test patch:
diff --git a/github/github-stringify_test.go b/github/github-stringify_test.go
index 0d64461b..6b4ac2da 100644
--- a/github/github-stringify_test.go
+++ b/github/github-stringify_test.go
@@ -897,6 +897,105 @@ func TestOrganization_String(t *testing.T) {
 	}
 }
 
+func TestPackage_String(t *testing.T) {
+	v := Package{
+		ID:             Int64(0),
+		Name:           String(""),
+		PackageType:    String(""),
+		HTMLURL:        String(""),
+		CreatedAt:      &Timestamp{},
+		UpdatedAt:      &Timestamp{},
+		Owner:          &User{},
+		PackageVersion: &PackageVersion{},
+		Registry:       &PackageRegistry{},
+	}
+	want := `github.Package{ID:0, Name:"", PackageType:"", HTMLURL:"", CreatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, UpdatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, Owner:github.User{}, PackageVersion:github.PackageVersion{}, Registry:github.PackageRegistry{}}`
+	if got := v.String(); got != want {
+		t.Errorf("Package.String = %v, want %v", got, want)
+	}
+}
+
+func TestPackageFile_String(t *testing.T) {
+	v := PackageFile{
+		DownloadURL: String(""),
+		ID:          Int64(0),
+		Name:        String(""),
+		SHA256:      String(""),
+		SHA1:        String(""),
+		MD5:         String(""),
+		ContentType: String(""),
+		State:       String(""),
+		Author:      &User{},
+		Size:        Int64(0),
+		CreatedAt:   &Timestamp{},
+		UpdatedAt:   &Timestamp{},
+	}
+	want := `github.PackageFile{DownloadURL:"", ID:0, Name:"", SHA256:"", SHA1:"", MD5:"", ContentType:"", State:"", Author:github.User{}, Size:0, CreatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, UpdatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}}`
+	if got := v.String(); got != want {
+		t.Errorf("PackageFile.String = %v, want %v", got, want)
+	}
+}
+
+func TestPackageRegistry_String(t *testing.T) {
+	v := PackageRegistry{
+		AboutURL: String(""),
+		Name:     String(""),
+		Type:     String(""),
+		URL:      String(""),
+		Vendor:   String(""),
+	}
+	want := `github.PackageRegistry{AboutURL:"", Name:"", Type:"", URL:"", Vendor:""}`
+	if got := v.String(); got != want {
+		t.Errorf("PackageRegistry.String = %v, want %v", got, want)
+	}
+}
+
+func TestPackageRelease_String(t *testing.T) {
+	v := PackageRelease{
+		URL:             String(""),
+		HTMLURL:         String(""),
+		ID:              Int64(0),
+		TagName:         String(""),
+		TargetCommitish: String(""),
+		Name:            String(""),
+		Draft:           Bool(false),
+		Author:          &User{},
+		Prerelease:      Bool(false),
+		CreatedAt:       &Timestamp{},
+		PublishedAt:     &Timestamp{},
+	}
+	want := `github.PackageRelease{URL:"", HTMLURL:"", ID:0, TagName:"", TargetCommitish:"", Name:"", Draft:false, Author:github.User{}, Prerelease:false, CreatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, PublishedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}}`
+	if got := v.String(); got != want {
+		t.Errorf("PackageRelease.String = %v, want %v", got, want)
+	}
+}
+
+func TestPackageVersion_String(t *testing.T) {
+	v := PackageVersion{
+		ID:                  Int64(0),
+		Version:             String(""),
+		Summary:             String(""),
+		Body:                String(""),
+		BodyHTML:            String(""),
+		Release:             &PackageRelease{},
+		Manifest:            String(""),
+		HTMLURL:             String(""),
+		TagName:             String(""),
+		TargetCommitish:     String(""),
+		TargetOID:           String(""),
+		Draft:               Bool(false),
+		Prerelease:          Bool(false),
+		CreatedAt:           &Timestamp{},
+		UpdatedAt:           &Timestamp{},
+		Author:              &User{},
+		InstallationCommand: String(""),
+	}
+	want := `github.PackageVersion{ID:0, Version:"", Summary:"", Body:"", BodyHTML:"", Release:github.PackageRelease{}, Manifest:"", HTMLURL:"", TagName:"", TargetCommitish:"", TargetOID:"", Draft:false, Prerelease:false, CreatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, UpdatedAt:github.Timestamp{0001-01-01 00:00:00 +0000 UTC}, Author:github.User{}, InstallationCommand:""}`
+	if got := v.String(); got != want {
+		t.Errorf("PackageVersion.String = %v, want %v", got, want)
+	}
+}
+
 func TestPageStats_String(t *testing.T) {
 	v := PageStats{
 		TotalPages: Int(0),
diff --git a/github/messages_test.go b/github/messages_test.go
index e0650048..9a0fd74a 100644
--- a/github/messages_test.go
+++ b/github/messages_test.go
@@ -275,6 +275,10 @@ func TestParseWebHook(t *testing.T) {
 			payload:     &OrgBlockEvent{},
 			messageType: "org_block",
 		},
+		{
+			payload:     &PackageEvent{},
+			messageType: "package",
+		},
 		{
 			payload:     &PageBuildEvent{},
 			messageType: "page_build",