Repository: hub4j/github-api
Pull request #1836 (2024-04-25 20:15:30)

Support repository renamed and transferred in event payload
# Description

Support repository [renamed](https://docs.github.com/en/webhooks/webhook-events-and-payloads?actionType=renamed#repository) and [transferred](https://docs.github.com/en/webhooks/webhook-events-and-payloads?actionType=transferred#repository) in event payload

# Before submitting a PR:

- [x] Changes must not break binary backwards compatibility. If you are unclear on how to make the change you think is needed while maintaining backward compatibility, [CONTRIBUTING.md](CONTRIBUTING.md) for details.
- [x] Add JavaDocs and other comments explaining the behavior. 
- [x] When adding or updating methods that fetch entities, add `@link` JavaDoc entries to the relevant documentation on https://docs.github.com/en/rest . 
- [x] Add tests that cover any added or changed code. This generally requires capturing snapshot test data. See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
- [x] Run `mvn -D enable-ci clean install site` locally. If this command doesn't succeed, your change will not pass CI.
- [x] Push your changes to a branch other than `main`. You will create your PR from that branch.

# When creating a PR: 

- [x] Fill in the "Description" above with clear summary of the changes. This includes:
  - [ ] If this PR fixes one or more issues, include "Fixes #<issue number>" lines for each issue. 
  - [x] Provide links to relevant documentation on https://docs.github.com/en/rest where possible. If not including links, explain why not.
- [x] All lines of new code should be covered by tests as reported by code coverage. Any lines that are not covered must have PR comments explaining why they cannot be covered. For example, "Reaching this particular exception is hard and is not a particular common scenario."
- [x] Enable "Allow edits from maintainers".



Patch:
diff --git a/src/main/java/org/kohsuke/github/GHEventPayload.java b/src/main/java/org/kohsuke/github/GHEventPayload.java
index 91cbde47a..2e34daa29 100644
--- a/src/main/java/org/kohsuke/github/GHEventPayload.java
+++ b/src/main/java/org/kohsuke/github/GHEventPayload.java
@@ -1445,6 +1445,16 @@ public abstract class GHEventPayload extends GitHubInteractiveObject {
      * @see <a href="https://docs.github.com/en/rest/reference/repos">Repositories</a>
      */
     public static class Repository extends GHEventPayload {
+        private GHRepositoryChanges changes;
+
+        /**
+         * Get changes.
+         *
+         * @return GHRepositoryChanges
+         */
+        public GHRepositoryChanges getChanges() {
+            return changes;
+        }
 
     }
 
diff --git a/src/main/java/org/kohsuke/github/GHRepositoryChanges.java b/src/main/java/org/kohsuke/github/GHRepositoryChanges.java
new file mode 100644
index 000000000..9c9aa578d
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/GHRepositoryChanges.java
@@ -0,0 +1,106 @@
+package org.kohsuke.github;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Changes made to a repository.
+ */
+@SuppressFBWarnings(value = { "UWF_UNWRITTEN_FIELD" }, justification = "JSON API")
+public class GHRepositoryChanges {
+    private FromRepository repository;
+    private Owner owner;
+
+    /**
+     * Get outer owner object.
+     *
+     * @return Owner
+     */
+    public Owner getOwner() {
+        return owner;
+    }
+
+    /**
+     * Outer object of owner from whom this repository was transferred.
+     */
+    public static class Owner {
+        private FromOwner from;
+
+        /**
+         * Get in owner object.
+         *
+         * @return FromOwner
+         */
+        public FromOwner getFrom() {
+            return from;
+        }
+    }
+
+    /**
+     * Owner from whom this repository was transferred.
+     */
+    public static class FromOwner {
+        private GHUser user;
+        private GHOrganization organization;
+
+        /**
+         * Get user from which this repository was transferred.
+         *
+         * @return user
+         */
+        @SuppressFBWarnings(value = { "EI_EXPOSE_REP" }, justification = "Expected")
+        public GHUser getUser() {
+            return user;
+        }
+
+        /**
+         * Get organization from which this repository was transferred.
+         *
+         * @return GHOrganization
+         */
+        @SuppressFBWarnings(value = { "EI_EXPOSE_REP" }, justification = "Expected")
+        public GHOrganization getOrganization() {
+            return organization;
+        }
+    }
+
+    /**
+     * Get repository.
+     *
+     * @return FromRepository
+     */
+    public FromRepository getRepository() {
+        return repository;
+    }
+
+    /**
+     * Repository object from which the name was changed.
+     */
+    public static class FromRepository {
+        private FromName name;
+
+        /**
+         * Get top level object for the previous name of the repository.
+         *
+         * @return FromName
+         */
+        public FromName getName() {
+            return name;
+        }
+    }
+
+    /**
+     * Repository name that was changed.
+     */
+    public static class FromName {
+        private String from;
+
+        /**
+         * Get previous name of the repository before rename.
+         *
+         * @return String
+         */
+        public String getFrom() {
+            return from;
+        }
+    }
+}


Test patch:
diff --git a/src/test/java/org/kohsuke/github/GHEventPayloadTest.java b/src/test/java/org/kohsuke/github/GHEventPayloadTest.java
index c346d368d..1e1513c2e 100644
--- a/src/test/java/org/kohsuke/github/GHEventPayloadTest.java
+++ b/src/test/java/org/kohsuke/github/GHEventPayloadTest.java
@@ -772,6 +772,57 @@ public class GHEventPayloadTest extends AbstractGitHubWireMockTest {
         assertThat(event.getSender().getLogin(), is("baxterthehacker"));
     }
 
+    /**
+     * Repository renamed.
+     *
+     * @throws Exception
+     *             the exception
+     */
+    @Test
+    public void repository_renamed() throws Exception {
+        final GHEventPayload.Repository event = GitHub.offline()
+                .parseEventPayload(payload.asReader(), GHEventPayload.Repository.class);
+        assertThat(event.getAction(), is("renamed"));
+        assertThat(event.getChanges().getRepository().getName().getFrom(), is("react-workshop"));
+        assertThat(event.getRepository().getName(), is("react-workshop-renamed"));
+        assertThat(event.getRepository().getOwner().getLogin(), is("EJG-Organization"));
+        assertThat(event.getOrganization().getLogin(), is("EJG-Organization"));
+        assertThat(event.getSender().getLogin(), is("eleanorgoh"));
+    }
+
+    /**
+     * Repository ownership transferred to an organization.
+     *
+     * @throws Exception
+     *             the exception
+     */
+    @Test
+    public void repository_transferred_to_org() throws Exception {
+        final GHEventPayload.Repository event = GitHub.offline()
+                .parseEventPayload(payload.asReader(), GHEventPayload.Repository.class);
+        assertThat(event.getAction(), is("transferred"));
+        assertThat(event.getChanges().getOwner().getFrom().getUser().getLogin(), is("eleanorgoh"));
+        assertThat(event.getChanges().getOwner().getFrom().getUser().getId(), is(66235606L));
+        assertThat(event.getChanges().getOwner().getFrom().getUser().getType(), is("User"));
+    }
+
+    /**
+     * Repository ownership transferred to a user.
+     *
+     * @throws Exception
+     *             the exception
+     */
+    @Test
+    public void repository_transferred_to_user() throws Exception {
+        final GHEventPayload.Repository event = GitHub.offline()
+                .parseEventPayload(payload.asReader(), GHEventPayload.Repository.class);
+        assertThat(event.getAction(), is("transferred"));
+        assertThat(event.getChanges().getOwner().getFrom().getOrganization().getLogin(), is("EJG-Organization"));
+        assertThat(event.getChanges().getOwner().getFrom().getOrganization().getId(), is(168135412L));
+        assertThat(event.getRepository().getOwner().getLogin(), is("eleanorgoh"));
+        assertThat(event.getRepository().getOwner().getType(), is("User"));
+    }
+
     /**
      * Status.
      *
diff --git a/src/test/resources/org/kohsuke/github/GHEventPayloadTest/repository_renamed.json b/src/test/resources/org/kohsuke/github/GHEventPayloadTest/repository_renamed.json
new file mode 100644
index 000000000..bd278f010
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHEventPayloadTest/repository_renamed.json
@@ -0,0 +1,149 @@
+{
+  "action": "renamed",
+  "changes": {
+    "repository": {
+      "name": {
+        "from": "react-workshop"
+      }
+    }
+  },
+  "repository": {
+    "id": 360319037,
+    "node_id": "MDEwOlJlcG9zaXRvcnkzNjAzMTkwMzc=",
+    "name": "react-workshop-renamed",
+    "full_name": "EJG-Organization/react-workshop-renamed",
+    "private": false,
+    "owner": {
+      "login": "EJG-Organization",
+      "id": 168135412,
+      "node_id": "O_kgDOCgWK9A",
+      "avatar_url": "https://avatars.githubusercontent.com/u/168135412?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/EJG-Organization",
+      "html_url": "https://github.com/EJG-Organization",
+      "followers_url": "https://api.github.com/users/EJG-Organization/followers",
+      "following_url": "https://api.github.com/users/EJG-Organization/following{/other_user}",
+      "gists_url": "https://api.github.com/users/EJG-Organization/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/EJG-Organization/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/EJG-Organization/subscriptions",
+      "organizations_url": "https://api.github.com/users/EJG-Organization/orgs",
+      "repos_url": "https://api.github.com/users/EJG-Organization/repos",
+      "events_url": "https://api.github.com/users/EJG-Organization/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/EJG-Organization/received_events",
+      "type": "Organization",
+      "site_admin": false
+    },
+    "html_url": "https://github.com/EJG-Organization/react-workshop-renamed",
+    "description": null,
+    "fork": true,
+    "url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed",
+    "forks_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/forks",
+    "keys_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/keys{/key_id}",
+    "collaborators_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/collaborators{/collaborator}",
+    "teams_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/teams",
+    "hooks_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/hooks",
+    "issue_events_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/issues/events{/number}",
+    "events_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/events",
+    "assignees_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/assignees{/user}",
+    "branches_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/branches{/branch}",
+    "tags_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/tags",
+    "blobs_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/git/blobs{/sha}",
+    "git_tags_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/git/tags{/sha}",
+    "git_refs_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/git/refs{/sha}",
+    "trees_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/git/trees{/sha}",
+    "statuses_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/statuses/{sha}",
+    "languages_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/languages",
+    "stargazers_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/stargazers",
+    "contributors_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/contributors",
+    "subscribers_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/subscribers",
+    "subscription_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/subscription",
+    "commits_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/commits{/sha}",
+    "git_commits_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/git/commits{/sha}",
+    "comments_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/comments{/number}",
+    "issue_comment_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/issues/comments{/number}",
+    "contents_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/contents/{+path}",
+    "compare_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/compare/{base}...{head}",
+    "merges_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/merges",
+    "archive_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/{archive_format}{/ref}",
+    "downloads_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/downloads",
+    "issues_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/issues{/number}",
+    "pulls_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/pulls{/number}",
+    "milestones_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/milestones{/number}",
+    "notifications_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/notifications{?since,all,participating}",
+    "labels_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/labels{/name}",
+    "releases_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/releases{/id}",
+    "deployments_url": "https://api.github.com/repos/EJG-Organization/react-workshop-renamed/deployments",
+    "created_at": "2021-04-21T22:09:16Z",
+    "updated_at": "2024-04-25T20:31:00Z",
+    "pushed_at": "2021-04-21T03:47:44Z",
+    "git_url": "git://github.com/EJG-Organization/react-workshop-renamed.git",
+    "ssh_url": "git@github.com:EJG-Organization/react-workshop-renamed.git",
+    "clone_url": "https://github.com/EJG-Organization/react-workshop-renamed.git",
+    "svn_url": "https://github.com/EJG-Organization/react-workshop-renamed",
+    "homepage": null,
+    "size": 196,
+    "stargazers_count": 0,
+    "watchers_count": 0,
+    "language": null,
+    "has_issues": false,
+    "has_projects": true,
+    "has_downloads": true,
+    "has_wiki": true,
+    "has_pages": false,
+    "has_discussions": false,
+    "forks_count": 0,
+    "mirror_url": null,
+    "archived": false,
+    "disabled": false,
+    "open_issues_count": 0,
+    "license": null,
+    "allow_forking": true,
+    "is_template": false,
+    "web_commit_signoff_required": false,
+    "topics": [
+
+    ],
+    "visibility": "public",
+    "forks": 0,
+    "open_issues": 0,
+    "watchers": 0,
+    "default_branch": "main",
+    "custom_properties": {
+
+    }
+  },
+  "organization": {
+    "login": "EJG-Organization",
+    "id": 168135412,
+    "node_id": "O_kgDOCgWK9A",
+    "url": "https://api.github.com/orgs/EJG-Organization",
+    "repos_url": "https://api.github.com/orgs/EJG-Organization/repos",
+    "events_url": "https://api.github.com/orgs/EJG-Organization/events",
+    "hooks_url": "https://api.github.com/orgs/EJG-Organization/hooks",
+    "issues_url": "https://api.github.com/orgs/EJG-Organization/issues",
+    "members_url": "https://api.github.com/orgs/EJG-Organization/members{/member}",
+    "public_members_url": "https://api.github.com/orgs/EJG-Organization/public_members{/member}",
+    "avatar_url": "https://avatars.githubusercontent.com/u/168135412?v=4",
+    "description": null
+  },
+  "sender": {
+    "login": "eleanorgoh",
+    "id": 66235606,
+    "node_id": "MDQ6VXNlcjY2MjM1NjA2",
+    "avatar_url": "https://avatars.githubusercontent.com/u/66235606?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/eleanorgoh",
+    "html_url": "https://github.com/eleanorgoh",
+    "followers_url": "https://api.github.com/users/eleanorgoh/followers",
+    "following_url": "https://api.github.com/users/eleanorgoh/following{/other_user}",
+    "gists_url": "https://api.github.com/users/eleanorgoh/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/eleanorgoh/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/eleanorgoh/subscriptions",
+    "organizations_url": "https://api.github.com/users/eleanorgoh/orgs",
+    "repos_url": "https://api.github.com/users/eleanorgoh/repos",
+    "events_url": "https://api.github.com/users/eleanorgoh/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/eleanorgoh/received_events",
+    "type": "User",
+    "site_admin": false
+  }
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHEventPayloadTest/repository_transferred_to_org.json b/src/test/resources/org/kohsuke/github/GHEventPayloadTest/repository_transferred_to_org.json
new file mode 100644
index 000000000..2e5814818
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHEventPayloadTest/repository_transferred_to_org.json
@@ -0,0 +1,168 @@
+{
+  "action": "transferred",
+  "changes": {
+    "owner": {
+      "from": {
+        "user": {
+          "login": "eleanorgoh",
+          "id": 66235606,
+          "node_id": "MDQ6VXNlcjY2MjM1NjA2",
+          "avatar_url": "https://avatars.githubusercontent.com/u/66235606?v=4",
+          "gravatar_id": "",
+          "url": "https://api.github.com/users/eleanorgoh",
+          "html_url": "https://github.com/eleanorgoh",
+          "followers_url": "https://api.github.com/users/eleanorgoh/followers",
+          "following_url": "https://api.github.com/users/eleanorgoh/following{/other_user}",
+          "gists_url": "https://api.github.com/users/eleanorgoh/gists{/gist_id}",
+          "starred_url": "https://api.github.com/users/eleanorgoh/starred{/owner}{/repo}",
+          "subscriptions_url": "https://api.github.com/users/eleanorgoh/subscriptions",
+          "organizations_url": "https://api.github.com/users/eleanorgoh/orgs",
+          "repos_url": "https://api.github.com/users/eleanorgoh/repos",
+          "events_url": "https://api.github.com/users/eleanorgoh/events{/privacy}",
+          "received_events_url": "https://api.github.com/users/eleanorgoh/received_events",
+          "type": "User",
+          "site_admin": false
+        }
+      }
+    }
+  },
+  "repository": {
+    "id": 360319037,
+    "node_id": "MDEwOlJlcG9zaXRvcnkzNjAzMTkwMzc=",
+    "name": "react-workshop",
+    "full_name": "EJG-Organization/react-workshop",
+    "private": false,
+    "owner": {
+      "login": "EJG-Organization",
+      "id": 168135412,
+      "node_id": "O_kgDOCgWK9A",
+      "avatar_url": "https://avatars.githubusercontent.com/u/168135412?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/EJG-Organization",
+      "html_url": "https://github.com/EJG-Organization",
+      "followers_url": "https://api.github.com/users/EJG-Organization/followers",
+      "following_url": "https://api.github.com/users/EJG-Organization/following{/other_user}",
+      "gists_url": "https://api.github.com/users/EJG-Organization/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/EJG-Organization/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/EJG-Organization/subscriptions",
+      "organizations_url": "https://api.github.com/users/EJG-Organization/orgs",
+      "repos_url": "https://api.github.com/users/EJG-Organization/repos",
+      "events_url": "https://api.github.com/users/EJG-Organization/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/EJG-Organization/received_events",
+      "type": "Organization",
+      "site_admin": false
+    },
+    "html_url": "https://github.com/EJG-Organization/react-workshop",
+    "description": null,
+    "fork": true,
+    "url": "https://api.github.com/repos/EJG-Organization/react-workshop",
+    "forks_url": "https://api.github.com/repos/EJG-Organization/react-workshop/forks",
+    "keys_url": "https://api.github.com/repos/EJG-Organization/react-workshop/keys{/key_id}",
+    "collaborators_url": "https://api.github.com/repos/EJG-Organization/react-workshop/collaborators{/collaborator}",
+    "teams_url": "https://api.github.com/repos/EJG-Organization/react-workshop/teams",
+    "hooks_url": "https://api.github.com/repos/EJG-Organization/react-workshop/hooks",
+    "issue_events_url": "https://api.github.com/repos/EJG-Organization/react-workshop/issues/events{/number}",
+    "events_url": "https://api.github.com/repos/EJG-Organization/react-workshop/events",
+    "assignees_url": "https://api.github.com/repos/EJG-Organization/react-workshop/assignees{/user}",
+    "branches_url": "https://api.github.com/repos/EJG-Organization/react-workshop/branches{/branch}",
+    "tags_url": "https://api.github.com/repos/EJG-Organization/react-workshop/tags",
+    "blobs_url": "https://api.github.com/repos/EJG-Organization/react-workshop/git/blobs{/sha}",
+    "git_tags_url": "https://api.github.com/repos/EJG-Organization/react-workshop/git/tags{/sha}",
+    "git_refs_url": "https://api.github.com/repos/EJG-Organization/react-workshop/git/refs{/sha}",
+    "trees_url": "https://api.github.com/repos/EJG-Organization/react-workshop/git/trees{/sha}",
+    "statuses_url": "https://api.github.com/repos/EJG-Organization/react-workshop/statuses/{sha}",
+    "languages_url": "https://api.github.com/repos/EJG-Organization/react-workshop/languages",
+    "stargazers_url": "https://api.github.com/repos/EJG-Organization/react-workshop/stargazers",
+    "contributors_url": "https://api.github.com/repos/EJG-Organization/react-workshop/contributors",
+    "subscribers_url": "https://api.github.com/repos/EJG-Organization/react-workshop/subscribers",
+    "subscription_url": "https://api.github.com/repos/EJG-Organization/react-workshop/subscription",
+    "commits_url": "https://api.github.com/repos/EJG-Organization/react-workshop/commits{/sha}",
+    "git_commits_url": "https://api.github.com/repos/EJG-Organization/react-workshop/git/commits{/sha}",
+    "comments_url": "https://api.github.com/repos/EJG-Organization/react-workshop/comments{/number}",
+    "issue_comment_url": "https://api.github.com/repos/EJG-Organization/react-workshop/issues/comments{/number}",
+    "contents_url": "https://api.github.com/repos/EJG-Organization/react-workshop/contents/{+path}",
+    "compare_url": "https://api.github.com/repos/EJG-Organization/react-workshop/compare/{base}...{head}",
+    "merges_url": "https://api.github.com/repos/EJG-Organization/react-workshop/merges",
+    "archive_url": "https://api.github.com/repos/EJG-Organization/react-workshop/{archive_format}{/ref}",
+    "downloads_url": "https://api.github.com/repos/EJG-Organization/react-workshop/downloads",
+    "issues_url": "https://api.github.com/repos/EJG-Organization/react-workshop/issues{/number}",
+    "pulls_url": "https://api.github.com/repos/EJG-Organization/react-workshop/pulls{/number}",
+    "milestones_url": "https://api.github.com/repos/EJG-Organization/react-workshop/milestones{/number}",
+    "notifications_url": "https://api.github.com/repos/EJG-Organization/react-workshop/notifications{?since,all,participating}",
+    "labels_url": "https://api.github.com/repos/EJG-Organization/react-workshop/labels{/name}",
+    "releases_url": "https://api.github.com/repos/EJG-Organization/react-workshop/releases{/id}",
+    "deployments_url": "https://api.github.com/repos/EJG-Organization/react-workshop/deployments",
+    "created_at": "2021-04-21T22:09:16Z",
+    "updated_at": "2024-04-25T20:28:46Z",
+    "pushed_at": "2021-04-21T03:47:44Z",
+    "git_url": "git://github.com/EJG-Organization/react-workshop.git",
+    "ssh_url": "git@github.com:EJG-Organization/react-workshop.git",
+    "clone_url": "https://github.com/EJG-Organization/react-workshop.git",
+    "svn_url": "https://github.com/EJG-Organization/react-workshop",
+    "homepage": null,
+    "size": 196,
+    "stargazers_count": 0,
+    "watchers_count": 0,
+    "language": null,
+    "has_issues": false,
+    "has_projects": true,
+    "has_downloads": true,
+    "has_wiki": true,
+    "has_pages": false,
+    "has_discussions": false,
+    "forks_count": 0,
+    "mirror_url": null,
+    "archived": false,
+    "disabled": false,
+    "open_issues_count": 0,
+    "license": null,
+    "allow_forking": true,
+    "is_template": false,
+    "web_commit_signoff_required": false,
+    "topics": [
+
+    ],
+    "visibility": "public",
+    "forks": 0,
+    "open_issues": 0,
+    "watchers": 0,
+    "default_branch": "main",
+    "custom_properties": {
+
+    }
+  },
+  "organization": {
+    "login": "EJG-Organization",
+    "id": 168135412,
+    "node_id": "O_kgDOCgWK9A",
+    "url": "https://api.github.com/orgs/EJG-Organization",
+    "repos_url": "https://api.github.com/orgs/EJG-Organization/repos",
+    "events_url": "https://api.github.com/orgs/EJG-Organization/events",
+    "hooks_url": "https://api.github.com/orgs/EJG-Organization/hooks",
+    "issues_url": "https://api.github.com/orgs/EJG-Organization/issues",
+    "members_url": "https://api.github.com/orgs/EJG-Organization/members{/member}",
+    "public_members_url": "https://api.github.com/orgs/EJG-Organization/public_members{/member}",
+    "avatar_url": "https://avatars.githubusercontent.com/u/168135412?v=4",
+    "description": null
+  },
+  "sender": {
+    "login": "eleanorgoh",
+    "id": 66235606,
+    "node_id": "MDQ6VXNlcjY2MjM1NjA2",
+    "avatar_url": "https://avatars.githubusercontent.com/u/66235606?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/eleanorgoh",
+    "html_url": "https://github.com/eleanorgoh",
+    "followers_url": "https://api.github.com/users/eleanorgoh/followers",
+    "following_url": "https://api.github.com/users/eleanorgoh/following{/other_user}",
+    "gists_url": "https://api.github.com/users/eleanorgoh/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/eleanorgoh/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/eleanorgoh/subscriptions",
+    "organizations_url": "https://api.github.com/users/eleanorgoh/orgs",
+    "repos_url": "https://api.github.com/users/eleanorgoh/repos",
+    "events_url": "https://api.github.com/users/eleanorgoh/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/eleanorgoh/received_events",
+    "type": "User",
+    "site_admin": false
+  }
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHEventPayloadTest/repository_transferred_to_user.json b/src/test/resources/org/kohsuke/github/GHEventPayloadTest/repository_transferred_to_user.json
new file mode 100644
index 000000000..57fbd5502
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHEventPayloadTest/repository_transferred_to_user.json
@@ -0,0 +1,145 @@
+{
+  "action": "transferred",
+  "changes": {
+    "owner": {
+      "from": {
+        "organization": {
+          "login": "EJG-Organization",
+          "id": 168135412,
+          "node_id": "O_kgDOCgWK9A",
+          "url": "https://api.github.com/orgs/EJG-Organization",
+          "repos_url": "https://api.github.com/orgs/EJG-Organization/repos",
+          "events_url": "https://api.github.com/orgs/EJG-Organization/events",
+          "hooks_url": "https://api.github.com/orgs/EJG-Organization/hooks",
+          "issues_url": "https://api.github.com/orgs/EJG-Organization/issues",
+          "members_url": "https://api.github.com/orgs/EJG-Organization/members{/member}",
+          "public_members_url": "https://api.github.com/orgs/EJG-Organization/public_members{/member}",
+          "avatar_url": "https://avatars.githubusercontent.com/u/168135412?v=4",
+          "description": null
+        }
+      }
+    }
+  },
+  "repository": {
+    "id": 360319037,
+    "node_id": "MDEwOlJlcG9zaXRvcnkzNjAzMTkwMzc=",
+    "name": "react-workshop-renamed",
+    "full_name": "eleanorgoh/react-workshop-renamed",
+    "private": false,
+    "owner": {
+      "login": "eleanorgoh",
+      "id": 66235606,
+      "node_id": "MDQ6VXNlcjY2MjM1NjA2",
+      "avatar_url": "https://avatars.githubusercontent.com/u/66235606?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/eleanorgoh",
+      "html_url": "https://github.com/eleanorgoh",
+      "followers_url": "https://api.github.com/users/eleanorgoh/followers",
+      "following_url": "https://api.github.com/users/eleanorgoh/following{/other_user}",
+      "gists_url": "https://api.github.com/users/eleanorgoh/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/eleanorgoh/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/eleanorgoh/subscriptions",
+      "organizations_url": "https://api.github.com/users/eleanorgoh/orgs",
+      "repos_url": "https://api.github.com/users/eleanorgoh/repos",
+      "events_url": "https://api.github.com/users/eleanorgoh/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/eleanorgoh/received_events",
+      "type": "User",
+      "site_admin": false
+    },
+    "html_url": "https://github.com/eleanorgoh/react-workshop-renamed",
+    "description": null,
+    "fork": true,
+    "url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed",
+    "forks_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/forks",
+    "keys_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/keys{/key_id}",
+    "collaborators_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/collaborators{/collaborator}",
+    "teams_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/teams",
+    "hooks_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/hooks",
+    "issue_events_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/issues/events{/number}",
+    "events_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/events",
+    "assignees_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/assignees{/user}",
+    "branches_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/branches{/branch}",
+    "tags_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/tags",
+    "blobs_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/git/blobs{/sha}",
+    "git_tags_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/git/tags{/sha}",
+    "git_refs_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/git/refs{/sha}",
+    "trees_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/git/trees{/sha}",
+    "statuses_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/statuses/{sha}",
+    "languages_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/languages",
+    "stargazers_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/stargazers",
+    "contributors_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/contributors",
+    "subscribers_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/subscribers",
+    "subscription_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/subscription",
+    "commits_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/commits{/sha}",
+    "git_commits_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/git/commits{/sha}",
+    "comments_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/comments{/number}",
+    "issue_comment_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/issues/comments{/number}",
+    "contents_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/contents/{+path}",
+    "compare_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/compare/{base}...{head}",
+    "merges_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/merges",
+    "archive_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/{archive_format}{/ref}",
+    "downloads_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/downloads",
+    "issues_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/issues{/number}",
+    "pulls_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/pulls{/number}",
+    "milestones_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/milestones{/number}",
+    "notifications_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/notifications{?since,all,participating}",
+    "labels_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/labels{/name}",
+    "releases_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/releases{/id}",
+    "deployments_url": "https://api.github.com/repos/eleanorgoh/react-workshop-renamed/deployments",
+    "created_at": "2021-04-21T22:09:16Z",
+    "updated_at": "2024-04-25T20:36:56Z",
+    "pushed_at": "2021-04-21T03:47:44Z",
+    "git_url": "git://github.com/eleanorgoh/react-workshop-renamed.git",
+    "ssh_url": "git@github.com:eleanorgoh/react-workshop-renamed.git",
+    "clone_url": "https://github.com/eleanorgoh/react-workshop-renamed.git",
+    "svn_url": "https://github.com/eleanorgoh/react-workshop-renamed",
+    "homepage": null,
+    "size": 196,
+    "stargazers_count": 0,
+    "watchers_count": 0,
+    "language": null,
+    "has_issues": false,
+    "has_projects": true,
+    "has_downloads": true,
+    "has_wiki": true,
+    "has_pages": false,
+    "has_discussions": false,
+    "forks_count": 0,
+    "mirror_url": null,
+    "archived": false,
+    "disabled": false,
+    "open_issues_count": 0,
+    "license": null,
+    "allow_forking": true,
+    "is_template": false,
+    "web_commit_signoff_required": false,
+    "topics": [
+
+    ],
+    "visibility": "public",
+    "forks": 0,
+    "open_issues": 0,
+    "watchers": 0,
+    "default_branch": "main"
+  },
+  "sender": {
+    "login": "eleanorgoh",
+    "id": 66235606,
+    "node_id": "MDQ6VXNlcjY2MjM1NjA2",
+    "avatar_url": "https://avatars.githubusercontent.com/u/66235606?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/eleanorgoh",
+    "html_url": "https://github.com/eleanorgoh",
+    "followers_url": "https://api.github.com/users/eleanorgoh/followers",
+    "following_url": "https://api.github.com/users/eleanorgoh/following{/other_user}",
+    "gists_url": "https://api.github.com/users/eleanorgoh/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/eleanorgoh/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/eleanorgoh/subscriptions",
+    "organizations_url": "https://api.github.com/users/eleanorgoh/orgs",
+    "repos_url": "https://api.github.com/users/eleanorgoh/repos",
+    "events_url": "https://api.github.com/users/eleanorgoh/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/eleanorgoh/received_events",
+    "type": "User",
+    "site_admin": false
+  }
+}
\ No newline at end of file