Skip to content
This repository has been archived by the owner on Oct 2, 2023. It is now read-only.

Commit

Permalink
Merge pull request #70 from nameisaravind/sonar-u1
Browse files Browse the repository at this point in the history
sonar refresh data by individual project
  • Loading branch information
nireeshT authored Oct 30, 2020
2 parents 39a6723 + 120a0c7 commit 053075b
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 3 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<description>CodeQuality Collector Microservices currently collects data from Sonar</description>
<url>https://hygieia.github.io/Hygieia/getting_started.html</url>
<packaging>jar</packaging>
<version>3.2.2-SNAPSHOT</version>
<version>3.2.3-SNAPSHOT</version>

<parent>
<groupId>org.springframework.boot</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class DefaultSonar6Client implements SonarClient {
private static final String URL_RESOURCES_AUTHENTICATED = "/api/projects/search?ps=500";
private static final String URL_RESOURCE_DETAILS = "/api/measures/component?format=json&componentId=%s&metricKeys=%s&includealerts=true";
static final String URL_PROJECT_ANALYSES = "/api/project_analyses/search?project=%s";
private static final String URL_PROJECT_INFO = "%s/api/components/show?component=%s";
private static final String URL_QUALITY_PROFILES = "/api/qualityprofiles/search";
private static final String URL_QUALITY_PROFILE_PROJECT_DETAILS = "/api/qualityprofiles/projects?key=";
private static final String URL_QUALITY_PROFILE_CHANGES = "/api/qualityprofiles/changelog?profileKey=";
Expand All @@ -55,6 +56,7 @@ public class DefaultSonar6Client implements SonarClient {
private static final String STATUS_ALERT = "ALERT";
private static final String DATE = "date";
private static final String EVENTS = "events";
private static final String COMPONENT = "component";

protected final RestClient restClient;
protected RestUserInfo userInfo = new RestUserInfo("","");
Expand Down Expand Up @@ -175,6 +177,24 @@ private void getProjects(String url, String key, JSONArray jsonArray, int pageNu
jsonArray.addAll(parseAsArray(urlFinal, key));
}

public SonarProject getProject(String projectKey, String instanceUrl) {
String url = String.format(URL_PROJECT_INFO, instanceUrl, projectKey);
SonarProject project = null;
try {
JSONObject component = child(getResponse(url), COMPONENT);
if (component != null) {
project = parseSonarProject(instanceUrl, component);
project.setEnabled(false);
project.setDescription(project.getProjectName());
}
} catch (ParseException e) {
LOG.error("Could not parse response from: " + url, e);
} catch (RestClientException rce) {
LOG.error(rce);
}
return project;
}

@Override
public CodeQuality currentCodeQuality(SonarProject project) throws HttpClientErrorException, ParseException {
String url = String.format(
Expand Down Expand Up @@ -331,6 +351,11 @@ protected String str(JSONObject json, String key) {
return obj == null ? null : obj.toString();
}

protected JSONObject child(JSONObject json, String key) {
JSONObject obj = (JSONObject) json.get(key);
return obj == null ? null : obj;
}

protected String strSafe(JSONObject json, String key) {
Object obj = json.get(key);
return obj == null ? "" : obj.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ public JSONArray getQualityProfileConfigurationChanges(String instanceUrl,JSONOb
}
}

@Override
public SonarProject getProject(String projectKey, String instanceUrl) {
return null;
}

protected JSONArray parseAsArray(String url) throws ParseException {
ResponseEntity<String> response = restClient.makeRestCallGet(url, this.userInfo);
return (JSONArray) new JSONParser().parse(response.getBody());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,5 @@ public interface SonarClient {
JSONArray getQualityProfiles(String instanceUrl) throws ParseException;
List<String> retrieveProfileAndProjectAssociation(String instanceUrl,JSONObject qualityProfile) throws ParseException;
JSONArray getQualityProfileConfigurationChanges(String instanceUrl,JSONObject qualityProfile) throws ParseException;


SonarProject getProject(String projectKey, String instanceUrl);
}
109 changes: 109 additions & 0 deletions src/main/java/com/capitalone/dashboard/controller/SonarController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.capitalone.dashboard.controller;

import com.capitalone.dashboard.collector.SonarClient;
import com.capitalone.dashboard.collector.SonarClientSelector;
import com.capitalone.dashboard.model.Collector;
import com.capitalone.dashboard.model.SonarProject;
import com.capitalone.dashboard.repository.CodeQualityRepository;
import com.capitalone.dashboard.repository.CollectorRepository;
import com.capitalone.dashboard.repository.SonarProjectRepository;
import com.capitalone.dashboard.util.SonarCollectorUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;

@RestController
@Validated
public class SonarController {

private final SonarProjectRepository sonarProjectRepository;
private final CodeQualityRepository codeQualityRepository;
private final CollectorRepository collectorRepository;
private SonarClientSelector sonarClientSelector;


private String instanceUrl;
private String projectName;
private String projectKey;
private Collector collector;
private SonarClient sonarClient;

@Autowired
public SonarController(SonarProjectRepository sonarProjectRepository,
CodeQualityRepository codeQualityRepository,
CollectorRepository collectorRepository,
SonarClientSelector sonarClientSelector) {
this.sonarProjectRepository = sonarProjectRepository;
this.codeQualityRepository = codeQualityRepository;
this.collectorRepository = collectorRepository;
this.sonarClientSelector = sonarClientSelector;
}

@RequestMapping(value = "/refresh", method = GET, produces = APPLICATION_JSON_VALUE)
public ResponseEntity<String> refresh(@Valid String projectName, @Valid String projectKey, @Valid String instanceUrl) {

gatherParams(projectName, projectKey, instanceUrl);
if (Objects.nonNull(instanceUrl)) {
this.sonarClient = this.sonarClientSelector.getSonarClient(this.sonarClientSelector.getSonarVersion(instanceUrl));
this.collector = collectorRepository.findByName("Sonar");

SonarProject projectToRefresh;
if (Objects.nonNull(this.collector)) {
if ((Objects.nonNull(projectName) && Objects.nonNull(projectToRefresh = getExistingProject()))
|| (Objects.nonNull(projectKey) && Objects.nonNull(projectToRefresh = createNewProjectIfNotExists()))) {
SonarCollectorUtil.updateCodeQualityData(this.collector, this.sonarClient, projectToRefresh);
return sendResponse("successfully refreshed sonar project");
}
return sendResponse("unable to refresh sonar project");
}
return sendResponse("sonar collector not found");
}
return sendResponse("sonar instance url is invalid");
}

private void gatherParams(String projectName, String projectKey, String instanceUrl) {
this.projectName = projectName;
this.projectKey = projectKey;
this.instanceUrl = instanceUrl;
}

private ResponseEntity<String> sendResponse(String message) {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity<>(message, httpHeaders, HttpStatus.OK);
}

private SonarProject createNewProjectIfNotExists() {
SonarProject project = null;
if (Objects.nonNull(this.projectKey)) {
SonarProject newProject = this.sonarClient.getProject(this.projectKey, this.instanceUrl);
if (Objects.nonNull(newProject)) {
SonarProject existingProject = sonarProjectRepository.findSonarProject(this.collector.getId(),
newProject.getInstanceUrl(), newProject.getProjectId());
project = Objects.nonNull(existingProject) ? existingProject : newProject;
}
}
return project;
}

private SonarProject getExistingProject() {
List<SonarProject> sonarProjects = sonarProjectRepository.
findSonarProjectsByProjectName(this.collector.getId(), this.instanceUrl, this.projectName);
return CollectionUtils.isNotEmpty(sonarProjects) ?
sonarProjects.stream().sorted(Comparator.comparing(SonarProject::getLastUpdated).reversed()).findFirst().get() : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ public interface SonarProjectRepository extends BaseCollectorItemRepository<Sona
@Query(value="{ 'collectorId' : ?0, options.instanceUrl : ?1, options.projectId : ?2}")
SonarProject findSonarProject(ObjectId collectorId, String instanceUrl, String projectId);

@Query(value="{ 'collectorId' : ?0, options.instanceUrl : ?1, options.projectName : ?2}")
List<SonarProject> findSonarProjectsByProjectName(ObjectId collectorId, String instanceUrl, String projectName);

@Query(value="{ 'collectorId' : ?0, options.instanceUrl : ?1, enabled: true}")
List<SonarProject> findEnabledProjects(ObjectId collectorId, String instanceUrl);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.capitalone.dashboard.util;

import com.capitalone.dashboard.collector.SonarClient;
import com.capitalone.dashboard.model.CodeQuality;
import com.capitalone.dashboard.model.CollectionError;
import com.capitalone.dashboard.model.Collector;
import com.capitalone.dashboard.model.SonarProject;
import com.capitalone.dashboard.repository.CodeQualityRepository;
import com.capitalone.dashboard.repository.SonarProjectRepository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.simple.parser.ParseException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;

@Component
public class SonarCollectorUtil {

private static final Log LOG = LogFactory.getLog(SonarCollectorUtil.class);

private static SonarProjectRepository sonarProjectRepository;
private static CodeQualityRepository codeQualityRepository;

public SonarCollectorUtil(SonarProjectRepository sonarProjectRepository, CodeQualityRepository codeQualityRepository) {
this.sonarProjectRepository = sonarProjectRepository;
this.codeQualityRepository = codeQualityRepository;
}


public static void updateCodeQualityData(Collector sonarCollector, SonarClient sonarClient, SonarProject project) {
try {
CodeQuality codeQuality = sonarClient.currentCodeQuality(project);
if (codeQuality != null) {
project.setLastUpdated(System.currentTimeMillis());
project.setCollectorId(sonarCollector.getId());
sonarProjectRepository.save(project);
codeQuality.setCollectorItemId(project.getId());
codeQuality.setTimestamp(System.currentTimeMillis());
codeQualityRepository.save(codeQuality);
}
} catch (HttpClientErrorException e) {
if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
project.setEnabled(false);
project.setLastUpdated(System.currentTimeMillis());
CollectionError error = new CollectionError("404", "disabled as the project no longer exists in Sonar");
project.getErrors().add(error);
sonarProjectRepository.save(project);
LOG.info(String.format("Disabled as a result of HTTPStatus.NOT_FOUND, projectName=%s instanceUrl=%s",
project.getProjectName(), project.getInstanceUrl()));
} else {
LOG.error(e.getStackTrace());
}
} catch (ParseException parseEx) {
CollectionError error = new CollectionError("500", parseEx.getMessage());
project.getErrors().add(error);
sonarProjectRepository.save(project);
LOG.error(parseEx);
}
}
}

0 comments on commit 053075b

Please sign in to comment.