]> source.dussan.org Git - sonar-scanner-cli.git/commitdiff
SONARUNNER-143 New API to retrieve issues produced by the analysis
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Thu, 30 Jul 2015 08:24:11 +0000 (10:24 +0200)
committerDuarte Meneses <duarte.meneses@sonarsource.com>
Thu, 30 Jul 2015 13:40:57 +0000 (15:40 +0200)
sonar-runner-api/src/main/java/org/sonar/runner/api/EmbeddedRunner.java
sonar-runner-api/src/main/java/org/sonar/runner/api/Issue.java [new file with mode: 0644]
sonar-runner-api/src/main/java/org/sonar/runner/api/IssueListener.java [new file with mode: 0644]
sonar-runner-api/src/test/java/org/sonar/runner/api/EmbeddedRunnerTest.java
sonar-runner-api/src/test/java/org/sonar/runner/impl/IsolatedLauncherFactoryTest.java
sonar-runner-batch-interface/pom.xml
sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IsolatedLauncher.java
sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IssueListener.java [new file with mode: 0644]
sonar-runner-batch/src/main/java/org/sonar/runner/batch/BatchIsolatedLauncher.java
sonar-runner-batch/src/main/java/org/sonar/runner/batch/Compatibility.java

index 6b2ae23e144717d513c82f77b89fe56a5e4deed6..c24bbb6e2b9918dbd4f711705d32750650d46f0e 100644 (file)
@@ -23,9 +23,12 @@ import java.io.File;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.nio.charset.Charset;
+import java.security.InvalidParameterException;
 import java.util.Locale;
 import java.util.Properties;
+
 import javax.annotation.Nullable;
+
 import org.sonar.home.cache.Logger;
 import org.sonar.runner.batch.IsolatedLauncher;
 import org.sonar.runner.impl.InternalProperties;
@@ -50,35 +53,7 @@ public class EmbeddedRunner {
   }
 
   public static EmbeddedRunner create(final LogOutput logOutput) {
-    Logger logger = new Logger() {
-
-      @Override
-      public void warn(String msg) {
-        logOutput.log(msg, LogOutput.Level.WARN);
-      }
-
-      @Override
-      public void info(String msg) {
-        logOutput.log(msg, LogOutput.Level.INFO);
-      }
-
-      @Override
-      public void error(String msg, Throwable t) {
-        StringWriter errors = new StringWriter();
-        t.printStackTrace(new PrintWriter(errors));
-        logOutput.log(msg + "\n" + errors.toString(), LogOutput.Level.ERROR);
-      }
-
-      @Override
-      public void error(String msg) {
-        logOutput.log(msg, LogOutput.Level.ERROR);
-      }
-
-      @Override
-      public void debug(String msg) {
-        logOutput.log(msg, LogOutput.Level.DEBUG);
-      }
-    };
+    Logger logger = new LoggerAdapter(logOutput);
     return new EmbeddedRunner(new IsolatedLauncherFactory(logger), logger, logOutput);
   }
 
@@ -131,6 +106,10 @@ public class EmbeddedRunner {
   }
 
   public void runAnalysis(Properties analysisProperties) {
+    runAnalysis(analysisProperties, null);
+  }
+
+  public void runAnalysis(Properties analysisProperties, @Nullable IssueListener issueListener) {
     Properties copy = new Properties();
     copy.putAll(analysisProperties);
     initAnalysisProperties(copy);
@@ -141,7 +120,7 @@ public class EmbeddedRunner {
       Utils.writeProperties(dumpFile, copy);
       logger.info("Simulation mode. Configuration written to " + dumpFile.getAbsolutePath());
     } else {
-      doExecute(copy);
+      doExecute(copy, issueListener);
     }
   }
 
@@ -216,14 +195,85 @@ public class EmbeddedRunner {
     }
   }
 
