import java.util.List;
import org.sonar.server.computation.context.ComputationContext;
import org.sonar.server.computation.event.EventRepository;
-import org.sonar.server.computation.measure.MeasureRepository;
import org.sonar.server.computation.step.PopulateComponentsUuidAndKeyStep;
public interface Component {
*/
EventRepository getEventRepository();
- /**
- * the measure repository for the current component
- */
- MeasureRepository getMeasureRepository();
-
}
*/
package org.sonar.server.computation.component;
-import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.sonar.api.measures.Metric;
import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.measure.db.MeasureDto;
-import org.sonar.core.persistence.DbSession;
import org.sonar.server.computation.ComputationContext;
-import org.sonar.server.computation.batch.BatchReportReader;
import org.sonar.server.computation.event.Event;
import org.sonar.server.computation.event.EventRepository;
-import org.sonar.server.computation.measure.MeasureRepository;
-import org.sonar.server.db.DbClient;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.ImmutableList.copyOf;
private final Type type;
private final BatchReport.Component component;
private final List<Component> children;
- private final BatchReportReader reportReader;
private final EventRepository eventRepository = new SetEventRepository();
// Mutable values
private String key;
private String uuid;
- public ComponentImpl(ComputationContext context, BatchReport.Component component,
- BatchReportReader reportReader, @Nullable Iterable<Component> children) {
+ public ComponentImpl(ComputationContext context, BatchReport.Component component, @Nullable Iterable<Component> children) {
this.context = context;
this.component = component;
- this.reportReader = reportReader;
this.type = convertType(component.getType());
this.children = children == null ? Collections.<Component>emptyList() : copyOf(filter(children, notNull()));
}
return eventRepository;
}
- @Override
- public MeasureRepository getMeasureRepository() {
- return new MeasureRepository() {
- @Override
- public Optional<MeasureDto> findPrevious(Metric<?> metric) {
- DbClient dbClient = context.getDbClient();
- try (DbSession dbSession = dbClient.openSession(false)) {
- return Optional.fromNullable(
- // TODO replace component.getKey() by ${link #getKey} as component.getKey() is only for project/module and does not take into
- // account usage of the branch
- dbClient.measureDao().findByComponentKeyAndMetricKey(dbSession, component.getKey(), metric.getKey())
- );
- }
- }
-
- @Override
- public Optional<BatchReport.Measure> findCurrent(final Metric<?> metric) {
- return Optional.fromNullable(Iterables.find(
- reportReader.readComponentMeasures(component.getRef()),
- new Predicate<BatchReport.Measure>() {
- @Override
- public boolean apply(@Nonnull BatchReport.Measure input) {
- return input.getMetricKey().equals(metric.getKey());
- }
- }
- ));
- }
- };
- }
-
private static class SetEventRepository implements EventRepository {
private final Set<Event> events = new HashSet<>();
return events;
}
}
+
}
private Component buildComponentRoot(ComputationContext computationContext, BatchReportReader reportReader) {
int rootComponentRef = reportReader.readMetadata().getRootComponentRef();
BatchReport.Component component = reportReader.readComponent(rootComponentRef);
- return new ComponentImpl(computationContext, component, reportReader, buildComponent(computationContext, rootComponentRef));
+ return new ComponentImpl(computationContext, component, buildComponent(computationContext, rootComponentRef));
}
private Iterable<Component> buildComponent(final ComputationContext computationContext, int componentRef) {
@Override
public Component apply(@Nonnull Integer componentRef) {
BatchReport.Component component = reportReader.readComponent(componentRef);
- return new ComponentImpl(computationContext, component, reportReader, buildComponent(computationContext, componentRef));
+ return new ComponentImpl(computationContext, component, buildComponent(computationContext, componentRef));
}
}
);
import org.sonar.server.computation.issue.ScmAccountCacheLoader;
import org.sonar.server.computation.issue.SourceLinesCache;
import org.sonar.server.computation.language.PlatformLanguageRepository;
+import org.sonar.server.computation.measure.MeasureRepositoryImpl;
import org.sonar.server.computation.measure.MetricCache;
import org.sonar.server.computation.step.ComputationStep;
import org.sonar.server.computation.step.ComputationSteps;
// repositories
PlatformLanguageRepository.class,
+ MeasureRepositoryImpl.class,
ProjectSettingsRepository.class,
// component caches
import com.google.common.base.Optional;
import org.sonar.core.measure.db.MeasureDto;
+import org.sonar.server.computation.component.Component;
public interface MeasureRepository {
// FIXME should not expose MeasureDto from DAO layer
- Optional<MeasureDto> findPrevious(Metric<?> metric);
+ Optional<MeasureDto> findPrevious(Component component, Metric<?> metric);
// FIXME should not expose Measure from BatchReport
- Optional<BatchReport.Measure> findCurrent(Metric<?> metric);
+ Optional<BatchReport.Measure> findCurrent(Component component, Metric<?> metric);
}
--- /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.server.computation.measure;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import javax.annotation.Nonnull;
+import org.sonar.api.measures.Metric;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.core.measure.db.MeasureDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.computation.batch.BatchReportReader;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.db.DbClient;
+
+public class MeasureRepositoryImpl implements MeasureRepository {
+ private final DbClient dbClient;
+ private final BatchReportReader reportReader;
+
+ public MeasureRepositoryImpl(DbClient dbClient, BatchReportReader reportReader) {
+ this.dbClient = dbClient;
+ this.reportReader = reportReader;
+ }
+
+ @Override
+ public Optional<MeasureDto> findPrevious(Component component, Metric<?> metric) {
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ return Optional.fromNullable(
+ // TODO replace component.getKey() by ${link #getKey} as component.getKey() is only for project/module and does not take into
+ // account usage of the branch
+ dbClient.measureDao().findByComponentKeyAndMetricKey(dbSession, component.getKey(), metric.getKey())
+ );
+ }
+ }
+
+ @Override
+ public Optional<BatchReport.Measure> findCurrent(Component component, final Metric<?> metric) {
+ return Optional.fromNullable(Iterables.find(
+ reportReader.readComponentMeasures(component.getRef()),
+ new Predicate<BatchReport.Measure>() {
+ @Override
+ public boolean apply(@Nonnull BatchReport.Measure input) {
+ return input.getMetricKey().equals(metric.getKey());
+ }
+ }
+ ));
+ }
+}
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
import org.sonar.server.computation.event.Event;
+import org.sonar.server.computation.measure.MeasureRepository;
import org.sonar.server.computation.qualityprofile.QPMeasureData;
import org.sonar.server.computation.qualityprofile.QualityProfile;
import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER;
public class QualityProfileEventsStep implements ComputationStep {
+ private final MeasureRepository measureRepository;
+
+ public QualityProfileEventsStep(MeasureRepository measureRepository) {
+ this.measureRepository = measureRepository;
+ }
@Override
public void execute(ComputationContext context) {
}
private void executeForProject(Component projectComponent) {
- Optional<MeasureDto> previousMeasure = projectComponent.getMeasureRepository().findPrevious(CoreMetrics.QUALITY_PROFILES);
+ Optional<MeasureDto> previousMeasure = measureRepository.findPrevious(projectComponent, CoreMetrics.QUALITY_PROFILES);
if (!previousMeasure.isPresent()) {
// first analysis -> do not generate events
return;
// Load current profiles
Map<String, QualityProfile> previousProfiles = QPMeasureData.fromJson(previousMeasure.get().getData()).getProfilesByKey();
- Optional<BatchReport.Measure> currentMeasure = projectComponent.getMeasureRepository().findCurrent(CoreMetrics.QUALITY_PROFILES);
+ Optional<BatchReport.Measure> currentMeasure = measureRepository.findCurrent(projectComponent, CoreMetrics.QUALITY_PROFILES);
if (!currentMeasure.isPresent()) {
throw new IllegalStateException("Missing measure " + CoreMetrics.QUALITY_PROFILES + " for component " + projectComponent.getRef());
}
package org.sonar.server.computation.component;
import com.google.common.collect.ImmutableList;
-import org.sonar.server.computation.context.ComputationContext;
-import org.sonar.server.computation.event.EventRepository;
-import org.sonar.server.computation.measure.MeasureRepository;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.server.computation.context.ComputationContext;
+import org.sonar.server.computation.event.EventRepository;
public class DumbComponent implements Component {
public static final Component DUMB_PROJECT = new DumbComponent(Type.PROJECT, 1, "PROJECT_KEY", "PROJECT_UUID");
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_ERROR);
}
- @Override
- public MeasureRepository getMeasureRepository() {
- throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_ERROR);
- }
}
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Nullable;
import org.junit.Test;
import org.sonar.api.config.Settings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.server.computation.qualityprofile.QualityProfile;
import org.sonar.server.db.DbClient;
-import javax.annotation.Nullable;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
private MeasureRepository measureRepository = mock(MeasureRepository.class);
private LanguageRepository languageRepository = mock(LanguageRepository.class);
- private QualityProfileEventsStep underTest = new QualityProfileEventsStep();
+ private QualityProfileEventsStep underTest = new QualityProfileEventsStep(measureRepository);
@Test
public void no_effect_if_no_previous_measure() {
- when(measureRepository.findPrevious(CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.<MeasureDto>absent());
-
ComputationContext context = newNoChildRootContext();
+
+ when(measureRepository.findPrevious(context.getRoot(), CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.<MeasureDto>absent());
+
underTest.execute(context);
assertThat(context.getRoot().getEventRepository().getEvents()).isEmpty();
@Test(expected = IllegalStateException.class)
public void ISE_if_no_current_measure() {
- when(measureRepository.findPrevious(CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.of(newMeasureDto()));
- when(measureRepository.findCurrent(CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.<BatchReport.Measure>absent());
+ ComputationContext context = newNoChildRootContext();
+
+ when(measureRepository.findPrevious(context.getRoot(), CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.of(newMeasureDto()));
+ when(measureRepository.findCurrent(context.getRoot(), CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.<BatchReport.Measure>absent());
- underTest.execute(newNoChildRootContext());
+ underTest.execute(context);
}
@Test
public void no_event_if_no_qp_now_nor_before() {
- mockMeasures(null, null);
-
ComputationContext context = newNoChildRootContext();
+
+ mockMeasures(context.getRoot(), null, null);
+
underTest.execute(context);
assertThat(context.getRoot().getEventRepository().getEvents()).isEmpty();
@Test
public void added_event_if_one_new_qp() {
QualityProfile qp = qp(QP_NAME_1, LANGUAGE_KEY_1);
- mockMeasures(null, arrayOf(qp));
+ ComputationContext context = newNoChildRootContext();
+
Language language = mockLanguageInRepository(LANGUAGE_KEY_1);
+ mockMeasures(context.getRoot(), null, arrayOf(qp));
- ComputationContext context = newNoChildRootContext();
underTest.execute(context);
List<Event> events = Lists.newArrayList(context.getRoot().getEventRepository().getEvents());
@Test
public void added_event_uses_language_key_in_message_if_language_not_found() {
QualityProfile qp = qp(QP_NAME_1, LANGUAGE_KEY_1);
- mockMeasures(null, arrayOf(qp));
+ ComputationContext context = newNoChildRootContext();
+
mockLanguageNotInRepository(LANGUAGE_KEY_1);
+ mockMeasures(context.getRoot(), null, arrayOf(qp));
- ComputationContext context = newNoChildRootContext();
underTest.execute(context);
List<Event> events = Lists.newArrayList(context.getRoot().getEventRepository().getEvents());
@Test
public void no_more_used_event_if_qp_no_more_listed() {
QualityProfile qp = qp(QP_NAME_1, LANGUAGE_KEY_1);
- mockMeasures(arrayOf(qp), null);
+ ComputationContext context = newNoChildRootContext();
+
+ mockMeasures(context.getRoot(), arrayOf(qp), null);
Language language = mockLanguageInRepository(LANGUAGE_KEY_1);
- ComputationContext context = newNoChildRootContext();
underTest.execute(context);
List<Event> events = Lists.newArrayList(context.getRoot().getEventRepository().getEvents());
@Test
public void no_more_used_event_uses_language_key_in_message_if_language_not_found() {
QualityProfile qp = qp(QP_NAME_1, LANGUAGE_KEY_1);
- mockMeasures(arrayOf(qp), null);
+ ComputationContext context = newNoChildRootContext();
+
+ mockMeasures(context.getRoot(), arrayOf(qp), null);
mockLanguageNotInRepository(LANGUAGE_KEY_1);
- ComputationContext context = newNoChildRootContext();
underTest.execute(context);
List<Event> events = Lists.newArrayList(context.getRoot().getEventRepository().getEvents());
@Test
public void no_event_if_same_qp_with_same_date() {
QualityProfile qp = qp(QP_NAME_1, LANGUAGE_KEY_1);
- mockMeasures(arrayOf(qp), arrayOf(qp));
-
ComputationContext context = newNoChildRootContext();
+
+ mockMeasures(context.getRoot(), arrayOf(qp), arrayOf(qp));
+
underTest.execute(context);
assertThat(context.getRoot().getEventRepository().getEvents()).isEmpty();
public void changed_event_if_same_qp_but_no_same_date() {
QualityProfile qp1 = qp(QP_NAME_1, LANGUAGE_KEY_1, parseDateTime("2011-04-25T01:05:13+0100"));
QualityProfile qp2 = qp(QP_NAME_1, LANGUAGE_KEY_1, parseDateTime("2011-04-25T01:05:17+0100"));
- mockMeasures(arrayOf(qp1), arrayOf(qp2));
+ ComputationContext context = newNoChildRootContext();
+
+ mockMeasures(context.getRoot(), arrayOf(qp1), arrayOf(qp2));
Language language = mockLanguageInRepository(LANGUAGE_KEY_1);
- ComputationContext context = newNoChildRootContext();
underTest.execute(context);
List<Event> events = Lists.newArrayList(context.getRoot().getEventRepository().getEvents());
@Test
public void verify_detection_with_complex_mix_of_qps() {
+ ComputationContext context = newNoChildRootContext();
+
mockMeasures(
- arrayOf(
+ context.getRoot(), arrayOf(
qp(QP_NAME_2, LANGUAGE_KEY_1),
qp(QP_NAME_2, LANGUAGE_KEY_2),
qp(QP_NAME_1, LANGUAGE_KEY_1, parseDateTime("2011-04-25T01:05:13+0100"))
));
mockNoLanguageInRepository();
- ComputationContext context = newNoChildRootContext();
underTest.execute(context);
assertThat(context.getRoot().getEventRepository().getEvents()).extracting("name").containsOnly(
- "Stop using '" + QP_NAME_2 + "' (" + LANGUAGE_KEY_1 + ")",
- "Use '" + QP_NAME_2 + "' (" + LANGUAGE_KEY_3 + ")",
- "Changes in '" + QP_NAME_1 + "' (" + LANGUAGE_KEY_1 + ")"
+ "Stop using '" + QP_NAME_2 + "' (" + LANGUAGE_KEY_1 + ")",
+ "Use '" + QP_NAME_2 + "' (" + LANGUAGE_KEY_3 + ")",
+ "Changes in '" + QP_NAME_1 + "' (" + LANGUAGE_KEY_1 + ")"
);
}
when(languageRepository.find(anyString())).thenReturn(Optional.<Language>absent());
}
- private void mockMeasures(@Nullable QualityProfile[] previous, @Nullable QualityProfile[] current) {
- when(measureRepository.findPrevious(CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.of(newMeasureDto(previous)));
- when(measureRepository.findCurrent(CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.of(newQPBatchMeasure(current)));
+ private void mockMeasures(Component component, @Nullable QualityProfile[] previous, @Nullable QualityProfile[] current) {
+ when(measureRepository.findPrevious(component, CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.of(newMeasureDto(previous)));
+ when(measureRepository.findCurrent(component, CoreMetrics.QUALITY_PROFILES)).thenReturn(Optional.of(newQPBatchMeasure(current)));
}
private static void verifyEvent(Event event, String expectedName, @Nullable String expectedData) {
return newContext(new ComponentTreeBuilder() {
@Override
public Component build(ComputationContext context) {
- return new EventAndMeasureRepoComponent(context, Component.Type.PROJECT, 1);
+ return new EvenRepoComponent(context, Component.Type.PROJECT, 1);
}
});
}
builder, languageRepository);
}
- private class EventAndMeasureRepoComponent extends DumbComponent {
+ private class EvenRepoComponent extends DumbComponent {
private final EventRepository eventRepository = new EventRepository() {
private final Set<Event> events = new HashSet<>();
}
};
- public EventAndMeasureRepoComponent(@Nullable org.sonar.server.computation.context.ComputationContext context,
+ public EvenRepoComponent(@Nullable org.sonar.server.computation.context.ComputationContext context,
Type type, int ref, @Nullable Component... children) {
super(context, type, ref, null, null, children);
}
- @Override
- public MeasureRepository getMeasureRepository() {
- return measureRepository;
- }
-
@Override
public EventRepository getEventRepository() {
return eventRepository;