Skip to content
Permalink
Browse files

Merge pull request #8 from aquarellian/master

JENKINS-31892
  • Loading branch information...
aquarellian committed Dec 4, 2015
2 parents 2c36e23 + ebf1544 commit cdf70f3753f6f3fdbfa38aef63bc7f39d88c06fd
@@ -72,7 +72,7 @@
<dependency>
<groupId>com.sonyericsson.hudson.plugins.gerrit</groupId>
<artifactId>gerrit-trigger</artifactId>
<version>2.17.2</version>
<version>2.16.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
@@ -17,7 +17,6 @@
import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.GerritTrigger;
import com.urswolfer.gerrit.client.rest.GerritAuthData;
import com.urswolfer.gerrit.client.rest.GerritRestApiFactory;

import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
@@ -29,7 +28,6 @@
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Publisher;
import hudson.util.FormValidation;

import org.jenkinsci.plugins.sonargerrit.data.SonarReportBuilder;
import org.jenkinsci.plugins.sonargerrit.data.converter.CustomIssueFormatter;
import org.jenkinsci.plugins.sonargerrit.data.converter.CustomReportFormatter;
@@ -44,8 +42,6 @@

import javax.annotation.Nullable;
import javax.servlet.ServletException;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
@@ -62,7 +58,8 @@