-  protected void doExecute(Properties analysisProperties) {
+  protected void doExecute(Properties analysisProperties, @Nullable IssueListener issueListener) {
     if (VersionUtils.isAtLeast52(launcher.getVersion())) {
-      launcher.execute(analysisProperties);
+      if (issueListener != null) {
+        launcher.execute(analysisProperties, new IssueListenerAdapter(issueListener));
+      } else {
+        launcher.execute(analysisProperties);
+      }
     } else {
+      if (issueListener != null) {
+        throw new InvalidParameterException("Issue listeners not supported in current version: " + launcher.getVersion());
+      }
       Properties prop = new Properties();
       prop.putAll(globalProperties());
       prop.putAll(analysisProperties);
       launcher.executeOldVersion(prop);
     }
   }
+
+  static class IssueListenerAdapter implements org.sonar.runner.batch.IssueListener {
+    private IssueListener apiIssueListener;
+
+    public IssueListenerAdapter(IssueListener apiIssueListener) {
+      this.apiIssueListener = apiIssueListener;
+    }
+
+    @Override
+    public void handle(org.sonar.runner.batch.IssueListener.Issue issue) {
+      apiIssueListener.handle(transformIssue(issue));
+    }
+
+    private static org.sonar.runner.api.Issue transformIssue(org.sonar.runner.batch.IssueListener.Issue batchIssue) {
+      org.sonar.runner.api.Issue.Builder issueBuilder = org.sonar.runner.api.Issue.builder();
+
+      issueBuilder.setAssignee(batchIssue.getAssignee());
+      issueBuilder.setComponentKey(batchIssue.getComponentKey());
+      issueBuilder.setKey(batchIssue.getKey());
+      issueBuilder.setLine(batchIssue.getLine());
+      issueBuilder.setMessage(batchIssue.getMessage());
+      issueBuilder.setNew(batchIssue.isNew());
+      issueBuilder.setResolution(batchIssue.getResolution());
+      issueBuilder.setRule(batchIssue.getRule());
+      issueBuilder.setStatus(batchIssue.getStatus());
+
+      return issueBuilder.build();
+    }
+  }
+
+  private static class LoggerAdapter implements Logger {
+    private LogOutput logOutput;
+
+    LoggerAdapter(LogOutput logOutput) {
+      this.logOutput = logOutput;
+    }
+
+    @Override
+    public void warn(String msg) {
+      logOutput.log(msg, LogOutput.Level.WARN);
+    }
+
+    @Override
+    public void info(String msg) {
+      logOutput.log(msg, LogOutput.Level.INFO);
+    }
+
+    @Override
+    public void error(String msg, Throwable t) {
+      StringWriter errors = new StringWriter();
+      t.printStackTrace(new PrintWriter(errors));
+      logOutput.log(msg + "\n" + errors.toString(), LogOutput.Level.ERROR);
+    }
+
+    @Override
+    public void error(String msg) {
+      logOutput.log(msg, LogOutput.Level.ERROR);
+    }
+
+    @Override
+    public void debug(String msg) {
+      logOutput.log(msg, LogOutput.Level.DEBUG);
+    }
+  };
 }
