diff --git a/src/main/java/org/kohsuke/github/GitHubConnectorResponseErrorHandler.java b/src/main/java/org/kohsuke/github/GitHubConnectorResponseErrorHandler.java index dc277ac856..e71e81921d 100644 --- a/src/main/java/org/kohsuke/github/GitHubConnectorResponseErrorHandler.java +++ b/src/main/java/org/kohsuke/github/GitHubConnectorResponseErrorHandler.java @@ -3,12 +3,16 @@ import org.jetbrains.annotations.NotNull; import org.kohsuke.github.connector.GitHubConnectorResponse; +import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import javax.annotation.Nonnull; import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; +import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR; import static java.net.HttpURLConnection.HTTP_NOT_FOUND; // TODO: Auto-generated Javadoc @@ -49,6 +53,10 @@ abstract class GitHubConnectorResponseErrorHandler { /** The status http bad request or greater. */ static GitHubConnectorResponseErrorHandler STATUS_HTTP_BAD_REQUEST_OR_GREATER = new GitHubConnectorResponseErrorHandler() { + private static final String CONTENT_TYPE = "Content-type"; + private static final String TEXT_HTML = "text/html"; + private static final String UNICORN_TITLE = "Unicorn!"; + @Override public boolean isError(@NotNull GitHubConnectorResponse connectorResponse) throws IOException { return connectorResponse.statusCode() >= HTTP_BAD_REQUEST; @@ -58,9 +66,38 @@ public boolean isError(@NotNull GitHubConnectorResponse connectorResponse) throw public void onError(@NotNull GitHubConnectorResponse connectorResponse) throws IOException { if (connectorResponse.statusCode() == HTTP_NOT_FOUND) { throw new FileNotFoundException(connectorResponse.request().url().toString()); + } else if (isServiceDown(connectorResponse)) { + throw new ServiceDownException(connectorResponse); } else { throw new HttpException(connectorResponse); } } + + private boolean isServiceDown(GitHubConnectorResponse connectorResponse) throws IOException { + if (connectorResponse.statusCode() < HTTP_INTERNAL_ERROR) { + return false; + } + + String contentTypeHeader = connectorResponse.header(CONTENT_TYPE); + if (contentTypeHeader != null && contentTypeHeader.contains(TEXT_HTML)) { + try (BufferedReader bufReader = new BufferedReader( + new InputStreamReader(connectorResponse.bodyStream(), StandardCharsets.UTF_8))) { + String line; + int hardLineCap = 25; + // <title> node is expected in the beginning anyway. + // This way we do not load the raw long images' Strings, which are later in the HTML code + // Regex or .contains would result in iterating the whole HTML document, if it didn't match + // UNICORN_TITLE + while (hardLineCap > 0 && (line = bufReader.readLine()) != null) { + if (line.trim().startsWith(UNICORN_TITLE)) { + return true; + } + hardLineCap--; + } + } + } + + return false; + } }; } diff --git a/src/main/java/org/kohsuke/github/ServiceDownException.java b/src/main/java/org/kohsuke/github/ServiceDownException.java new file mode 100644 index 0000000000..81f35b33b0 --- /dev/null +++ b/src/main/java/org/kohsuke/github/ServiceDownException.java @@ -0,0 +1,26 @@ +package org.kohsuke.github; + +import org.kohsuke.github.connector.GitHubConnectorResponse; + +import java.io.IOException; + +/** + * Special {@link IOException} case for http exceptions, when {@link HttpException} is thrown due to GitHub service + * being down. + * + * Inherits from {@link HttpException} to maintain compatibility with existing clients. + * + * @author <a href="mailto:rbudinsk@redhat.com">Rastislav Budinsky</a> + */ +public class ServiceDownException extends HttpException { + + /** + * Instantiates a new service down exception. + * + * @param connectorResponse + * the connector response to base this on + */ + public ServiceDownException(GitHubConnectorResponse connectorResponse) { + super(connectorResponse); + } +} diff --git a/src/test/java/org/kohsuke/github/GitHubTest.java b/src/test/java/org/kohsuke/github/GitHubTest.java index 4b4a848545..fc2c76c21f 100644 --- a/src/test/java/org/kohsuke/github/GitHubTest.java +++ b/src/test/java/org/kohsuke/github/GitHubTest.java @@ -397,4 +397,20 @@ public void testHeaderFieldName() throws Exception { org.getResponseHeaderFields().keySet().contains("CacHe-ControL")); assertThat(org.getResponseHeaderFields().get("cachE-cOntrol").get(0), is("private, max-age=60, s-maxage=60")); } + + /** + * Test expect GitHub {@link ServiceDownException} + * + */ + @Test + public void testCatchServiceDownException() { + snapshotNotAllowed(); + try { + GHRepository repo = gitHub.getRepository("hub4j-test-org/github-api"); + repo.getFileContent("ghcontent-ro/service-down"); + fail("Exception was expected"); + } catch (IOException e) { + assertThat(e.getClass().getName(), equalToIgnoringCase(ServiceDownException.class.getName())); + } + } } diff --git a/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/__files/1-user.json b/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/__files/1-user.json new file mode 100644 index 0000000000..232c9a329c --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/__files/1-user.json @@ -0,0 +1,34 @@ +{ + "login": "The-Huginn", + "id": 78657734, + "node_id": "MDQ6VXNlcjc4NjU3NzM0", + "avatar_url": "https://avatars.githubusercontent.com/u/78657734?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/The-Huginn", + "html_url": "https://github.com/The-Huginn", + "followers_url": "https://api.github.com/users/The-Huginn/followers", + "following_url": "https://api.github.com/users/The-Huginn/following{/other_user}", + "gists_url": "https://api.github.com/users/The-Huginn/gists{/gist_id}", + "starred_url": "https://api.github.com/users/The-Huginn/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/The-Huginn/subscriptions", + "organizations_url": "https://api.github.com/users/The-Huginn/orgs", + "repos_url": "https://api.github.com/users/The-Huginn/repos", + "events_url": "https://api.github.com/users/The-Huginn/events{/privacy}", + "received_events_url": "https://api.github.com/users/The-Huginn/received_events", + "type": "User", + "site_admin": false, + "name": "Rastislav Budinsky", + "company": "Red Hat", + "blog": "thehuginn.com", + "location": null, + "email": null, + "hireable": null, + "bio": null, + "twitter_username": "The_Hug1nn", + "public_repos": 47, + "public_gists": 0, + "followers": 3, + "following": 2, + "created_at": "2021-02-06T17:33:36Z", + "updated_at": "2024-03-11T08:56:45Z" +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/__files/2-r_h_github-api.json b/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/__files/2-r_h_github-api.json new file mode 100644 index 0000000000..3c0b7ec286 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/__files/2-r_h_github-api.json @@ -0,0 +1,364 @@ +{ + "id": 206888201, + "node_id": "MDEwOlJlcG9zaXRvcnkyMDY4ODgyMDE=", + "name": "github-api", + "full_name": "hub4j-test-org/github-api", + "private": false, + "owner": { + "login": "hub4j-test-org", + "id": 7544739, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=", + "avatar_url": "https://avatars.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 + }, + "html_url": "https://github.com/hub4j-test-org/github-api", + "description": "Tricky", + "fork": true, + "url": "https://api.github.com/repos/hub4j-test-org/github-api", + "forks_url": "https://api.github.com/repos/hub4j-test-org/github-api/forks", + "keys_url": "https://api.github.com/repos/hub4j-test-org/github-api/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/hub4j-test-org/github-api/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/hub4j-test-org/github-api/teams", + "hooks_url": "https://api.github.com/repos/hub4j-test-org/github-api/hooks", + "issue_events_url": "https://api.github.com/repos/hub4j-test-org/github-api/issues/events{/number}", + "events_url": "https://api.github.com/repos/hub4j-test-org/github-api/events", + "assignees_url": "https://api.github.com/repos/hub4j-test-org/github-api/assignees{/user}", + "branches_url": "https://api.github.com/repos/hub4j-test-org/github-api/branches{/branch}", + "tags_url": "https://api.github.com/repos/hub4j-test-org/github-api/tags", + "blobs_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/hub4j-test-org/github-api/statuses/{sha}", + "languages_url": "https://api.github.com/repos/hub4j-test-org/github-api/languages", + "stargazers_url": "https://api.github.com/repos/hub4j-test-org/github-api/stargazers", + "contributors_url": "https://api.github.com/repos/hub4j-test-org/github-api/contributors", + "subscribers_url": "https://api.github.com/repos/hub4j-test-org/github-api/subscribers", + "subscription_url": "https://api.github.com/repos/hub4j-test-org/github-api/subscription", + "commits_url": "https://api.github.com/repos/hub4j-test-org/github-api/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/hub4j-test-org/github-api/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/hub4j-test-org/github-api/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/hub4j-test-org/github-api/contents/{+path}", + "compare_url": "https://api.github.com/repos/hub4j-test-org/github-api/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/hub4j-test-org/github-api/merges", + "archive_url": "https://api.github.com/repos/hub4j-test-org/github-api/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/hub4j-test-org/github-api/downloads", + "issues_url": "https://api.github.com/repos/hub4j-test-org/github-api/issues{/number}", + "pulls_url": "https://api.github.com/repos/hub4j-test-org/github-api/pulls{/number}", + "milestones_url": "https://api.github.com/repos/hub4j-test-org/github-api/milestones{/number}", + "notifications_url": "https://api.github.com/repos/hub4j-test-org/github-api/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/hub4j-test-org/github-api/labels{/name}", + "releases_url": "https://api.github.com/repos/hub4j-test-org/github-api/releases{/id}", + "deployments_url": "https://api.github.com/repos/hub4j-test-org/github-api/deployments", + "created_at": "2019-09-06T23:26:04Z", + "updated_at": "2023-01-31T10:03:44Z", + "pushed_at": "2024-03-09T14:27:07Z", + "git_url": "git://github.com/hub4j-test-org/github-api.git", + "ssh_url": "git@github.com:hub4j-test-org/github-api.git", + "clone_url": "https://github.com/hub4j-test-org/github-api.git", + "svn_url": "https://github.com/hub4j-test-org/github-api", + "homepage": "http://github-api.kohsuke.org/", + "size": 18977, + "stargazers_count": 1, + "watchers_count": 1, + "language": "Java", + "has_issues": true, + "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": 7, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [], + "visibility": "public", + "forks": 0, + "open_issues": 7, + "watchers": 1, + "default_branch": "main", + "permissions": { + "admin": false, + "maintain": false, + "push": false, + "triage": false, + "pull": true + }, + "custom_properties": {}, + "organization": { + "login": "hub4j-test-org", + "id": 7544739, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=", + "avatar_url": "https://avatars.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 + }, + "parent": { + "id": 617210, + "node_id": "MDEwOlJlcG9zaXRvcnk2MTcyMTA=", + "name": "github-api", + "full_name": "hub4j/github-api", + "private": false, + "owner": { + "login": "hub4j", + "id": 54909825, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0OTA5ODI1", + "avatar_url": "https://avatars.githubusercontent.com/u/54909825?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/hub4j", + "html_url": "https://github.com/hub4j", + "followers_url": "https://api.github.com/users/hub4j/followers", + "following_url": "https://api.github.com/users/hub4j/following{/other_user}", + "gists_url": "https://api.github.com/users/hub4j/gists{/gist_id}", + "starred_url": "https://api.github.com/users/hub4j/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/hub4j/subscriptions", + "organizations_url": "https://api.github.com/users/hub4j/orgs", + "repos_url": "https://api.github.com/users/hub4j/repos", + "events_url": "https://api.github.com/users/hub4j/events{/privacy}", + "received_events_url": "https://api.github.com/users/hub4j/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/hub4j/github-api", + "description": "Java API for GitHub", + "fork": false, + "url": "https://api.github.com/repos/hub4j/github-api", + "forks_url": "https://api.github.com/repos/hub4j/github-api/forks", + "keys_url": "https://api.github.com/repos/hub4j/github-api/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/hub4j/github-api/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/hub4j/github-api/teams", + "hooks_url": "https://api.github.com/repos/hub4j/github-api/hooks", + "issue_events_url": "https://api.github.com/repos/hub4j/github-api/issues/events{/number}", + "events_url": "https://api.github.com/repos/hub4j/github-api/events", + "assignees_url": "https://api.github.com/repos/hub4j/github-api/assignees{/user}", + "branches_url": "https://api.github.com/repos/hub4j/github-api/branches{/branch}", + "tags_url": "https://api.github.com/repos/hub4j/github-api/tags", + "blobs_url": "https://api.github.com/repos/hub4j/github-api/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/hub4j/github-api/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/hub4j/github-api/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/hub4j/github-api/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/hub4j/github-api/statuses/{sha}", + "languages_url": "https://api.github.com/repos/hub4j/github-api/languages", + "stargazers_url": "https://api.github.com/repos/hub4j/github-api/stargazers", + "contributors_url": "https://api.github.com/repos/hub4j/github-api/contributors", + "subscribers_url": "https://api.github.com/repos/hub4j/github-api/subscribers", + "subscription_url": "https://api.github.com/repos/hub4j/github-api/subscription", + "commits_url": "https://api.github.com/repos/hub4j/github-api/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/hub4j/github-api/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/hub4j/github-api/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/hub4j/github-api/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/hub4j/github-api/contents/{+path}", + "compare_url": "https://api.github.com/repos/hub4j/github-api/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/hub4j/github-api/merges", + "archive_url": "https://api.github.com/repos/hub4j/github-api/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/hub4j/github-api/downloads", + "issues_url": "https://api.github.com/repos/hub4j/github-api/issues{/number}", + "pulls_url": "https://api.github.com/repos/hub4j/github-api/pulls{/number}", + "milestones_url": "https://api.github.com/repos/hub4j/github-api/milestones{/number}", + "notifications_url": "https://api.github.com/repos/hub4j/github-api/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/hub4j/github-api/labels{/name}", + "releases_url": "https://api.github.com/repos/hub4j/github-api/releases{/id}", + "deployments_url": "https://api.github.com/repos/hub4j/github-api/deployments", + "created_at": "2010-04-19T04:13:03Z", + "updated_at": "2024-03-12T00:08:34Z", + "pushed_at": "2024-03-12T23:45:28Z", + "git_url": "git://github.com/hub4j/github-api.git", + "ssh_url": "git@github.com:hub4j/github-api.git", + "clone_url": "https://github.com/hub4j/github-api.git", + "svn_url": "https://github.com/hub4j/github-api", + "homepage": "https://github-api.kohsuke.org/", + "size": 47209, + "stargazers_count": 1090, + "watchers_count": 1090, + "language": "Java", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "has_discussions": true, + "forks_count": 704, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 154, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + "api", + "client-library", + "github", + "github-api", + "github-api-v3", + "java", + "java-api" + ], + "visibility": "public", + "forks": 704, + "open_issues": 154, + "watchers": 1090, + "default_branch": "main" + }, + "source": { + "id": 617210, + "node_id": "MDEwOlJlcG9zaXRvcnk2MTcyMTA=", + "name": "github-api", + "full_name": "hub4j/github-api", + "private": false, + "owner": { + "login": "hub4j", + "id": 54909825, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0OTA5ODI1", + "avatar_url": "https://avatars.githubusercontent.com/u/54909825?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/hub4j", + "html_url": "https://github.com/hub4j", + "followers_url": "https://api.github.com/users/hub4j/followers", + "following_url": "https://api.github.com/users/hub4j/following{/other_user}", + "gists_url": "https://api.github.com/users/hub4j/gists{/gist_id}", + "starred_url": "https://api.github.com/users/hub4j/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/hub4j/subscriptions", + "organizations_url": "https://api.github.com/users/hub4j/orgs", + "repos_url": "https://api.github.com/users/hub4j/repos", + "events_url": "https://api.github.com/users/hub4j/events{/privacy}", + "received_events_url": "https://api.github.com/users/hub4j/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/hub4j/github-api", + "description": "Java API for GitHub", + "fork": false, + "url": "https://api.github.com/repos/hub4j/github-api", + "forks_url": "https://api.github.com/repos/hub4j/github-api/forks", + "keys_url": "https://api.github.com/repos/hub4j/github-api/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/hub4j/github-api/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/hub4j/github-api/teams", + "hooks_url": "https://api.github.com/repos/hub4j/github-api/hooks", + "issue_events_url": "https://api.github.com/repos/hub4j/github-api/issues/events{/number}", + "events_url": "https://api.github.com/repos/hub4j/github-api/events", + "assignees_url": "https://api.github.com/repos/hub4j/github-api/assignees{/user}", + "branches_url": "https://api.github.com/repos/hub4j/github-api/branches{/branch}", + "tags_url": "https://api.github.com/repos/hub4j/github-api/tags", + "blobs_url": "https://api.github.com/repos/hub4j/github-api/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/hub4j/github-api/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/hub4j/github-api/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/hub4j/github-api/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/hub4j/github-api/statuses/{sha}", + "languages_url": "https://api.github.com/repos/hub4j/github-api/languages", + "stargazers_url": "https://api.github.com/repos/hub4j/github-api/stargazers", + "contributors_url": "https://api.github.com/repos/hub4j/github-api/contributors", + "subscribers_url": "https://api.github.com/repos/hub4j/github-api/subscribers", + "subscription_url": "https://api.github.com/repos/hub4j/github-api/subscription", + "commits_url": "https://api.github.com/repos/hub4j/github-api/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/hub4j/github-api/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/hub4j/github-api/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/hub4j/github-api/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/hub4j/github-api/contents/{+path}", + "compare_url": "https://api.github.com/repos/hub4j/github-api/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/hub4j/github-api/merges", + "archive_url": "https://api.github.com/repos/hub4j/github-api/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/hub4j/github-api/downloads", + "issues_url": "https://api.github.com/repos/hub4j/github-api/issues{/number}", + "pulls_url": "https://api.github.com/repos/hub4j/github-api/pulls{/number}", + "milestones_url": "https://api.github.com/repos/hub4j/github-api/milestones{/number}", + "notifications_url": "https://api.github.com/repos/hub4j/github-api/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/hub4j/github-api/labels{/name}", + "releases_url": "https://api.github.com/repos/hub4j/github-api/releases{/id}", + "deployments_url": "https://api.github.com/repos/hub4j/github-api/deployments", + "created_at": "2010-04-19T04:13:03Z", + "updated_at": "2024-03-12T00:08:34Z", + "pushed_at": "2024-03-12T23:45:28Z", + "git_url": "git://github.com/hub4j/github-api.git", + "ssh_url": "git@github.com:hub4j/github-api.git", + "clone_url": "https://github.com/hub4j/github-api.git", + "svn_url": "https://github.com/hub4j/github-api", + "homepage": "https://github-api.kohsuke.org/", + "size": 47209, + "stargazers_count": 1090, + "watchers_count": 1090, + "language": "Java", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "has_discussions": true, + "forks_count": 704, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 154, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "allow_forking": true, + "is_template": false, + "web_commit_signoff_required": false, + "topics": [ + "api", + "client-library", + "github", + "github-api", + "github-api-v3", + "java", + "java-api" + ], + "visibility": "public", + "forks": 704, + "open_issues": 154, + "watchers": 1090, + "default_branch": "main" + }, + "network_count": 704, + "subscribers_count": 1 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/mappings/1-user.json b/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/mappings/1-user.json new file mode 100644 index 0000000000..f27f181144 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/mappings/1-user.json @@ -0,0 +1,49 @@ +{ + "id": "e23625f3-8aa2-48ae-9aeb-e5dc645f55f3", + "name": "user", + "request": { + "url": "/user", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "application/vnd.github.v3+json" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "1-user.json", + "headers": { + "Server": "GitHub.com", + "Date": "Wed, 13 Mar 2024 08:54:05 GMT", + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "private, max-age=60, s-maxage=60", + "Vary": [ + "Accept, Authorization, Cookie, X-GitHub-OTP", + "Accept-Encoding, Accept, X-Requested-With" + ], + "ETag": "W/\"03b6fc1dc9210c8476fb4d8d5a0dbb36e2e7e6bc12839d7bf0a86f9105a65948\"", + "Last-Modified": "Mon, 11 Mar 2024 08:56:45 GMT", + "github-authentication-token-expiration": "2024-04-12 09:29:42 +0200", + "X-GitHub-Media-Type": "github.v3; format=json", + "x-github-api-version-selected": "2022-11-28", + "X-RateLimit-Limit": "5000", + "X-RateLimit-Remaining": "4971", + "X-RateLimit-Reset": "1710322407", + "X-RateLimit-Used": "29", + "X-RateLimit-Resource": "core", + "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": "4D88:3116FB:184AC74:1879A5D:65F169AD" + } + }, + "uuid": "e23625f3-8aa2-48ae-9aeb-e5dc645f55f3", + "persistent": true, + "insertionIndex": 1 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/mappings/2-r_h_github-api.json b/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/mappings/2-r_h_github-api.json new file mode 100644 index 0000000000..37b288933c --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/mappings/2-r_h_github-api.json @@ -0,0 +1,50 @@ +{ + "id": "1e027d1b-af17-456f-88af-de973a74a34a", + "name": "repos_hub4j-test-org_github-api", + "request": { + "url": "/repos/hub4j-test-org/github-api", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "application/vnd.github.v3+json" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "2-r_h_github-api.json", + "headers": { + "Server": "GitHub.com", + "Date": "Wed, 13 Mar 2024 08:54:05 GMT", + "Content-Type": "application/json; charset=utf-8", + "Cache-Control": "private, max-age=60, s-maxage=60", + "Vary": [ + "Accept, Authorization, Cookie, X-GitHub-OTP", + "Accept-Encoding, Accept, X-Requested-With" + ], + "ETag": "W/\"15ec8f099b28d234345233ef57e40f4fea394e5e6e27b57cd1853b4f944840f4\"", + "Last-Modified": "Tue, 31 Jan 2023 10:03:44 GMT", + "github-authentication-token-expiration": "2024-04-12 09:29:42 +0200", + "X-GitHub-Media-Type": "github.v3; format=json", + "x-accepted-github-permissions": "metadata=read", + "x-github-api-version-selected": "2022-11-28", + "X-RateLimit-Limit": "5000", + "X-RateLimit-Remaining": "4969", + "X-RateLimit-Reset": "1710322407", + "X-RateLimit-Used": "31", + "X-RateLimit-Resource": "core", + "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": "299E:1F85E5:C1DE580:C320F81:65F169AD" + } + }, + "uuid": "1e027d1b-af17-456f-88af-de973a74a34a", + "persistent": true, + "insertionIndex": 2 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/mappings/3-r_h_g_contents_ghcontent-ro_service-down.json b/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/mappings/3-r_h_g_contents_ghcontent-ro_service-down.json new file mode 100644 index 0000000000..2d5d37180b --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/testCatchServiceDownException/mappings/3-r_h_g_contents_ghcontent-ro_service-down.json @@ -0,0 +1,44 @@ +{ + "id": "16923b89-9f2f-4f90-9c8a-169e90581e7a", + "name": "repos_hub4j-test-org_github-api_contents_ghcontent-ro_service-down", + "request": { + "url": "/repos/hub4j-test-org/github-api/contents/ghcontent-ro/service-down", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "application/vnd.github.v3+json" + } + } + }, + "response": { + "status": 503, + "body": "<!DOCTYPE html>\n<!--\n\nHello future GitHubber! I bet you're here to remove those nasty inline styles,\nDRY up these templates and make 'em nice and re-usable, right?\n\nPlease, don't. https://github.com/styleguide/templates/2.0\n\n-->\n<html>\n <head>\n <title>Unicorn! · GitHub\n \n \n \n\n
\n

\n \n

\n\n

We had issues producing the response to your request.

\n

Sorry about that. Please try refreshing and contact us if the problem persists.

\n
\n Contact Support —\n GitHub Status —\n @githubstatus\n
\n\n \n\n \n
\n \n\n", + "headers": { + "Server": "GitHub.com", + "Date": "Wed, 13 Mar 2024 08:54:06 GMT", + "Content-Type": "text/html; charset=utf-8", + "github-authentication-token-expiration": "2024-04-12 09:29:42 +0200", + "X-GitHub-Media-Type": "github.v3; format=json", + "x-accepted-github-permissions": "contents=read", + "x-github-api-version-selected": "2022-11-28", + "X-RateLimit-Limit": "5000", + "X-RateLimit-Remaining": "4968", + "X-RateLimit-Reset": "1710322407", + "X-RateLimit-Used": "32", + "X-RateLimit-Resource": "core", + "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'", + "Vary": "Accept-Encoding, Accept, X-Requested-With", + "X-GitHub-Request-Id": "2EA8:339F21:17997EC:17C8638:65F169AE" + } + }, + "uuid": "16923b89-9f2f-4f90-9c8a-169e90581e7a", + "persistent": true, + "insertionIndex": 3 +} \ No newline at end of file