From: Duarte Meneses Date: Mon, 11 Jun 2018 08:49:18 +0000 (+0200) Subject: SONAR-10464 Improve error message when passing a wrong organization during the analysis X-Git-Tag: 7.5~1050 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=618039ace997ff9fda4735988edd19233159ac9b;p=sonarqube.git SONAR-10464 Improve error message when passing a wrong organization during the analysis --- diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java index 0b2be6f39e9..8d68be56d4f 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultQualityProfileLoader.java @@ -26,6 +26,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.BinaryOperator; +import java.util.function.Supplier; import javax.annotation.Nullable; import org.sonar.api.utils.MessageException; import org.sonar.scanner.bootstrap.ScannerWsClient; @@ -33,6 +34,7 @@ import org.sonar.scanner.scan.ScanProperties; import org.sonarqube.ws.Qualityprofiles.SearchWsResponse; import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile; import org.sonarqube.ws.client.GetRequest; +import org.sonarqube.ws.client.HttpException; import static java.util.function.Function.identity; import static java.util.stream.Collectors.toMap; @@ -52,16 +54,31 @@ public class DefaultQualityProfileLoader implements QualityProfileLoader { @Override public List loadDefault(@Nullable String profileName) { StringBuilder url = new StringBuilder(WS_URL + "?defaults=true"); - return loadAndOverrideIfNeeded(profileName, url); + return handleErrors(profileName, url, () -> "Failed to load the default quality profiles"); } @Override public List load(String projectKey, @Nullable String profileName) { StringBuilder url = new StringBuilder(WS_URL + "?projectKey=").append(encodeForUrl(projectKey)); - return loadAndOverrideIfNeeded(profileName, url); + return handleErrors(profileName, url, () -> String.format("Failed to load the quality profiles of project '%s'", projectKey)); } - private List loadAndOverrideIfNeeded(@Nullable String profileName, StringBuilder url) { + private List handleErrors(@Nullable String profileName, StringBuilder url, Supplier errorMsg) { + try { + return loadAndOverrideIfNeeded(profileName, url); + } catch (HttpException e) { + if (e.code() == 404) { + throw MessageException.of(errorMsg.get() + ": " + ScannerWsClient.tryParseAsJsonError(e.content())); + } + throw new IllegalStateException(errorMsg.get(), e); + } catch (MessageException e) { + throw e; + } catch (Exception e) { + throw new IllegalStateException(errorMsg.get(), e); + } + } + + private List loadAndOverrideIfNeeded(@Nullable String profileName, StringBuilder url) throws IOException { properties.organizationKey().ifPresent(k -> url.append("&organization=").append(encodeForUrl(k))); Map result = call(url.toString()); @@ -78,16 +95,13 @@ public class DefaultQualityProfileLoader implements QualityProfileLoader { return new ArrayList<>(result.values()); } - private Map call(String url) { + private Map call(String url) throws IOException { GetRequest getRequest = new GetRequest(url); try (InputStream is = wsClient.call(getRequest).contentStream()) { SearchWsResponse profiles = SearchWsResponse.parseFrom(is); List profilesList = profiles.getProfilesList(); return profilesList.stream().collect(toMap(QualityProfile::getLanguage, identity(), throwingMerger(), LinkedHashMap::new)); - } catch (IOException e) { - throw new IllegalStateException("Failed to load quality profiles", e); } - } private static BinaryOperator throwingMerger() { diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultQualityProfileLoaderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultQualityProfileLoaderTest.java index b1786ef3ad9..2e7f4857f8b 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultQualityProfileLoaderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultQualityProfileLoaderTest.java @@ -33,6 +33,7 @@ import org.sonar.scanner.bootstrap.ScannerWsClient; import org.sonar.scanner.scan.ScanProperties; import org.sonarqube.ws.Qualityprofiles; import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile; +import org.sonarqube.ws.client.HttpException; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -116,6 +117,18 @@ public class DefaultQualityProfileLoaderTest { verifyNoMoreInteractions(wsClient); } + @Test + public void load_throws_MessageException_if_organization_is_not_found() throws IOException { + HttpException e = new HttpException("", 404, "{\"errors\":[{\"msg\":\"No organization with key 'myorg'\"}]}"); + WsTestUtil.mockException(wsClient, e); + + exception.expect(MessageException.class); + exception.expectMessage("Failed to load the quality profiles of project 'project': No organization with key 'myorg'"); + + underTest.load("project", null); + verifyNoMoreInteractions(wsClient); + } + private void verifyCalledPath(String expectedPath) { WsTestUtil.verifyCall(wsClient, expectedPath); } diff --git a/tests/src/test/java/org/sonarqube/tests/analysis/ScannerTest.java b/tests/src/test/java/org/sonarqube/tests/analysis/ScannerTest.java index 1e9c7eeab54..2f8aafeaee9 100644 --- a/tests/src/test/java/org/sonarqube/tests/analysis/ScannerTest.java +++ b/tests/src/test/java/org/sonarqube/tests/analysis/ScannerTest.java @@ -26,10 +26,12 @@ import java.io.File; import java.io.IOException; import java.util.Map; import org.apache.commons.io.FileUtils; +import org.apache.http.MessageConstraintException; import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.sonarqube.qa.util.Tester; import org.sonarqube.tests.Category3Suite; @@ -55,6 +57,9 @@ public class ScannerTest { @Rule public Tester tester = new Tester(orchestrator).disableOrganizations(); + @Rule + public ExpectedException exception = ExpectedException.none(); + @Before public void setUp() { ItUtils.restoreProfile(orchestrator, getClass().getResource("/analysis/BatchTest/one-issue-per-line.xml")); @@ -251,13 +256,13 @@ public class ScannerTest { File cache = new File(userHome, "cache"); assertThat(cache).exists().isDirectory(); - int cachedFiles = FileUtils.listFiles(cache, new String[]{"jar"}, true).size(); + int cachedFiles = FileUtils.listFiles(cache, new String[] {"jar"}, true).size(); assertThat(cachedFiles).isGreaterThan(5); assertThat(result.getLogs()).contains("User cache: " + cache.getAbsolutePath()); result = scan("shared/xoo-sample", "sonar.userHome", userHome.getAbsolutePath()); - int cachedFiles2 = FileUtils.listFiles(cache, new String[]{"jar"}, true).size(); + int cachedFiles2 = FileUtils.listFiles(cache, new String[] {"jar"}, true).size(); assertThat(cachedFiles).isEqualTo(cachedFiles2); assertThat(result.getLogs()).contains("User cache: " + cache.getAbsolutePath()); } @@ -380,6 +385,15 @@ public class ScannerTest { assertThat(getComponent(orchestrator, "com.sonarsource.it.samples:moduleB")).isNotNull(); } + @Test + public void use_invalid_organization_key() { + BuildResult result = scanQuietly("shared/xoo-sample", + "sonar.organization", "non-existing-org"); + + assertThat(result.isSuccess()).isFalse(); + assertThat(result.getLogs()).contains("Failed to load the default quality profiles: No organization with key 'non-existing-org'"); + } + private BuildResult scan(String projectPath, String... props) { SonarScanner scanner = configureScanner(projectPath, props); return orchestrator.executeBuild(scanner);