Skip to content

Commit

Permalink
Get maven project version from the Sonar REST API.
Browse files Browse the repository at this point in the history
  • Loading branch information
steinarb committed Nov 22, 2017
1 parent 0f3a14d commit a07a528
Show file tree
Hide file tree
Showing 12 changed files with 153 additions and 353 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.sql.Connection;
Expand Down Expand Up @@ -55,7 +53,6 @@

@Component(service={Servlet.class}, property={"alias=/sonar-collector"} )
public class SonarCollectorServlet extends HttpServlet {
private static final String MAVEN_VERSION = "sonar.analysis.mavenVersion";
private static final long serialVersionUID = -8421243385012454373L;
private static final String SONAR_MEASURES_COMPONENTS_METRIC_KEYS = "sonar.measures.components.metricKeys";
private static final String SONARCOLLECTOR_JDBCURL = "sonar.collector.jdbcurl";
Expand Down Expand Up @@ -143,13 +140,16 @@ SonarBuild callbackToSonarServerToGetMetrics(ServletRequest request) throws IOEx
JsonNode root = mapper.readTree(postbody);
long analysedAt = parseTimestamp(root.path("analysedAt").asText());
String project = root.path("project").path("key").asText();
String version = root.path("properties").path(MAVEN_VERSION).asText();
URL serverUrl = new URL(root.path("serverUrl").asText());
URL componentsShowUrl = createSonarComponentsShowUrl(serverUrl, project);
HttpURLConnection componentsShowUrlConnection = openConnection(componentsShowUrl);
JsonNode componentsShowRoot = mapper.readTree(componentsShowUrlConnection.getInputStream());
String version = componentsShowRoot.path("component").path("version").asText();
SonarBuild build = new SonarBuild(analysedAt, project, version, serverUrl);
logWarningIfVersionIsMissing(build);
logWarningIfVersionIsMissing(build, componentsShowUrl);
URL measurementsUrl = createSonarMeasurementsComponentUrl(build, getMetricKeys());
HttpURLConnection connection = openConnection(measurementsUrl);
JsonNode measurementsRoot = mapper.readTree(connection.getInputStream());
HttpURLConnection measurementsUrlConnection = openConnection(measurementsUrl);
JsonNode measurementsRoot = mapper.readTree(measurementsUrlConnection.getInputStream());
parseMeasures(build.getMeasurements(), measurementsRoot.path("component").path("measures"));
return build;
}
Expand All @@ -159,9 +159,9 @@ long parseTimestamp(String timestamp) {
return ZonedDateTime.parse(timestamp, isoZonedDateTimeformatter).toEpochSecond() * 1000;
}