diff --git a/sonar-runner-api/src/main/java/org/sonar/runner/api/Issue.java b/sonar-runner-api/src/main/java/org/sonar/runner/api/Issue.java
new file mode 100644 (file)
index 0000000..184a0b5
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * SonarQube Runner - API
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.runner.api;
+
+import javax.annotation.concurrent.Immutable;
+
+import java.util.Date;
+
+@Immutable
+public final class Issue {
+  private final String key;
+  private final String componentKey;
+  private final Integer line;
+  private final String message;
+  private final String rule;
+  private final String status;
+  private final String resolution;
+  private final boolean isNew;
+  private final String assignee;
+
+  private Issue(String key, String componentKey, Integer line, String message, String rule, String status, String resolution, boolean isNew, String assignee) {
+    super();
+    this.key = key;
+    this.componentKey = componentKey;
+    this.line = line;
+    this.message = message;
+    this.rule = rule;
+    this.status = status;
+    this.resolution = resolution;
+    this.isNew = isNew;
+    this.assignee = assignee;
+  }
+
+  public static class Builder {
+    private String key;
+    private String componentKey;
+    private Integer line;
+    private String message;
+    private String rule;
+    private String status;
+    private String resolution;
+    private boolean isNew;
+    private String assignee;
+
+    public String getKey() {
+      return key;
+    }
+
+    public Builder setKey(String key) {
+      this.key = key;
+      return this;
+    }
+
+    public String getComponentKey() {
+      return componentKey;
+    }
+
+    public Builder setComponentKey(String componentKey) {
+      this.componentKey = componentKey;
+      return this;
+    }
+
+    public Integer getLine() {
+      return line;
+    }
+
+    public Builder setLine(Integer line) {
+      this.line = line;
+      return this;
+    }
+
+    public String getMessage() {
+      return message;
+    }
+
+    public Builder setMessage(String message) {
+      this.message = message;
+      return this;
+    }
+
+    public String getRule() {
+      return rule;
+    }
+
+    public Builder setRule(String rule) {
+      this.rule = rule;
+      return this;
+    }
+
+    public String getStatus() {
+      return status;
+    }
+
+    public Builder setStatus(String status) {
+      this.status = status;
+      return this;
+    }
+
+    public String getResolution() {
+      return resolution;
+    }
+
+    public Builder setResolution(String resolution) {
+      this.resolution = resolution;
+      return this;
+    }
+
+    public boolean isNew() {
+      return isNew;
+    }
+
+    public Builder setNew(boolean isNew) {
+      this.isNew = isNew;
+      return this;
+    }
+
+    public String getAssignee() {
+      return assignee;
+    }
+
+    public Builder setAssignee(String assignee) {
+      this.assignee = assignee;
+      return this;
+    }
+
+    public Issue build() {
+      return new Issue(key, componentKey, line, message, rule, status, resolution, isNew, assignee);
+    }
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public String getKey() {
+    return key;
+  }
+
+  public String getComponentKey() {
+    return componentKey;
+  }
+
+  public Integer getLine() {
+    return line;
+  }
+
+  public String getMessage() {
+    return message;
+  }
+
+  public String getRule() {
+    return rule;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public String getResolution() {
+    return resolution;
+  }
+
+  public boolean isNew() {
+    return isNew;
+  }
+
+  public String getAssignee() {
+    return assignee;
+  }
+
+}
diff --git a/sonar-runner-api/src/main/java/org/sonar/runner/api/IssueListener.java b/sonar-runner-api/src/main/java/org/sonar/runner/api/IssueListener.java
new file mode 100644 (file)
index 0000000..a804a93
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube Runner - API
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.runner.api;
+
+public interface IssueListener {
+  void handle(Issue issue);
+}
index e838381301d00befa69cf02c8e7c06fcacc29b70..05df62c92d5484c22d195d74141184ea9128aa9c 100644 (file)
  */
 package org.sonar.runner.api;
 
+import org.sonar.runner.api.EmbeddedRunner.IssueListenerAdapter;
+
+import java.awt.geom.IllegalPathStateException;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.nio.charset.Charset;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Properties;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -32,7 +38,6 @@ import org.mockito.ArgumentMatcher;
 import org.sonar.home.cache.Logger;
 import org.sonar.runner.batch.IsolatedLauncher;
 import org.sonar.runner.impl.IsolatedLauncherFactory;
-
 import static org.fest.assertions.Assertions.assertThat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.argThat;
@@ -155,6 +160,40 @@ public class EmbeddedRunnerTest {
     }));
   }
 
