From b2d48e99b9f6138ce640e11ffb682ca074ac4c91 Mon Sep 17 00:00:00 2001 From: Pavlos Tzianos Date: Tue, 8 Apr 2025 17:33:10 +0100 Subject: [PATCH 1/2] Add support for registry_package event as of the time of this writing, the Github documentation describes two events related to packages. One called package and one called registry_package. According to the documentation, users should switch to using the package event instead of the registry_package event. However, when working with the actual permissions and events, there is no package event but there is a RegistryPackage event that can be enabled for a Github App. It looks like the documentation is wrong and the registry_package event was added after the package event and it's the registry_package event that users should expect to receive. --- github/event_types.go | 20 ++++ github/event_types_test.go | 129 ++++++++++++++++++++++++++ github/github-accessors.go | 56 +++++++++++ github/github-accessors_test.go | 59 ++++++++++++ github/messages.go | 1 + github/messages_test.go | 5 + github/repos_hooks_deliveries_test.go | 1 + 7 files changed, 271 insertions(+) diff --git a/github/event_types.go b/github/event_types.go index 6a6caf19ddb..d956c97df50 100644 --- a/github/event_types.go +++ b/github/event_types.go @@ -1467,6 +1467,26 @@ type ReleaseEvent struct { Org *Organization `json:"organization,omitempty"` } +// RegistryPackageEvent represents activity related to GitHub Packages. +// The Webhook event name is "registry_package". +// +// This event is triggered when a GitHub Package is published or updated. +// +// GitHub API docs: https://docs.github.com/en/webhooks/webhook-events-and-payloads#registry_package +type RegistryPackageEvent struct { + // Action is the action that was performed. + // Can be "published" or "updated". + Action *string `json:"action,omitempty"` + RegistryPackage *Package `json:"registry_package,omitempty"` + Repository *Repository `json:"repository,omitempty"` + Organization *Organization `json:"organization,omitempty"` + Enterprise *Enterprise `json:"enterprise,omitempty"` + Sender *User `json:"sender,omitempty"` + + // The following fields are only populated by Webhook events. + Installation *Installation `json:"installation,omitempty"` +} + // RepositoryEvent is triggered when a repository is created, archived, unarchived, // renamed, edited, transferred, made public, or made private. Organization hooks are // also triggered when a repository is deleted. diff --git a/github/event_types_test.go b/github/event_types_test.go index 296c1d35c9c..3cfe6034eba 100644 --- a/github/event_types_test.go +++ b/github/event_types_test.go @@ -8320,6 +8320,135 @@ func TestPackageEvent_Marshal(t *testing.T) { testJSONMarshal(t, u, want) } +func TestRegistryPackageEvent_Marshal(t *testing.T) { + t.Parallel() + testJSONMarshal(t, &RegistryPackageEvent{}, "{}") + + u := &RegistryPackageEvent{ + Action: Ptr("a"), + RegistryPackage: &Package{ + ID: Ptr(int64(1)), + Name: Ptr("n"), + PackageType: Ptr("pt"), + HTMLURL: Ptr("hurl"), + CreatedAt: &Timestamp{referenceTime}, + UpdatedAt: &Timestamp{referenceTime}, + Owner: &User{ + Login: Ptr("l"), + ID: Ptr(int64(1)), + NodeID: Ptr("n"), + URL: Ptr("u"), + ReposURL: Ptr("r"), + EventsURL: Ptr("e"), + AvatarURL: Ptr("a"), + }, + PackageVersion: &PackageVersion{ID: Ptr(int64(1))}, + Registry: &PackageRegistry{Name: Ptr("n")}, + }, + Repository: &Repository{ + ID: Ptr(int64(1)), + URL: Ptr("s"), + Name: Ptr("n"), + }, + Organization: &Organization{ + BillingEmail: Ptr("be"), + Blog: Ptr("b"), + Company: Ptr("c"), + Email: Ptr("e"), + TwitterUsername: Ptr("tu"), + Location: Ptr("loc"), + Name: Ptr("n"), + Description: Ptr("d"), + IsVerified: Ptr(true), + HasOrganizationProjects: Ptr(true), + HasRepositoryProjects: Ptr(true), + DefaultRepoPermission: Ptr("drp"), + MembersCanCreateRepos: Ptr(true), + MembersCanCreateInternalRepos: Ptr(true), + MembersCanCreatePrivateRepos: Ptr(true), + MembersCanCreatePublicRepos: Ptr(false), + MembersAllowedRepositoryCreationType: Ptr("marct"), + MembersCanCreatePages: Ptr(true), + MembersCanCreatePublicPages: Ptr(false), + MembersCanCreatePrivatePages: Ptr(true), + }, + Sender: &User{ + Login: Ptr("l"), + ID: Ptr(int64(1)), + NodeID: Ptr("n"), + URL: Ptr("u"), + ReposURL: Ptr("r"), + EventsURL: Ptr("e"), + AvatarURL: Ptr("a"), + }, + } + + want := `{ + "action": "a", + "registry_package": { + "id": 1, + "name": "n", + "package_type": "pt", + "html_url": "hurl", + "created_at": ` + referenceTimeStr + `, + "updated_at": ` + referenceTimeStr + `, + "owner": { + "login": "l", + "id": 1, + "node_id": "n", + "avatar_url": "a", + "url": "u", + "events_url": "e", + "repos_url": "r" + }, + "package_version": { + "id": 1 + }, + "registry": { + "name": "n" + } + }, + "repository": { + "id": 1, + "name": "n", + "url": "s" + }, + "organization": { + "name": "n", + "company": "c", + "blog": "b", + "location": "loc", + "email": "e", + "twitter_username": "tu", + "description": "d", + "billing_email": "be", + "is_verified": true, + "has_organization_projects": true, + "has_repository_projects": true, + "default_repository_permission": "drp", + "members_can_create_repositories": true, + "members_can_create_public_repositories": false, + "members_can_create_private_repositories": true, + "members_can_create_internal_repositories": true, + "members_allowed_repository_creation_type": "marct", + "members_can_create_pages": true, + "members_can_create_public_pages": false, + "members_can_create_private_pages": true + }, + "sender": { + "login": "l", + "id": 1, + "node_id": "n", + "avatar_url": "a", + "url": "u", + "events_url": "e", + "repos_url": "r" + } + }` + + testJSONMarshal(t, u, want) +} + func TestPersonalAccessTokenRequestEvent_Marshal(t *testing.T) { t.Parallel() testJSONMarshal(t, &PersonalAccessTokenRequestEvent{}, "{}") diff --git a/github/github-accessors.go b/github/github-accessors.go index 9860c8c806d..1e2442789d6 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -20862,6 +20862,62 @@ func (r *RegistrationToken) GetToken() string { return *r.Token } +// GetAction returns the Action field if it's non-nil, zero value otherwise. +func (r *RegistryPackageEvent) GetAction() string { + if r == nil || r.Action == nil { + return "" + } + return *r.Action +} + +// GetEnterprise returns the Enterprise field. +func (r *RegistryPackageEvent) GetEnterprise() *Enterprise { + if r == nil { + return nil + } + return r.Enterprise +} + +// GetInstallation returns the Installation field. +func (r *RegistryPackageEvent) GetInstallation() *Installation { + if r == nil { + return nil + } + return r.Installation +} + +// GetOrganization returns the Organization field. +func (r *RegistryPackageEvent) GetOrganization() *Organization { + if r == nil { + return nil + } + return r.Organization +} + +// GetRegistryPackage returns the RegistryPackage field. +func (r *RegistryPackageEvent) GetRegistryPackage() *Package { + if r == nil { + return nil + } + return r.RegistryPackage +} + +// GetRepository returns the Repository field. +func (r *RegistryPackageEvent) GetRepository() *Repository { + if r == nil { + return nil + } + return r.Repository +} + +// GetSender returns the Sender field. +func (r *RegistryPackageEvent) GetSender() *User { + if r == nil { + return nil + } + return r.Sender +} + // GetBrowserDownloadURL returns the BrowserDownloadURL field if it's non-nil, zero value otherwise. func (r *ReleaseAsset) GetBrowserDownloadURL() string { if r == nil || r.BrowserDownloadURL == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 99011135579..8dadb706cd6 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -26887,6 +26887,65 @@ func TestRegistrationToken_GetToken(tt *testing.T) { r.GetToken() } +func TestRegistryPackageEvent_GetAction(tt *testing.T) { + tt.Parallel() + var zeroValue string + r := &RegistryPackageEvent{Action: &zeroValue} + r.GetAction() + r = &RegistryPackageEvent{} + r.GetAction() + r = nil + r.GetAction() +} + +func TestRegistryPackageEvent_GetEnterprise(tt *testing.T) { + tt.Parallel() + r := &RegistryPackageEvent{} + r.GetEnterprise() + r = nil + r.GetEnterprise() +} + +func TestRegistryPackageEvent_GetInstallation(tt *testing.T) { + tt.Parallel() + r := &RegistryPackageEvent{} + r.GetInstallation() + r = nil + r.GetInstallation() +} + +func TestRegistryPackageEvent_GetOrganization(tt *testing.T) { + tt.Parallel() + r := &RegistryPackageEvent{} + r.GetOrganization() + r = nil + r.GetOrganization() +} + +func TestRegistryPackageEvent_GetRegistryPackage(tt *testing.T) { + tt.Parallel() + r := &RegistryPackageEvent{} + r.GetRegistryPackage() + r = nil + r.GetRegistryPackage() +} + +func TestRegistryPackageEvent_GetRepository(tt *testing.T) { + tt.Parallel() + r := &RegistryPackageEvent{} + r.GetRepository() + r = nil + r.GetRepository() +} + +func TestRegistryPackageEvent_GetSender(tt *testing.T) { + tt.Parallel() + r := &RegistryPackageEvent{} + r.GetSender() + r = nil + r.GetSender() +} + func TestReleaseAsset_GetBrowserDownloadURL(tt *testing.T) { tt.Parallel() var zeroValue string diff --git a/github/messages.go b/github/messages.go index 59b214b355a..2b5cce7504a 100644 --- a/github/messages.go +++ b/github/messages.go @@ -95,6 +95,7 @@ var ( "pull_request_review_thread": &PullRequestReviewThreadEvent{}, "pull_request_target": &PullRequestTargetEvent{}, "push": &PushEvent{}, + "registry_package": &RegistryPackageEvent{}, "repository": &RepositoryEvent{}, "repository_dispatch": &RepositoryDispatchEvent{}, "repository_import": &RepositoryImportEvent{}, diff --git a/github/messages_test.go b/github/messages_test.go index e6c3027caab..1be311d8779 100644 --- a/github/messages_test.go +++ b/github/messages_test.go @@ -539,6 +539,11 @@ func TestParseWebHook(t *testing.T) { payload: &WorkflowRunEvent{}, messageType: "workflow_run", }, + + { + payload: &RegistryPackageEvent{}, + messageType: "registry_package", + }, } for _, test := range tests { diff --git a/github/repos_hooks_deliveries_test.go b/github/repos_hooks_deliveries_test.go index 81421c7901c..812895a09b3 100644 --- a/github/repos_hooks_deliveries_test.go +++ b/github/repos_hooks_deliveries_test.go @@ -184,6 +184,7 @@ var hookDeliveryPayloadTypeToStruct = map[string]interface{}{ "pull_request_target": &PullRequestTargetEvent{}, "push": &PushEvent{}, "release": &ReleaseEvent{}, + "registry_package": &RegistryPackageEvent{}, "repository": &RepositoryEvent{}, "repository_dispatch": &RepositoryDispatchEvent{}, "repository_import": &RepositoryImportEvent{}, From 2ea91ea032acbdda8ff28db6b8c75622068b9f59 Mon Sep 17 00:00:00 2001 From: Pavlos Tzianos Date: Wed, 9 Apr 2025 20:59:08 +0100 Subject: [PATCH 2/2] sort all new data structures and test functions --- github/event_types.go | 40 ++-- github/event_types_test.go | 258 +++++++++++++------------- github/messages_test.go | 9 +- github/repos_hooks_deliveries_test.go | 2 +- 4 files changed, 154 insertions(+), 155 deletions(-) diff --git a/github/event_types.go b/github/event_types.go index d956c97df50..b5369865608 100644 --- a/github/event_types.go +++ b/github/event_types.go @@ -1446,6 +1446,26 @@ type PushEventRepoOwner struct { Email *string `json:"email,omitempty"` } +// RegistryPackageEvent represents activity related to GitHub Packages. +// The Webhook event name is "registry_package". +// +// This event is triggered when a GitHub Package is published or updated. +// +// GitHub API docs: https://docs.github.com/en/webhooks/webhook-events-and-payloads#registry_package +type RegistryPackageEvent struct { + // Action is the action that was performed. + // Can be "published" or "updated". + Action *string `json:"action,omitempty"` + RegistryPackage *Package `json:"registry_package,omitempty"` + Repository *Repository `json:"repository,omitempty"` + Organization *Organization `json:"organization,omitempty"` + Enterprise *Enterprise `json:"enterprise,omitempty"` + Sender *User `json:"sender,omitempty"` + + // The following fields are only populated by Webhook events. + Installation *Installation `json:"installation,omitempty"` +} + // ReleaseEvent is triggered when a release is published, unpublished, created, // edited, deleted, or prereleased. // The Webhook event name is "release". @@ -1467,26 +1487,6 @@ type ReleaseEvent struct { Org *Organization `json:"organization,omitempty"` } -// RegistryPackageEvent represents activity related to GitHub Packages. -// The Webhook event name is "registry_package". -// -// This event is triggered when a GitHub Package is published or updated. -// -// GitHub API docs: https://docs.github.com/en/webhooks/webhook-events-and-payloads#registry_package -type RegistryPackageEvent struct { - // Action is the action that was performed. - // Can be "published" or "updated". - Action *string `json:"action,omitempty"` - RegistryPackage *Package `json:"registry_package,omitempty"` - Repository *Repository `json:"repository,omitempty"` - Organization *Organization `json:"organization,omitempty"` - Enterprise *Enterprise `json:"enterprise,omitempty"` - Sender *User `json:"sender,omitempty"` - - // The following fields are only populated by Webhook events. - Installation *Installation `json:"installation,omitempty"` -} - // RepositoryEvent is triggered when a repository is created, archived, unarchived, // renamed, edited, transferred, made public, or made private. Organization hooks are // also triggered when a repository is deleted. diff --git a/github/event_types_test.go b/github/event_types_test.go index 3cfe6034eba..17dd96d8ac8 100644 --- a/github/event_types_test.go +++ b/github/event_types_test.go @@ -8320,135 +8320,6 @@ func TestPackageEvent_Marshal(t *testing.T) { testJSONMarshal(t, u, want) } -func TestRegistryPackageEvent_Marshal(t *testing.T) { - t.Parallel() - testJSONMarshal(t, &RegistryPackageEvent{}, "{}") - - u := &RegistryPackageEvent{ - Action: Ptr("a"), - RegistryPackage: &Package{ - ID: Ptr(int64(1)), - Name: Ptr("n"), - PackageType: Ptr("pt"), - HTMLURL: Ptr("hurl"), - CreatedAt: &Timestamp{referenceTime}, - UpdatedAt: &Timestamp{referenceTime}, - Owner: &User{ - Login: Ptr("l"), - ID: Ptr(int64(1)), - NodeID: Ptr("n"), - URL: Ptr("u"), - ReposURL: Ptr("r"), - EventsURL: Ptr("e"), - AvatarURL: Ptr("a"), - }, - PackageVersion: &PackageVersion{ID: Ptr(int64(1))}, - Registry: &PackageRegistry{Name: Ptr("n")}, - }, - Repository: &Repository{ - ID: Ptr(int64(1)), - URL: Ptr("s"), - Name: Ptr("n"), - }, - Organization: &Organization{ - BillingEmail: Ptr("be"), - Blog: Ptr("b"), - Company: Ptr("c"), - Email: Ptr("e"), - TwitterUsername: Ptr("tu"), - Location: Ptr("loc"), - Name: Ptr("n"), - Description: Ptr("d"), - IsVerified: Ptr(true), - HasOrganizationProjects: Ptr(true), - HasRepositoryProjects: Ptr(true), - DefaultRepoPermission: Ptr("drp"), - MembersCanCreateRepos: Ptr(true), - MembersCanCreateInternalRepos: Ptr(true), - MembersCanCreatePrivateRepos: Ptr(true), - MembersCanCreatePublicRepos: Ptr(false), - MembersAllowedRepositoryCreationType: Ptr("marct"), - MembersCanCreatePages: Ptr(true), - MembersCanCreatePublicPages: Ptr(false), - MembersCanCreatePrivatePages: Ptr(true), - }, - Sender: &User{ - Login: Ptr("l"), - ID: Ptr(int64(1)), - NodeID: Ptr("n"), - URL: Ptr("u"), - ReposURL: Ptr("r"), - EventsURL: Ptr("e"), - AvatarURL: Ptr("a"), - }, - } - - want := `{ - "action": "a", - "registry_package": { - "id": 1, - "name": "n", - "package_type": "pt", - "html_url": "hurl", - "created_at": ` + referenceTimeStr + `, - "updated_at": ` + referenceTimeStr + `, - "owner": { - "login": "l", - "id": 1, - "node_id": "n", - "avatar_url": "a", - "url": "u", - "events_url": "e", - "repos_url": "r" - }, - "package_version": { - "id": 1 - }, - "registry": { - "name": "n" - } - }, - "repository": { - "id": 1, - "name": "n", - "url": "s" - }, - "organization": { - "name": "n", - "company": "c", - "blog": "b", - "location": "loc", - "email": "e", - "twitter_username": "tu", - "description": "d", - "billing_email": "be", - "is_verified": true, - "has_organization_projects": true, - "has_repository_projects": true, - "default_repository_permission": "drp", - "members_can_create_repositories": true, - "members_can_create_public_repositories": false, - "members_can_create_private_repositories": true, - "members_can_create_internal_repositories": true, - "members_allowed_repository_creation_type": "marct", - "members_can_create_pages": true, - "members_can_create_public_pages": false, - "members_can_create_private_pages": true - }, - "sender": { - "login": "l", - "id": 1, - "node_id": "n", - "avatar_url": "a", - "url": "u", - "events_url": "e", - "repos_url": "r" - } - }` - - testJSONMarshal(t, u, want) -} - func TestPersonalAccessTokenRequestEvent_Marshal(t *testing.T) { t.Parallel() testJSONMarshal(t, &PersonalAccessTokenRequestEvent{}, "{}") @@ -8769,6 +8640,135 @@ func TestPingEvent_Marshal(t *testing.T) { testJSONMarshal(t, u, want) } +func TestRegistryPackageEvent_Marshal(t *testing.T) { + t.Parallel() + testJSONMarshal(t, &RegistryPackageEvent{}, "{}") + + u := &RegistryPackageEvent{ + Action: Ptr("a"), + RegistryPackage: &Package{ + ID: Ptr(int64(1)), + Name: Ptr("n"), + PackageType: Ptr("pt"), + HTMLURL: Ptr("hurl"), + CreatedAt: &Timestamp{referenceTime}, + UpdatedAt: &Timestamp{referenceTime}, + Owner: &User{ + Login: Ptr("l"), + ID: Ptr(int64(1)), + NodeID: Ptr("n"), + URL: Ptr("u"), + ReposURL: Ptr("r"), + EventsURL: Ptr("e"), + AvatarURL: Ptr("a"), + }, + PackageVersion: &PackageVersion{ID: Ptr(int64(1))}, + Registry: &PackageRegistry{Name: Ptr("n")}, + }, + Repository: &Repository{ + ID: Ptr(int64(1)), + URL: Ptr("s"), + Name: Ptr("n"), + }, + Organization: &Organization{ + BillingEmail: Ptr("be"), + Blog: Ptr("b"), + Company: Ptr("c"), + Email: Ptr("e"), + TwitterUsername: Ptr("tu"), + Location: Ptr("loc"), + Name: Ptr("n"), + Description: Ptr("d"), + IsVerified: Ptr(true), + HasOrganizationProjects: Ptr(true), + HasRepositoryProjects: Ptr(true), + DefaultRepoPermission: Ptr("drp"), + MembersCanCreateRepos: Ptr(true), + MembersCanCreateInternalRepos: Ptr(true), + MembersCanCreatePrivateRepos: Ptr(true), + MembersCanCreatePublicRepos: Ptr(false), + MembersAllowedRepositoryCreationType: Ptr("marct"), + MembersCanCreatePages: Ptr(true), + MembersCanCreatePublicPages: Ptr(false), + MembersCanCreatePrivatePages: Ptr(true), + }, + Sender: &User{ + Login: Ptr("l"), + ID: Ptr(int64(1)), + NodeID: Ptr("n"), + URL: Ptr("u"), + ReposURL: Ptr("r"), + EventsURL: Ptr("e"), + AvatarURL: Ptr("a"), + }, + } + + want := `{ + "action": "a", + "registry_package": { + "id": 1, + "name": "n", + "package_type": "pt", + "html_url": "hurl", + "created_at": ` + referenceTimeStr + `, + "updated_at": ` + referenceTimeStr + `, + "owner": { + "login": "l", + "id": 1, + "node_id": "n", + "avatar_url": "a", + "url": "u", + "events_url": "e", + "repos_url": "r" + }, + "package_version": { + "id": 1 + }, + "registry": { + "name": "n" + } + }, + "repository": { + "id": 1, + "name": "n", + "url": "s" + }, + "organization": { + "name": "n", + "company": "c", + "blog": "b", + "location": "loc", + "email": "e", + "twitter_username": "tu", + "description": "d", + "billing_email": "be", + "is_verified": true, + "has_organization_projects": true, + "has_repository_projects": true, + "default_repository_permission": "drp", + "members_can_create_repositories": true, + "members_can_create_public_repositories": false, + "members_can_create_private_repositories": true, + "members_can_create_internal_repositories": true, + "members_allowed_repository_creation_type": "marct", + "members_can_create_pages": true, + "members_can_create_public_pages": false, + "members_can_create_private_pages": true + }, + "sender": { + "login": "l", + "id": 1, + "node_id": "n", + "avatar_url": "a", + "url": "u", + "events_url": "e", + "repos_url": "r" + } + }` + + testJSONMarshal(t, u, want) +} + func TestRepositoryDispatchEvent_Marshal(t *testing.T) { t.Parallel() testJSONMarshal(t, &RepositoryDispatchEvent{}, "{}") diff --git a/github/messages_test.go b/github/messages_test.go index 1be311d8779..a2b9feac92b 100644 --- a/github/messages_test.go +++ b/github/messages_test.go @@ -459,6 +459,10 @@ func TestParseWebHook(t *testing.T) { payload: &PushEvent{}, messageType: "push", }, + { + payload: &RegistryPackageEvent{}, + messageType: "registry_package", + }, { payload: &ReleaseEvent{}, messageType: "release", @@ -539,11 +543,6 @@ func TestParseWebHook(t *testing.T) { payload: &WorkflowRunEvent{}, messageType: "workflow_run", }, - - { - payload: &RegistryPackageEvent{}, - messageType: "registry_package", - }, } for _, test := range tests { diff --git a/github/repos_hooks_deliveries_test.go b/github/repos_hooks_deliveries_test.go index 812895a09b3..6acb7a81e69 100644 --- a/github/repos_hooks_deliveries_test.go +++ b/github/repos_hooks_deliveries_test.go @@ -183,8 +183,8 @@ var hookDeliveryPayloadTypeToStruct = map[string]interface{}{ "pull_request_review_thread": &PullRequestReviewThreadEvent{}, "pull_request_target": &PullRequestTargetEvent{}, "push": &PushEvent{}, - "release": &ReleaseEvent{}, "registry_package": &RegistryPackageEvent{}, + "release": &ReleaseEvent{}, "repository": &RepositoryEvent{}, "repository_dispatch": &RepositoryDispatchEvent{}, "repository_import": &RepositoryImportEvent{},