private void logWarningIfVersionIsMissing(SonarBuild build) {
private void logWarningIfVersionIsMissing(SonarBuild build, URL componentsShowUrl) {
if ("".equals(build.getVersion())) {
logservice.log(LogService.LOG_WARNING, String.format("Maven version is missing from build \"%s\". Remember to add -D%s=$POM_VERSION to the sonar command", build.getProject(), MAVEN_VERSION));
logservice.log(LogService.LOG_WARNING, String.format("Maven version is missing from build \"%s\". API URL used to request the version, is: %s", build.getProject(), componentsShowUrl.toString()));
}
}

Expand Down Expand Up @@ -213,7 +213,12 @@ public String getJdbcUrl() {
return System.getProperty(SONARCOLLECTOR_JDBCURL, applicationProperties.getProperty(SONARCOLLECTOR_JDBCURL));
}

public URL createSonarMeasurementsComponentUrl(SonarBuild build, String[] metricKeys) throws UnsupportedEncodingException, MalformedURLException {
public URL createSonarComponentsShowUrl(URL serverUrl, String project) throws IOException {
String localPath = String.format("/api/components/show?component=%s", URLEncoder.encode(project,"UTF-8"));
return new URL(serverUrl, localPath);
}

public URL createSonarMeasurementsComponentUrl(SonarBuild build, String[] metricKeys) throws IOException {
String localPath = String.format("/api/measures/component?componentKey=%s&metricKeys=%s", URLEncoder.encode(build.getProject(),"UTF-8"), String.join(",", metricKeys));
return new URL(build.getServerUrl(), localPath);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,11 @@ private static void addTestPropertiesToSystemProperties() throws IOException {
@Test
public void testReceiveSonarWebhookCall() throws ServletException, IOException, SQLException {
URLConnectionFactory factory = mock(URLConnectionFactory.class);
InputStream measurementsBody = getClass().getClassLoader().getResourceAsStream("json/sonar/api-measures-component-get-many-metrics.json");
HttpURLConnection measurementsConnection = mock(HttpURLConnection.class);
when(measurementsConnection.getInputStream()).thenReturn(measurementsBody);
when(factory.openConnection(any())).thenReturn(measurementsConnection);
HttpURLConnection componentsShowConnection = createConnectionFromResource("json/sonar/api-components-show-version-1.0.0-SNAPSHOT.json");
HttpURLConnection measurementsConnection = createConnectionFromResource("json/sonar/api-measures-component-get-many-metrics.json");
when(factory.openConnection(any()))
.thenReturn(componentsShowConnection)
.thenReturn(measurementsConnection);
HttpServletRequest request = mock(HttpServletRequest.class);
ServletInputStream value = wrap(getClass().getClassLoader().getResourceAsStream("json/sonar/webhook-post.json"));
when(request.getInputStream()).thenReturn(value);
Expand Down Expand Up @@ -136,44 +137,68 @@ public void testUseNoArgumentConstructorAndReceiveSonarWebhookCall() throws Serv
public void testCallbackToSonarServerToGetMetrics() throws ServletException, IOException {
MockLogService logservice = new MockLogService();
URLConnectionFactory factory = mock(URLConnectionFactory.class);
HttpURLConnection componentsShowNoMavenVersion = createConnectionFromResource("json/sonar/api-components-show-component-not-found.json");
HttpURLConnection componentsShowWithSnapshot = createConnectionFromResource("json/sonar/api-components-show-version-1.0.0-SNAPSHOT.json");
HttpURLConnection componentsShow = createConnectionFromResource("json/sonar/api-components-show-version-1.0.0.json");
HttpURLConnection[] connections = createConnectionFromResource("json/sonar/api-measures-component-get-many-metrics.json", 3);
when(factory.openConnection(any()))
.thenReturn(componentsShowNoMavenVersion)
.thenReturn(connections[0])
.thenReturn(componentsShowWithSnapshot)
.thenReturn(connections[1])
.thenReturn(componentsShow)
.thenReturn(connections[2]);
SonarCollectorServlet servlet = new SonarCollectorServlet(factory);
servlet.setLogservice(logservice);
ServletRequest request = mock(ServletRequest.class);
ServletInputStream webhookPostBody = wrap(getClass().getClassLoader().getResourceAsStream("json/sonar/webhook-post.json"));
ServletInputStream webhookPostBodyWithMavenSnapshotVersion = wrap(getClass().getClassLoader().getResourceAsStream("json/sonar/webhook-post-with-snapshot-maven-version.json"));
ServletInputStream webhookPostBodyWithMavenVersion = wrap(getClass().getClassLoader().getResourceAsStream("json/sonar/webhook-post-with-maven-version.json"));
String resource = "json/sonar/webhook-post.json";
ServletInputStream[] webhookPostBody = createServletInputStreamFromResource(resource, 3);
when(request.getInputStream())
.thenReturn(webhookPostBody)
.thenReturn(webhookPostBodyWithMavenSnapshotVersion)
.thenReturn(webhookPostBodyWithMavenVersion);

long expectedTimeInMillisecondsSinceEpoch = ZonedDateTime.parse("2016-11-18T10:46:28+0100", SonarCollectorServlet.isoZonedDateTimeformatter).toEpochSecond() * 1000;
SonarBuild build = servlet.callbackToSonarServerToGetMetrics(request);
assertEquals("org.sonarqube:example", build.getProject());
assertEquals(expectedTimeInMillisecondsSinceEpoch, build.getAnalysedAt());
assertEquals("", build.getVersion());
assertEquals("http://localhost:9000", build.getServerUrl().toString());
.thenReturn(webhookPostBody[0])
.thenReturn(webhookPostBody[1])
.thenReturn(webhookPostBody[2]);

long expectedTimeInMillisecondsSinceEpoch = ZonedDateTime.parse("2017-11-19T10:39:24+0100", SonarCollectorServlet.isoZonedDateTimeformatter).toEpochSecond() * 1000;
assertEquals("Expected no log messages initially", 0, logservice.getLogmessages().size());
SonarBuild buildWithNoMavenVersion = servlet.callbackToSonarServerToGetMetrics(request);
assertEquals("no.priv.bang.sonar.sonar-collector:parent", buildWithNoMavenVersion.getProject());
assertEquals(expectedTimeInMillisecondsSinceEpoch, buildWithNoMavenVersion.getAnalysedAt());
assertEquals("", buildWithNoMavenVersion.getVersion());
assertEquals("Expected a single warning log message from missing maven version", 1, logservice.getLogmessages().size());
assertEquals("http://localhost:9000", buildWithNoMavenVersion.getServerUrl().toString());

SonarBuild buildWithMavenSnapshotVersion = servlet.callbackToSonarServerToGetMetrics(request);
assertEquals("org.sonarqube:example", buildWithMavenSnapshotVersion.getProject());
assertEquals("no.priv.bang.sonar.sonar-collector:parent", buildWithMavenSnapshotVersion.getProject());
assertEquals(expectedTimeInMillisecondsSinceEpoch, buildWithMavenSnapshotVersion.getAnalysedAt());
assertEquals("1.0.0-SNAPSHOT", buildWithMavenSnapshotVersion.getVersion());
assertEquals("http://localhost:9000", buildWithMavenSnapshotVersion.getServerUrl().toString());

SonarBuild buildWithMavenVersion = servlet.callbackToSonarServerToGetMetrics(request);
assertEquals("org.sonarqube:example", buildWithMavenVersion.getProject());
assertEquals("no.priv.bang.sonar.sonar-collector:parent", buildWithMavenVersion.getProject());
assertEquals(expectedTimeInMillisecondsSinceEpoch, buildWithMavenVersion.getAnalysedAt());
assertEquals("1.0.0", buildWithMavenVersion.getVersion());
assertEquals("http://localhost:9000", buildWithMavenVersion.getServerUrl().toString());
}

@Test
public void testCreateGetMetricsUrl() throws ServletException, IOException {
public void testCreateSonarComponentsShowUrl() throws ServletException, IOException {
URLConnectionFactory factory = mock(URLConnectionFactory.class);
SonarCollectorServlet servlet = new SonarCollectorServlet(factory);
String[] metricKeys = servlet.getMetricKeys();
assertEquals(9, metricKeys.length);
String project = "no.priv.bang.ukelonn:parent";
URL serverUrl = new URL("http://localhost:9000");
URL metricsUrl = servlet.createSonarComponentsShowUrl(serverUrl, project);
assertEquals(serverUrl.getProtocol(), metricsUrl.getProtocol());
assertEquals(serverUrl.getHost(), metricsUrl.getHost());
assertEquals(serverUrl.getPort(), metricsUrl.getPort());
assertEquals("/api/components/show", metricsUrl.getPath());
String query = URLDecoder.decode(metricsUrl.getQuery(), "UTF-8");
assertThat(query, containsString(project));
}

@Test
public void testCreateSonarMeasurementsComponentUrl() throws ServletException, IOException {
URLConnectionFactory factory = mock(URLConnectionFactory.class);
SonarCollectorServlet servlet = new SonarCollectorServlet(factory);
String[] metricKeys = servlet.getMetricKeys();
Expand Down Expand Up @@ -253,6 +278,15 @@ public void testParseTimestamp() throws IOException {
assertEquals(39, calendar.get(Calendar.MINUTE));
}

private ServletInputStream[] createServletInputStreamFromResource(String resource, int numberOfCopies) {
ServletInputStream[] streams = new ServletInputStream[numberOfCopies];
for(int i=0; i<numberOfCopies; ++i) {
streams[i] = wrap(getClass().getClassLoader().getResourceAsStream(resource));
}

return streams;
}

private HttpURLConnection[] createConnectionFromResource(String resource, int numberOfCopies) throws IOException {
HttpURLConnection[] connections = new HttpURLConnection[numberOfCopies];
for(int i=0; i<numberOfCopies; ++i) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"errors": [
{
"msg": "Component key 'no.priv.bang.sonar.sonar-collector:parent' not found"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"errors": [
{
"msg": "Either 'componentId' or 'component' must be provided"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"component": {
"organization": "default-organization",
"id": "AV_PTIC-nHoAyOYzcfvA",
"key": "no.priv.bang.sonar.sonar-collector:parent",
"name": "SonarQube data collector parent project",
"qualifier": "TRK",
"analysisDate": "2017-11-19T22:40:36+0100",
"tags": [],
"visibility": "public",
"leakPeriodDate": "2017-11-18T16:52:24+0100",
"version": "1.0.0-SNAPSHOT"
},
"ancestors": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"component": {
"organization": "default-organization",
"id": "AV_PTIC-nHoAyOYzcfvA",
"key": "no.priv.bang.sonar.sonar-collector:parent",
"name": "SonarQube data collector parent project",
"qualifier": "TRK",
"analysisDate": "2017-11-19T22:40:36+0100",
"tags": [],
"visibility": "public",
"leakPeriodDate": "2017-11-18T16:52:24+0100",
"version": "1.0.0"
},
"ancestors": []
}

This file was deleted.

This file was deleted.

0 comments on commit a07a528

Please sign in to comment.