]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4689 Batch API to get issues of the current project
authorJulien HENRY <julien.henry@sonarsource.com>
Mon, 23 Sep 2013 15:26:16 +0000 (17:26 +0200)
committerJulien HENRY <julien.henry@sonarsource.com>
Mon, 23 Sep 2013 15:27:59 +0000 (17:27 +0200)
16 files changed:
sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java
sonar-batch/src/main/java/org/sonar/batch/issue/DefaultModuleIssues.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/issue/DefaultProjectIssues.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java
sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssuableTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/DefaultModuleIssuesTest.java [deleted file]
sonar-batch/src/test/java/org/sonar/batch/issue/DefaultProjectIssuesTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/issue/ModuleIssues.java [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/issue/ProjectIssues.java [new file with mode: 0644]

index ca8cf60059c82d02960c0b2ec70fa33974f48eae..4d4a47d6df299107030f9866356bd6a7bd8b5885 100644 (file)
@@ -49,7 +49,7 @@ import org.sonar.batch.DefaultResourceCreationLock;
 import org.sonar.batch.ProjectTree;
 import org.sonar.batch.ResourceFilters;
 import org.sonar.batch.issue.DeprecatedViolations;
-import org.sonar.batch.issue.DefaultModuleIssues;
+import org.sonar.batch.issue.ModuleIssues;
 import org.sonar.core.component.ComponentKeys;
 import org.sonar.core.component.ScanGraph;
 
@@ -82,7 +82,7 @@ public class DefaultIndex extends SonarIndex {
   private Map<Resource, Map<Resource, Dependency>> incomingDependenciesByResource = Maps.newHashMap();
   private ProjectTree projectTree;
   private final DeprecatedViolations deprecatedViolations;
-  private DefaultModuleIssues moduleIssues;
+  private ModuleIssues moduleIssues;
 
   public DefaultIndex(PersistenceManager persistence, DefaultResourceCreationLock lock, ProjectTree projectTree, MetricFinder metricFinder,
                       ScanGraph graph, DeprecatedViolations deprecatedViolations) {
@@ -124,7 +124,7 @@ public class DefaultIndex extends SonarIndex {
     return currentProject;
   }
 
-  public void setCurrentProject(Project project, ResourceFilters resourceFilters, DefaultModuleIssues moduleIssues) {
+  public void setCurrentProject(Project project, ResourceFilters resourceFilters, ModuleIssues moduleIssues) {
     this.currentProject = project;
 
     // the following components depend on the current module, so they need to be reloaded.
index 5b7c4c8092cdfd6363e7457a05e41838aca6ffe3..98665d60bbd7c0c4ea0bcdd9be10eaab46c6f999 100644 (file)
@@ -33,11 +33,11 @@ import java.util.List;
  */
 public class DefaultIssuable implements Issuable {
 
-  private final DefaultModuleIssues moduleIssues;
+  private final ModuleIssues moduleIssues;
   private final IssueCache cache;
   private final Component component;
 
-  DefaultIssuable(Component component, DefaultModuleIssues moduleIssues, IssueCache cache) {
+  DefaultIssuable(Component component, ModuleIssues moduleIssues, IssueCache cache) {
     this.component = component;
     this.moduleIssues = moduleIssues;
     this.cache = cache;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultModuleIssues.java b/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultModuleIssues.java
deleted file mode 100644 (file)
index 1bc61bd..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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  02110-1301, USA.
- */
-package org.sonar.batch.issue;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.ModuleIssues;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.Project;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.ActiveRule;
-import org.sonar.api.rules.Violation;
-import org.sonar.core.issue.DefaultIssueBuilder;
-
-import javax.annotation.Nullable;
-
-/**
- * Initialize the issues raised during scan.
- */
-public class DefaultModuleIssues implements ModuleIssues {
-
-  private final RulesProfile qProfile;
-  private final IssueCache cache;
-  private final Project project;
-  private final IssueFilters filters;
-
-  public DefaultModuleIssues(RulesProfile qProfile, IssueCache cache, Project project, IssueFilters filters) {
-    this.qProfile = qProfile;
-    this.cache = cache;
-    this.project = project;
-    this.filters = filters;
-  }
-
-  public boolean initAndAddIssue(DefaultIssue issue) {
-    return initAndAddIssue(issue, null);
-  }
-
-  public boolean initAndAddViolation(Violation violation) {
-    DefaultIssue issue = newIssue(violation);
-    return initAndAddIssue(issue, violation);
-  }
-
-  private DefaultIssue newIssue(Violation violation) {
-    return (DefaultIssue) new DefaultIssueBuilder()
-      .componentKey(violation.getResource().getEffectiveKey())
-      .ruleKey(RuleKey.of(violation.getRule().getRepositoryKey(), violation.getRule().getKey()))
-      .effortToFix(violation.getCost())
-      .line(violation.getLineId())
-      .message(violation.getMessage())
-      .severity(violation.getSeverity() != null ? violation.getSeverity().name() : null)
-      .build();
-  }
-
-  private boolean initAndAddIssue(DefaultIssue issue, @Nullable Violation violation) {
-    // TODO fail fast : if rule does not exist
-
-    ActiveRule activeRule = qProfile.getActiveRule(issue.ruleKey().repository(), issue.ruleKey().rule());
-    if (activeRule == null || activeRule.getRule() == null) {
-      // rule does not exist or is not enabled -> ignore the issue
-      return false;
-    }
-    issue.setCreationDate(project.getAnalysisDate());
-    issue.setUpdateDate(project.getAnalysisDate());
-    if (issue.severity() == null) {
-      issue.setSeverity(activeRule.getSeverity().name());
-    }
-
-    if (filters.accept(issue, violation)) {
-      cache.put(issue);
-      return true;
-    }
-    return false;
-  }
-
-  @Override
-  public Iterable<Issue> issues() {
-    return (Iterable) Iterables.filter(cache.all(), new ModulePredicate(project, false));
-  }
-
-  @Override
-  public Iterable<Issue> resolvedIssues() {
-    return (Iterable) Iterables.filter(cache.all(), new ModulePredicate(project, true));
-  }
-
-  private static class ModulePredicate implements Predicate<DefaultIssue> {
-    private final boolean resolved;
-    private final String key;
-    private final String keyPrefix;
-
-    private ModulePredicate(Project project, boolean resolved) {
-      this.resolved = resolved;
-      this.key = project.getEffectiveKey();
-      this.keyPrefix = project.getEffectiveKey() + ":";
-    }
-
-    @Override
-    public boolean apply(@Nullable DefaultIssue issue) {
-      if (issue != null && (issue.componentKey().equals(key) || issue.componentKey().startsWith(keyPrefix))) {
-        return resolved ? issue.resolution() != null : issue.resolution()==null;
-      }
-      return false;
-    }
-  }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultProjectIssues.java b/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultProjectIssues.java
new file mode 100644 (file)
index 0000000..3e3154f
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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  02110-1301, USA.
+ */
+package org.sonar.batch.issue;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.ProjectIssues;
+import org.sonar.api.issue.internal.DefaultIssue;
+
+import javax.annotation.Nullable;
+
+/**
+ * Expose list of issues for the current project
+ * @since 4.0
+ */
+public class DefaultProjectIssues implements ProjectIssues {
+
+  private final IssueCache cache;
+
+  public DefaultProjectIssues(IssueCache cache) {
+    this.cache = cache;
+  }
+
+  @Override
+  public Iterable<Issue> issues() {
+    return (Iterable) Iterables.filter(cache.all(), new ResolvedPredicate(false));
+  }
+
+  @Override
+  public Iterable<Issue> resolvedIssues() {
+    return (Iterable) Iterables.filter(cache.all(), new ResolvedPredicate(true));
+  }
+
+  private static class ResolvedPredicate implements Predicate<DefaultIssue> {
+    private final boolean resolved;
+
+    private ResolvedPredicate(boolean resolved) {
+      this.resolved = resolved;
+    }
+
+    @Override
+    public boolean apply(@Nullable DefaultIssue issue) {
+      if (issue != null) {
+        return resolved ? issue.resolution() != null : issue.resolution() == null;
+      }
+      return false;
+    }
+  }
+}
index cd34582c24c0b6c25bf0deb224bd8e25b0dc69f8..b1c791f4069aa83853481104714d72ac23638469 100644 (file)
@@ -33,10 +33,10 @@ import javax.annotation.CheckForNull;
  */
 public class IssuableFactory extends PerspectiveBuilder<Issuable> {
 
-  private final DefaultModuleIssues moduleIssues;
+  private final ModuleIssues moduleIssues;
   private final IssueCache cache;
 
-  public IssuableFactory(DefaultModuleIssues moduleIssues, IssueCache cache) {
+  public IssuableFactory(ModuleIssues moduleIssues, IssueCache cache) {
     super(Issuable.class);
     this.moduleIssues = moduleIssues;
     this.cache = cache;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java b/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
new file mode 100644 (file)
index 0000000..7bef926
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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  02110-1301, USA.
+ */
+package org.sonar.batch.issue;
+
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.resources.Project;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.ActiveRule;
+import org.sonar.api.rules.Violation;
+import org.sonar.core.issue.DefaultIssueBuilder;
+
+import javax.annotation.Nullable;
+
+/**
+ * Initialize the issues raised during scan.
+ */
+public class ModuleIssues {
+
+  private final RulesProfile qProfile;
+  private final IssueCache cache;
+  private final Project project;
+  private final IssueFilters filters;
+
+  public ModuleIssues(RulesProfile qProfile, IssueCache cache, Project project, IssueFilters filters) {
+    this.qProfile = qProfile;
+    this.cache = cache;
+    this.project = project;
+    this.filters = filters;
+  }
+
+  public boolean initAndAddIssue(DefaultIssue issue) {
+    return initAndAddIssue(issue, null);
+  }
+
+  public boolean initAndAddViolation(Violation violation) {
+    DefaultIssue issue = newIssue(violation);
+    return initAndAddIssue(issue, violation);
+  }
+
+  private DefaultIssue newIssue(Violation violation) {
+    return (DefaultIssue) new DefaultIssueBuilder()
+      .componentKey(violation.getResource().getEffectiveKey())
+      .ruleKey(RuleKey.of(violation.getRule().getRepositoryKey(), violation.getRule().getKey()))
+      .effortToFix(violation.getCost())
+      .line(violation.getLineId())
+      .message(violation.getMessage())
+      .severity(violation.getSeverity() != null ? violation.getSeverity().name() : null)
+      .build();
+  }
+
+  private boolean initAndAddIssue(DefaultIssue issue, @Nullable Violation violation) {
+    // TODO fail fast : if rule does not exist
+
+    ActiveRule activeRule = qProfile.getActiveRule(issue.ruleKey().repository(), issue.ruleKey().rule());
+    if (activeRule == null || activeRule.getRule() == null) {
+      // rule does not exist or is not enabled -> ignore the issue
+      return false;
+    }
+    issue.setCreationDate(project.getAnalysisDate());
+    issue.setUpdateDate(project.getAnalysisDate());
+    if (issue.severity() == null) {
+      issue.setSeverity(activeRule.getSeverity().name());
+    }
+
+    if (filters.accept(issue, violation)) {
+      cache.put(issue);
+      return true;
+    }
+    return false;
+  }
+}
index 543f01e294015e6d0690f55adbc04b4a011548b1..b97118be253acae5ac068a8430262df5b4f5fd52 100644 (file)
@@ -19,8 +19,6 @@
  */
 package org.sonar.batch.scan;
 
-import org.sonar.core.measure.MeasurementFilters;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.BatchExtension;
@@ -31,7 +29,13 @@ import org.sonar.api.resources.Languages;
 import org.sonar.api.resources.Project;
 import org.sonar.api.scan.filesystem.FileExclusions;
 import org.sonar.api.scan.filesystem.PathResolver;
-import org.sonar.batch.*;
+import org.sonar.batch.DefaultProjectClasspath;
+import org.sonar.batch.DefaultSensorContext;
+import org.sonar.batch.DefaultTimeMachine;
+import org.sonar.batch.ProfileProvider;
+import org.sonar.batch.ProjectTree;
+import org.sonar.batch.ResourceFilters;
+import org.sonar.batch.ViolationFilters;
 import org.sonar.batch.bootstrap.BatchExtensionDictionnary;
 import org.sonar.batch.bootstrap.ExtensionInstaller;
 import org.sonar.batch.bootstrap.ExtensionMatcher;
@@ -42,11 +46,16 @@ import org.sonar.batch.index.DefaultIndex;
 import org.sonar.batch.index.ResourcePersister;
 import org.sonar.batch.issue.IssuableFactory;
 import org.sonar.batch.issue.IssueFilters;
-import org.sonar.batch.issue.DefaultModuleIssues;
+import org.sonar.batch.issue.ModuleIssues;
 import org.sonar.batch.phases.PhaseExecutor;
 import org.sonar.batch.phases.PhasesTimeProfiler;
-import org.sonar.batch.scan.filesystem.*;
+import org.sonar.batch.scan.filesystem.DeprecatedFileSystemAdapter;
+import org.sonar.batch.scan.filesystem.ExclusionFilters;
+import org.sonar.batch.scan.filesystem.FileSystemLogger;
+import org.sonar.batch.scan.filesystem.LanguageFilters;
+import org.sonar.batch.scan.filesystem.ModuleFileSystemProvider;
 import org.sonar.core.component.ScanPerspectives;
+import org.sonar.core.measure.MeasurementFilters;
 
 public class ModuleScanContainer extends ComponentContainer {
   private static final Logger LOG = LoggerFactory.getLogger(ModuleScanContainer.class);
@@ -113,11 +122,10 @@ public class ModuleScanContainer extends ComponentContainer {
       new ProfileProvider(),
 
       // issues
-      DefaultModuleIssues.class,
       IssuableFactory.class,
+      ModuleIssues.class,
 
-      ScanPerspectives.class
-    );
+      ScanPerspectives.class);
   }
 
   private void addExtensions() {
@@ -140,7 +148,7 @@ public class ModuleScanContainer extends ComponentContainer {
     DefaultIndex index = getComponentByType(DefaultIndex.class);
     index.setCurrentProject(module,
       getComponentByType(ResourceFilters.class),
-      getComponentByType(DefaultModuleIssues.class));
+      getComponentByType(ModuleIssues.class));
 
     getComponentByType(PhaseExecutor.class).execute(module);
   }
index 9bc0c43c94047cf9d7290e42caa22ece85e11c14..7992aab42ea32f670b522bbb034e84843dc14f3d 100644 (file)
@@ -52,6 +52,7 @@ import org.sonar.batch.index.MemoryOptimizer;
 import org.sonar.batch.index.ResourceCache;
 import org.sonar.batch.index.SnapshotCache;
 import org.sonar.batch.index.SourcePersister;
+import org.sonar.batch.issue.DefaultProjectIssues;
 import org.sonar.batch.issue.DeprecatedViolations;
 import org.sonar.batch.issue.IssueCache;
 import org.sonar.batch.issue.IssuePersister;
@@ -143,6 +144,7 @@ public class ProjectScanContainer extends ComponentContainer {
       ScanIssueStorage.class,
       IssuePersister.class,
       IssueNotifications.class,
+      DefaultProjectIssues.class,
 
       // tests
       TestPlanPerspectiveLoader.class,
index 2431cefbbb5038f35e7e9a0082a81b9df7c4f4ad..cd039e17d9abd776af66891033a4e7ad55900e99 100644 (file)
@@ -39,7 +39,7 @@ import org.sonar.batch.DefaultResourceCreationLock;
 import org.sonar.batch.ProjectTree;
 import org.sonar.batch.ResourceFilters;
 import org.sonar.batch.issue.DeprecatedViolations;
-import org.sonar.batch.issue.DefaultModuleIssues;
+import org.sonar.batch.issue.ModuleIssues;
 import org.sonar.core.component.ScanGraph;
 
 import static com.google.common.collect.Lists.newArrayList;
@@ -77,7 +77,7 @@ public class DefaultIndexTest {
     rule = Rule.create("repoKey", "ruleKey", "Rule");
     rule.setId(1);
     rulesProfile.activateRule(rule, null);
-    index.setCurrentProject(project, new ResourceFilters(new ResourceFilter[]{filter}), mock(DefaultModuleIssues.class));
+    index.setCurrentProject(project, new ResourceFilters(new ResourceFilter[]{filter}), mock(ModuleIssues.class));
     index.doStart(project);
   }
 
index f66cc03aa162b37bba52b6a5fb70b55b178bc9d9..24a12f98c0fb58b5342562922cff45dd35757e61 100644 (file)
@@ -33,7 +33,7 @@ import static org.mockito.Mockito.when;
 
 public class DefaultIssuableTest {
 
-  DefaultModuleIssues moduleIssues = mock(DefaultModuleIssues.class);
+  ModuleIssues moduleIssues = mock(ModuleIssues.class);
   IssueCache cache = mock(IssueCache.class);
   Component component = mock(Component.class);
 
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultModuleIssuesTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultModuleIssuesTest.java
deleted file mode 100644 (file)
index 27f14f4..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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  02110-1301, USA.
- */
-package org.sonar.batch.issue;
-
-import com.google.common.collect.Lists;
-import org.apache.commons.lang.time.DateUtils;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.JavaFile;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.rules.ActiveRule;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RulePriority;
-import org.sonar.api.rules.Violation;
-
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.List;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.*;
-
-public class DefaultModuleIssuesTest {
-
-  static final RuleKey SQUID_RULE_KEY = RuleKey.of("squid", "AvoidCycle");
-
-  IssueCache cache = mock(IssueCache.class);
-  RulesProfile qProfile = mock(RulesProfile.class);
-  Project project = mock(Project.class);
-  IssueFilters filters = mock(IssueFilters.class);
-  DefaultModuleIssues moduleIssues = new DefaultModuleIssues(qProfile, cache, project, filters);
-
-  @Before
-  public void setUp() {
-    when(project.getAnalysisDate()).thenReturn(new Date());
-    when(project.getEffectiveKey()).thenReturn("org.apache:struts-core");
-  }
-
-  @Test
-  public void should_ignore_null_active_rule() throws Exception {
-    when(qProfile.getActiveRule(anyString(), anyString())).thenReturn(null);
-
-    DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY);
-    boolean added = moduleIssues.initAndAddIssue(issue);
-
-    assertThat(added).isFalse();
-    verifyZeroInteractions(cache);
-  }
-
-  @Test
-  public void should_ignore_null_rule_of_active_rule() throws Exception {
-    ActiveRule activeRule = mock(ActiveRule.class);
-    when(activeRule.getRule()).thenReturn(null);
-    when(qProfile.getActiveRule(anyString(), anyString())).thenReturn(activeRule);
-
-    DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY);
-    boolean added = moduleIssues.initAndAddIssue(issue);
-
-    assertThat(added).isFalse();
-    verifyZeroInteractions(cache);
-  }
-
-  @Test
-  public void should_add_issue_to_cache() throws Exception {
-    Rule rule = Rule.create("squid", "AvoidCycle");
-    ActiveRule activeRule = mock(ActiveRule.class);
-    when(activeRule.getRule()).thenReturn(rule);
-    when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
-    when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
-
-    Date analysisDate = new Date();
-    when(project.getAnalysisDate()).thenReturn(analysisDate);
-
-    DefaultIssue issue = new DefaultIssue()
-      .setKey("ABCDE")
-      .setRuleKey(SQUID_RULE_KEY)
-      .setSeverity(Severity.CRITICAL);
-    when(filters.accept(issue, null)).thenReturn(true);
-
-    boolean added = moduleIssues.initAndAddIssue(issue);
-
-    assertThat(added).isTrue();
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(cache).put(argument.capture());
-    assertThat(argument.getValue().severity()).isEqualTo(Severity.CRITICAL);
-    assertThat(argument.getValue().creationDate()).isEqualTo(DateUtils.truncate(analysisDate, Calendar.SECOND));
-  }
-
-  @Test
-  public void should_use_severity_from_active_rule_if_no_severity() throws Exception {
-    Rule rule = Rule.create("squid", "AvoidCycle");
-    ActiveRule activeRule = mock(ActiveRule.class);
-    when(activeRule.getRule()).thenReturn(rule);
-    when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
-    when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
-
-    Date analysisDate = new Date();
-    when(project.getAnalysisDate()).thenReturn(analysisDate);
-
-    DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY).setSeverity(null);
-    when(filters.accept(issue, null)).thenReturn(true);
-    moduleIssues.initAndAddIssue(issue);
-
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(cache).put(argument.capture());
-    assertThat(argument.getValue().severity()).isEqualTo(Severity.INFO);
-    assertThat(argument.getValue().creationDate()).isEqualTo(DateUtils.truncate(analysisDate, Calendar.SECOND));
-  }
-
-  @Test
-  public void should_add_deprecated_violation() throws Exception {
-    Rule rule = Rule.create("squid", "AvoidCycle");
-    Resource resource = new JavaFile("org.struts.Action").setEffectiveKey("struts:org.struts.Action");
-    Violation violation = new Violation(rule, resource);
-    violation.setLineId(42);
-    violation.setSeverity(RulePriority.CRITICAL);
-    violation.setMessage("the message");
-
-    ActiveRule activeRule = mock(ActiveRule.class);
-    when(activeRule.getRule()).thenReturn(rule);
-    when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
-    when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
-    when(filters.accept(any(DefaultIssue.class), eq(violation))).thenReturn(true);
-
-    boolean added = moduleIssues.initAndAddViolation(violation);
-    assertThat(added).isTrue();
-
-    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
-    verify(cache).put(argument.capture());
-    DefaultIssue issue = argument.getValue();
-    assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
-    assertThat(issue.line()).isEqualTo(42);
-    assertThat(issue.message()).isEqualTo("the message");
-    assertThat(issue.key()).isNotEmpty();
-    assertThat(issue.ruleKey().toString()).isEqualTo("squid:AvoidCycle");
-    assertThat(issue.componentKey().toString()).isEqualTo("struts:org.struts.Action");
-  }
-
-  @Test
-  public void should_filter_issue() throws Exception {
-    Rule rule = Rule.create("squid", "AvoidCycle");
-    ActiveRule activeRule = mock(ActiveRule.class);
-    when(activeRule.getRule()).thenReturn(rule);
-    when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
-    when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
-
-    DefaultIssue issue = new DefaultIssue()
-      .setKey("ABCDE")
-      .setRuleKey(SQUID_RULE_KEY)
-      .setSeverity(Severity.CRITICAL);
-
-    when(filters.accept(issue, null)).thenReturn(false);
-
-    boolean added = moduleIssues.initAndAddIssue(issue);
-
-    assertThat(added).isFalse();
-    verifyZeroInteractions(cache);
-  }
-
-  @Test
-  public void should_get_module_issues() throws Exception {
-    DefaultIssue issueOnModule = new DefaultIssue().setKey("1").setRuleKey(SQUID_RULE_KEY).setComponentKey("org.apache:struts-core");
-    DefaultIssue issueInModule = new DefaultIssue().setKey("2").setRuleKey(SQUID_RULE_KEY).setComponentKey("org.apache:struts-core:Action");
-    DefaultIssue resolvedIssueInModule = new DefaultIssue().setKey("3").setRuleKey(SQUID_RULE_KEY).setComponentKey("org.apache:struts-core:Action").setResolution(Issue.RESOLUTION_FIXED);
-
-    when(cache.all()).thenReturn(Arrays.<DefaultIssue>asList(
-      // issue on root module
-      new DefaultIssue().setKey("4").setRuleKey(SQUID_RULE_KEY).setSeverity(Severity.CRITICAL).setComponentKey("org.apache:struts"),
-
-      // issue in root module
-      new DefaultIssue().setKey("5").setRuleKey(SQUID_RULE_KEY).setSeverity(Severity.CRITICAL).setComponentKey("org.apache:struts:FileInRoot"),
-
-      issueOnModule, issueInModule, resolvedIssueInModule
-    ));
-
-    // unresolved issues
-    List<Issue> issues = Lists.newArrayList(moduleIssues.issues());
-    assertThat(issues).containsOnly(issueInModule, issueOnModule);
-
-    List<Issue> resolvedIssues = Lists.newArrayList(moduleIssues.resolvedIssues());
-    assertThat(resolvedIssues).containsOnly(resolvedIssueInModule);
-  }
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultProjectIssuesTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultProjectIssuesTest.java
new file mode 100644 (file)
index 0000000..17a4c4e
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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  02110-1301, USA.
+ */
+package org.sonar.batch.issue;
+
+import com.google.common.collect.Lists;
+import org.junit.Test;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DefaultProjectIssuesTest {
+
+  static final RuleKey SQUID_RULE_KEY = RuleKey.of("squid", "AvoidCycle");
+
+  IssueCache cache = mock(IssueCache.class);
+  DefaultProjectIssues projectIssues = new DefaultProjectIssues(cache);
+
+  @Test
+  public void should_get_all_issues() throws Exception {
+    DefaultIssue issueOnModule = new DefaultIssue().setKey("1").setRuleKey(SQUID_RULE_KEY).setComponentKey("org.apache:struts-core");
+    DefaultIssue issueInModule = new DefaultIssue().setKey("2").setRuleKey(SQUID_RULE_KEY).setComponentKey("org.apache:struts-core:Action");
+    DefaultIssue resolvedIssueInModule = new DefaultIssue().setKey("3").setRuleKey(SQUID_RULE_KEY).setComponentKey("org.apache:struts-core:Action")
+      .setResolution(Issue.RESOLUTION_FIXED);
+
+    DefaultIssue issueOnRoot = new DefaultIssue().setKey("4").setRuleKey(SQUID_RULE_KEY).setSeverity(Severity.CRITICAL).setComponentKey("org.apache:struts");
+    DefaultIssue issueInRoot = new DefaultIssue().setKey("5").setRuleKey(SQUID_RULE_KEY).setSeverity(Severity.CRITICAL).setComponentKey("org.apache:struts:FileInRoot");
+    when(cache.all()).thenReturn(Arrays.<DefaultIssue> asList(
+      issueOnRoot, issueInRoot,
+      issueOnModule, issueInModule, resolvedIssueInModule
+      ));
+
+    // unresolved issues
+    List<Issue> issues = Lists.newArrayList(projectIssues.issues());
+    assertThat(issues).containsOnly(issueOnRoot, issueInRoot, issueInModule, issueOnModule);
+
+    List<Issue> resolvedIssues = Lists.newArrayList(projectIssues.resolvedIssues());
+    assertThat(resolvedIssues).containsOnly(resolvedIssueInModule);
+  }
+}
index 65e4b5d706cb064a82ae8ac4a6946122b3566c21..1fc8e129ee366301e888eb93be9446964746ee61 100644 (file)
@@ -34,7 +34,7 @@ import static org.mockito.Mockito.mock;
 
 public class IssuableFactoryTest {
 
-  DefaultModuleIssues moduleIssues = mock(DefaultModuleIssues.class);
+  ModuleIssues moduleIssues = mock(ModuleIssues.class);
   IssueCache cache = mock(IssueCache.class, Mockito.RETURNS_MOCKS);
 
   @Test
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
new file mode 100644 (file)
index 0000000..2fc2f8d
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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  02110-1301, USA.
+ */
+package org.sonar.batch.issue;
+
+import org.apache.commons.lang.time.DateUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.resources.JavaFile;
+import org.sonar.api.resources.Project;
+import org.sonar.api.resources.Resource;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.ActiveRule;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RulePriority;
+import org.sonar.api.rules.Violation;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class ModuleIssuesTest {
+
+  static final RuleKey SQUID_RULE_KEY = RuleKey.of("squid", "AvoidCycle");
+
+  IssueCache cache = mock(IssueCache.class);
+  RulesProfile qProfile = mock(RulesProfile.class);
+  Project project = mock(Project.class);
+  IssueFilters filters = mock(IssueFilters.class);
+  ModuleIssues moduleIssues = new ModuleIssues(qProfile, cache, project, filters);
+
+  @Before
+  public void setUp() {
+    when(project.getAnalysisDate()).thenReturn(new Date());
+    when(project.getEffectiveKey()).thenReturn("org.apache:struts-core");
+  }
+
+  @Test
+  public void should_ignore_null_active_rule() throws Exception {
+    when(qProfile.getActiveRule(anyString(), anyString())).thenReturn(null);
+
+    DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY);
+    boolean added = moduleIssues.initAndAddIssue(issue);
+
+    assertThat(added).isFalse();
+    verifyZeroInteractions(cache);
+  }
+
+  @Test
+  public void should_ignore_null_rule_of_active_rule() throws Exception {
+    ActiveRule activeRule = mock(ActiveRule.class);
+    when(activeRule.getRule()).thenReturn(null);
+    when(qProfile.getActiveRule(anyString(), anyString())).thenReturn(activeRule);
+
+    DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY);
+    boolean added = moduleIssues.initAndAddIssue(issue);
+
+    assertThat(added).isFalse();
+    verifyZeroInteractions(cache);
+  }
+
+  @Test
+  public void should_add_issue_to_cache() throws Exception {
+    Rule rule = Rule.create("squid", "AvoidCycle");
+    ActiveRule activeRule = mock(ActiveRule.class);
+    when(activeRule.getRule()).thenReturn(rule);
+    when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
+    when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
+
+    Date analysisDate = new Date();
+    when(project.getAnalysisDate()).thenReturn(analysisDate);
+
+    DefaultIssue issue = new DefaultIssue()
+      .setKey("ABCDE")
+      .setRuleKey(SQUID_RULE_KEY)
+      .setSeverity(Severity.CRITICAL);
+    when(filters.accept(issue, null)).thenReturn(true);
+
+    boolean added = moduleIssues.initAndAddIssue(issue);
+
+    assertThat(added).isTrue();
+    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
+    verify(cache).put(argument.capture());
+    assertThat(argument.getValue().severity()).isEqualTo(Severity.CRITICAL);
+    assertThat(argument.getValue().creationDate()).isEqualTo(DateUtils.truncate(analysisDate, Calendar.SECOND));
+  }
+
+  @Test
+  public void should_use_severity_from_active_rule_if_no_severity() throws Exception {
+    Rule rule = Rule.create("squid", "AvoidCycle");
+    ActiveRule activeRule = mock(ActiveRule.class);
+    when(activeRule.getRule()).thenReturn(rule);
+    when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
+    when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
+
+    Date analysisDate = new Date();
+    when(project.getAnalysisDate()).thenReturn(analysisDate);
+
+    DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY).setSeverity(null);
+    when(filters.accept(issue, null)).thenReturn(true);
+    moduleIssues.initAndAddIssue(issue);
+
+    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
+    verify(cache).put(argument.capture());
+    assertThat(argument.getValue().severity()).isEqualTo(Severity.INFO);
+    assertThat(argument.getValue().creationDate()).isEqualTo(DateUtils.truncate(analysisDate, Calendar.SECOND));
+  }
+
+  @Test
+  public void should_add_deprecated_violation() throws Exception {
+    Rule rule = Rule.create("squid", "AvoidCycle");
+    Resource resource = new JavaFile("org.struts.Action").setEffectiveKey("struts:org.struts.Action");
+    Violation violation = new Violation(rule, resource);
+    violation.setLineId(42);
+    violation.setSeverity(RulePriority.CRITICAL);
+    violation.setMessage("the message");
+
+    ActiveRule activeRule = mock(ActiveRule.class);
+    when(activeRule.getRule()).thenReturn(rule);
+    when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
+    when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
+    when(filters.accept(any(DefaultIssue.class), eq(violation))).thenReturn(true);
+
+    boolean added = moduleIssues.initAndAddViolation(violation);
+    assertThat(added).isTrue();
+
+    ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
+    verify(cache).put(argument.capture());
+    DefaultIssue issue = argument.getValue();
+    assertThat(issue.severity()).isEqualTo(Severity.CRITICAL);
+    assertThat(issue.line()).isEqualTo(42);
+    assertThat(issue.message()).isEqualTo("the message");
+    assertThat(issue.key()).isNotEmpty();
+    assertThat(issue.ruleKey().toString()).isEqualTo("squid:AvoidCycle");
+    assertThat(issue.componentKey().toString()).isEqualTo("struts:org.struts.Action");
+  }
+
+  @Test
+  public void should_filter_issue() throws Exception {
+    Rule rule = Rule.create("squid", "AvoidCycle");
+    ActiveRule activeRule = mock(ActiveRule.class);
+    when(activeRule.getRule()).thenReturn(rule);
+    when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
+    when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
+
+    DefaultIssue issue = new DefaultIssue()
+      .setKey("ABCDE")
+      .setRuleKey(SQUID_RULE_KEY)
+      .setSeverity(Severity.CRITICAL);
+
+    when(filters.accept(issue, null)).thenReturn(false);
+
+    boolean added = moduleIssues.initAndAddIssue(issue);
+
+    assertThat(added).isFalse();
+    verifyZeroInteractions(cache);
+  }
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/ModuleIssues.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/ModuleIssues.java
deleted file mode 100644 (file)
index 2f1a974..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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  02110-1301, USA.
- */
-package org.sonar.api.issue;
-
-import org.sonar.api.BatchComponent;
-
-/**
- * Used by batch components to get the issues of the current module. It does not allow
- * to get issues of all project modules.
- *
- * @since 4.0
- */
-public interface ModuleIssues extends BatchComponent {
-
-  /**
-   * All the unresolved issues of the current module, including the issues reported by end-users.
-   */
-  Iterable<Issue> issues();
-
-  /**
-   * All the issues of this module that have been marked as resolved during this scan
-   */
-  Iterable<Issue> resolvedIssues();
-}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/ProjectIssues.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/ProjectIssues.java
new file mode 100644 (file)
index 0000000..3665989
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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  02110-1301, USA.
+ */
+package org.sonar.api.issue;
+
+import org.sonar.api.BatchComponent;
+import org.sonar.api.batch.InstantiationStrategy;
+import org.sonar.api.batch.PostJob;
+
+import static org.sonar.api.batch.InstantiationStrategy.PER_BATCH;
+
+/**
+ * Used by batch components to get the issues of the project. You have to wait for all
+ * issues to have been computed (for example in a {@link PostJob}) to be sure all issues have
+ * been computed.
+ *
+ * @since 4.0
+ */
+@InstantiationStrategy(PER_BATCH)
+public interface ProjectIssues extends BatchComponent {
+
+  /**
+   * All the unresolved issues of the project, including the issues reported by end-users.
+   */
+  Iterable<Issue> issues();
+
+  /**
+   * All the issues of this project that have been marked as resolved during this scan
+   */
+  Iterable<Issue> resolvedIssues();
+}