Skip to content

Commit

Permalink
Support pull request analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
reda-alaoui committed Jan 15, 2022
1 parent ff66bca commit e1cf83f
Show file tree
Hide file tree
Showing 32 changed files with 1,333 additions and 229 deletions.
424 changes: 285 additions & 139 deletions README.md

Large diffs are not rendered by default.

Binary file added doc/sonar-pull-request-analysis-radio.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/sonar-scanner-wrapper.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 12 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@
<gerrit-rest-java-client.version>0.9.4.0</gerrit-rest-java-client.version>
<junit.jupiter.version>5.8.2</junit.jupiter.version>
<testcontainers.version>1.16.2</testcontainers.version>
<okhttp.version>4.9.2</okhttp.version>
<jackson.version>2.13.0</jackson.version>
<sonar.version>2.13.1</sonar.version>

<git-code-format-maven-plugin.version>2.7</git-code-format-maven-plugin.version>
<assertj-core.version>3.21.0</assertj-core.version>
<logback-classic.version>1.2.3</logback-classic.version>
<sonar-ws.version>7.7</sonar-ws.version>
</properties>

<name>Sonar Gerrit Plugin</name>
Expand Down Expand Up @@ -88,6 +88,11 @@
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20190722</version>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down Expand Up @@ -124,6 +129,12 @@
<artifactId>gerrit-rest-java-client-shaded</artifactId>
<version>${gerrit-rest-java-client.version}</version>
</dependency>
<dependency>
<groupId>org.sonarsource.sonarqube</groupId>
<artifactId>sonar-ws</artifactId>
<version>${sonar-ws.version}</version>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
Expand Down Expand Up @@ -185,12 +196,6 @@
<artifactId>durable-task</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public void perform(
GerritRevision revision = GerritConnector.connect(connectionInfo).fetchRevision();

// load inspection report
InspectionReport report = inspectionConfig.analyse(listener, revision, filePath);
InspectionReport report = inspectionConfig.analyse(run, listener, revision, filePath);

Map<String, Set<Integer>> fileToChangedLines = revision.getFileToChangedLines();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
@Restricted(NoExternalUse.class)
public class TaskListenerLogger {

public static void log(TaskListener listener, String message, Object... params) {
listener.getLogger().printf(message, params);
listener.getLogger().println();
}

public static void logMessage(
TaskListener listener, Logger logger, Level level, String message, Object... params) {
message = getLocalized(message, params);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package org.jenkinsci.plugins.sonargerrit.sonar;

import hudson.FilePath;
import hudson.model.Run;
import hudson.model.TaskListener;
import java.io.IOException;
import org.jenkinsci.plugins.sonargerrit.gerrit.Revision;

/** @author Réda Housni Alaoui */
public interface AnalysisStrategy {

InspectionReport analyse(TaskListener listener, Revision revision, FilePath workspace)
InspectionReport analyse(
Run<?, ?> run, TaskListener listener, Revision revision, FilePath workspace)
throws IOException, InterruptedException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.jenkinsci.plugins.sonargerrit.sonar;

import javax.annotation.Nullable;

/** @author Réda Housni Alaoui */
public interface Component {
String getKey();

@Nullable
String getPath();

@Nullable
String getModuleKey();
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.jenkinsci.plugins.sonargerrit.sonar.preview_mode_analysis;
package org.jenkinsci.plugins.sonargerrit.sonar;

import static com.google.common.base.Preconditions.checkNotNull;

Expand Down Expand Up @@ -28,13 +28,13 @@
* </pre>
*/
@Restricted(NoExternalUse.class)
class ComponentPathBuilder {
public class Components {

private final Map<String, Node> nodes = Maps.newHashMap();

public ComponentPathBuilder(final List<ComponentRepresentation> components) {
public Components(final List<? extends Component> components) {
checkNotNull(components);
for (final ComponentRepresentation c : components) {
for (final Component c : components) {
nodes.put(c.getKey(), new Node(c));
}
}
Expand Down Expand Up @@ -109,11 +109,11 @@ private Node getNodeByComponentKey(final String componentKey) {
private static class Node {
private static final String GERRIT_FILE_DELIMITER = "/";

private final ComponentRepresentation component;
private final Component component;

private Node parent;

public Node(final ComponentRepresentation c) {
public Node(final Component c) {
checkNotNull(c);
this.component = c;
}
Expand Down Expand Up @@ -154,7 +154,7 @@ private void buildPath(final StringBuilder path) {
}
}

public ComponentRepresentation getComponent() {
public Component getComponent() {
return component;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import hudson.FilePath;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.plugins.sonar.SonarInstallation;
import java.io.IOException;
Expand All @@ -19,6 +20,7 @@
import org.jenkinsci.plugins.sonargerrit.sonar.preview_mode_analysis.PreviewModeAnalysisStrategy;
import org.jenkinsci.plugins.sonargerrit.sonar.preview_mode_analysis.SonarQubeInstallations;
import org.jenkinsci.plugins.sonargerrit.sonar.preview_mode_analysis.SubJobConfig;
import org.jenkinsci.plugins.sonargerrit.sonar.pull_request_analysis.PullRequestAnalysisStrategy;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

Expand Down Expand Up @@ -70,9 +72,10 @@ protected Object readResolve() {
@DataBoundConstructor
public Inspection() {}

public InspectionReport analyse(TaskListener listener, Revision revision, FilePath workspace)
public InspectionReport analyse(
Run<?, ?> run, TaskListener listener, Revision revision, FilePath workspace)
throws IOException, InterruptedException {
return analysisStrategy.analyse(listener, revision, workspace);
return analysisStrategy.analyse(run, listener, revision, workspace);
}

public AnalysisStrategy getAnalysisStrategy() {
Expand Down Expand Up @@ -198,7 +201,9 @@ public static class DescriptorImpl extends Descriptor<Inspection> {
@SuppressWarnings("unused")
public List<Descriptor<?>> getAnalysisStrategyDescriptors() {
Jenkins jenkins = Jenkins.get();
return ImmutableList.of(jenkins.getDescriptorOrDie(PreviewModeAnalysisStrategy.class));
return ImmutableList.of(
jenkins.getDescriptorOrDie(PullRequestAnalysisStrategy.class),
jenkins.getDescriptorOrDie(PreviewModeAnalysisStrategy.class));
}

@Override
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/org/jenkinsci/plugins/sonargerrit/sonar/Rule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.jenkinsci.plugins.sonargerrit.sonar;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

/** @author Réda Housni Alaoui */
@Restricted(NoExternalUse.class)
public class Rule {

private final String id;

public Rule(String id) {
this.id = id;
}

public String id() {
return id;
}

public String createLink(String sonarQubeUrl) {
if (sonarQubeUrl == null) {
return id;
}
StringBuilder sb = new StringBuilder();
String url = sonarQubeUrl.trim();
if (!(url.startsWith("http://") || sonarQubeUrl.startsWith("https://"))) {
sb.append("http://");
}
sb.append(url);
if (!(url.endsWith("/"))) {
sb.append("/");
}
sb.append("coding_rules#rule_key=");
sb.append(escapeHttp(id)); // squid%3AS1319
return sb.toString();
}

private String escapeHttp(String query) {
try {
return URLEncoder.encode(query, "UTF-8");
} catch (UnsupportedEncodingException e) {
return query;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import javax.annotation.Nullable;
import org.jenkinsci.plugins.sonargerrit.sonar.Component;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

/** Project: Sonar-Gerrit Plugin Author: Tatiana Didik */
@Restricted(NoExternalUse.class)
class ComponentRepresentation {
class ComponentRepresentation implements Component {
@SuppressWarnings("unused")
@SuppressFBWarnings("UWF_UNWRITTEN_FIELD")
private String key;
Expand All @@ -24,15 +25,18 @@ class ComponentRepresentation {
@SuppressFBWarnings("UWF_UNWRITTEN_FIELD")
private String status;

@Override
public String getKey() {
return key;
}

@Override
@Nullable
public String getPath() {
return path;
}

@Override
@Nullable
public String getModuleKey() {
return moduleKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import hudson.FilePath;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.plugins.sonar.SonarGlobalConfiguration;
import hudson.plugins.sonar.SonarInstallation;
Expand Down Expand Up @@ -127,7 +128,8 @@ public boolean isPathCorrectionNeeded() {
}

@Override
public InspectionReport analyse(TaskListener listener, Revision revision, FilePath workspace)
public InspectionReport analyse(
Run<?, ?> run, TaskListener listener, Revision revision, FilePath workspace)
throws IOException, InterruptedException {
return new SonarConnector(listener, this, revision, getSonarQubeInstallation().orElse(null))
.readSonarReports(workspace);
Expand Down Expand Up @@ -162,7 +164,7 @@ public ListBoxModel doFillSonarQubeInstallationNameItems() {

@Override
public String getDisplayName() {
return "Preview mode analysis";
return "Preview mode analysis (until SonarQube 7.6)";
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.jenkinsci.plugins.sonargerrit.sonar.preview_mode_analysis;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date;
import org.jenkinsci.plugins.sonargerrit.sonar.Components;
import org.jenkinsci.plugins.sonargerrit.sonar.Issue;
import org.jenkinsci.plugins.sonargerrit.sonar.Rule;
import org.jenkinsci.plugins.sonargerrit.sonar.Severity;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
Expand All @@ -13,56 +13,34 @@
class SimpleIssue implements Issue {

private final IssueRepresentation representation;
private final ComponentPathBuilder pathBuilder;
private final Components components;
private final SubJobConfig config;
private final String sonarQubeUrl;

private String filepath;

public SimpleIssue(
IssueRepresentation representation,
ComponentPathBuilder pathBuilder,
Components components,
SubJobConfig config,
String sonarQubeUrl) {
this.representation = representation;
this.pathBuilder = pathBuilder;
this.components = components;
this.config = config;
this.sonarQubeUrl = sonarQubeUrl;
}

@Override
public String getRuleLink() {
if (sonarQubeUrl == null) {
return getRule();
}
StringBuilder sb = new StringBuilder();
String url = sonarQubeUrl.trim();
if (!(url.startsWith("http://") || sonarQubeUrl.startsWith("https://"))) {
sb.append("http://");
}
sb.append(url);
if (!(url.endsWith("/"))) {
sb.append("/");
}
sb.append("coding_rules#rule_key=");
sb.append(escapeHttp(getRule())); // squid%3AS1319
return sb.toString();
}

private String escapeHttp(String query) {
try {
return URLEncoder.encode(query, "UTF-8");
} catch (UnsupportedEncodingException e) {
return query;
}
return new Rule(getRule()).createLink(sonarQubeUrl);
}

@Override
public String getFilepath() {
if (filepath == null) {
if (pathBuilder != null) {
if (components != null) {
filepath =
pathBuilder
components
.buildPrefixedPathForComponentWithKey(getComponent(), config.getProjectPath())
.or(getComponent());
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.logging.Logger;
import org.jenkinsci.plugins.sonargerrit.TaskListenerLogger;
import org.jenkinsci.plugins.sonargerrit.gerrit.Revision;
import org.jenkinsci.plugins.sonargerrit.sonar.Components;
import org.jenkinsci.plugins.sonargerrit.sonar.InspectionReport;
import org.jenkinsci.plugins.sonargerrit.sonar.Issue;
import org.kohsuke.accmod.Restricted;
Expand Down Expand Up @@ -93,10 +94,10 @@ public void readSonarReports(List<ReportInfo> reports, ReportRecorder reportReco
// multimap file-to-issues generation for each report
for (ReportInfo info : reports) {
ReportRepresentation report = info.report;
final ComponentPathBuilder pathBuilder = new ComponentPathBuilder(report.getComponents());
final Components components = new Components(report.getComponents());
for (IssueRepresentation issue : report.getIssues()) {
Issue issueToRecord =
decorator.decorate(new SimpleIssue(issue, pathBuilder, info.config, sonarQubeUrl));
decorator.decorate(new SimpleIssue(issue, components, info.config, sonarQubeUrl));
reportRecorder.recordIssue(issueToRecord);
}
}
Expand Down
Loading

0 comments on commit e1cf83f

Please sign in to comment.