public class SonarToGerritPublisher extends Publisher {

private static final String DEFAULT_PATH = "target/sonar/sonar-report.json";
private static final String DEFAULT_SONAR_REPORT_PATH = "target/sonar/sonar-report.json";
private static final String DEFAULT_PROJECT_PATH = "";
private static final String DEFAULT_SONAR_URL = "http://localhost:9000";
private static final String DEFAULT_CATEGORY = "Code-Review";
private static final int DEFAULT_SCORE = 0;
@@ -77,9 +74,12 @@
public static final String GERRIT_NAME_ENV_VAR_NAME = "GERRIT_NAME";
public static final String GERRIT_PATCHSET_NUMBER_ENV_VAR_NAME = "GERRIT_PATCHSET_NUMBER";

// left here for compatibility with previous version. will be removed in further releases
private final String path;
private final String projectPath;

private final String sonarURL;
private final String path;
private List<SubJobConfig> subJobConfigs;
private final String severity;
private final boolean changedLinesOnly;
private final boolean newIssuesOnly;
@@ -96,14 +96,13 @@


@DataBoundConstructor
public SonarToGerritPublisher(String projectPath, String sonarURL, String path,
String severity, boolean changedLinesOnly, boolean newIssuesOnly,
String noIssuesToPostText, String someIssuesToPostText, String issueComment,
boolean postScore, String category, String noIssuesScore, String issuesScore,
String noIssuesNotification, String issuesNotification) {
this.projectPath = MoreObjects.firstNonNull(projectPath, EMPTY_STR);
public SonarToGerritPublisher(String sonarURL, List<SubJobConfig> subJobConfigs,
String severity, boolean changedLinesOnly, boolean newIssuesOnly,
String noIssuesToPostText, String someIssuesToPostText, String issueComment,
boolean postScore, String category, String noIssuesScore, String issuesScore,
String noIssuesNotification, String issuesNotification) {
this.sonarURL = MoreObjects.firstNonNull(sonarURL, DEFAULT_SONAR_URL);
this.path = MoreObjects.firstNonNull(path, DEFAULT_PATH);
this.subJobConfigs = subJobConfigs;
this.severity = MoreObjects.firstNonNull(severity, Severity.MAJOR.name());
this.changedLinesOnly = changedLinesOnly;
this.newIssuesOnly = newIssuesOnly;
@@ -116,12 +115,13 @@ public SonarToGerritPublisher(String projectPath, String sonarURL, String path,
this.issuesScore = issuesScore;
this.noIssuesNotification = noIssuesNotification;
this.issuesNotification = issuesNotification;
}

public String getPath() {
return path;
// old values - not used anymore. will be deleted in further releases
this.path = null;
this.projectPath = null;
}


public String getSeverity() {
return severity;
}
@@ -150,10 +150,6 @@ public String getIssueComment() {
return issueComment;
}

public String getProjectPath() {
return projectPath;
}

@SuppressWarnings(value = "unused")
public boolean isPostScore() {
return postScore;
@@ -186,25 +182,14 @@ public String getIssuesScore() {
@Override
public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException,
InterruptedException {
FilePath reportPath = build.getWorkspace().child(getPath());
if (!reportPath.exists()) {
logMessage(listener, "jenkins.plugin.error.sonar.report.not.exists", Level.SEVERE, reportPath);

List<ReportInfo> issueInfos = readSonarReports(listener, build.getWorkspace());
if (issueInfos == null) {
logMessage(listener, "jenkins.plugin.validation.path.no.project.config.available", Level.SEVERE);
return false;
}
logMessage(listener, "jenkins.plugin.getting.report", Level.INFO, reportPath);

SonarReportBuilder builder = new SonarReportBuilder();
String reportJson = reportPath.readToString();
Report report = builder.fromJson(reportJson);
logMessage(listener, "jenkins.plugin.report.loaded", Level.INFO, report.getIssues().size());

// Step 1 - Filter issues by issues only predicates
Iterable<Issue> filtered = filterIssuesByPredicates(report);
// LOGGER.log(Level.INFO, "{0} issues left after filtration by predicates (severity, ... etc)", Lists.newArrayList(filtered).size());

// Step 2 - Calculate real file name for issues and store to multimap
Multimap<String, Issue> file2issues = generateFilenameToIssuesMap(report, filtered);
// logResultMap(file2issues, "Map file2issues contains {0} elements");
Multimap<String, Issue> file2issues = generateFilenameToIssuesMapFilteredByPredicates(issueInfos);

// Step 3 - Prepare Gerrit REST API client
// Check Gerrit configuration is available
@@ -271,14 +256,62 @@ public boolean apply(@Nullable String input) {
return true;
}

@VisibleForTesting
Multimap<String, Issue> generateFilenameToIssuesMapFilteredByPredicates(List<ReportInfo> issueInfos) {
Multimap<String, Issue> file2issues = LinkedListMultimap.create();
for (ReportInfo info : issueInfos) {

Report report = info.report;

// Step 1 - Filter issues by issues only predicates
Iterable<Issue> filtered = filterIssuesByPredicates(report.getIssues());

// Step 2 - Calculate real file name for issues and store to multimap
file2issues.putAll(generateFilenameToIssuesMapFilteredByPredicates(info.directoryPath, report, filtered));
}
return file2issues;
}

private Report readSonarReport(BuildListener listener, FilePath workspace, SubJobConfig config) throws IOException,
InterruptedException {
FilePath reportPath = workspace.child(config.getSonarReportPath());
if (!reportPath.exists()) {
logMessage(listener, "jenkins.plugin.error.sonar.report.not.exists", Level.SEVERE, reportPath);
return null;
}
logMessage(listener, "jenkins.plugin.getting.report", Level.INFO, reportPath);

SonarReportBuilder builder = new SonarReportBuilder();
String reportJson = reportPath.readToString();
Report report = builder.fromJson(reportJson);
logMessage(listener, "jenkins.plugin.report.loaded", Level.INFO, report.getIssues().size());
return report;
}

@VisibleForTesting
List<ReportInfo> readSonarReports(BuildListener listener, FilePath workspace) throws IOException,
InterruptedException {
List<ReportInfo> reports = new ArrayList<ReportInfo>();
for (SubJobConfig subJobConfig : getSubJobConfigs(false)) { // to be replaced by this.subJobConfigs in further releases - this code is to support older versions
Report report = readSonarReport(listener, workspace, subJobConfig);
if (report == null) {
return null;
}
reports.add(new ReportInfo(subJobConfig.getProjectPath(), report));
}
return reports;
}

private String getEnvVar(AbstractBuild build, BuildListener listener, String name) throws IOException, InterruptedException {
EnvVars envVars = build.getEnvironment(listener);
return envVars.get(name);
}

private void logMessage(BuildListener listener, String message, Level l, Object... params) {
message = getLocalized(message, params);
listener.getLogger().println(message);
if (listener != null) { // it can be it tests
listener.getLogger().println(message);
}
LOGGER.log(l, message);
}

@@ -291,6 +324,23 @@ private int getReviewMark(int finalIssuesCount) {
return parseNumber(mark, DEFAULT_SCORE);
}

public List<SubJobConfig> getSubJobConfigs() {
return getSubJobConfigs(true);
}

public List<SubJobConfig> getSubJobConfigs(boolean addDefault) {
if (subJobConfigs == null) {
subJobConfigs = new ArrayList<SubJobConfig>();
// add configuration from previous plugin version
if (path != null || projectPath != null) {
subJobConfigs.add(new SubJobConfig(projectPath, path));
} else if (addDefault) {
subJobConfigs.add(new SubJobConfig(DEFAULT_PROJECT_PATH, DEFAULT_SONAR_REPORT_PATH));
}
}
return subJobConfigs;
}

private ReviewInput.NotifyHandling getNotificationSettings(int finalIssuesCount) {
if (finalIssuesCount > 0) {
ReviewInput.NotifyHandling value = (issuesNotification == null ? null : ReviewInput.NotifyHandling.valueOf(issuesNotification));
@@ -380,7 +430,7 @@ void filterIssuesByChangedLines(Multimap<String, Issue> finalIssues, RevisionApi
}

@VisibleForTesting
Multimap<String, Issue> generateFilenameToIssuesMap(Report report, Iterable<Issue> filtered) {
Multimap<String, Issue> generateFilenameToIssuesMapFilteredByPredicates(String projectPath, Report report, Iterable<Issue> filtered) {
Multimap<String, Issue> file2issues = LinkedListMultimap.create();

/* The next code prepares data to process situations like this one:
@@ -426,8 +476,7 @@ private String appendDelimiter(String subPath) {
}

@VisibleForTesting
Iterable<Issue> filterIssuesByPredicates(Report report) {
List<Issue> issues = report.getIssues();
Iterable<Issue> filterIssuesByPredicates(List<Issue> issues) {
Severity sev = Severity.valueOf(severity);
return Iterables.filter(issues,
Predicates.and(
@@ -444,6 +493,22 @@ public DescriptorImpl getDescriptor() {
return (DescriptorImpl) super.getDescriptor();
}

@Override
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.NONE;
}

@VisibleForTesting
class ReportInfo {
private String directoryPath;
private Report report;

public ReportInfo(String directoryPath, Report report) {
this.directoryPath = directoryPath;
this.report = report;
}
}

/**
* Descriptor for {@link SonarToGerritPublisher}. Used as a singleton.
* The class is marked as public so that it can be accessed from views.
@@ -463,27 +528,6 @@ public DescriptorImpl() {
load();
}

/**
* Performs on-the-fly validation of the form field 'path'.
*
* @param value This parameter receives the value that the user has typed.
* @return Indicates the outcome of the validation. This is sent to the browser.
* <p/>
* Note that returning {@link FormValidation#error(String)} does not
* prevent the form from being saved. It just means that a message
* will be displayed to the user.
*/
@SuppressWarnings(value = "unused")
public FormValidation doCheckPath(@QueryParameter String value)
throws IOException, ServletException {
if (value.length() == 0)
return FormValidation.warning(getLocalized("jenkins.plugin.validation.path.empty"));
File f = new File(value);
if (!f.exists())
return FormValidation.error(String.format(getLocalized("jenkins.plugin.validation.path.no.such.file"), value));
return FormValidation.ok();
}

/**
* Performs on-the-fly validation of the form field 'sonarURL'.
*
@@ -669,11 +713,7 @@ public boolean isApplicable(Class<? extends AbstractProject> aClass) {
public String getDisplayName() {
return getLocalized("jenkins.plugin.build.step.name");
}
}

@Override
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.NONE;
}
}

@@ -0,0 +1,43 @@
package org.jenkinsci.plugins.sonargerrit;

import hudson.Extension;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;
import org.kohsuke.stapler.DataBoundConstructor;

/**
* Project: Sonar-Gerrit Plugin
* Author: Tatiana Didik
* Created: 02.12.2015 12:11
* <p/>
* $Id$
*/

public class SubJobConfig extends AbstractDescribableImpl<SubJobConfig> {
private String projectPath;
private String sonarReportPath;

@DataBoundConstructor
public SubJobConfig(String projectPath, String sonarReportPath) {
this.projectPath = projectPath;
this.sonarReportPath = sonarReportPath;
}

public String getProjectPath() {
return projectPath;
}

public String getSonarReportPath() {
return sonarReportPath;
}

@Extension
public static class DescriptorImpl extends Descriptor<SubJobConfig> {
public String getDisplayName() {
return "SubJobConfig";
}
}

}


@@ -15,6 +15,8 @@ jenkins.plugin.error.gerrit.server.empty=Cannot obtain Gerrit server name. Pleas
jenkins.plugin.error.gerrit.config.empty=Cannot obtain Gerrit configuration. Please check your Gerrit Trigger settings
jenkins.plugin.error.gerrit.user.empty=Gerrit authentication is not configured. Please check Gerrit Trigger settings
jenkins.plugin.error.sonar.report.not.exists=SonarQube report '%s' does not exist. Please check plugin settings
jenkins.plugin.validation.path.no.project.config.available=No SonarQube report available. Please check your Project Settings
jenkins.plugin.validation.path.no.project.config=At least one Project Settings configuration required
jenkins.plugin.validation.review.severity.unknown=Unknown severity
jenkins.plugin.validation.review.category.unknown=Unknown category
jenkins.plugin.validation.review.score.not.numeric=Score should be numeric
Oops, something went wrong.

0 comments on commit cdf70f3

Please sign in to comment.
You can’t perform that action at this time.