*/
package org.sonar.plugins.core.issue;
-import org.sonar.batch.components.Period;
-
-import org.sonar.batch.components.TimeMachineConfiguration;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.*;
import org.apache.commons.lang.time.DateUtils;
import org.sonar.api.resources.ResourceUtils;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RulePriority;
+import org.sonar.batch.components.Period;
+import org.sonar.batch.components.TimeMachineConfiguration;
import javax.annotation.Nullable;
* @since 3.6
*/
@DependsUpon(DecoratorBarriers.ISSUES_TRACKED)
+@RequiresDB
public class CountUnresolvedIssuesDecorator implements Decorator {
private final ResourcePerspectives perspectives;
import org.sonar.api.batch.Decorator;
import org.sonar.api.batch.DecoratorContext;
import org.sonar.api.batch.Phase;
+import org.sonar.api.batch.RequiresDB;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.Metric;
import static com.google.common.base.Preconditions.checkState;
@Phase(name = Phase.Name.PRE)
+@RequiresDB
public class ManualMeasureDecorator implements Decorator {
private DatabaseSession session;
*/
package org.sonar.plugins.core.timemachine;
-import org.sonar.api.batch.Decorator;
-import org.sonar.api.batch.DecoratorBarriers;
-import org.sonar.api.batch.DecoratorContext;
-import org.sonar.api.batch.DependedUpon;
+import org.sonar.api.batch.*;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.resources.Project;
import static org.sonar.api.utils.DateUtils.dateToLong;
@DependedUpon(DecoratorBarriers.END_OF_TIME_MACHINE)
+@RequiresDB
public final class TimeMachineConfigurationPersister implements Decorator {
private final TimeMachineConfiguration timeMachineConfiguration;
*/
package org.sonar.plugins.core.timemachine;
-import org.sonar.batch.components.TimeMachineConfiguration;
-
-import org.sonar.batch.components.PastSnapshot;
-import org.sonar.batch.components.PastMeasuresLoader;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.batch.Decorator;
-import org.sonar.api.batch.DecoratorBarriers;
-import org.sonar.api.batch.DecoratorContext;
-import org.sonar.api.batch.DependedUpon;
-import org.sonar.api.batch.DependsUpon;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.MeasuresFilters;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.measures.MetricFinder;
-import org.sonar.api.measures.RuleMeasure;
+import org.sonar.api.batch.*;
+import org.sonar.api.measures.*;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.technicaldebt.batch.Characteristic;
+import org.sonar.batch.components.PastMeasuresLoader;
+import org.sonar.batch.components.PastSnapshot;
+import org.sonar.batch.components.TimeMachineConfiguration;
import javax.annotation.Nullable;
import java.util.Map;
@DependedUpon(DecoratorBarriers.END_OF_TIME_MACHINE)
+@RequiresDB
public class VariationDecorator implements Decorator {
private List<PastSnapshot> projectPastSnapshots;
}
}
+ public static void appendToFile(Message message, File toFile) {
+ try (OutputStream out = new BufferedOutputStream(new FileOutputStream(toFile, true))) {
+ message.writeDelimitedTo(out);
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to append protocol buffer data to file " + toFile, e);
+ }
+ }
+
public static <MESSAGE extends Message> void writeMessagesToFile(Iterable<MESSAGE> messages, File file) {
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(file, true))) {
for (MESSAGE message : messages) {
ProtobufUtil.writeMessagesToFile(fileDependencies, file);
}
+ public void appendFileDependency(int componentRef, BatchReport.FileDependency fileDependency) {
+ File file = fileStructure.fileFor(FileStructure.Domain.FILE_DEPENDENCIES, componentRef);
+ ProtobufUtil.appendToFile(fileDependency, file);
+ }
+
public void writeModuleDependencies(int componentRef, Iterable<BatchReport.ModuleDependencies.ModuleDependency> dependencies) {
BatchReport.ModuleDependencies.Builder builder = BatchReport.ModuleDependencies.newBuilder();
builder.addAllDep(dependencies);
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 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.dependency;
-
-import com.persistit.Value;
-import com.persistit.encoding.CoderContext;
-import com.persistit.encoding.ValueCoder;
-import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
-
-class DefaultDependencyValueCoder implements ValueCoder {
-
- @Override
- public void put(Value value, Object object, CoderContext context) {
- DefaultDependency dep = (DefaultDependency) object;
- value.putUTF(dep.fromKey());
- value.putUTF(dep.toKey());
- value.put(dep.weight());
- }
-
- @Override
- public Object get(Value value, Class clazz, CoderContext context) {
- String fromKey = value.getString();
- String toKey = value.getString();
- int weight = value.getInt();
- return new DefaultDependency()
- .setFromKey(fromKey)
- .setToKey(toKey)
- .setWeight(weight);
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 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.dependency;
-
-import com.google.common.base.Preconditions;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
-import org.sonar.batch.index.Cache;
-import org.sonar.batch.index.Cache.Entry;
-import org.sonar.batch.index.Caches;
-
-import javax.annotation.CheckForNull;
-
-/**
- * Cache of all dependencies. This cache is shared amongst all project modules.
- * module key -> from key -> to key -> Dependency
- */
-public class DependencyCache implements BatchComponent {
-
- private final Cache<DefaultDependency> cache;
-
- public DependencyCache(Caches caches) {
- caches.registerValueCoder(DefaultDependency.class, new DefaultDependencyValueCoder());
- cache = caches.createCache("dependencies");
- }
-
- public Iterable<Entry<DefaultDependency>> entries() {
- return cache.entries();
- }
-
- @CheckForNull
- public DefaultDependency get(String moduleKey, String fromKey, String toKey) {
- Preconditions.checkNotNull(moduleKey);
- Preconditions.checkNotNull(fromKey);
- Preconditions.checkNotNull(toKey);
- return cache.get(moduleKey, fromKey, toKey);
- }
-
- public DependencyCache put(String moduleKey, DefaultDependency dependency) {
- Preconditions.checkNotNull(moduleKey);
- Preconditions.checkNotNull(dependency);
- cache.put(moduleKey, dependency.fromKey(), dependency.toKey(), dependency);
- return this;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.batch.dependency;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
*/
package org.sonar.batch.index;
-import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.design.Dependency;
import org.sonar.api.design.DependencyDto;
import org.sonar.api.resources.Project;
-import org.sonar.batch.dependency.DependencyCache;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.batch.report.ReportPublisher;
import javax.annotation.Nullable;
private final ResourceCache resourceCache;
private final DatabaseSession session;
- private final DependencyCache dependencyCache;
+ private final ReportPublisher reportPublisher;
+ private final BatchReport.FileDependency.Builder builder = BatchReport.FileDependency.newBuilder();
- public DependencyPersister(ResourceCache resourceCache, DependencyCache dependencyCache, @Nullable DatabaseSession session) {
+ public DependencyPersister(ResourceCache resourceCache, ReportPublisher reportPublisher, @Nullable DatabaseSession session) {
this.resourceCache = resourceCache;
- this.dependencyCache = dependencyCache;
+ this.reportPublisher = reportPublisher;
this.session = session;
}
- public DependencyPersister(ResourceCache resourceCache, DependencyCache dependencyCache) {
- this(resourceCache, dependencyCache, null);
+ public DependencyPersister(ResourceCache resourceCache, ReportPublisher reportPublisher) {
+ this(resourceCache, reportPublisher, null);
}
public void saveDependency(Project project, Dependency dependency) {
BatchResource projectResource = resourceCache.get(project);
if (fromResource.isFile() && toResource.isFile()) {
- dependencyCache.put(project.getEffectiveKey(), new DefaultDependency().setFromKey(fromResource.key()).setToKey(toResource.key()).setWeight(dependency.getWeight()));
+ builder.clear();
+ reportPublisher.getWriter().appendFileDependency(fromResource.batchId(), builder.setToFileRef(toResource.batchId()).setWeight(dependency.getWeight()).build());
}
if (session != null) {
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.fs.*;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
import org.sonar.api.batch.sensor.duplication.Duplication;
import org.sonar.api.batch.sensor.highlighting.TypeOfText;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.measures.Measure;
-import org.sonar.batch.dependency.DependencyCache;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.index.Cache.Entry;
import org.sonar.batch.index.ResourceCache;
private Map<String, InputFile> inputFiles = new HashMap<>();
private Map<String, Component> reportComponents = new HashMap<>();
private Map<String, InputDir> inputDirs = new HashMap<>();
- private Map<String, Map<String, Integer>> dependencies = new HashMap<>();
private BatchReportReader reader;
@Override
storeMeasures(container);
storeDuplication(container);
- storeDependencies(container);
}
private void storeReportComponents(int componentRef, String parentModuleKey, @Nullable String branch) {
}
}
- private void storeDependencies(ProjectScanContainer container) {
- DependencyCache dependencyCache = container.getComponentByType(DependencyCache.class);
- for (Entry<DefaultDependency> entry : dependencyCache.entries()) {
- String fromKey = entry.key()[1].toString();
- String toKey = entry.key()[2].toString();
- if (!dependencies.containsKey(fromKey)) {
- dependencies.put(fromKey, new HashMap<String, Integer>());
- }
- dependencies.get(fromKey).put(toKey, entry.value().weight());
- }
- }
-
public List<Issue> issues() {
return issues;
}
return null;
}
+ public BatchReport.FileDependency fileDependencyFor(InputFile file, InputFile anotherFile) {
+ int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef();
+ int otherRef = reportComponents.get(((DefaultInputFile) anotherFile).key()).getRef();
+ try (InputStream inputStream = FileUtils.openInputStream(getReportReader().readFileDependencies(ref))) {
+ BatchReport.FileDependency dep = BatchReport.FileDependency.PARSER.parseDelimitedFrom(inputStream);
+ while (dep != null) {
+ if (dep.getToFileRef() == otherRef) {
+ return dep;
+ }
+ dep = BatchReport.FileDependency.PARSER.parseDelimitedFrom(inputStream);
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ return null;
+ }
+
public BatchReport.CoverageDetail coveragePerTestFor(InputFile testFile, String testName) {
int ref = reportComponents.get(((DefaultInputFile) testFile).key()).getRef();
try (InputStream inputStream = FileUtils.openInputStream(getReportReader().readCoverageDetails(ref))) {
}
return null;
}
-
- /**
- * @return null if no dependency else return dependency weight.
- */
- @CheckForNull
- public Integer dependencyWeight(InputFile from, InputFile to) {
- String fromKey = ((DefaultInputFile) from).key();
- String toKey = ((DefaultInputFile) to).key();
- return dependencies.containsKey(fromKey) ? dependencies.get(fromKey).get(toKey) : null;
- }
}
*/
package org.sonar.batch.phases;
-import org.sonar.batch.deprecated.decorator.DefaultDecoratorContext;
-
-import org.sonar.batch.deprecated.decorator.DecoratorsSelector;
import com.google.common.collect.Lists;
import org.sonar.api.BatchComponent;
+import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.Decorator;
import org.sonar.api.batch.DecoratorContext;
import org.sonar.api.batch.SonarIndex;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.SonarException;
import org.sonar.batch.bootstrap.BatchExtensionDictionnary;
+import org.sonar.batch.deprecated.decorator.DecoratorsSelector;
+import org.sonar.batch.deprecated.decorator.DefaultDecoratorContext;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.events.EventBus;
import org.sonar.batch.scan.measure.MeasureCache;
public class DecoratorsExecutor implements BatchComponent {
- private DecoratorsSelector decoratorsSelector;
- private SonarIndex index;
- private EventBus eventBus;
- private Project project;
- private CoverageExclusions coverageFilter;
- private MeasureCache measureCache;
- private MetricFinder metricFinder;
+ private final DecoratorsSelector decoratorsSelector;
+ private final SonarIndex index;
+ private final EventBus eventBus;
+ private final Project project;
+ private final CoverageExclusions coverageFilter;
+ private final MeasureCache measureCache;
+ private final MetricFinder metricFinder;
private final DuplicationCache duplicationCache;
+ private final AnalysisMode analysisMode;
public DecoratorsExecutor(BatchExtensionDictionnary batchExtDictionnary,
Project project, SonarIndex index, EventBus eventBus, CoverageExclusions coverageFilter, MeasureCache measureCache, MetricFinder metricFinder,
- DuplicationCache duplicationCache) {
+ DuplicationCache duplicationCache, AnalysisMode analysisMode) {
this.measureCache = measureCache;
this.metricFinder = metricFinder;
this.duplicationCache = duplicationCache;
+ this.analysisMode = analysisMode;
this.decoratorsSelector = new DecoratorsSelector(batchExtDictionnary);
this.index = index;
this.eventBus = eventBus;
}
public void execute() {
+ if (analysisMode.isPreview()) {
+ // Decorators are not executed in preview mode
+ return;
+ }
Collection<Decorator> decorators = decoratorsSelector.select(project);
eventBus.fireEvent(new DecoratorsPhaseEvent(Lists.newArrayList(decorators), true));
((DefaultDecoratorContext) decorateResource(project, decorators, true)).end();
import org.sonar.batch.bootstrap.*;
import org.sonar.batch.debt.DebtModelProvider;
import org.sonar.batch.debt.IssueChangelogDebtCalculator;
-import org.sonar.batch.dependency.DependencyCache;
import org.sonar.batch.deprecated.components.DefaultResourceCreationLock;
import org.sonar.batch.deprecated.components.PeriodsDefinition;
import org.sonar.batch.duplication.DuplicationCache;
// Dependencies
DependencyPersister.class,
- DependencyCache.class,
// Quality Gate
new QualityGateProvider(),
*/
package org.sonar.batch.mediumtest.dependency;
+import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.io.FileUtils;
import org.junit.After;
.build())
.start();
- assertThat(result.dependencyWeight(result.inputFile("src/sample.xoo"), result.inputFile("src/sample2.xoo"))).isEqualTo(3);
- assertThat(result.dependencyWeight(result.inputFile("src/sample.xoo"), result.inputFile("src/foo/sample3.xoo"))).isEqualTo(6);
+ assertThat(result.fileDependencyFor(result.inputFile("src/sample.xoo"), result.inputFile("src/sample2.xoo")).getWeight()).isEqualTo(3);
+ assertThat(result.fileDependencyFor(result.inputFile("src/sample.xoo"), result.inputFile("src/foo/sample3.xoo")).getWeight()).isEqualTo(6);
}
+ @Test
+ public void manyDependenciesNoCycle() throws IOException {
+
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ int nbFiles = 100;
+ for (int nb = 1; nb <= nbFiles; nb++) {
+ File xooFile = new File(srcDir, "dir1/sample" + nb + ".xoo");
+ FileUtils.write(xooFile, "foo");
+ File xooFile2 = new File(srcDir, "dir2/sample" + nb + ".xoo");
+ FileUtils.write(xooFile2, "foo");
+ File xooDepFile = new File(srcDir, "dir1/sample" + nb + ".xoo.deps");
+ for (int otherId = 1; otherId <= nbFiles; otherId++) {
+ FileUtils.write(xooDepFile, "src/dir2/sample" + otherId + ".xoo:1\n", Charsets.UTF_8, true);
+ }
+ }
+
+ TaskResult result = tester.newTask()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build())
+ .start();
+
+ assertThat(result.fileDependencyFor(result.inputFile("src/dir1/sample1.xoo"), result.inputFile("src/dir2/sample1.xoo")).getWeight()).isEqualTo(1);
+
+ }
}
.newScanTask(new File(projectDir, "sonar-project.properties"))
.start();
- assertThat(result.allMeasures()).hasSize(20);
+ assertThat(result.allMeasures()).hasSize(58);
}
@Test
.build())
.start();
- assertThat(result.allMeasures()).hasSize(4);
+ assertThat(result.allMeasures()).hasSize(28);
assertThat(result.allMeasures()).contains(new DefaultMeasure<Integer>()
.forMetric(CoreMetrics.LINES)
.put("sonar.sources", "src")
.put("sonar.scm.disabled", "true")
.put("sonar.scm.provider", "xoo")
+ .put("sonar.cpd.xoo.skip", "true")
.build())
.start();
- assertThat(result.allMeasures()).extracting("metric.key").containsOnly("lines", "quality_profiles");
+ BatchReport.Changesets changesets = getChangesets(baseDir, 0);
+ assertThat(changesets).isNull();
}
}
package org.sonar.batch.phases;
import org.junit.Test;
+import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.Decorator;
import org.sonar.api.batch.DecoratorContext;
import org.sonar.api.batch.SonarIndex;
doThrow(new SonarException()).when(decorator).decorate(any(Resource.class), any(DecoratorContext.class));
DecoratorsExecutor executor = new DecoratorsExecutor(mock(BatchExtensionDictionnary.class), new Project("key"), mock(SonarIndex.class),
- mock(EventBus.class), mock(CoverageExclusions.class), mock(MeasureCache.class), mock(MetricFinder.class), mock(DuplicationCache.class));
+ mock(EventBus.class), mock(CoverageExclusions.class), mock(MeasureCache.class), mock(MetricFinder.class), mock(DuplicationCache.class), mock(AnalysisMode.class));
try {
executor.executeDecorator(decorator, mock(DefaultDecoratorContext.class), File.create("src/org/foo/Bar.java", null, false));
fail("Exception has not been thrown");
/**
* @since 1.10
*/
-@RequiresDB
public interface Decorator extends BatchExtension, CheckProject {
/**
* requires database access. As a result such extension will be disabled in preview mode.
*
*
- * @since 3.4
+ * @since 5.1
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
*/
package org.sonar.api.batch.sensor.dependency.internal;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-
import com.google.common.base.Preconditions;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.sonar.api.batch.sensor.dependency.Dependency;
import org.sonar.api.batch.sensor.dependency.NewDependency;
import org.sonar.api.batch.sensor.internal.DefaultStorable;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
import javax.annotation.Nullable;
@Override
public DefaultDependency weight(int weight) {
- Preconditions.checkArgument(weight > 1, "weight should be greater than 1");
+ Preconditions.checkArgument(weight >= 1, "weight should be greater than 0");
this.weight = weight;
return this;
}