From a0227569ab0b05009b7a9947505ddbb90e1a4a6f Mon Sep 17 00:00:00 2001 From: Johnathan Gilday Date: Mon, 15 Jan 2024 13:08:07 -0500 Subject: [PATCH 1/2] Add Suspended Installation Properties to GHAppInstallation A suspended app installation has suspended_at and suspended_by properties that were missing from the GHAppInstallation class. --- .../org/kohsuke/github/GHAppInstallation.java | 23 +++++++ .../kohsuke/github/GHAppInstallationTest.java | 24 ++++++++ .../__files/1-app.json | 42 +++++++++++++ .../__files/2-app_installations.json | 61 +++++++++++++++++++ .../mappings/1-app.json | 42 +++++++++++++ .../mappings/2-app_installations.json | 41 +++++++++++++ 6 files changed, 233 insertions(+) create mode 100644 src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/__files/1-app.json create mode 100644 src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/__files/2-app_installations.json create mode 100644 src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/mappings/1-app.json create mode 100644 src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/mappings/2-app_installations.json diff --git a/src/main/java/org/kohsuke/github/GHAppInstallation.java b/src/main/java/org/kohsuke/github/GHAppInstallation.java index cf5bda32b0..99d849842c 100644 --- a/src/main/java/org/kohsuke/github/GHAppInstallation.java +++ b/src/main/java/org/kohsuke/github/GHAppInstallation.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.net.URL; import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -45,6 +46,8 @@ public class GHAppInstallation extends GHObject { @JsonProperty("repository_selection") private GHRepositorySelection repositorySelection; private String htmlUrl; + private Date suspendedAt; + private GHUser suspendedBy; /** * Gets the html url. @@ -311,6 +314,26 @@ public void setRepositorySelection(GHRepositorySelection repositorySelection) { throw new RuntimeException("Do not use this method."); } + /** + * Gets suspended at. + * + * @return the suspended at + */ + @SuppressFBWarnings(value = { "EI_EXPOSE_REP" }, justification = "Expected behavior") + public Date getSuspendedAt() { + return suspendedAt; + } + + /** + * Gets suspended by. + * + * @return the suspended by + */ + @SuppressFBWarnings(value = { "EI_EXPOSE_REP" }, justification = "Expected behavior") + public GHUser getSuspendedBy() { + return suspendedBy; + } + /** * Delete a Github App installation *

diff --git a/src/test/java/org/kohsuke/github/GHAppInstallationTest.java b/src/test/java/org/kohsuke/github/GHAppInstallationTest.java index 1a380a9739..d6218d1121 100644 --- a/src/test/java/org/kohsuke/github/GHAppInstallationTest.java +++ b/src/test/java/org/kohsuke/github/GHAppInstallationTest.java @@ -3,11 +3,16 @@ import org.junit.Test; import java.io.IOException; +import java.time.LocalDateTime; +import java.time.Month; +import java.time.ZoneOffset; +import java.util.Date; import java.util.List; import static org.hamcrest.Matchers.*; // TODO: Auto-generated Javadoc + /** * The Class GHAppInstallationTest. */ @@ -61,4 +66,23 @@ public void testGetMarketplaceAccount() throws IOException { assertThat(plan.getType(), equalTo(GHMarketplaceAccountType.ORGANIZATION)); } + /** + * Test list installations, and one of the installations has been suspended. + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + @Test + public void testListSuspendedInstallation() throws IOException { + GHAppInstallation appInstallation = getAppInstallationWithToken(jwtProvider1.getEncodedAuthorization()); + + final GHUser suspendedBy = appInstallation.getSuspendedBy(); + assertThat(suspendedBy.getLogin(), equalTo("gilday")); + + final Date suspendedAt = appInstallation.getSuspendedAt(); + final Date expectedSuspendedAt = Date + .from(LocalDateTime.of(2024, Month.FEBRUARY, 26, 2, 43, 12).toInstant(ZoneOffset.UTC)); + assertThat(suspendedAt, equalTo(expectedSuspendedAt)); + } + } diff --git a/src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/__files/1-app.json b/src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/__files/1-app.json new file mode 100644 index 0000000000..89a67cab2d --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/__files/1-app.json @@ -0,0 +1,42 @@ +{ + "id": 83009, + "slug": "cleanthat", + "node_id": "MDM6QXBwNjU1NTA=", + "owner": { + "login": "solven-eu", + "id": 34552197, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjM0NTUyMTk3", + "avatar_url": "https://avatars.githubusercontent.com/u/34552197?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/solven-eu", + "html_url": "https://github.com/solven-eu", + "followers_url": "https://api.github.com/users/solven-eu/followers", + "following_url": "https://api.github.com/users/solven-eu/following{/other_user}", + "gists_url": "https://api.github.com/users/solven-eu/gists{/gist_id}", + "starred_url": "https://api.github.com/users/solven-eu/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/solven-eu/subscriptions", + "organizations_url": "https://api.github.com/users/solven-eu/orgs", + "repos_url": "https://api.github.com/users/solven-eu/repos", + "events_url": "https://api.github.com/users/solven-eu/events{/privacy}", + "received_events_url": "https://api.github.com/users/solven-eu/received_events", + "type": "Organization", + "site_admin": false + }, + "name": "CleanThat", + "description": "Cleanthat cleans branches automatically to fix/improve your code.\r\n\r\nFeatures :\r\n- Fix branches a pull_requests head\r\n- Open pull_request to fix protected branches\r\n- Format `.md`, `.java`, `.scala`, `.json`, `.yaml` with the help of [Spotless](https://github.com/diffplug/spotless)\r\n- Refactor `.java` files to improve code-style, security and stability", + "external_url": "https://github.com/solven-eu/cleanthat", + "html_url": "https://github.com/apps/cleanthat", + "created_at": "2020-05-19T13:45:43Z", + "updated_at": "2023-01-27T06:10:21Z", + "permissions": { + "checks": "write", + "contents": "write", + "metadata": "read", + "pull_requests": "write" + }, + "events": [ + "pull_request", + "push" + ], + "installations_count": 280 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/__files/2-app_installations.json b/src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/__files/2-app_installations.json new file mode 100644 index 0000000000..8514a67338 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/__files/2-app_installations.json @@ -0,0 +1,61 @@ +[ + { + "id": 12131496, + "account": { + "login": "hub4j-test-org", + "id": 7544739, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=", + "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/hub4j-test-org", + "html_url": "https://github.com/hub4j-test-org", + "followers_url": "https://api.github.com/users/hub4j-test-org/followers", + "following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}", + "gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}", + "starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions", + "organizations_url": "https://api.github.com/users/hub4j-test-org/orgs", + "repos_url": "https://api.github.com/users/hub4j-test-org/repos", + "events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}", + "received_events_url": "https://api.github.com/users/hub4j-test-org/received_events", + "type": "Organization", + "site_admin": false + }, + "repository_selection": "selected", + "access_tokens_url": "https://api.github.com/app/installations/12131496/access_tokens", + "repositories_url": "https://api.github.com/installation/repositories", + "html_url": "https://github.com/organizations/hub4j-test-org/settings/installations/12131496", + "app_id": 83009, + "app_slug": "ghapi-test-app-2", + "target_id": 7544739, + "target_type": "Organization", + "permissions": {}, + "events": [], + "created_at": "2020-09-30T15:05:32.000Z", + "updated_at": "2020-09-30T15:05:32.000Z", + "single_file_name": null, + "has_multiple_single_files": false, + "single_file_paths": [], + "suspended_by": { + "login": "gilday", + "id": 1431609, + "node_id": "MDQ6VXNlcjE0MzE2MDk=", + "avatar_url": "https://avatars.githubusercontent.com/u/1431609?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/gilday", + "html_url": "https://github.com/gilday", + "followers_url": "https://api.github.com/users/gilday/followers", + "following_url": "https://api.github.com/users/gilday/following{/other_user}", + "gists_url": "https://api.github.com/users/gilday/gists{/gist_id}", + "starred_url": "https://api.github.com/users/gilday/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/gilday/subscriptions", + "organizations_url": "https://api.github.com/users/gilday/orgs", + "repos_url": "https://api.github.com/users/gilday/repos", + "events_url": "https://api.github.com/users/gilday/events{/privacy}", + "received_events_url": "https://api.github.com/users/gilday/received_events", + "type": "User", + "site_admin": false + }, + "suspended_at": "2024-02-26T02:43:12Z" + } +] diff --git a/src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/mappings/1-app.json b/src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/mappings/1-app.json new file mode 100644 index 0000000000..51181fa14b --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/mappings/1-app.json @@ -0,0 +1,42 @@ +{ + "id": "144fdb7f-667e-4cf4-bd37-67ed11bdc421", + "name": "app", + "request": { + "url": "/app", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "application/vnd.github.machine-man-preview+json" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "1-app.json", + "headers": { + "Server": "GitHub.com", + "Date": "Sun, 19 Mar 2023 13:02:50 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/\"00fa67d861eb73a934cd9229b76c2dc7c2c235babf8d281e2dd4a1e31ca3b930\"", + "X-GitHub-Media-Type": "github.v3; param=machine-man-preview; 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'", + "X-GitHub-Request-Id": "C09A:5A83:172C70C:179D1FD:641707FA" + } + }, + "uuid": "144fdb7f-667e-4cf4-bd37-67ed11bdc421", + "persistent": true, + "insertionIndex": 1 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/mappings/2-app_installations.json b/src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/mappings/2-app_installations.json new file mode 100644 index 0000000000..abae32ba46 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHAppInstallationTest/wiremock/testListSuspendedInstallation/mappings/2-app_installations.json @@ -0,0 +1,41 @@ +{ + "id": "45ac2593-8123-49ae-ad1a-ded446491b14", + "name": "app_installations", + "request": { + "url": "/app/installations", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "application/vnd.github.machine-man-preview+json" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "2-app_installations.json", + "headers": { + "Date": "Thu, 05 Nov 2020 20:42:31 GMT", + "Content-Type": "application/json; charset=utf-8", + "Server": "GitHub.com", + "Status": "200 OK", + "Cache-Control": "public, max-age=60, s-maxage=60", + "Vary": [ + "Accept", + "Accept-Encoding, Accept, X-Requested-With", + "Accept-Encoding" + ], + "ETag": "W/\"60d3ec5c9014799f5e12b88e16e771a386b905ad8d41cd18aed34e58b11c58d4\"", + "X-GitHub-Media-Type": "github.v3; param=machine-man-preview; format=json", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", + "X-Frame-Options": "deny", + "X-Content-Type-Options": "nosniff", + "X-XSS-Protection": "1; mode=block", + "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", + "Content-Security-Policy": "default-src 'none'", + "X-GitHub-Request-Id": "9294:AE05:BDAC831:DB35870:5FA463B7" + } + }, + "uuid": "45ac2593-8123-49ae-ad1a-ded446491b14", + "persistent": true, + "insertionIndex": 2 +} \ No newline at end of file From 726ace5312e61384e8fa0abb0da7deeef003f68a Mon Sep 17 00:00:00 2001 From: Liam Newman Date: Fri, 8 Mar 2024 14:38:51 -0800 Subject: [PATCH 2/2] Store suspendedAt as String --- src/main/java/org/kohsuke/github/GHAppInstallation.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHAppInstallation.java b/src/main/java/org/kohsuke/github/GHAppInstallation.java index 99d849842c..7466c0abe2 100644 --- a/src/main/java/org/kohsuke/github/GHAppInstallation.java +++ b/src/main/java/org/kohsuke/github/GHAppInstallation.java @@ -46,7 +46,7 @@ public class GHAppInstallation extends GHObject { @JsonProperty("repository_selection") private GHRepositorySelection repositorySelection; private String htmlUrl; - private Date suspendedAt; + private String suspendedAt; private GHUser suspendedBy; /** @@ -319,9 +319,8 @@ public void setRepositorySelection(GHRepositorySelection repositorySelection) { * * @return the suspended at */ - @SuppressFBWarnings(value = { "EI_EXPOSE_REP" }, justification = "Expected behavior") public Date getSuspendedAt() { - return suspendedAt; + return GitHubClient.parseDate(suspendedAt); } /**