From 33c39f3cfc0f7bbb28ac0a3e9e43d096f937d7fd Mon Sep 17 00:00:00 2001 From: Anuj Hydrabadi <129152617+anujhydrabadi@users.noreply.github.com> Date: Tue, 21 Jan 2025 12:27:00 +0530 Subject: [PATCH] List app installation requests endpoint (#2012) Co-authored-by: Liam Newman --- src/main/java/org/kohsuke/github/GHApp.java | 16 ++++++ .../github/GHAppInstallationRequest.java | 42 ++++++++++++++++ .../github-api/serialization-config.json | 5 +- .../java/org/kohsuke/github/GHAppTest.java | 22 +++++++++ .../__files/1-app.json | 42 ++++++++++++++++ .../__files/2-app_installation-requests.json | 49 +++++++++++++++++++ .../mappings/1-app.json | 39 +++++++++++++++ .../mappings/2-app_installation-requests.json | 39 +++++++++++++++ 8 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/kohsuke/github/GHAppInstallationRequest.java create mode 100644 src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/__files/1-app.json create mode 100644 src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/__files/2-app_installation-requests.json create mode 100644 src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/mappings/1-app.json create mode 100644 src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/mappings/2-app_installation-requests.json diff --git a/src/main/java/org/kohsuke/github/GHApp.java b/src/main/java/org/kohsuke/github/GHApp.java index fd1db5c609..9a6ba57072 100644 --- a/src/main/java/org/kohsuke/github/GHApp.java +++ b/src/main/java/org/kohsuke/github/GHApp.java @@ -120,6 +120,22 @@ public Map getPermissions() { return Collections.unmodifiableMap(permissions); } + /** + * Obtains all the installation requests associated with this app. + *

+ * You must use a JWT to access this endpoint. + * + * @return a list of App installation requests + * @see List + * installation requests + */ + public PagedIterable listInstallationRequests() { + return root().createRequest() + .withUrlPath("/app/installation-requests") + .toIterable(GHAppInstallationRequest[].class, null); + } + /** * Obtains all the installations associated with this app. *

diff --git a/src/main/java/org/kohsuke/github/GHAppInstallationRequest.java b/src/main/java/org/kohsuke/github/GHAppInstallationRequest.java new file mode 100644 index 0000000000..a2e7c279fe --- /dev/null +++ b/src/main/java/org/kohsuke/github/GHAppInstallationRequest.java @@ -0,0 +1,42 @@ +package org.kohsuke.github; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +/** + * A Github App Installation Request. + * + * @author Anuj Hydrabadi + * @see GHApp#listInstallationRequests() GHApp#listInstallationRequests() + */ +public class GHAppInstallationRequest extends GHObject { + /** + * Create default GHAppInstallationRequest instance + */ + public GHAppInstallationRequest() { + } + + private GHOrganization account; + + private GHUser requester; + + /** + * Gets the organization where the app was requested to be installed. + * + * @return the organization where the app was requested to be installed. + */ + @SuppressFBWarnings(value = { "EI_EXPOSE_REP", "UWF_UNWRITTEN_FIELD" }, justification = "Expected behavior") + public GHOrganization getAccount() { + return account; + } + + /** + * Gets the user who requested the installation. + * + * @return the user who requested the installation. + */ + @SuppressFBWarnings(value = { "EI_EXPOSE_REP", "UWF_UNWRITTEN_FIELD" }, justification = "Expected behavior") + public GHUser getRequester() { + return requester; + } + +} diff --git a/src/main/resources/META-INF/native-image/org.kohsuke/github-api/serialization-config.json b/src/main/resources/META-INF/native-image/org.kohsuke/github-api/serialization-config.json index 6c7dd370a1..3e80bb939b 100644 --- a/src/main/resources/META-INF/native-image/org.kohsuke/github-api/serialization-config.json +++ b/src/main/resources/META-INF/native-image/org.kohsuke/github-api/serialization-config.json @@ -119,6 +119,9 @@ { "name": "org.kohsuke.github.GHAppInstallationsPage" }, + { + "name": "org.kohsuke.github.GHAppInstallationRequest" + }, { "name": "org.kohsuke.github.GHAppInstallationToken" }, @@ -1340,4 +1343,4 @@ { "name": "org.kohsuke.github.SkipFromToString" } -] \ No newline at end of file +] diff --git a/src/test/java/org/kohsuke/github/GHAppTest.java b/src/test/java/org/kohsuke/github/GHAppTest.java index 27a3023636..8b74185140 100644 --- a/src/test/java/org/kohsuke/github/GHAppTest.java +++ b/src/test/java/org/kohsuke/github/GHAppTest.java @@ -69,6 +69,28 @@ public void getGitHubApp() throws IOException { assertThat(app.getInstallationsCount(), is((long) 1)); } + /** + * List installation requests. + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + @Test + public void listInstallationRequests() throws IOException { + GHApp app = gitHub.getApp(); + List installations = app.listInstallationRequests().toList(); + assertThat(installations.size(), is(1)); + + GHAppInstallationRequest appInstallation = installations.get(0); + assertThat(appInstallation.getId(), is((long) 1037204)); + assertThat(appInstallation.getAccount().getId(), is((long) 195438329)); + assertThat(appInstallation.getAccount().getLogin(), is("approval-test")); + assertThat(appInstallation.getRequester().getId(), is((long) 195437694)); + assertThat(appInstallation.getRequester().getLogin(), is("kaladinstormblessed2")); + assertThat(appInstallation.getCreatedAt(), is(GitHubClient.parseDate("2025-01-17T15:50:51Z"))); + assertThat(appInstallation.getNodeId(), is("MDMwOkludGVncmF0aW9uSW5zdGFsbGF0aW9uUmVxdWVzdDEwMzcyMDQ=")); + } + /** * List installations. * diff --git a/src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/__files/1-app.json b/src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/__files/1-app.json new file mode 100644 index 0000000000..6eddba3601 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/__files/1-app.json @@ -0,0 +1,42 @@ +{ + "id": 986532, + "client_id": "Iv23liTxF5NAu46u9qto", + "slug": "anuj-github-app", + "node_id": "A_kwDOB7K2ac4ADw2k", + "owner": { + "login": "kaladinstormblessed", + "id": 129152617, + "node_id": "U_kgDOB7K2aQ", + "avatar_url": "https://avatars.githubusercontent.com/u/129152617?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/kaladinstormblessed", + "html_url": "https://github.com/kaladinstormblessed", + "followers_url": "https://api.github.com/users/kaladinstormblessed/followers", + "following_url": "https://api.github.com/users/kaladinstormblessed/following{/other_user}", + "gists_url": "https://api.github.com/users/kaladinstormblessed/gists{/gist_id}", + "starred_url": "https://api.github.com/users/kaladinstormblessed/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/kaladinstormblessed/subscriptions", + "organizations_url": "https://api.github.com/users/kaladinstormblessed/orgs", + "repos_url": "https://api.github.com/users/kaladinstormblessed/repos", + "events_url": "https://api.github.com/users/kaladinstormblessed/events{/privacy}", + "received_events_url": "https://api.github.com/users/kaladinstormblessed/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "name": "anuj-github-app", + "description": "", + "external_url": "https://cloud.cloud", + "html_url": "https://github.com/apps/anuj-github-app", + "created_at": "2024-09-03T07:14:38Z", + "updated_at": "2025-01-17T10:52:47Z", + "permissions": { + "administration": "write", + "contents": "write", + "members": "read", + "metadata": "read", + "pull_requests": "read" + }, + "events": [], + "installations_count": 6 +} diff --git a/src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/__files/2-app_installation-requests.json b/src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/__files/2-app_installation-requests.json new file mode 100644 index 0000000000..46c2ad4c16 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/__files/2-app_installation-requests.json @@ -0,0 +1,49 @@ +[ + { + "id": 1037204, + "node_id": "MDMwOkludGVncmF0aW9uSW5zdGFsbGF0aW9uUmVxdWVzdDEwMzcyMDQ=", + "account": { + "login": "approval-test", + "id": 195438329, + "node_id": "O_kgDOC6Ym-Q", + "avatar_url": "https://avatars.githubusercontent.com/u/195438329?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/approval-test", + "html_url": "https://github.com/approval-test", + "followers_url": "https://api.github.com/users/approval-test/followers", + "following_url": "https://api.github.com/users/approval-test/following{/other_user}", + "gists_url": "https://api.github.com/users/approval-test/gists{/gist_id}", + "starred_url": "https://api.github.com/users/approval-test/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/approval-test/subscriptions", + "organizations_url": "https://api.github.com/users/approval-test/orgs", + "repos_url": "https://api.github.com/users/approval-test/repos", + "events_url": "https://api.github.com/users/approval-test/events{/privacy}", + "received_events_url": "https://api.github.com/users/approval-test/received_events", + "type": "Organization", + "user_view_type": "public", + "site_admin": false + }, + "requester": { + "login": "kaladinstormblessed2", + "id": 195437694, + "node_id": "U_kgDOC6Ykfg", + "avatar_url": "https://avatars.githubusercontent.com/u/195437694?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/kaladinstormblessed2", + "html_url": "https://github.com/kaladinstormblessed2", + "followers_url": "https://api.github.com/users/kaladinstormblessed2/followers", + "following_url": "https://api.github.com/users/kaladinstormblessed2/following{/other_user}", + "gists_url": "https://api.github.com/users/kaladinstormblessed2/gists{/gist_id}", + "starred_url": "https://api.github.com/users/kaladinstormblessed2/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/kaladinstormblessed2/subscriptions", + "organizations_url": "https://api.github.com/users/kaladinstormblessed2/orgs", + "repos_url": "https://api.github.com/users/kaladinstormblessed2/repos", + "events_url": "https://api.github.com/users/kaladinstormblessed2/events{/privacy}", + "received_events_url": "https://api.github.com/users/kaladinstormblessed2/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "created_at": "2025-01-17T15:50:51Z" + } +] diff --git a/src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/mappings/1-app.json b/src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/mappings/1-app.json new file mode 100644 index 0000000000..24036fcca0 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/mappings/1-app.json @@ -0,0 +1,39 @@ +{ + "id": "7dd11376-7827-4472-9b35-d129d432687e", + "name": "app", + "request": { + "url": "/app", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "application/vnd.github+json" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "1-app.json", + "headers": { + "Date": "Fri, 17 Jan 2025 17:53:40 GMT", + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "public, max-age=60, s-maxage=60", + "Vary": "Accept,Accept-Encoding, Accept, X-Requested-With", + "ETag": "W/\"2ae03ff428b2f6f2651437f7bbb52bcc5aa4fd43ec20540006591c05a6c4de48\"", + "X-GitHub-Media-Type": "github.v3; format=json", + "x-github-api-version-selected": "2022-11-28", + "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset", + "Access-Control-Allow-Origin": "*", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", + "X-Frame-Options": "deny", + "X-Content-Type-Options": "nosniff", + "X-XSS-Protection": "0", + "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", + "Content-Security-Policy": "default-src 'none'", + "Server": "github.com", + "X-GitHub-Request-Id": "C286:10C02C:61556D:734A43:678A9923" + } + }, + "uuid": "7dd11376-7827-4472-9b35-d129d432687e", + "persistent": true, + "insertionIndex": 1 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/mappings/2-app_installation-requests.json b/src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/mappings/2-app_installation-requests.json new file mode 100644 index 0000000000..51f4a3a9ec --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHAppTest/wiremock/listInstallationRequests/mappings/2-app_installation-requests.json @@ -0,0 +1,39 @@ +{ + "id": "2e6e47a0-0341-45c9-87f6-eda0865764d7", + "name": "app_installation-requests", + "request": { + "url": "/app/installation-requests", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "application/vnd.github+json" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "2-app_installation-requests.json", + "headers": { + "Date": "Fri, 17 Jan 2025 17:53:40 GMT", + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "public, max-age=60, s-maxage=60", + "Vary": "Accept,Accept-Encoding, Accept, X-Requested-With", + "ETag": "W/\"1030c589d5482f2436758d79218af5ab17bd8b28c5b92792fe383357cae28d39\"", + "X-GitHub-Media-Type": "github.v3; format=json", + "x-github-api-version-selected": "2022-11-28", + "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset", + "Access-Control-Allow-Origin": "*", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", + "X-Frame-Options": "deny", + "X-Content-Type-Options": "nosniff", + "X-XSS-Protection": "0", + "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", + "Content-Security-Policy": "default-src 'none'", + "Server": "github.com", + "X-GitHub-Request-Id": "C287:E5098:509DB7:5CBEB7:678A9924" + } + }, + "uuid": "2e6e47a0-0341-45c9-87f6-eda0865764d7", + "persistent": true, + "insertionIndex": 2 +} \ No newline at end of file