]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20667 Add a specific event to the first analysis after a SQ upgrade
authorMatteo Mara <matteo.mara@sonarsource.com>
Thu, 5 Oct 2023 08:11:53 +0000 (10:11 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 13 Oct 2023 20:02:55 +0000 (20:02 +0000)
13 files changed:
server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/PersistEventsStepIT.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/event/Event.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistEventsStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/SqUpgradeDetectionEventsStep.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/event/EventTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/SqUpgradeDetectionEventsStepTest.java [new file with mode: 0644]
server/sonar-db-dao/src/it/java/org/sonar/db/event/EventDaoIT.java
server/sonar-db-dao/src/main/java/org/sonar/db/event/EventDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/event/EventDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/event/EventMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/event/EventMapper.xml
server/sonar-webserver-webapi/src/main/java/org/sonar/server/projectanalysis/ws/EventCategory.java

index 348b0bf02a6e8335b90e1fc5cc51e7a25194b3bd..c2b31e821a550e11b135312430238f7759c16f17 100644 (file)
@@ -34,6 +34,7 @@ import org.sonar.ce.task.projectanalysis.event.Event;
 import org.sonar.ce.task.projectanalysis.event.EventRepository;
 import org.sonar.ce.task.step.ComputationStep;
 import org.sonar.ce.task.step.TestComputationStepContext;
+import org.sonar.core.platform.SonarQubeVersion;
 import org.sonar.core.util.UuidFactory;
 import org.sonar.core.util.UuidFactoryImpl;
 import org.sonar.db.DbTester;
@@ -51,6 +52,7 @@ import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builde
 import static org.sonar.db.event.EventDto.CATEGORY_ALERT;
 import static org.sonar.db.event.EventDto.CATEGORY_ISSUE_DETECTION;
 import static org.sonar.db.event.EventDto.CATEGORY_PROFILE;
+import static org.sonar.db.event.EventDto.CATEGORY_SQ_UPGRADE;
 import static org.sonar.db.event.EventDto.CATEGORY_VERSION;
 
 public class PersistEventsStepIT extends BaseStepTest {
@@ -88,6 +90,8 @@ public class PersistEventsStepIT extends BaseStepTest {
   private final EventRepository eventRepository = mock(EventRepository.class);
   private final UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE;
 
+  private final SonarQubeVersion sonarQubeVersion = mock();
+
   private PersistEventsStep underTest;
 
   @Before
@@ -213,6 +217,33 @@ public class PersistEventsStepIT extends BaseStepTest {
     assertThat(eventDto.getCreatedAt()).isEqualTo(NOW);
   }
 
+  @Test
+  public void execute_whenSqUpgradeEventRaised_shouldPersist() {
+    when(system2.now()).thenReturn(NOW);
+    treeRootHolder.setRoot(ROOT);
+    Event sqUpgradeEvent = Event.createSqUpgrade("10.3");
+    when(eventRepository.getEvents()).thenReturn(List.of(sqUpgradeEvent));
+
+    underTest.execute(new TestComputationStepContext());
+
+    assertThat(dbTester.countRowsOfTable(dbTester.getSession(), "events")).isEqualTo(2);
+    List<EventDto> eventDtos = dbTester.getDbClient().eventDao().selectByComponentUuid(dbTester.getSession(), ROOT.getUuid());
+    assertThat(eventDtos)
+      .extracting(EventDto::getCategory)
+      .containsOnly(CATEGORY_SQ_UPGRADE, CATEGORY_VERSION);
+    EventDto eventDto = eventDtos.stream()
+      .filter(t -> CATEGORY_SQ_UPGRADE.equals(t.getCategory()))
+      .findAny()
+      .orElseGet(() -> fail("Issue detection event not found"));
+    assertThat(eventDto.getComponentUuid()).isEqualTo(ROOT.getUuid());
+    assertThat(eventDto.getName()).isEqualTo(sqUpgradeEvent.getName());
+    assertThat(eventDto.getCategory()).isEqualTo(CATEGORY_SQ_UPGRADE);
+    assertThat(eventDto.getDescription()).isNull();
+    assertThat(eventDto.getData()).isNull();
+    assertThat(eventDto.getDate()).isEqualTo(analysisMetadataHolder.getAnalysisDate());
+    assertThat(eventDto.getCreatedAt()).isEqualTo(NOW);
+  }
+
   @Test
   public void keep_one_event_by_version() {
     ComponentDto projectDto = dbTester.components().insertPublicProject().getMainBranchComponent();
index 1b2ccff2f89c67a8c297f729834158303df75467..0eed401454dd7d1ad5dccd9d5a28c38172a1a596 100644 (file)
@@ -60,6 +60,10 @@ public class Event {
     return new Event(name, Category.ISSUE_DETECTION);
   }
 
+  public static Event createSqUpgrade(String name) {
+    return new Event(name, Category.SQ_UPGRADE);
+  }
+
   public String getName() {
     return name;
   }
@@ -96,7 +100,7 @@ public class Event {
   }
 
   public enum Category {
-    ALERT, PROFILE, ISSUE_DETECTION
+    ALERT, PROFILE, ISSUE_DETECTION, SQ_UPGRADE
   }
 
 }
index 711427f678db61bafd74989f64fa8089c1f3e010..bee3402d951426c74d486dfa55fee2eb0f87582f 100644 (file)
@@ -123,6 +123,7 @@ public class PersistEventsStep implements ComputationStep {
         case ALERT -> EventDto.CATEGORY_ALERT;
         case PROFILE -> EventDto.CATEGORY_PROFILE;
         case ISSUE_DETECTION -> EventDto.CATEGORY_ISSUE_DETECTION;
+        case SQ_UPGRADE -> EventDto.CATEGORY_SQ_UPGRADE;
       };
     }
 
index 731935a5425edc6f2ac176c97db58655814a70a5..de6e12dc657e9c721ca4cc2624199daf88af8de8 100644 (file)
@@ -53,6 +53,7 @@ public class ReportComputationSteps extends AbstractComputationSteps {
 
     // Pre analysis operations
     PreMeasuresComputationChecksStep.class,
+    SqUpgradeDetectionEventsStep.class,
 
     // load project related stuffs
     LoadFileHashesAndStatusStep.class,
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/SqUpgradeDetectionEventsStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/SqUpgradeDetectionEventsStep.java
new file mode 100644 (file)
index 0000000..fbf79c0
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.ce.task.projectanalysis.step;
+
+import java.util.List;
+import org.sonar.ce.task.projectanalysis.component.Component;
+import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
+import org.sonar.ce.task.projectanalysis.event.Event;
+import org.sonar.ce.task.projectanalysis.event.EventRepository;
+import org.sonar.ce.task.step.ComputationStep;
+import org.sonar.core.platform.SonarQubeVersion;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.event.EventDto;
+
+/**
+ * Computation of SQ Upgrade events
+ */
+public class SqUpgradeDetectionEventsStep implements ComputationStep {
+  private final TreeRootHolder treeRootHolder;
+  private final DbClient dbClient;
+  private final EventRepository eventRepository;
+  private final SonarQubeVersion sonarQubeVersion;
+
+  public SqUpgradeDetectionEventsStep(TreeRootHolder treeRootHolder, DbClient dbClient,
+    EventRepository eventRepository, SonarQubeVersion sonarQubeVersion) {
+    this.treeRootHolder = treeRootHolder;
+    this.dbClient = dbClient;
+    this.eventRepository = eventRepository;
+    this.sonarQubeVersion = sonarQubeVersion;
+  }
+
+  @Override
+  public void execute(Context context) {
+    executeForBranch(treeRootHolder.getRoot());
+  }
+
+  private void executeForBranch(Component branchComponent) {
+    String currentSqVersion = sonarQubeVersion.get().toString();
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      List<EventDto> sqUpgradeEvents = dbClient.eventDao().selectSqUpgradesByMostRecentFirst(dbSession, branchComponent.getUuid());
+
+      //We don't really care about newer versions, we want to log the events related to a version change.
+      boolean isFirstAnalysisForSqVersion = sqUpgradeEvents.isEmpty() || !currentSqVersion.equals(sqUpgradeEvents.get(0).getName());
+
+      if (isFirstAnalysisForSqVersion) {
+        Event event = Event.createSqUpgrade(currentSqVersion);
+        eventRepository.add(event);
+      }
+    }
+  }
+
+  @Override
+  public String getDescription() {
+    return "Generate SQ Upgrade analysis events";
+  }
+}
index 264f14d2cc2eaf1817cb8f4547eae40105faf1b9..d8b7b9977815b2effc098daaf773316e761b2a6d 100644 (file)
@@ -68,4 +68,13 @@ public class EventTest {
       .isEqualTo(source)
       .isNotNull();
   }
+
+  @Test
+  public void createSqUpgradeEvents_verify_fields() {
+    Event event = Event.createSqUpgrade(SOME_NAME);
+    assertThat(event.getName()).isEqualTo(SOME_NAME);
+    assertThat(event.getCategory()).isEqualTo(Event.Category.SQ_UPGRADE);
+    assertThat(event.getData()).isNull();
+    assertThat(event.getDescription()).isNull();
+  }
 }
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/SqUpgradeDetectionEventsStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/SqUpgradeDetectionEventsStepTest.java
new file mode 100644 (file)
index 0000000..0eba6dd
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.ce.task.projectanalysis.step;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.sonar.api.utils.Version;
+import org.sonar.ce.task.projectanalysis.component.Component;
+import org.sonar.ce.task.projectanalysis.component.ReportComponent;
+import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
+import org.sonar.ce.task.projectanalysis.event.Event;
+import org.sonar.ce.task.projectanalysis.event.EventRepository;
+import org.sonar.ce.task.step.TestComputationStepContext;
+import org.sonar.core.platform.SonarQubeVersion;
+import org.sonar.db.DbClient;
+import org.sonar.db.event.EventDto;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.groups.Tuple.tuple;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class SqUpgradeDetectionEventsStepTest {
+
+  @Rule
+  public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
+  private final DbClient dbClient = mock();
+  private final EventRepository eventRepository = mock();
+
+  private final ArgumentCaptor<Event> eventArgumentCaptor = ArgumentCaptor.forClass(Event.class);
+
+  private final SonarQubeVersion sonarQubeVersion = mock();
+
+  private final SqUpgradeDetectionEventsStep underTest = new SqUpgradeDetectionEventsStep(treeRootHolder, dbClient, eventRepository, sonarQubeVersion);
+
+  @Before
+  public void setUp() {
+    treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("uuid").setKey("key").build());
+  }
+
+  @Test
+  public void givenNoPreviousUpgradeEvents_whenStepIsExecuted_thenANewUpgradeEventIsCreated() {
+    when(sonarQubeVersion.get()).thenReturn(Version.parse("10.3"));
+    when(dbClient.eventDao()).thenReturn(mock());
+    when(dbClient.eventDao().selectSqUpgradesByMostRecentFirst(any(), any())).thenReturn(Collections.emptyList());
+
+    underTest.execute(new TestComputationStepContext());
+
+    verify(eventRepository, times(1)).add(eventArgumentCaptor.capture());
+    verifyNoMoreInteractions(eventRepository);
+
+    assertThat(eventArgumentCaptor.getAllValues())
+      .extracting(Event::getCategory, Event::getName)
+      .containsExactly(tuple(Event.Category.SQ_UPGRADE, "10.3"));
+  }
+
+  @Test
+  public void givenUpgradeEventWithTheSameSqVersion_whenStepIsExecuted_thenNothingIsPersisted() {
+    when(sonarQubeVersion.get()).thenReturn(Version.parse("10.3"));
+    when(dbClient.eventDao()).thenReturn(mock());
+    when(dbClient.eventDao().selectSqUpgradesByMostRecentFirst(any(), any())).thenReturn(getUpgradeEvents("10.3", "10.2"));
+
+    underTest.execute(new TestComputationStepContext());
+
+    verifyNoMoreInteractions(eventRepository);
+  }
+
+  private List<EventDto> getUpgradeEvents(String... versions) {
+    return Arrays.stream(versions)
+      .map(version -> new EventDto().setCategory(EventDto.CATEGORY_SQ_UPGRADE).setName(version))
+      .toList();
+  }
+
+  @Test
+  public void givenUpgradeEventWithDifferentSqVersion_whenStepIsExecuted_thenANewUpgradeEventIsCreated() {
+    when(sonarQubeVersion.get()).thenReturn(Version.parse("10.3"));
+    when(dbClient.eventDao()).thenReturn(mock());
+    when(dbClient.eventDao().selectSqUpgradesByMostRecentFirst(any(), any())).thenReturn(getUpgradeEvents("10.2", "10.1"));
+
+    underTest.execute(new TestComputationStepContext());
+
+    verify(eventRepository, times(1)).add(eventArgumentCaptor.capture());
+    verifyNoMoreInteractions(eventRepository);
+
+    assertThat(eventArgumentCaptor.getAllValues())
+      .extracting(Event::getCategory, Event::getName)
+      .containsExactly(tuple(Event.Category.SQ_UPGRADE, "10.3"));
+  }
+
+  @Test
+  public void whenGetDescriptionIsCalled_shouldReturnExpectedValue() {
+    assertThat(underTest.getDescription()).isEqualTo("Generate SQ Upgrade analysis events");
+  }
+
+}
index 3501b5dcf2dd2b68b5b02f805dd79496b38a8d45..05d57208c361195bda799320a16a85d62a809829 100644 (file)
@@ -199,6 +199,24 @@ public class EventDaoIT {
     assertThat(result.getDescription()).isEqualTo("New Description");
   }
 