+  @Test
+  public void test_issue_adapter() {
+    final List<Issue> issuesRecorded = new LinkedList<>();
+    IssueListener apiIssueListener = new IssueListener() {
+      @Override
+      public void handle(Issue issue) {
+        issuesRecorded.add(issue);
+      }
+    };
+    IssueListenerAdapter adapter = new IssueListenerAdapter(apiIssueListener);
+
+    org.sonar.runner.batch.IssueListener.Issue batchIssue = new org.sonar.runner.batch.IssueListener.Issue();
+    batchIssue.setAssignee("assignee");
+    adapter.handle(batchIssue);
+
+    assertThat(issuesRecorded).hasSize(1);
+    assertThat(issuesRecorded.get(0).getAssignee()).isEqualTo("assignee");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void reject_issue_listener_old_version() {
+    when(launcher.getVersion()).thenReturn("4.5");
+    launch_with_issue_listener();
+  }
+
+  @Test
+  public void launch_with_issue_listener() {
+    runner.start();
+    runner.runAnalysis(mock(Properties.class), mock(IssueListener.class));
+    runner.stop();
+
+    verify(launcher).execute(any(Properties.class), any(org.sonar.runner.batch.IssueListener.class));
+  }
+
   @Test
   public void should_launch_batch_analysisProperties() {
     runner.setGlobalProperty("sonar.projectKey", "foo");
index a186d72fa711facfb39513321e6995595ffa9c5d..957d840fa31d3cebb1709e33a9b1d9372e721f35 100644 (file)
  */
 package org.sonar.runner.impl;
 
+import org.sonar.runner.batch.IssueListener;
+
 import java.util.Properties;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.home.cache.Logger;
 import org.sonar.runner.batch.IsolatedLauncher;
 import org.sonar.runner.batch.LogOutput;
-
 import static org.fest.assertions.Fail.fail;
 import static org.mockito.Mockito.mock;
 
@@ -55,6 +57,7 @@ public class IsolatedLauncherFactoryTest {
 
   public static class FakeIsolatedLauncher implements IsolatedLauncher {
     public static Properties props = null;
+    public static IssueListener listener = null;
 
     @Override
     public void start(Properties properties, LogOutput logger) {
@@ -77,5 +80,11 @@ public class IsolatedLauncherFactoryTest {
     public String getVersion() {
       return null;
     }
+
+    @Override
+    public void execute(Properties properties, IssueListener listener) {
+      FakeIsolatedLauncher.props = properties;
+      FakeIsolatedLauncher.listener = listener;
+    }
   }
 }
index 6555e66d58ff5ba4756b66b6184601d7bdcaafba..cf19ca9f14ebe7b40a2cdfa651c161432459ae35 100644 (file)
@@ -9,11 +9,4 @@
   <artifactId>sonar-runner-batch-interface</artifactId>
   <name>SonarQube Runner - Batch Interface</name>
   
-  <dependencies>
-    <dependency>
-      <groupId>org.codehaus.sonar</groupId>
-      <artifactId>sonar-home</artifactId>
-      <scope>provided</scope>
-    </dependency>
-  </dependencies>
 </project>
index 834c11b94c3d0732dc199534052f5f7b92045487..cb09445ad294a68c2870c7a9cf225e9817ac04ec 100644 (file)
@@ -28,8 +28,11 @@ public interface IsolatedLauncher {
   void stop();
 
   void execute(Properties properties);
-
+  
+  void execute(Properties properties, IssueListener listener);
+  
   void executeOldVersion(Properties properties);
 
   String getVersion();
+
 }
diff --git a/sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IssueListener.java b/sonar-runner-batch-interface/src/main/java/org/sonar/runner/batch/IssueListener.java
new file mode 100644 (file)
index 0000000..72a94e4
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * SonarQube Runner - Batch Interface
+ * Copyright (C) 2011 SonarSource
+ * sonarqube@googlegroups.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.runner.batch;
+
+import java.util.Date;
+
+public interface IssueListener {
+  void handle(Issue issue);
+
+  class Issue {
+    private String key;
+    private String componentKey;
+    private Integer line;
+    private String message;
+    private String rule;
+    private String status;
+    private String resolution;
+    private boolean isNew;
+    private String assignee;
+
+    public void setKey(String key) {
+      this.key = key;
+    }
+
+    public void setComponentKey(String componentKey) {
+      this.componentKey = componentKey;
+    }
+
+    public void setLine(Integer line) {
+      this.line = line;
+    }
+
+    public void setMessage(String message) {
+      this.message = message;
+    }
+
+    public void setRule(String rule) {
+      this.rule = rule;
+    }
+
+    public void setStatus(String status) {
+      this.status = status;
+    }
+
+    public void setResolution(String resolution) {
+      this.resolution = resolution;
+    }
+
+    public void setNew(boolean isNew) {
+      this.isNew = isNew;
+    }
+
+    public void setAssignee(String assignee) {
+      this.assignee = assignee;
+    }
+
+    public String getKey() {
+      return key;
+    }
+
+    public String getComponentKey() {
+      return componentKey;
+    }
+
+    public Integer getLine() {
+      return line;
+    }
+
+    public String getMessage() {
+      return message;
+    }
+
+    public String getRule() {
+      return rule;
+    }
+
+    public String getStatus() {
+      return status;
+    }
+
+    public String getResolution() {
+      return resolution;
+    }
+
+    public boolean isNew() {
+      return isNew;
+    }
+
+    public String getAssignee() {
+      return assignee;
+    }
+
+  }
+}
index 6b6a7103c2be2a7f44d5371173b465138c4dbfad..098e929ab6aa97a7edc6eb19ffd962dd204fb8a7 100644 (file)
@@ -54,6 +54,12 @@ public class BatchIsolatedLauncher implements IsolatedLauncher {
     batch.executeTask((Map) properties);
   }
 
+  @Override
+  public void execute(Properties properties, IssueListener listener) {
+    org.sonar.batch.bootstrapper.IssueListener batchIssueListener = Compatibility.getBatchIssueListener(listener);
+    batch.executeTask((Map) properties, batchIssueListener);
+  }
+
   Batch createBatch(Properties properties, @Nullable final org.sonar.runner.batch.LogOutput logOutput) {
     EnvironmentInformation env = new EnvironmentInformation(properties.getProperty("sonarRunner.app"), properties.getProperty("sonarRunner.appVersion"));
     Batch.Builder builder = Batch.builder()
index a2d16d0490a027bb5f35bbb983bd139f45723987..99eb70c9ae709b076009c23d62fd7a353eb3b2ac 100644 (file)
  */
 package org.sonar.runner.batch;
 
+import org.sonar.api.issue.Issue;
 import org.sonar.batch.bootstrapper.Batch;
 import org.sonar.batch.bootstrapper.LogOutput;
 
 public class Compatibility {
-
   private Compatibility() {
     // Utility class
   }
@@ -39,4 +39,34 @@ public class Compatibility {
     });
   }
 
+  static org.sonar.batch.bootstrapper.IssueListener getBatchIssueListener(IssueListener listener) {
+    return new IssueListenerAdapter(listener);
+  }
+
+  static class IssueListenerAdapter implements org.sonar.batch.bootstrapper.IssueListener {
+    private IssueListener listener;
+
+    public IssueListenerAdapter(IssueListener listener) {
+      this.listener = listener;
+    }
+
+    @Override
+    public void handle(Issue issue) {
+      listener.handle(transformIssue(issue));
+    }
+
+    private static IssueListener.Issue transformIssue(Issue batchIssue) {
+      IssueListener.Issue newIssue = new IssueListener.Issue();
+      newIssue.setAssignee(batchIssue.assignee());
+      newIssue.setComponentKey(batchIssue.componentKey());
+      newIssue.setKey(batchIssue.key());
+      newIssue.setResolution(batchIssue.resolution());
+      newIssue.setRule(batchIssue.ruleKey().toString());
+      newIssue.setMessage(batchIssue.message());
+      newIssue.setNew(batchIssue.isNew());
+      newIssue.setLine(batchIssue.line());
+      
+      return newIssue;
+    }
+  }
 }