diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/CommunityBranchPlugin.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/CommunityBranchPlugin.java index 39a55198f..65f1b4620 100644 --- a/src/main/java/com/github/mc1arke/sonarqube/plugin/CommunityBranchPlugin.java +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/CommunityBranchPlugin.java @@ -114,7 +114,7 @@ public void load(CoreExtension.Context context) { PropertyDefinition.builder(GraphqlCheckRunProvider.PULL_REQUEST_GITHUB_URL) .category(PULL_REQUEST_CATEGORY_LABEL).subCategory(GITHUB_INTEGRATION_SUBCATEGORY_LABEL) .onQualifiers(Qualifiers.APP).name("The API URL for a GitHub instance").description( - "The API url for a GitHub instance. https://api.github.com/ for github.com, https://github.company.com/api/ when using GitHub Enterprise") + "The API url for a GitHub instance. https://api.github.com/ for github.com, https://github.company.com/api/v3 when using GitHub Enterprise") .type(PropertyType.STRING).defaultValue("https://api.github.com").build(), PropertyDefinition.builder(PullRequestBuildStatusDecorator.PULL_REQUEST_COMMENT_SUMMARY_ENABLED).category(PULL_REQUEST_CATEGORY_LABEL).subCategory(GENERAL) diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v3/RestApplicationAuthenticationProvider.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v3/RestApplicationAuthenticationProvider.java index fe3b2690d..906bd4cdc 100644 --- a/src/main/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v3/RestApplicationAuthenticationProvider.java +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v3/RestApplicationAuthenticationProvider.java @@ -76,7 +76,7 @@ public RepositoryAuthenticationToken getInstallationToken(String apiUrl, String ObjectMapper objectMapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - URLConnection appConnection = urlProvider.createUrlConnection(apiUrl + (apiUrl.endsWith("api") ? "/v3" : (apiUrl.endsWith("api/") ? "v3" : "")) + "/app/installations"); + URLConnection appConnection = urlProvider.createUrlConnection(getV3Url(apiUrl) + "/app/installations"); appConnection.setRequestProperty(ACCEPT_HEADER, APP_PREVIEW_ACCEPT_HEADER); appConnection.setRequestProperty(AUTHORIZATION_HEADER, BEARER_AUTHORIZATION_HEADER_PREFIX + jwtToken); @@ -131,6 +131,15 @@ public RepositoryAuthenticationToken getInstallationToken(String apiUrl, String "No token could be found with access to the requested repository with the given application ID and key"); } + private static String getV3Url(String apiUrl) { + if (apiUrl.endsWith("/")) { + apiUrl = apiUrl.substring(0, apiUrl.length() - 1); + } + if (apiUrl.endsWith("/api")) { + apiUrl = apiUrl + "/v3"; + } + return apiUrl; + } private static PrivateKey createPrivateKey(String apiPrivateKey) throws IOException { try (PEMParser pemParser = new PEMParser(new StringReader(apiPrivateKey))) { diff --git a/src/main/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v4/GraphqlCheckRunProvider.java b/src/main/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v4/GraphqlCheckRunProvider.java index 133c7acf7..43e9e7f4b 100644 --- a/src/main/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v4/GraphqlCheckRunProvider.java +++ b/src/main/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v4/GraphqlCheckRunProvider.java @@ -149,7 +149,7 @@ public void createCheckRun(AnalysisDetails analysisDetails, UnifyConfiguration u GraphQLRequestEntity graphQLRequestEntity = - graphqlProvider.createRequestBuilder().url(apiUrl + (apiUrl.endsWith("/") ? "graphql" : "/graphql")).headers(headers) + graphqlProvider.createRequestBuilder().url(getGraphqlUrl(apiUrl)).headers(headers) .request(CreateCheckRun.class) .arguments(new Arguments("createCheckRun", new Argument<>("input", repositoryInputObject))) .requestMethod(GraphQLTemplate.GraphQLMethod.MUTATE).build(); @@ -174,6 +174,18 @@ public void createCheckRun(AnalysisDetails analysisDetails, UnifyConfiguration u } } + private static String getGraphqlUrl(String apiUrl) { + if (apiUrl.endsWith("/")) { + apiUrl = apiUrl.substring(0, apiUrl.length() - 1); + } + if (apiUrl.endsWith("/v3")) { + apiUrl = apiUrl.substring(0, apiUrl.length() - 3); + } + apiUrl = apiUrl + "/graphql"; + + return apiUrl; + } + private static CheckAnnotationLevel mapToGithubAnnotationLevel(String sonarqubeSeverity) { switch (sonarqubeSeverity) { case Severity.INFO: diff --git a/src/test/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v3/RestApplicationAuthenticationProviderTest.java b/src/test/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v3/RestApplicationAuthenticationProviderTest.java index 63421992b..5466301d5 100644 --- a/src/test/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v3/RestApplicationAuthenticationProviderTest.java +++ b/src/test/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v3/RestApplicationAuthenticationProviderTest.java @@ -60,6 +60,16 @@ public void testTokenRetrievedHappyPathApiPathTrailingSlash() throws IOException testTokenForUrl("apiUrl/api/", "apiUrl/api/v3/app/installations"); } + @Test + public void testTokenRetrievedHappyPathV3Path() throws IOException { + testTokenForUrl("apiUrl/api/v3", "apiUrl/api/v3/app/installations"); + } + + @Test + public void testTokenRetrievedHappyPathV3PathTrailingSlash() throws IOException { + testTokenForUrl("apiUrl/api/v3/", "apiUrl/api/v3/app/installations"); + } + private void testTokenForUrl(String apiUrl, String fullUrl) throws IOException { UrlConnectionProvider urlProvider = mock(UrlConnectionProvider.class); Clock clock = Clock.fixed(Instant.ofEpochMilli(123456789L), ZoneId.of("UTC")); diff --git a/src/test/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v4/GraphqlCheckRunProviderTest.java b/src/test/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v4/GraphqlCheckRunProviderTest.java index 6b3ba012e..c4bce3770 100644 --- a/src/test/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v4/GraphqlCheckRunProviderTest.java +++ b/src/test/java/com/github/mc1arke/sonarqube/plugin/ce/pullrequest/github/v4/GraphqlCheckRunProviderTest.java @@ -189,12 +189,36 @@ public void createCheckRunHappyPathOkStatus() throws IOException, GeneralSecurit createCheckRunHappyPath(QualityGate.Status.OK, "http://api.target.domain", "http://api.target.domain/graphql"); } + @Test + public void createCheckRunHappyPathOkStatusTrailingSlash() throws IOException, GeneralSecurityException { + createCheckRunHappyPath(QualityGate.Status.OK, "http://api.target.domain/", "http://api.target.domain/graphql"); + } + + @Test + public void createCheckRunHappyPathOkStatusApiPath() throws IOException, GeneralSecurityException { + createCheckRunHappyPath(QualityGate.Status.OK, "http://api.target.domain/api", "http://api.target.domain/api/graphql"); + } + + @Test + public void createCheckRunHappyPathOkStatusApiPathTrailingSlash() throws IOException, GeneralSecurityException { + createCheckRunHappyPath(QualityGate.Status.OK, "http://api.target.domain/api/", "http://api.target.domain/api/graphql"); + } + + @Test + public void createCheckRunHappyPathOkStatusV3Path() throws IOException, GeneralSecurityException { + createCheckRunHappyPath(QualityGate.Status.OK, "http://api.target.domain/api/v3", "http://api.target.domain/api/graphql"); + } + + @Test + public void createCheckRunHappyPathOkStatusV3PathTrailingSlash() throws IOException, GeneralSecurityException { + createCheckRunHappyPath(QualityGate.Status.OK, "http://api.target.domain/api/v3/", "http://api.target.domain/api/graphql"); + } + @Test public void createCheckRunHappyPathErrorStatus() throws IOException, GeneralSecurityException { createCheckRunHappyPath(QualityGate.Status.ERROR, "http://abc.de/", "http://abc.de/graphql"); } - private void createCheckRunHappyPath(QualityGate.Status status, String basePath, String fullPath) throws IOException, GeneralSecurityException { when(server.getPublicRootUrl()).thenReturn("http://sonar.server/root");