+  @Test
+  public void givenSomeSqUpgradeEvents_whenRetrieved_shouldReturnCorrectlyOrderedByDateDescending() {
+    long olderDate = 1L;
+    long newerDate = 2L;
+
+    ComponentDto componentDto = ComponentTesting.newPrivateProjectDto();
+    SnapshotDto analysis = dbTester.components().insertProjectAndSnapshot(componentDto);
+    dbTester.events().insertEvent(newEvent(analysis).setCategory(EventDto.CATEGORY_SQ_UPGRADE).setDate(olderDate).setUuid("E1"));
+    dbTester.events().insertEvent(newEvent(analysis).setCategory(EventDto.CATEGORY_SQ_UPGRADE).setDate(newerDate).setUuid("E2"));
+
+    List<EventDto> events = underTest.selectSqUpgradesByMostRecentFirst(dbSession, componentDto.uuid());
+    assertThat(events).hasSize(2);
+    assertThat(events.get(0).getUuid()).isEqualTo("E2");
+    assertThat(events.get(0).getDate()).isEqualTo(newerDate);
+    assertThat(events.get(1).getUuid()).isEqualTo("E1");
+    assertThat(events.get(1).getDate()).isEqualTo(olderDate);
+  }
+
   @Test
   public void delete_by_uuid() {
     dbTester.events().insertEvent(newEvent(newAnalysis(ComponentTesting.newPrivateProjectDto())).setUuid("E1"));
index 49f2d0cf2a181348a76b29ff53befdb1ca686756..598c73e1ff449de246258dc906ac0ad0b64d8295 100644 (file)
@@ -49,6 +49,10 @@ public class EventDao implements Dao {
     return mapper(session).selectVersions(componentUuid);
   }
 
+  public List<EventDto> selectSqUpgradesByMostRecentFirst(DbSession session, String componentUuid) {
+    return mapper(session).selectSqUpgrades(componentUuid);
+  }
+
   public EventDto insert(DbSession session, EventDto dto) {
     mapper(session).insert(dto);
 
index c03d11d7cf62320d9447f23b4da3238d53b60b2c..e54ded6a98e76e38c59b6f9db243fc1383954d51 100644 (file)
@@ -33,6 +33,7 @@ public class EventDto {
   public static final String CATEGORY_PROFILE = "Profile";
   public static final String CATEGORY_DEFINITION_CHANGE = "Definition change";
   public static final String CATEGORY_ISSUE_DETECTION = "Issue Detection";
+  public static final String CATEGORY_SQ_UPGRADE = "SQ Upgrade";
   private String uuid;
   private String analysisUuid;
   private String componentUuid;
index ddb8becc86fd83ae18156a2afe307becbe5b663d..63c18c821c46b92979448143566a5fa5734f1ba8 100644 (file)
@@ -35,6 +35,8 @@ public interface EventMapper {
 
   List<EventDto> selectVersions(@Param("componentUuid") String componentUuid);
 
+  List<EventDto> selectSqUpgrades(@Param("componentUuid") String componentUuid);
+
   void insert(EventDto dto);
 
   void update(@Param("uuid") String uuid, @Param("name") @Nullable String name, @Param("description") @Nullable String description);
index c367b2a7d0751b8fc26bd3ba88a6c486abb9b7e7..e5ada5f0c30af52f2647cbb3022416765d211603 100644 (file)
       e.event_date desc
   </select>
 
+    <select id="selectSqUpgrades" resultType="Event" parameterType="map">
+    select
+      <include refid="eventColumns"/>
+    from events e
+    inner join snapshots s on
+      s.uuid = e.analysis_uuid
+      and s.status = 'P'
+      and s.root_component_uuid = #{componentUuid,jdbcType=VARCHAR}
+    where
+      e.category = 'SQ Upgrade'
+    order by
+      e.event_date desc
+  </select>
+
   <insert id="insert" parameterType="Event">
     INSERT INTO events (uuid, analysis_uuid, component_uuid, name, category, description, event_data, event_date, created_at)
     VALUES (
index 1e3371820e116031705e9a2c809097f4e70bbb7d..77c506e9d7cac7d09806d8adb4ef606cb507c7be 100644 (file)
@@ -25,7 +25,8 @@ public enum EventCategory {
   QUALITY_PROFILE("Profile"),
   QUALITY_GATE("Alert"),
   DEFINITION_CHANGE("Definition change"),
-  ISSUE_DETECTION("Issue Detection");
+  ISSUE_DETECTION("Issue Detection"),
+  SQ_UPGRADE("SQ Upgrade");
 
   private final String label;