import org.sonar.db.event.EventDto;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.ce.task.projectanalysis.component.Component.Type.DIRECTORY;
public void setup() {
analysisMetadataHolder.setAnalysisDate(someDate.getTime()).setUuid(ANALYSIS_UUID);
underTest = new PersistEventsStep(dbTester.getDbClient(), system2, treeRootHolder, analysisMetadataHolder, eventRepository, uuidFactory);
- when(eventRepository.getEvents(any(Component.class))).thenReturn(Collections.emptyList());
+ when(eventRepository.getEvents()).thenReturn(Collections.emptyList());
}
@Override
when(system2.now()).thenReturn(NOW);
treeRootHolder.setRoot(ROOT);
Event alert = Event.createAlert("Failed", null, "Open issues > 0");
- when(eventRepository.getEvents(ROOT)).thenReturn(ImmutableList.of(alert));
+ when(eventRepository.getEvents()).thenReturn(ImmutableList.of(alert));
underTest.execute(new TestComputationStepContext());
when(system2.now()).thenReturn(NOW);
treeRootHolder.setRoot(ROOT);
Event profile = Event.createProfile("foo", null, "bar");
- when(eventRepository.getEvents(ROOT)).thenReturn(ImmutableList.of(profile));
+ when(eventRepository.getEvents()).thenReturn(ImmutableList.of(profile));
underTest.execute(new TestComputationStepContext());
*/
package org.sonar.ce.task.projectanalysis.event;
-import org.sonar.ce.task.projectanalysis.component.Component;
-
public interface EventRepository {
/**
- * @throws NullPointerException if {@code component} or {@code event} is {@code null}
- * @throws IllegalArgumentException if type of {@code component} is not {@link Component.Type#PROJECT}
+ * @throws NullPointerException if {@code event} is {@code null}
*/
- void add(Component component, Event event);
+ void add(Event event);
- /**
- * @throws NullPointerException if {@code component} is {@code null}
- */
- Iterable<Event> getEvents(Component component);
+ Iterable<Event> getEvents();
}
*/
package org.sonar.ce.task.projectanalysis.event;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
-import org.sonar.ce.task.projectanalysis.component.Component;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
-import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
public class EventRepositoryImpl implements EventRepository {
- private final Multimap<String, Event> events = HashMultimap.create();
+ private final List<Event> events = new LinkedList<>();
@Override
- public void add(Component component, Event event) {
- checkArgument(component.getType() == Component.Type.PROJECT, "Component must be of type PROJECT");
- events.put(component.getUuid(), requireNonNull(event));
+ public void add(Event event) {
+ events.add(requireNonNull(event));
}
@Override
- public Iterable<Event> getEvents(Component component) {
- return this.events.get(component.getUuid());
+ public Iterable<Event> getEvents() {
+ return Collections.unmodifiableList(this.events);
}
}
import org.sonar.api.utils.System2;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit;
-import org.sonar.ce.task.projectanalysis.component.DepthTraversalTypeAwareCrawler;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
-import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitorAdapter;
import org.sonar.ce.task.projectanalysis.event.Event;
import org.sonar.ce.task.projectanalysis.event.EventRepository;
import org.sonar.ce.task.step.ComputationStep;
public void execute(ComputationStep.Context context) {
try (DbSession dbSession = dbClient.openSession(false)) {
long analysisDate = analysisMetadataHolder.getAnalysisDate();
- new DepthTraversalTypeAwareCrawler(new PersistEventComponentVisitor(dbSession, analysisDate))
- .visit(treeRootHolder.getRoot());
+ new PersistEvent(dbSession, analysisDate).process(treeRootHolder.getRoot());
dbSession.commit();
}
}
return "Persist events";
}
- private class PersistEventComponentVisitor extends TypeAwareVisitorAdapter {
+ private class PersistEvent {
private final DbSession session;
private final long analysisDate;
- PersistEventComponentVisitor(DbSession session, long analysisDate) {
- super(CrawlerDepthLimit.PROJECT, Order.PRE_ORDER);
+ PersistEvent(DbSession session, long analysisDate) {
this.session = session;
this.analysisDate = analysisDate;
}
- @Override
- public void visitProject(Component project) {
+ public void process(Component project) {
processEvents(session, project, analysisDate);
saveVersionEvent(session, project, analysisDate);
}
.setDescription(event.getDescription())
.setData(event.getData());
// FIXME bulk insert
- for (EventDto batchEventDto : StreamSupport.stream(eventRepository.getEvents(component).spliterator(), false).map(eventToEventDto).toList()) {
+ for (EventDto batchEventDto : StreamSupport.stream(eventRepository.getEvents().spliterator(), false).map(eventToEventDto).toList()) {
dbClient.eventDao().insert(session, batchEventDto);
}
}
*/
package org.sonar.ce.task.projectanalysis.step;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
import org.sonar.api.measures.CoreMetrics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.analysis.Branch;
import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.component.ComponentVisitor;
-import org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit;
-import org.sonar.ce.task.projectanalysis.component.DepthTraversalTypeAwareCrawler;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
-import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitorAdapter;
import org.sonar.ce.task.projectanalysis.event.Event;
import org.sonar.ce.task.projectanalysis.event.EventRepository;
import org.sonar.ce.task.projectanalysis.measure.Measure;
import org.sonar.server.qualitygate.notification.QGChangeNotification;
import static java.util.Collections.singleton;
-import javax.annotation.Nullable;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
/**
* This step must be executed after computation of quality gate measure {@link QualityGateMeasuresStep}
if (analysisMetadataHolder.isPullRequest()) {
return;
}
- new DepthTraversalTypeAwareCrawler(
- new TypeAwareVisitorAdapter(CrawlerDepthLimit.PROJECT, ComponentVisitor.Order.PRE_ORDER) {
- @Override
- public void visitProject(Component project) {
- executeForProject(project);
- }
- }).visit(treeRootHolder.getRoot());
+ executeForProject(treeRootHolder.getRoot());
}
private void executeForProject(Component project) {
if (baseStatus.getStatus() != rawStatus.getStatus()) {
// The QualityGate status has changed
- createEvent(project, rawStatus.getStatus().getLabel(), rawStatus.getText());
+ createEvent(rawStatus.getStatus().getLabel(), rawStatus.getText());
boolean isNewKo = rawStatus.getStatus() == Measure.Level.OK;
notifyUsers(project, rawStatus, isNewKo);
}
private void checkNewQualityGate(Component project, QualityGateStatus rawStatus) {
if (rawStatus.getStatus() != Measure.Level.OK) {
// There were no defined alerts before, so this one is a new one
- createEvent(project, rawStatus.getStatus().getLabel(), rawStatus.getText());
+ createEvent(rawStatus.getStatus().getLabel(), rawStatus.getText());
notifyUsers(project, rawStatus, true);
}
}
notificationService.deliver(notification);
}
- private void createEvent(Component project, String name, @Nullable String description) {
- eventRepository.add(project, Event.createAlert(name, null, description));
+ private void createEvent(String name, @Nullable String description) {
+ eventRepository.add(Event.createAlert(name, null, description));
}
@Override
import org.sonar.api.resources.Language;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit;
-import org.sonar.ce.task.projectanalysis.component.DepthTraversalTypeAwareCrawler;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
-import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitorAdapter;
import org.sonar.ce.task.projectanalysis.event.Event;
import org.sonar.ce.task.projectanalysis.event.EventRepository;
import org.sonar.ce.task.projectanalysis.language.LanguageRepository;
import org.sonar.server.qualityprofile.QPMeasureData;
import org.sonar.server.qualityprofile.QualityProfile;
-import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.ADDED;
import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.REMOVED;
import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.UPDATED;
/**
* Computation of quality profile events
- *
* As it depends upon {@link CoreMetrics#QUALITY_PROFILES_KEY}, it must be executed after {@link ComputeQProfileMeasureStep}
*/
public class QualityProfileEventsStep implements ComputationStep {
private final MeasureRepository measureRepository;
private final EventRepository eventRepository;
private final LanguageRepository languageRepository;
- private QProfileStatusRepository qProfileStatusRepository;
+ private final QProfileStatusRepository qProfileStatusRepository;
public QualityProfileEventsStep(TreeRootHolder treeRootHolder,
MetricRepository metricRepository, MeasureRepository measureRepository, LanguageRepository languageRepository,
@Override
public void execute(ComputationStep.Context context) {
- new DepthTraversalTypeAwareCrawler(
- new TypeAwareVisitorAdapter(CrawlerDepthLimit.PROJECT, POST_ORDER) {
- @Override
- public void visitProject(Component tree) {
- executeForProject(tree);
- }
- }).visit(treeRootHolder.getRoot());
+ executeForProject(treeRootHolder.getRoot());
}
private void executeForProject(Component projectComponent) {
Map<String, QualityProfile> rawProfiles = QPMeasureData.fromJson(rawMeasure.get().getStringValue()).getProfilesByKey();
Map<String, QualityProfile> baseProfiles = parseJsonData(baseMeasure.get());
- detectNewOrUpdatedProfiles(projectComponent, baseProfiles, rawProfiles);
- detectNoMoreUsedProfiles(projectComponent, baseProfiles);
+ detectNewOrUpdatedProfiles(baseProfiles, rawProfiles);
+ detectNoMoreUsedProfiles(baseProfiles);
}
private static Map<String, QualityProfile> parseJsonData(Measure measure) {
return QPMeasureData.fromJson(data).getProfilesByKey();
}
- private void detectNoMoreUsedProfiles(Component context, Map<String, QualityProfile> baseProfiles) {
+ private void detectNoMoreUsedProfiles(Map<String, QualityProfile> baseProfiles) {
for (QualityProfile baseProfile : baseProfiles.values()) {
if (qProfileStatusRepository.get(baseProfile.getQpKey()).filter(REMOVED::equals).isPresent()) {
- markAsRemoved(context, baseProfile);
+ markAsRemoved(baseProfile);
}
}
}
- private void detectNewOrUpdatedProfiles(Component component, Map<String, QualityProfile> baseProfiles, Map<String, QualityProfile> rawProfiles) {
+ private void detectNewOrUpdatedProfiles(Map<String, QualityProfile> baseProfiles, Map<String, QualityProfile> rawProfiles) {
for (QualityProfile profile : rawProfiles.values()) {
qProfileStatusRepository.get(profile.getQpKey()).ifPresent(status -> {
if (status.equals(ADDED)) {
- markAsAdded(component, profile);
+ markAsAdded(profile);
} else if (status.equals(UPDATED)) {
- markAsChanged(component, baseProfiles.get(profile.getQpKey()), profile);
+ markAsChanged(baseProfiles.get(profile.getQpKey()), profile);
}
});
}
}
- private void markAsChanged(Component component, QualityProfile baseProfile, QualityProfile profile) {
+ private void markAsChanged(QualityProfile baseProfile, QualityProfile profile) {
Date from = baseProfile.getRulesUpdatedAt();
String data = KeyValueFormat.format(ImmutableSortedMap.of(
"key", profile.getQpKey(),
"from", UtcDateUtils.formatDateTime(fixDate(from)),
"to", UtcDateUtils.formatDateTime(fixDate(profile.getRulesUpdatedAt()))));
- eventRepository.add(component, createQProfileEvent(profile, "Changes in %s", data));
+ eventRepository.add(createQProfileEvent(profile, "Changes in %s", data));
}
- private void markAsRemoved(Component component, QualityProfile profile) {
- eventRepository.add(component, createQProfileEvent(profile, "Stop using %s"));
+ private void markAsRemoved(QualityProfile profile) {
+ eventRepository.add(createQProfileEvent(profile, "Stop using %s"));
}
- private void markAsAdded(Component component, QualityProfile profile) {
- eventRepository.add(component, createQProfileEvent(profile, "Use %s"));
+ private void markAsAdded(QualityProfile profile) {
+ eventRepository.add(createQProfileEvent(profile, "Use %s"));
}
private Event createQProfileEvent(QualityProfile profile, String namePattern) {
*/
package org.sonar.ce.task.projectanalysis.event;
-import java.util.Arrays;
import org.junit.Test;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ReportComponent;
-import org.sonar.ce.task.projectanalysis.component.ViewsComponent;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.assertj.core.api.Assertions.fail;
public class EventRepositoryImplTest {
- private static final Component COMPONENT_1 = newComponent(1);
- private static final Component COMPONENT_2 = newComponent(2);
private static final Event EVENT_1 = Event.createProfile("event_1", null, null);
private static final Event EVENT_2 = Event.createProfile("event_2", null, null);
- private EventRepositoryImpl underTest = new EventRepositoryImpl();
+ private final EventRepositoryImpl underTest = new EventRepositoryImpl();
@Test
public void getEvents_returns_empty_iterable_when_repository_is_empty() {
- assertThat(underTest.getEvents(COMPONENT_1)).isEmpty();
- }
-
- @Test
- public void getEvents_discriminates_per_component() {
- underTest.add(COMPONENT_1, EVENT_1);
- underTest.add(COMPONENT_2, EVENT_2);
-
- assertThat(underTest.getEvents(COMPONENT_1)).extracting("name").containsExactly(EVENT_1.getName());
- assertThat(underTest.getEvents(COMPONENT_2)).extracting("name").containsExactly(EVENT_2.getName());
- }
-
- @Test
- public void add_throws_NPE_if_component_arg_is_null() {
- assertThatThrownBy(() -> underTest.add(null, EVENT_1))
- .isInstanceOf(NullPointerException.class);
+ assertThat(underTest.getEvents()).isEmpty();
}
@Test
public void add_throws_NPE_if_even_arg_is_null() {
- assertThatThrownBy(() -> underTest.add(COMPONENT_1, null))
+ assertThatThrownBy(() -> underTest.add(null))
.isInstanceOf(NullPointerException.class);
}
@Test
- public void add_throws_IAE_for_any_component_type_but_PROJECT() {
- Arrays.stream(Component.Type.values())
- .filter(type -> type != Component.Type.PROJECT)
- .map(type -> {
- if (type.isReportType()) {
- return ReportComponent.builder(type, 1).build();
- } else {
- return ViewsComponent.builder(type, 1).build();
- }
- })
- .forEach(component -> {
- try {
- underTest.add(component, EVENT_1);
- fail("should have raised an IAE");
- } catch (IllegalArgumentException e) {
- assertThat(e).hasMessage("Component must be of type PROJECT");
- }
- });
- }
-
- @Test
- public void can_add_and_retrieve_many_events_per_component() {
- underTest.add(COMPONENT_1, EVENT_1);
- underTest.add(COMPONENT_1, EVENT_2);
+ public void can_add_and_retrieve_many_events() {
+ underTest.add(EVENT_1);
+ underTest.add(EVENT_2);
- assertThat(underTest.getEvents(COMPONENT_1)).extracting("name").containsOnly(EVENT_1.getName(), EVENT_2.getName());
+ assertThat(underTest.getEvents()).extracting("name").containsOnly(EVENT_1.getName(), EVENT_2.getName());
}
private static Component newComponent(int i) {
verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
verify(measureRepository).getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric);
- verify(eventRepository).add(eq(PROJECT_COMPONENT), eventArgumentCaptor.capture());
+ verify(eventRepository).add(eventArgumentCaptor.capture());
verifyNoMoreInteractions(measureRepository, eventRepository);
Event event = eventArgumentCaptor.getValue();
verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
verify(measureRepository).getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric);
- verify(eventRepository).add(eq(PROJECT_COMPONENT), eventArgumentCaptor.capture());
+ verify(eventRepository).add(eventArgumentCaptor.capture());
verifyNoMoreInteractions(measureRepository, eventRepository);
Event event = eventArgumentCaptor.getValue();
underTest.execute(new TestComputationStepContext());
- verify(eventRepository).add(eq(treeRootHolder.getRoot()), eventArgumentCaptor.capture());
+ verify(eventRepository).add(eventArgumentCaptor.capture());
verifyNoMoreInteractions(eventRepository);
verifyEvent(eventArgumentCaptor.getValue(), "Use '" + qp.getQpName() + "' (" + language.getName() + ")", null);
}
underTest.execute(new TestComputationStepContext());
- verify(eventRepository).add(eq(treeRootHolder.getRoot()), eventArgumentCaptor.capture());
+ verify(eventRepository).add(eventArgumentCaptor.capture());
verifyNoMoreInteractions(eventRepository);
verifyEvent(eventArgumentCaptor.getValue(), "Use '" + qp.getQpName() + "' (" + qp.getLanguageKey() + ")", null);
}
underTest.execute(new TestComputationStepContext());
- verify(eventRepository).add(eq(treeRootHolder.getRoot()), eventArgumentCaptor.capture());
+ verify(eventRepository).add(eventArgumentCaptor.capture());
verifyNoMoreInteractions(eventRepository);
verifyEvent(eventArgumentCaptor.getValue(), "Stop using '" + qp.getQpName() + "' (" + language.getName() + ")", null);
}
underTest.execute(new TestComputationStepContext());
- verify(eventRepository).add(eq(treeRootHolder.getRoot()), eventArgumentCaptor.capture());
+ verify(eventRepository).add(eventArgumentCaptor.capture());
verifyNoMoreInteractions(eventRepository);
verifyEvent(eventArgumentCaptor.getValue(), "Stop using '" + qp.getQpName() + "' (" + qp.getLanguageKey() + ")", null);
}
underTest.execute(new TestComputationStepContext());
- verify(eventRepository, never()).add(any(Component.class), any(Event.class));
+ verify(eventRepository, never()).add(any(Event.class));
}
@Test
underTest.execute(new TestComputationStepContext());
- verify(eventRepository).add(eq(treeRootHolder.getRoot()), eventArgumentCaptor.capture());
+ verify(eventRepository).add(eventArgumentCaptor.capture());
verifyNoMoreInteractions(eventRepository);
verifyEvent(eventArgumentCaptor.getValue(),
"Changes in '" + qp2.getQpName() + "' (" + language.getName() + ")",
public void verify_detection_with_complex_mix_of_qps() {
final Set<Event> events = new HashSet<>();
doAnswer(invocationOnMock -> {
- events.add((Event) invocationOnMock.getArguments()[1]);
+ events.add((Event) invocationOnMock.getArguments()[0]);
return null;
- }).when(eventRepository).add(eq(treeRootHolder.getRoot()), any(Event.class));
+ }).when(eventRepository).add(any(Event.class));
Date date = new Date();
QualityProfile qp1 = qp(QP_NAME_2, LANGUAGE_KEY_1, date);
SnapshotDto oldAnalysisOnThirdProject = db.components().insertSnapshot(thirdProject, s -> s.setStatus(STATUS_PROCESSED).setCreatedAt(otherFrom - 1L));
insertActivity(thirdProject.uuid(), oldAnalysisOnThirdProject, SUCCESS);
- List<SnapshotDto> result = underTest.selectFinishedByComponentUuidsAndFromDates(dbSession,
+ List<SnapshotDto> result = underTest.selectFinishedByProjectUuidsAndFromDates(dbSession,
Arrays.asList(firstProject.uuid(), secondProject.uuid(), thirdProject.uuid()),
Arrays.asList(from, otherFrom, otherFrom));
SnapshotDto canceledAnalysis = db.components().insertSnapshot(project, s -> s.setStatus(STATUS_PROCESSED).setCreatedAt(from));
insertActivity(project.uuid(), canceledAnalysis, CANCELED);
- List<SnapshotDto> result = underTest.selectFinishedByComponentUuidsAndFromDates(dbSession, singletonList(project.uuid()), singletonList(from));
+ List<SnapshotDto> result = underTest.selectFinishedByProjectUuidsAndFromDates(dbSession, singletonList(project.uuid()), singletonList(from));
assertThat(result).extracting(SnapshotDto::getUuid)
.containsExactlyInAnyOrder(finishedAnalysis.getUuid(), canceledAnalysis.getUuid());
SnapshotDto analysisOnSecondBranch = db.components().insertSnapshot(secondBranch, s -> s.setStatus(STATUS_PROCESSED).setCreatedAt(from));
insertActivity(project.uuid(), analysisOnSecondBranch, SUCCESS);
- List<SnapshotDto> result = underTest.selectFinishedByComponentUuidsAndFromDates(dbSession, singletonList(project.uuid()), singletonList(from));
+ List<SnapshotDto> result = underTest.selectFinishedByProjectUuidsAndFromDates(dbSession, singletonList(project.uuid()), singletonList(from));
assertThat(result).extracting(SnapshotDto::getUuid)
.containsExactlyInAnyOrder(finishedAnalysis.getUuid(), otherFinishedAnalysis.getUuid(), analysisOnSecondBranch.getUuid());
*
* Note that branches analysis of projects are also returned.
*/
- public List<SnapshotDto> selectFinishedByComponentUuidsAndFromDates(DbSession dbSession, List<String> componentUuids, List<Long> fromDates) {
- checkArgument(componentUuids.size() == fromDates.size(), "The number of components (%s) and from dates (%s) must be the same.",
- String.valueOf(componentUuids.size()),
+ public List<SnapshotDto> selectFinishedByProjectUuidsAndFromDates(DbSession dbSession, List<String> projectUuids, List<Long> fromDates) {
+ checkArgument(projectUuids.size() == fromDates.size(), "The number of components (%s) and from dates (%s) must be the same.",
+ String.valueOf(projectUuids.size()),
String.valueOf(fromDates.size()));
- List<ComponentUuidFromDatePair> componentUuidFromDatePairs = IntStream.range(0, componentUuids.size())
- .mapToObj(i -> new ComponentUuidFromDatePair(componentUuids.get(i), fromDates.get(i)))
- .collect(MoreCollectors.toList(componentUuids.size()));
+ List<ComponentUuidFromDatePair> componentUuidFromDatePairs = IntStream.range(0, projectUuids.size())
+ .mapToObj(i -> new ComponentUuidFromDatePair(projectUuids.get(i), fromDates.get(i)))
+ .collect(MoreCollectors.toList(projectUuids.size()));
- return executeLargeInputs(componentUuidFromDatePairs, partition -> mapper(dbSession).selectFinishedByComponentUuidsAndFromDates(partition), i -> i / 2);
+ return executeLargeInputs(componentUuidFromDatePairs, partition -> mapper(dbSession).selectFinishedByProjectUuidsAndFromDates(partition), i -> i / 2);
}
public void switchIsLastFlagAndSetProcessedStatus(DbSession dbSession, String componentUuid, String analysisUuid) {
void update(SnapshotDto analysis);
- List<SnapshotDto> selectFinishedByComponentUuidsAndFromDates(@Param("componentUuidFromDatePairs") List<ComponentUuidFromDatePair> pairs);
+ List<SnapshotDto> selectFinishedByProjectUuidsAndFromDates(@Param("projectUuidFromDatePairs") List<ComponentUuidFromDatePair> pairs);
@CheckForNull
Long selectLastAnalysisDateByProject(String projectUuid);
</if>
</select>
- <select id="selectFinishedByComponentUuidsAndFromDates" parameterType="map" resultType="Snapshot">
+ <select id="selectFinishedByProjectUuidsAndFromDates" parameterType="map" resultType="Snapshot">
select
<include refid="snapshotColumns" />
from snapshots s
inner join components p on p.uuid=s.component_uuid and p.enabled=${_true}
inner join project_branches pb on pb.uuid=p.uuid
where
- <foreach collection="componentUuidFromDatePairs" open="(" close=")" item="componentUuidFromDatePair" separator=" or ">
- (pb.project_uuid=#{componentUuidFromDatePair.componentUuid, jdbcType=VARCHAR} and s.created_at >= #{componentUuidFromDatePair.from, jdbcType=BIGINT})
+ <foreach collection="projectUuidFromDatePairs" open="(" close=")" item="projectUuidFromDatePair" separator=" or ">
+ (pb.project_uuid=#{projectUuidFromDatePair.componentUuid, jdbcType=VARCHAR} and s.created_at >= #{projectUuidFromDatePair.from, jdbcType=BIGINT})
</foreach>
and s.status = 'P'
order by
import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.BranchType;
import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ProjectData;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.server.es.EsTester;
userSession.logIn();
when(server.getPublicRootUrl()).thenReturn("https://sonarcloud.io");
ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
- userSession.addProjectPermission(USER, project);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project));
SnapshotDto analysis = insertAnalysis(project, 1_500_000_000_000L);
insertIssue(project, analysis);
insertIssue(project, analysis);
public void many_issues_events() {
userSession.logIn();
long from = 1_500_000_000_000L;
- ComponentDto project = db.components().insertPrivateProject(p -> p.setName("SonarQube")).getMainBranchComponent();
- userSession.addProjectPermission(USER, project);
- SnapshotDto analysis = insertAnalysis(project, from);
- insertIssue(project, analysis);
- insertIssue(project, analysis);
+ ProjectData projectData = db.components().insertPrivateProject(p -> p.setName("SonarQube"));
+ ComponentDto mainBranchComponent = projectData.getMainBranchComponent();
+ userSession.addProjectPermission(USER, projectData.getProjectDto());
+ SnapshotDto analysis = insertAnalysis(mainBranchComponent, from);
+ insertIssue(mainBranchComponent, analysis);
+ insertIssue(mainBranchComponent, analysis);
issueIndexer.indexAllIssues();
String fromDate = formatDateTime(from - 1_000L);
SearchEventsWsResponse result = ws.newRequest()
- .setParam(PARAM_PROJECTS, project.getKey())
+ .setParam(PARAM_PROJECTS, mainBranchComponent.getKey())
.setParam(PARAM_FROM, fromDate)
.executeProtobuf(SearchEventsWsResponse.class);
assertThat(result.getEventsList()).extracting(Event::getCategory, Event::getMessage, Event::getProject, Event::getDate)
- .containsExactly(tuple("NEW_ISSUES", "You have 2 new issues on project 'SonarQube'", project.getKey(),
+ .containsExactly(tuple("NEW_ISSUES", "You have 2 new issues on project 'SonarQube'", mainBranchComponent.getKey(),
formatDateTime(from)));
}
public void return_link_to_issue_search_for_new_issues_event() {
userSession.logIn("my_login");
ComponentDto project = db.components().insertPrivateProject(p -> p.setKey("my_project")).getMainBranchComponent();
- userSession.addProjectPermission(USER, project);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project));
SnapshotDto analysis = insertAnalysis(project, 1_400_000_000_000L);
insertIssue(project, analysis);
issueIndexer.indexAllIssues();
userSession.logIn().setSystemAdministrator();
when(server.getPublicRootUrl()).thenReturn("https://sonarcloud.io");
ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
- userSession.addProjectPermission(USER, project);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project));
String branchName1 = "branch1";
ComponentDto branch1 = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH).setKey(branchName1));
SnapshotDto branch1Analysis = insertAnalysis(branch1, project.uuid(), 1_500_000_000_000L);
userSession.logIn().setSystemAdministrator();
when(server.getPublicRootUrl()).thenReturn("https://sonarcloud.io");
ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
- userSession.addProjectPermission(USER, project);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project));
String nonMainBranchName = "nonMain";
ComponentDto nonMainBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH).setKey(nonMainBranchName));
SnapshotDto nonMainBranchAnalysis = insertAnalysis(nonMainBranch, project.uuid(), 1_500_000_000_000L);
userSession.logIn("rågnar").setSystemAdministrator();
long from = 1_500_000_000_000L;
ComponentDto project = db.components().insertPrivateProject(p -> p.setKey("M&M's")).getMainBranchComponent();
- userSession.addProjectPermission(USER, project);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project));
SnapshotDto analysis = insertAnalysis(project, from);
insertIssue(project, analysis);
issueIndexer.indexAllIssues();
private static final long ANY_TIMESTAMP = 1666666666L;
- private Server server = mock(Server.class);
- private IssueIndex issueIndex = new IssueIndex(es.client(), null, userSession, null);
- private IssueIndexSyncProgressChecker issueIndexSyncProgressChecker = mock(IssueIndexSyncProgressChecker.class);
- private WsActionTester ws = new WsActionTester(new SearchEventsAction(db.getDbClient(), userSession, server, issueIndex,
+ private final Server server = mock(Server.class);
+ private final IssueIndex issueIndex = new IssueIndex(es.client(), null, userSession, null);
+ private final IssueIndexSyncProgressChecker issueIndexSyncProgressChecker = mock(IssueIndexSyncProgressChecker.class);
+ private final WsActionTester ws = new WsActionTester(new SearchEventsAction(db.getDbClient(), userSession, server, issueIndex,
issueIndexSyncProgressChecker));
@Test
public void quality_gate_events() {
when(server.getPublicRootUrl()).thenReturn("https://sonarcloud.io");
ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
- userSession.addProjectPermission(USER, project);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project));
SnapshotDto projectAnalysis = insertSuccessfulActivity(project, 1_500_000_000_000L);
db.events().insertEvent(newQualityGateEvent(projectAnalysis).setDate(projectAnalysis.getCreatedAt()).setName("Failed"));
public void branch_quality_gate_events() {
when(server.getPublicRootUrl()).thenReturn("https://sonarcloud.io");
ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
- userSession.addProjectPermission(USER, project);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project));
String branchName = randomAlphanumeric(248);
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH).setKey(branchName));
insertSuccessfulActivity(project, 1_500_000_000_000L);
@Test
public void return_only_latest_quality_gate_event() {
ComponentDto project = db.components().insertPrivateProject(p -> p.setName("My Project")).getMainBranchComponent();
- userSession.addProjectPermission(USER, project);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project));
SnapshotDto a1 = insertSuccessfulActivity(project, 1_500_000_000_000L);
EventDto e1 = db.events().insertEvent(newQualityGateEvent(a1).setName("Failed").setDate(a1.getCreatedAt()));
SnapshotDto a2 = insertSuccessfulActivity(project, 1_500_000_000_001L);
@Test
public void return_link_to_dashboard_for_quality_gate_event() {
ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
- userSession.addProjectPermission(USER, project);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project));
SnapshotDto analysis = insertSuccessfulActivity(project, 1_500_000_000_000L);
EventDto e1 = db.events().insertEvent(newQualityGateEvent(analysis).setName("Failed").setDate(analysis.getCreatedAt()));
when(server.getPublicRootUrl()).thenReturn("https://sonarcloud.io");
@Test
public void encode_link() {
ComponentDto project = db.components().insertPrivateProject(p -> p.setKey("M&M's")).getMainBranchComponent();
- userSession.addProjectPermission(USER, project);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project));
SnapshotDto analysis = insertSuccessfulActivity(project, 1_500_000_000_000L);
EventDto event = db.events().insertEvent(newQualityGateEvent(analysis).setName("Failed").setDate(analysis.getCreatedAt()));
when(server.getPublicRootUrl()).thenReturn("http://sonarcloud.io");
@Test
public void filter_quality_gate_event() {
ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
- userSession.addProjectPermission(USER, project);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project));
SnapshotDto analysis = insertSuccessfulActivity(project, 1_500_000_000_000L);
EventDto qualityGateEvent = db.events().insertEvent(newQualityGateEvent(analysis).setDate(analysis.getCreatedAt()));
EventDto versionEvent = db.events().insertEvent(newEvent(analysis).setCategory(EventCategory.VERSION.getLabel()).setDate(analysis.getCreatedAt()));
@Test
public void filter_by_from_date_inclusive() {
ComponentDto project1 = db.components().insertPrivateProject().getMainBranchComponent();
- userSession.addProjectPermission(USER, project1);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project1));
ComponentDto project2 = db.components().insertPrivateProject().getMainBranchComponent();
- userSession.addProjectPermission(USER, project2);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project2));
ComponentDto project3 = db.components().insertPrivateProject().getMainBranchComponent();
- userSession.addProjectPermission(USER, project3);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project3));
long from1 = 1_500_000_000_000L;
long from2 = 1_400_000_000_000L;
long from3 = 1_300_000_000_000L;
@Test
public void return_one_quality_gate_change_per_project() {
ComponentDto project1 = db.components().insertPrivateProject(p -> p.setName("p1")).getMainBranchComponent();
- userSession.addProjectPermission(USER, project1);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project1));
ComponentDto project2 = db.components().insertPrivateProject(p -> p.setName("p2")).getMainBranchComponent();
- userSession.addProjectPermission(USER, project2);
+ userSession.addProjectPermission(USER, db.components().getProjectDtoByMainBranch(project2));
long from = 1_500_000_000_000L;
SnapshotDto a11 = insertSuccessfulActivity(project1, from);
SnapshotDto a12 = insertSuccessfulActivity(project1, from + 1L);
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
try (DbSession dbSession = dbClient.openSession(false)) {
List<ProjectDto> authorizedProjects = searchProjects(dbSession, projectKeys);
Map<String, ProjectDto> projectsByUuid = authorizedProjects.stream().collect(uniqueIndex(ProjectDto::getUuid));
- List<UuidFromPair> uuidFromPairs = componentUuidFromPairs(fromDates, projectKeys, authorizedProjects);
- List<SnapshotDto> analyses = dbClient.snapshotDao().selectFinishedByComponentUuidsAndFromDates(dbSession, componentUuids(uuidFromPairs), fromDates(uuidFromPairs));
+ List<UuidFromPair> uuidFromPairs = buildUuidFromPairs(fromDates, projectKeys, authorizedProjects);
+ List<SnapshotDto> analyses = dbClient.snapshotDao().selectFinishedByProjectUuidsAndFromDates(dbSession, componentUuids(uuidFromPairs), fromDates(uuidFromPairs));
if (analyses.isEmpty()) {
return Stream.empty();
return link;
}
- private static List<UuidFromPair> componentUuidFromPairs(List<Long> fromDates, List<String> projectKeys, List<ProjectDto> authorizedProjects) {
+ private static List<UuidFromPair> buildUuidFromPairs(List<Long> fromDates, List<String> projectKeys, List<ProjectDto> authorizedProjects) {
checkRequest(projectKeys.size() == fromDates.size(), "The number of components (%s) and from dates (%s) must be the same.", projectKeys.size(), fromDates.size());
Map<String, Long> fromDatesByProjectKey = IntStream.range(0, projectKeys.size()).boxed()
.collect(uniqueIndex(projectKeys::get, fromDates::get));