Browse Source

SONAR-6261 Persist events in compute stack

tags/5.2-RC1
Julien Lancelot 9 years ago
parent
commit
7485c34dea
62 changed files with 2964 additions and 151 deletions
  1. 2
    2
      plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/events.html.erb
  2. 1
    1
      plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/timeline.html.erb
  3. 129
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistEventsStep.java
  4. 7
    0
      server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java
  5. 3
    1
      server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrations.java
  6. 55
    0
      server/sonar-server/src/main/java/org/sonar/server/db/migrations/v52/FeedEventsComponentUuid.java
  7. 45
    0
      server/sonar-server/src/main/java/org/sonar/server/event/db/EventDao.java
  8. 24
    0
      server/sonar-server/src/main/java/org/sonar/server/event/db/package-info.java
  9. 193
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistEventsStepTest.java
  10. 63
    0
      server/sonar-server/src/test/java/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest.java
  11. 117
    0
      server/sonar-server/src/test/java/org/sonar/server/event/db/EventDaoTest.java
  12. 10
    0
      server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/add_events-result.xml
  13. 6
    0
      server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/add_version_event-result.xml
  14. 3
    0
      server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/empty.xml
  15. 14
    0
      server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/keep_one_event_by_version-result.xml
  16. 10
    0
      server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/keep_one_event_by_version.xml
  17. 13
    0
      server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/nothing_to_do_when_no_events_in_report.xml
  18. 5
    0
      server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/migrate-result.xml
  19. 11
    0
      server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/migrate.xml
  20. 11
    0
      server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/not_migrate_already_migrated_data.xml
  21. 35
    0
      server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/schema.sql
  22. 6
    0
      server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/delete.xml
  23. 3
    0
      server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/empty.xml
  24. 6
    0
      server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/insert-result.xml
  25. 13
    0
      server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/shared.xml
  26. 25
    7
      server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/events_controller.rb
  27. 6
    6
      server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_controller.rb
  28. 1
    1
      server/sonar-web/src/main/webapp/WEB-INF/app/models/event.rb
  29. 1
    1
      server/sonar-web/src/main/webapp/WEB-INF/app/models/project.rb
  30. 32
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/903_add_events_component_uuid.rb
  31. 31
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/904_feed_events_component_uuid.rb
  32. 32
    0
      server/sonar-web/src/main/webapp/WEB-INF/db/migrate/905_remove_events_resource_id.rb
  33. 92
    4
      sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/Constants.java
  34. 1611
    68
      sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/output/BatchReport.java
  35. 13
    1
      sonar-batch-protocol/src/main/protobuf/batch_report.proto
  36. 6
    0
      sonar-batch-protocol/src/main/protobuf/constants.proto
  37. 3
    4
      sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersion.java
  38. 3
    2
      sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java
  39. 5
    5
      sonar-batch/src/test/resources/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersionTest/no-previous-version.xml
  40. 7
    7
      sonar-batch/src/test/resources/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersionTest/with-previous-version-deleted.xml
  41. 7
    7
      sonar-batch/src/test/resources/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersionTest/with-previous-version.xml
  42. 132
    0
      sonar-core/src/main/java/org/sonar/core/event/EventDto.java
  43. 35
    0
      sonar-core/src/main/java/org/sonar/core/event/db/EventMapper.java
  44. 24
    0
      sonar-core/src/main/java/org/sonar/core/event/db/package-info.java
  45. 24
    0
      sonar-core/src/main/java/org/sonar/core/event/package-info.java
  46. 1
    1
      sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
  47. 4
    1
      sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
  48. 3
    3
      sonar-core/src/main/java/org/sonar/core/purge/PurgeCommands.java
  49. 1
    1
      sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java
  50. 35
    0
      sonar-core/src/main/resources/org/sonar/core/event/db/EventMapper.xml
  51. 3
    0
      sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
  52. 2
    2
      sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl
  53. 4
    4
      sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml
  54. 3
    3
      sonar-core/src/test/resources/org/sonar/core/persistence/PreviewDatabaseFactoryTest/should_create_database.xml
  55. 1
    1
      sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldDeleteResource.xml
  56. 1
    1
      sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldDeleteSnapshot-result.xml
  57. 2
    2
      sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldDeleteSnapshot.xml
  58. 2
    2
      sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldPurgeSnapshot-result.xml
  59. 2
    2
      sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldPurgeSnapshot.xml
  60. 1
    1
      sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldSelectPurgeableSnapshots.xml
  61. 22
    9
      sonar-plugin-api/src/main/java/org/sonar/api/batch/Event.java
  62. 2
    1
      sonar-plugin-api/src/main/java/org/sonar/api/database/model/ResourceModel.java

+ 2
- 2
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/events.html.erb View File

@@ -1,8 +1,8 @@
<%
if @resource.scope=='PRJ'

conditions = "resource_id=:resource_id"
values = {:resource_id => @resource.id}
conditions = "component_uuid=:component_uuid"
values = {:component_uuid => @resource.uuid}
# in order to not display events linked to deleted snapshot, we build the SQL request with 'NOT IN' as most of the time, there won't be unprocessed snapshots
snapshots_to_be_deleted = Snapshot.find(:all, :conditions => ["status='U' AND project_id=?", @resource.id])
unless snapshots_to_be_deleted.empty?

+ 1
- 1
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/timeline.html.erb View File

@@ -101,7 +101,7 @@
from_date = first_date if !from_date || from_date > first_date
end
end
Event.find(:all, :conditions => ["resource_id=? AND event_date>=?", @resource.id, from_date.to_i*1000], :order => 'event_date').each() do |event|
Event.find(:all, :conditions => ["component_uuid=? AND event_date>=?", @resource.uuid, from_date.to_i*1000], :order => 'event_date').each() do |event|
if events[event.event_date]
events[event.event_date] << event
else

+ 129
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistEventsStep.java View File

@@ -0,0 +1,129 @@
/*
* 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.step;

import org.sonar.api.resources.Qualifiers;
import org.sonar.api.utils.System2;
import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReportReader;
import org.sonar.core.event.EventDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
import org.sonar.server.computation.ComputationContext;
import org.sonar.server.db.DbClient;

import java.util.List;

public class PersistEventsStep implements ComputationStep {

private final DbClient dbClient;
private final System2 system2;

public PersistEventsStep(DbClient dbClient, System2 system2) {
this.dbClient = dbClient;
this.system2 = system2;
}

@Override
public String[] supportedProjectQualifiers() {
return new String[] {Qualifiers.PROJECT};
}

@Override
public void execute(ComputationContext context) {
DbSession session = dbClient.openSession(false);
try {
int rootComponentRef = context.getReportMetadata().getRootComponentRef();
recursivelyProcessComponent(session, context, rootComponentRef);
session.commit();
} finally {
MyBatis.closeQuietly(session);
}
}

private void recursivelyProcessComponent(DbSession session, ComputationContext context, int componentRef) {
BatchReportReader reportReader = context.getReportReader();
BatchReport.Component component = reportReader.readComponent(componentRef);
processEvents(session, component, context.getReportMetadata().getAnalysisDate());
createVersionEvent(session, component, context.getReportMetadata().getAnalysisDate());

for (Integer childRef : component.getChildRefsList()) {
recursivelyProcessComponent(session, context, childRef);
}
}

private void processEvents(DbSession session, BatchReport.Component component, Long analysisDate) {
List<BatchReport.Event> events = component.getEventsList();
if (!events.isEmpty()) {
for (BatchReport.Event event : component.getEventsList()) {
dbClient.eventDao().insert(session, createBaseEvent(component, analysisDate)
.setName(event.getName())
.setCategory(convertCategory(event.getCategory()))
.setDescription(event.hasDescription() ? event.getDescription() : null)
.setData(event.hasEventData() ? event.getEventData() : null)
);
}
}
}

private void createVersionEvent(DbSession session, BatchReport.Component component, Long analysisDate) {
if (component.hasVersion()) {
deletePreviousEventsHavingSameVersion(session, component);
dbClient.eventDao().insert(session, createBaseEvent(component, analysisDate)
.setName(component.getVersion())
.setCategory(EventDto.CATEGORY_VERSION)
);
}
}

private void deletePreviousEventsHavingSameVersion(DbSession session, BatchReport.Component component){
for (EventDto dto : dbClient.eventDao().selectByComponentUuid(session, component.getUuid())) {
if (dto.getCategory().equals(EventDto.CATEGORY_VERSION) && dto.getName().equals(component.getVersion())) {
dbClient.eventDao().delete(session, dto.getId());
}
}
}

private EventDto createBaseEvent(BatchReport.Component component, Long analysisDate) {
return new EventDto()
.setComponentUuid(component.getUuid())
.setSnapshotId(component.getSnapshotId())
.setCreatedAt(system2.now())
.setDate(analysisDate);
}

private static String convertCategory(Constants.EventCategory category) {
switch (category) {
case ALERT:
return EventDto.CATEGORY_ALERT;
case PROFILE:
return EventDto.CATEGORY_PROFILE;
default:
throw new IllegalArgumentException(String.format("Unsupported category %s", category.name()));
}
}

@Override
public String getDescription() {
return "Persist component links";
}
}

+ 7
- 0
server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java View File

@@ -43,6 +43,7 @@ import org.sonar.server.computation.db.AnalysisReportDao;
import org.sonar.server.dashboard.db.DashboardDao;
import org.sonar.server.dashboard.db.WidgetDao;
import org.sonar.server.dashboard.db.WidgetPropertyDao;
import org.sonar.server.event.db.EventDao;
import org.sonar.server.issue.db.IssueDao;
import org.sonar.server.measure.persistence.MeasureDao;
import org.sonar.server.measure.persistence.MetricDao;
@@ -91,6 +92,7 @@ public class DbClient implements ServerComponent {
private final AuthorDao authorDao;
private final ComponentIndexDao componentIndexDao;
private final ComponentLinkDao componentLinkDao;
private final EventDao eventDao;

public DbClient(Database db, MyBatis myBatis, DaoComponent... daoComponents) {
this.db = db;
@@ -126,6 +128,7 @@ public class DbClient implements ServerComponent {
authorDao = getDao(map, AuthorDao.class);
componentIndexDao = getDao(map, ComponentIndexDao.class);
componentLinkDao = getDao(map, ComponentLinkDao.class);
eventDao = getDao(map, EventDao.class);
}

public Database database() {
@@ -240,6 +243,10 @@ public class DbClient implements ServerComponent {
return componentLinkDao;
}

public EventDao eventDao() {
return eventDao;
}

private <K> K getDao(Map<Class, DaoComponent> map, Class<K> clazz) {
return (K) map.get(clazz);
}

+ 3
- 1
server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrations.java View File

@@ -31,6 +31,7 @@ import org.sonar.server.db.migrations.v451.AddMissingCustomRuleParametersMigrati
import org.sonar.server.db.migrations.v451.DeleteUnescapedActivities;
import org.sonar.server.db.migrations.v50.*;
import org.sonar.server.db.migrations.v51.*;
import org.sonar.server.db.migrations.v52.FeedEventsComponentUuid;
import org.sonar.server.db.migrations.v52.FeedProjectLinksComponentUuid;

import java.util.List;
@@ -97,6 +98,7 @@ public interface DatabaseMigrations {
RemovePermissionsOnModulesMigration.class,

// 5.2
FeedProjectLinksComponentUuid.class
FeedProjectLinksComponentUuid.class,
FeedEventsComponentUuid.class
);
}

+ 55
- 0
server/sonar-server/src/main/java/org/sonar/server/db/migrations/v52/FeedEventsComponentUuid.java View File

@@ -0,0 +1,55 @@
/*
* 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.db.migrations.v52;

import org.sonar.core.persistence.Database;
import org.sonar.server.db.migrations.BaseDataChange;
import org.sonar.server.db.migrations.MassUpdate;
import org.sonar.server.db.migrations.Select;
import org.sonar.server.db.migrations.SqlStatement;

import java.sql.SQLException;

public class FeedEventsComponentUuid extends BaseDataChange {

public FeedEventsComponentUuid(Database db) {
super(db);
}

@Override
public void execute(Context context) throws SQLException {
MassUpdate update = context.prepareMassUpdate().rowPluralName("events");
update.select(
"SELECT p.uuid, event.id " +
"FROM events event " +
"INNER JOIN projects p ON p.id=event.resource_id " +
"WHERE event.component_uuid is null");
update.update("UPDATE events SET component_uuid=? WHERE id=?");
update.execute(new MassUpdate.Handler() {
@Override
public boolean handle(Select.Row row, SqlStatement update) throws SQLException {
update.setString(1, row.getString(1));
update.setLong(2, row.getLong(2));
return true;
}
});
}
}

+ 45
- 0
server/sonar-server/src/main/java/org/sonar/server/event/db/EventDao.java View File

@@ -0,0 +1,45 @@
/*
* 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.event.db;

import org.sonar.api.ServerComponent;
import org.sonar.core.event.EventDto;
import org.sonar.core.event.db.EventMapper;
import org.sonar.core.persistence.DaoComponent;
import org.sonar.core.persistence.DbSession;

import java.util.List;

public class EventDao implements ServerComponent, DaoComponent {

public List<EventDto> selectByComponentUuid(DbSession session, String componentUuid) {
return session.getMapper(EventMapper.class).selectByComponentUuid(componentUuid);
}

public void insert(DbSession session, EventDto dto) {
session.getMapper(EventMapper.class).insert(dto);
}

public void delete(DbSession session, Long id) {
session.getMapper(EventMapper.class).delete(id);
}

}

+ 24
- 0
server/sonar-server/src/main/java/org/sonar/server/event/db/package-info.java View File

@@ -0,0 +1,24 @@
/*
* 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.server.event.db;

import javax.annotation.ParametersAreNonnullByDefault;

+ 193
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistEventsStepTest.java View File

@@ -0,0 +1,193 @@
/*
* 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.step;

import org.junit.*;
import org.junit.experimental.categories.Category;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.utils.System2;
import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReportReader;
import org.sonar.batch.protocol.output.BatchReportWriter;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.DbTester;
import org.sonar.server.computation.ComputationContext;
import org.sonar.server.db.DbClient;
import org.sonar.server.event.db.EventDao;
import org.sonar.test.DbTests;

import java.io.File;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@Category(DbTests.class)
public class PersistEventsStepTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@ClassRule
public static DbTester dbTester = new DbTester();

DbSession session;

EventDao dao;

System2 system2;

PersistEventsStep step;

@Before
public void setup() throws Exception {
session = dbTester.myBatis().openSession(false);
dao = new EventDao();
DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), dao);

system2 = mock(System2.class);
when(system2.now()).thenReturn(1225630680000L);

step = new PersistEventsStep(dbClient, system2);
}

@After
public void tearDown() throws Exception {
session.close();
}

@Test
public void execute_only_on_projects() throws Exception {
assertThat(step.supportedProjectQualifiers()).containsOnly("TRK");
}

@Test
public void nothing_to_do_when_no_events_in_report() throws Exception {
dbTester.prepareDbUnit(getClass(), "nothing_to_do_when_no_events_in_report.xml");

File reportDir = temp.newFolder();
BatchReportWriter writer = new BatchReportWriter(reportDir);
writer.writeMetadata(BatchReport.Metadata.newBuilder()
.setRootComponentRef(1)
.setProjectKey("PROJECT_KEY")
.setAnalysisDate(150000000L)
.build());

writer.writeComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
.setUuid("ABCD")
.build());

step.execute(new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)));

dbTester.assertDbUnit(getClass(), "nothing_to_do_when_no_events_in_report.xml", "events");
}

@Test
public void persist_report_events() throws Exception {
dbTester.prepareDbUnit(getClass(), "empty.xml");

File reportDir = temp.newFolder();
BatchReportWriter writer = new BatchReportWriter(reportDir);
writer.writeMetadata(BatchReport.Metadata.newBuilder()
.setRootComponentRef(1)
.setProjectKey("PROJECT_KEY")
.setAnalysisDate(150000000L)
.build());

writer.writeComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
.setUuid("ABCD")
.setSnapshotId(1000L)
.addEvents(BatchReport.Event.newBuilder()
.setName("Red (was Orange)")
.setCategory(Constants.EventCategory.ALERT)
.setDescription("Open issues > 0")
.build()
)
.addEvents(BatchReport.Event.newBuilder()
.setName("Changes in 'Default' (Java)")
.setCategory(Constants.EventCategory.PROFILE)
.setEventData("from=2014-10-12T08:36:25+0000;key=java-default;to=2014-10-12T10:36:25+0000")
.build()
)
.build());

step.execute(new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)));

dbTester.assertDbUnit(getClass(), "add_events-result.xml", "events");
}

@Test
public void create_version_event() throws Exception {
dbTester.prepareDbUnit(getClass(), "empty.xml");

File reportDir = temp.newFolder();
BatchReportWriter writer = new BatchReportWriter(reportDir);
writer.writeMetadata(BatchReport.Metadata.newBuilder()
.setRootComponentRef(1)
.setProjectKey("PROJECT_KEY")
.setAnalysisDate(150000000L)
.build());

writer.writeComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
.setUuid("ABCD")
.setSnapshotId(1000L)
.setVersion("1.0")
.build());

step.execute(new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)));

dbTester.assertDbUnit(getClass(), "add_version_event-result.xml", "events");
}

@Test
public void keep_one_event_by_version() throws Exception {
dbTester.prepareDbUnit(getClass(), "keep_one_event_by_version.xml");

File reportDir = temp.newFolder();
BatchReportWriter writer = new BatchReportWriter(reportDir);
writer.writeMetadata(BatchReport.Metadata.newBuilder()
.setRootComponentRef(1)
.setProjectKey("PROJECT_KEY")
.setAnalysisDate(150000000L)
.build());

writer.writeComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
.setUuid("ABCD")
.setSnapshotId(1001L)
.setVersion("1.5-SNAPSHOT")
.build());

step.execute(new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)));

dbTester.assertDbUnit(getClass(), "keep_one_event_by_version-result.xml", "events");
}

}

+ 63
- 0
server/sonar-server/src/test/java/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest.java View File

@@ -0,0 +1,63 @@
/*
* 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.db.migrations.v52;

import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.sonar.core.persistence.DbTester;
import org.sonar.server.db.migrations.DatabaseMigration;

public class FeedEventsComponentUuidTest {

@ClassRule
public static DbTester db = new DbTester().schema(FeedEventsComponentUuidTest.class, "schema.sql");

DatabaseMigration migration;

@Before
public void setUp() throws Exception {
db.executeUpdateSql("truncate table events");
db.executeUpdateSql("truncate table projects");

migration = new FeedEventsComponentUuid(db.database());
}

@Test
public void migrate_empty_db() throws Exception {
migration.execute();
}

@Test
public void migrate() throws Exception {
db.prepareDbUnit(this.getClass(), "migrate.xml");
migration.execute();
db.assertDbUnit(this.getClass(), "migrate-result.xml", "events");
}

@Test
public void not_migrate_already_migrated_data() throws Exception {
db.prepareDbUnit(this.getClass(), "not_migrate_already_migrated_data.xml");
migration.execute();
db.assertDbUnit(this.getClass(), "not_migrate_already_migrated_data.xml", "events");
}

}

+ 117
- 0
server/sonar-server/src/test/java/org/sonar/server/event/db/EventDaoTest.java View File

@@ -0,0 +1,117 @@
/*
* 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.event.db;

import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.sonar.core.event.EventDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.DbTester;
import org.sonar.test.DbTests;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@Category(DbTests.class)
public class EventDaoTest {

@ClassRule
public static DbTester dbTester = new DbTester();

DbSession session;

EventDao dao;

@Before
public void setup() throws Exception {
session = dbTester.myBatis().openSession(false);
dao = new EventDao();
}

@After
public void tearDown() throws Exception {
session.close();
}

@Test
public void select_by_component_uuid() throws Exception {
dbTester.prepareDbUnit(getClass(), "shared.xml");

List<EventDto> dtos = dao.selectByComponentUuid(session, "ABCD");
assertThat(dtos).hasSize(3);

dtos = dao.selectByComponentUuid(session, "BCDE");
assertThat(dtos).hasSize(1);

EventDto dto = dtos.get(0);
assertThat(dto.getId()).isEqualTo(4L);
assertThat(dto.getComponentUuid()).isEqualTo("BCDE");
assertThat(dto.getSnapshotId()).isEqualTo(1000L);
assertThat(dto.getName()).isEqualTo("1.0");
assertThat(dto.getCategory()).isEqualTo("Version");
assertThat(dto.getDescription()).isEqualTo("Version 1.0");
assertThat(dto.getData()).isEqualTo("some data");
assertThat(dto.getDate()).isEqualTo(1413407091086L);
assertThat(dto.getCreatedAt()).isEqualTo(1225630680000L);
}

@Test
public void return_different_categories() throws Exception {
dbTester.prepareDbUnit(getClass(), "shared.xml");

List<EventDto> dtos = dao.selectByComponentUuid(session, "ABCD");
assertThat(dtos).extracting("category").containsOnly(EventDto.CATEGORY_ALERT, EventDto.CATEGORY_PROFILE, EventDto.CATEGORY_VERSION);
}

@Test
public void insert() throws Exception {
dbTester.prepareDbUnit(getClass(), "empty.xml");

dao.insert(session, new EventDto()
.setName("1.0")
.setCategory(EventDto.CATEGORY_VERSION)
.setDescription("Version 1.0")
.setData("some data")
.setDate(1413407091086L)
.setComponentUuid("ABCD")
.setSnapshotId(1000L)
.setCreatedAt(1225630680000L)
);
session.commit();

dbTester.assertDbUnit(getClass(), "insert-result.xml", "events");
}

@Test
public void delete() throws Exception {
dbTester.prepareDbUnit(getClass(), "delete.xml");

dao.delete(session, 1L);
session.commit();

assertThat(dbTester.countRowsOfTable("events")).isEqualTo(0);
}

}

+ 10
- 0
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/add_events-result.xml View File

@@ -0,0 +1,10 @@
<dataset>

<events id="1" name="Red (was Orange)" category="Alert" description="Open issues > 0"
event_data="[null]"
event_date="150000000" component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
<events id="2" name="Changes in 'Default' (Java)" category="Profile" description="[null]"
event_data="from=2014-10-12T08:36:25+0000;key=java-default;to=2014-10-12T10:36:25+0000"
event_date="150000000" component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />

</dataset>

+ 6
- 0
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/add_version_event-result.xml View File

@@ -0,0 +1,6 @@
<dataset>

<events id="1" name="1.0" category="Version" description="[null]" event_data="[null]" event_date="150000000"
component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />

</dataset>

+ 3
- 0
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/empty.xml View File

@@ -0,0 +1,3 @@
<dataset>

</dataset>

+ 14
- 0
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/keep_one_event_by_version-result.xml View File

@@ -0,0 +1,14 @@
<dataset>

<events id="1" name="1.3-SNAPSHOT" category="Version" description="[null]" event_data="[null]" event_date="120000000"
component_uuid="ABCD" snapshot_id="1000" created_at="120000000" />
<events id="2" name="1.4" category="Version" description="[null]" event_data="[null]" event_date="130000000"
component_uuid="ABCD" snapshot_id="1000" created_at="130000000" />
<!-- Has been removed -->
<!--<events id="3" name="1.5-SNAPSHOT" category="Version" description="[null]" event_data="[null]" event_date="140000000"-->
<!--component_uuid="ABCD" snapshot_id="1000" created_at="140000000" />-->

<events id="4" name="1.5-SNAPSHOT" category="Version" description="[null]" event_data="[null]" event_date="150000000"
component_uuid="ABCD" snapshot_id="1001" created_at="1225630680000" />

</dataset>

+ 10
- 0
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/keep_one_event_by_version.xml View File

@@ -0,0 +1,10 @@
<dataset>

<events id="1" name="1.3-SNAPSHOT" category="Version" description="[null]" event_data="[null]" event_date="120000000"
component_uuid="ABCD" snapshot_id="1000" created_at="120000000" />
<events id="2" name="1.4" category="Version" description="[null]" event_data="[null]" event_date="130000000"
component_uuid="ABCD" snapshot_id="1000" created_at="130000000" />
<events id="3" name="1.5-SNAPSHOT" category="Version" description="[null]" event_data="[null]" event_date="140000000"
component_uuid="ABCD" snapshot_id="1000" created_at="140000000" />

</dataset>

+ 13
- 0
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/nothing_to_do_when_no_events_in_report.xml View File

@@ -0,0 +1,13 @@
<dataset>

<events id="1" name="1.0" category="Version" description="Version 1.0" event_data="some data" event_date="1413407091086"
component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
<events id="2" name="Red (was Orange)" category="Alert" description="Critical issues variation > 0 since previous version (1.0 - 2015 Feb 09), Open issues > 0"
event_data="[null]" event_date="1413407091086" component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
<events id="3" name="Changes in 'Default' (Java)" category="Profile" description="Version 1.0" event_data="from=2014-10-12T08:36:25+0000;key=java-default;to=2014-10-12T10:36:25+0000"
event_date="1413407091086" component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />

<events id="4" name="1.0" category="Version" description="Version 1.0" event_data="some data" event_date="1413407091086"
component_uuid="BCDE" snapshot_id="1000" created_at="1225630680000" />

</dataset>

+ 5
- 0
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/migrate-result.xml View File

@@ -0,0 +1,5 @@
<dataset>

<events id="1" name="1.0" resource_id="1" component_uuid="ABCD" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description="" event_data="[null]"/>

</dataset>

+ 11
- 0
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/migrate.xml View File

@@ -0,0 +1,11 @@
<dataset>

<projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts" deprecated_kee="org.struts:struts"
uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=""
description="the description" long_name="Apache Struts"
enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]"
created_at="2008-12-02 13:58:00.00" authorization_updated_at="[null]"/>

<events id="1" name="1.0" resource_id="1" component_uuid="[null]" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description="" event_data="[null]"/>

</dataset>

+ 11
- 0
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/not_migrate_already_migrated_data.xml View File

@@ -0,0 +1,11 @@
<dataset>

<projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts" deprecated_kee="org.struts:struts"
uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=""
description="the description" long_name="Apache Struts"
enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]"
created_at="2008-12-02 13:58:00.00" authorization_updated_at="[null]"/>

<events id="1" name="1.0" resource_id="1" component_uuid="ABCD" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description="" event_data="[null]"/>

</dataset>

+ 35
- 0
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/schema.sql View File

@@ -0,0 +1,35 @@
CREATE TABLE "PROJECTS" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"KEE" VARCHAR(400),
"ROOT_ID" INTEGER,
"UUID" VARCHAR(50),
"PROJECT_UUID" VARCHAR(50),
"MODULE_UUID" VARCHAR(50),
"MODULE_UUID_PATH" VARCHAR(4000),
"NAME" VARCHAR(256),
"DESCRIPTION" VARCHAR(2000),
"ENABLED" BOOLEAN NOT NULL DEFAULT TRUE,
"SCOPE" VARCHAR(3),
"QUALIFIER" VARCHAR(10),
"DEPRECATED_KEE" VARCHAR(400),
"PATH" VARCHAR(2000),
"LANGUAGE" VARCHAR(20),
"COPY_RESOURCE_ID" INTEGER,
"LONG_NAME" VARCHAR(256),
"PERSON_ID" INTEGER,
"CREATED_AT" TIMESTAMP,
"AUTHORIZATION_UPDATED_AT" BIGINT
);

CREATE TABLE "EVENTS" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"NAME" VARCHAR(400),
"RESOURCE_ID" INTEGER,
"COMPONENT_UUID" VARCHAR(50),
"SNAPSHOT_ID" INTEGER,
"CATEGORY" VARCHAR(50),
"EVENT_DATE" BIGINT NOT NULL,
"CREATED_AT" BIGINT NOT NULL,
"DESCRIPTION" VARCHAR(4000),
"EVENT_DATA" VARCHAR(4000)
);

+ 6
- 0
server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/delete.xml View File

@@ -0,0 +1,6 @@
<dataset>

<events id="1" name="1.0" category="Version" description="Version 1.0" event_data="some data" event_date="1225630680000"
component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />

</dataset>

+ 3
- 0
server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/empty.xml View File

@@ -0,0 +1,3 @@
<dataset>

</dataset>

+ 6
- 0
server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/insert-result.xml View File

@@ -0,0 +1,6 @@
<dataset>

<events id="1" name="1.0" category="Version" description="Version 1.0" event_data="some data" event_date="1413407091086"
component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />

</dataset>

+ 13
- 0
server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/shared.xml View File

@@ -0,0 +1,13 @@
<dataset>

<events id="1" name="1.0" category="Version" description="Version 1.0" event_data="some data" event_date="1413407091086"
component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
<events id="2" name="Red (was Orange)" category="Alert" description="Critical issues variation > 0 since previous version (1.0 - 2015 Feb 09), Open issues > 0"
event_data="[null]" event_date="1413407091086" component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
<events id="3" name="Changes in 'Default' (Java)" category="Profile" description="Version 1.0" event_data="from=2014-10-12T08:36:25+0000;key=java-default;to=2014-10-12T10:36:25+0000"
event_date="1413407091086" component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />

<events id="4" name="1.0" category="Version" description="Version 1.0" event_data="some data" event_date="1413407091086"
component_uuid="BCDE" snapshot_id="1000" created_at="1225630680000" />

</dataset>

+ 25
- 7
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/events_controller.rb View File

@@ -37,10 +37,10 @@ class Api::EventsController < Api::ApiController
end
if @resource
conditions<<'resource_id=:rid'
values[:rid]=@resource.id
conditions<<'component_uuid=:component_uuid'
values[:component_uuid]=@resource.uuid
else
conditions<<'resource_id IS NULL'
conditions<<'component_uuid IS NULL'
end

from=nil
@@ -87,7 +87,7 @@ class Api::EventsController < Api::ApiController
def show
begin
event=Event.find(params[:id])
load_resource(:user, event.resource_id)
load_resource_by_uuid(:user, event.component_uuid)

respond_to do |format|
format.json { render :json => jsonp(events_to_json([event])) }
@@ -144,7 +144,7 @@ class Api::EventsController < Api::ApiController
name = params[:name]
desc = params[:description]
category = params[:category]
snapshots = Snapshot.find(:all, :include => 'events', :conditions => ["(root_snapshot_id = ? OR id = ?) AND scope = 'PRJ'", root_snapshot.id, root_snapshot.id])
snapshots = Snapshot.find(:all, :include => ['events', 'project'], :conditions => ["(root_snapshot_id = ? OR id = ?) AND scope = 'PRJ'", root_snapshot.id, root_snapshot.id])
snapshots.each do |snapshot|
# if this is a 'Version' event, must propagate the version number to the snapshot
if category==EventCategory::KEY_VERSION
@@ -157,7 +157,7 @@ class Api::EventsController < Api::ApiController
:description => desc,
:category => category,
:snapshot => snapshot,
:resource_id => snapshot.project_id,
:component_uuid => snapshot.project.uuid,
:event_date => snapshot.created_at
)
event.save!
@@ -185,7 +185,7 @@ class Api::EventsController < Api::ApiController
def destroy
begin
event=Event.find(params[:id])
load_resource(:admin, event.resource_id)
load_resource_by_uuid(:admin, event.component_uuid)
events = []
name = event.name
@@ -238,6 +238,24 @@ class Api::EventsController < Api::ApiController
end
end

def load_resource_by_uuid(required_resource_role, component_uuid=nil)
if component_uuid
@resource=Project.first(:conditions => {:uuid => component_uuid})
if @resource.nil?
raise ApiException.new 404, "Component uuid not found: #{component_uuid}"
end

unless has_role?(required_resource_role, @resource)
raise ApiException.new 401, "Unauthorized"
end
else
# global events
unless is_admin?
raise ApiException.new 401, "Unauthorized"
end
end
end

def events_to_json(events=[])
json=[]
events.each do |event|

+ 6
- 6
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_controller.rb View File

@@ -283,7 +283,7 @@ class ProjectController < ApplicationController
end

def update_version
snapshot=Snapshot.find(params[:sid])
snapshot=Snapshot.find(params[:sid], :include => 'project')
not_found("Snapshot not found") unless snapshot
access_denied unless is_admin?(snapshot)

@@ -307,7 +307,7 @@ class ProjectController < ApplicationController
# We create an event for every concerned snapshot
snapshots.each do |snapshot|
event = Event.create!(:name => params[:version_name], :snapshot => snapshot,
:resource_id => snapshot.project_id, :category => EventCategory::KEY_VERSION,
:component_uuid => snapshot.project.uuid, :category => EventCategory::KEY_VERSION,
:event_date => snapshot.created_at)
end
flash[:notice] = message('project_history.version_created', :params => params[:version_name])
@@ -359,7 +359,7 @@ class ProjectController < ApplicationController
e = Event.new({:name => params[:event_name],
:category => EventCategory::KEY_OTHER,
:snapshot => s,
:resource_id => s.project_id,
:component_uuid => s.project.uuid,
:event_date => s.created_at})
e.save!
end
@@ -385,7 +385,7 @@ class ProjectController < ApplicationController
flash[:notice] = message('project_history.event_updated')
end

redirect_to :action => 'history', :id => event.resource_id
redirect_to :action => 'history', :id => event.resource.id
end

def delete_event
@@ -394,7 +394,7 @@ class ProjectController < ApplicationController
access_denied unless is_admin?(event.resource)

name = event.name
resource_id = event.resource_id
resource_id = event.resource.id
events = find_events(event)
Event.transaction do
events.map { |e| e.id }.each_slice(999) do |safe_for_oracle_ids|
@@ -416,7 +416,7 @@ class ProjectController < ApplicationController
end

def find_project_snapshots(root_snapshot_id)
snapshots = Snapshot.find(:all, :include => 'events', :conditions => ["(root_snapshot_id = ? OR id = ?) AND scope = 'PRJ'", root_snapshot_id, root_snapshot_id])
Snapshot.find(:all, :include => ['events', 'project'], :conditions => ["(root_snapshot_id = ? OR id = ?) AND scope = 'PRJ'", root_snapshot_id, root_snapshot_id])
end

# Returns all an array that contains the given event + all the events that are the same, but which are attached on the submodules

+ 1
- 1
server/sonar-web/src/main/webapp/WEB-INF/app/models/event.rb View File

@@ -23,7 +23,7 @@ class Event < ActiveRecord::Base
validates_length_of :name, :within => 1..400
validates_length_of :category, :within => 1..50

belongs_to :resource, :class_name => 'Project', :foreign_key => 'resource_id'
belongs_to :resource, :class_name => 'Project', :foreign_key => 'component_uuid', :primary_key => 'uuid'
belongs_to :snapshot

before_save :populate_snapshot

+ 1
- 1
server/sonar-web/src/main/webapp/WEB-INF/app/models/project.rb View File

@@ -23,7 +23,7 @@ class Project < ActiveRecord::Base

has_many :snapshots
has_many :processed_snapshots, :class_name => 'Snapshot', :conditions => "status='#{Snapshot::STATUS_PROCESSED}' AND qualifier<>'LIB'", :order => 'created_at asc'
has_many :events, :foreign_key => 'resource_id', :order => 'event_date DESC'
has_many :events, :foreign_key => 'component_uuid', :primary_key => 'uuid', :order => 'event_date DESC'
has_many :project_links, :foreign_key => 'component_uuid', :primary_key => 'uuid', :dependent => :delete_all, :order => 'link_type'
has_many :user_roles, :foreign_key => 'resource_id'
has_many :group_roles, :foreign_key => 'resource_id'

+ 32
- 0
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/903_add_events_component_uuid.rb View File

@@ -0,0 +1,32 @@
#
# 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.
#

#
# SonarQube 5.2
# SONAR-6261
#
class AddEventsComponentUuid < ActiveRecord::Migration

def self.up
add_column 'events', 'component_uuid', :string, :limit => 50
add_index 'events', 'component_uuid', :name => 'events_component_uuid'
end

end

+ 31
- 0
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/904_feed_events_component_uuid.rb View File

@@ -0,0 +1,31 @@
#
# 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.
#

#
# SonarQube 5.2
# SONAR-6261
#
class FeedEventsComponentUuid < ActiveRecord::Migration

def self.up
execute_java_migration('org.sonar.server.db.migrations.v52.FeedEventsComponentUuid')
end

end

+ 32
- 0
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/905_remove_events_resource_id.rb View File

@@ -0,0 +1,32 @@
#
# 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.
#

#
# SonarQube 5.2
# SONAR-6261
#
class RemoveEventsResourceId < ActiveRecord::Migration

def self.up
remove_index 'events', :name => 'events_resource_id'
remove_column 'events', 'resource_id'
end

end

+ 92
- 4
sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/Constants.java View File

@@ -235,6 +235,92 @@ public final class Constants {
// @@protoc_insertion_point(enum_scope:ComponentType)
}

/**
* Protobuf enum {@code EventCategory}
*
* <pre>
* temporary enum during development of computation stack
* </pre>
*/
public enum EventCategory
implements com.google.protobuf.ProtocolMessageEnum {
/**
* <code>ALERT = 0;</code>
*/
ALERT(0, 0),
/**
* <code>PROFILE = 1;</code>
*/
PROFILE(1, 1),
;

/**
* <code>ALERT = 0;</code>
*/
public static final int ALERT_VALUE = 0;
/**
* <code>PROFILE = 1;</code>
*/
public static final int PROFILE_VALUE = 1;


public final int getNumber() { return value; }

public static EventCategory valueOf(int value) {
switch (value) {
case 0: return ALERT;
case 1: return PROFILE;
default: return null;
}
}

public static com.google.protobuf.Internal.EnumLiteMap<EventCategory>
internalGetValueMap() {
return internalValueMap;
}
private static com.google.protobuf.Internal.EnumLiteMap<EventCategory>
internalValueMap =
new com.google.protobuf.Internal.EnumLiteMap<EventCategory>() {
public EventCategory findValueByNumber(int number) {
return EventCategory.valueOf(number);
}
};

public final com.google.protobuf.Descriptors.EnumValueDescriptor
getValueDescriptor() {
return getDescriptor().getValues().get(index);
}
public final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptorForType() {
return getDescriptor();
}
public static final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptor() {
return org.sonar.batch.protocol.Constants.getDescriptor().getEnumTypes().get(2);
}

private static final EventCategory[] VALUES = values();

public static EventCategory valueOf(
com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
if (desc.getType() != getDescriptor()) {
throw new java.lang.IllegalArgumentException(
"EnumValueDescriptor is not for this type.");
}
return VALUES[desc.getIndex()];
}

private final int index;
private final int value;

private EventCategory(int index, int value) {
this.index = index;
this.value = value;
}

// @@protoc_insertion_point(enum_scope:EventCategory)
}

/**
* Protobuf enum {@code ComponentLinkType}
*/
@@ -319,7 +405,7 @@ public final class Constants {
}
public static final com.google.protobuf.Descriptors.EnumDescriptor
getDescriptor() {
return org.sonar.batch.protocol.Constants.getDescriptor().getEnumTypes().get(2);
return org.sonar.batch.protocol.Constants.getDescriptor().getEnumTypes().get(3);
}

private static final ComponentLinkType[] VALUES = values();
@@ -357,9 +443,11 @@ public final class Constants {
"\t\n\005MINOR\020\001\022\t\n\005MAJOR\020\002\022\014\n\010CRITICAL\020\003\022\013\n\007B" +
"LOCKER\020\004*X\n\rComponentType\022\013\n\007PROJECT\020\000\022\n" +
"\n\006MODULE\020\001\022\r\n\tDIRECTORY\020\002\022\010\n\004FILE\020\003\022\010\n\004V" +
"IEW\020\004\022\013\n\007SUBVIEW\020\005*F\n\021ComponentLinkType\022" +
"\010\n\004HOME\020\000\022\007\n\003SCM\020\001\022\013\n\007SCM_DEV\020\002\022\t\n\005ISSUE" +
"\020\003\022\006\n\002CI\020\004B\034\n\030org.sonar.batch.protocolH\001"
"IEW\020\004\022\013\n\007SUBVIEW\020\005*\'\n\rEventCategory\022\t\n\005A" +
"LERT\020\000\022\013\n\007PROFILE\020\001*F\n\021ComponentLinkType" +
"\022\010\n\004HOME\020\000\022\007\n\003SCM\020\001\022\013\n\007SCM_DEV\020\002\022\t\n\005ISSU" +
"E\020\003\022\006\n\002CI\020\004B\034\n\030org.sonar.batch.protocolH" +
"\001"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {

+ 1611
- 68
sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/output/BatchReport.java
File diff suppressed because it is too large
View File


+ 13
- 1
sonar-batch-protocol/src/main/protobuf/batch_report.proto View File

@@ -53,6 +53,15 @@ message ComponentLink {
optional string href = 2;
}

// temporary message during development of computation stack
message Event {
optional int32 component_ref = 1;
optional string name = 2;
optional string description = 3;
optional EventCategory category = 4;
optional string event_data = 5;
}

message Component {
optional int32 ref = 1;
optional string path = 2;
@@ -62,10 +71,13 @@ message Component {
optional string language = 6;
repeated int32 child_ref = 7 [packed=true];
repeated ComponentLink link = 10;
// Only available on PROJECT and MODULE type
optional string version = 12;

// temporary fields during development of computation stack
optional int32 snapshot_id = 8;
optional int64 snapshot_id = 8;
optional string uuid = 9;
repeated Event events = 11;
}

message Issue {

+ 6
- 0
sonar-batch-protocol/src/main/protobuf/constants.proto View File

@@ -38,6 +38,12 @@ enum ComponentType {
SUBVIEW = 5;
}

// temporary enum during development of computation stack
enum EventCategory {
ALERT = 0;
PROFILE = 1;
}

enum ComponentLinkType {
HOME = 0;
SCM = 1;

+ 3
- 4
sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersion.java View File

@@ -19,13 +19,12 @@
*/
package org.sonar.batch.deprecated.components;

import org.sonar.batch.components.PastSnapshot;

import org.sonar.api.BatchExtension;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.Event;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.batch.components.PastSnapshot;

import java.util.List;

@@ -43,8 +42,8 @@ public class PastSnapshotFinderByPreviousVersion implements BatchExtension {
String currentVersion = projectSnapshot.getVersion();
Integer resourceId = projectSnapshot.getResourceId();

String hql = "from " + Event.class.getSimpleName() +
" where name<>:version AND category='Version' AND resourceId=:resourceId ORDER BY date DESC";
String hql = "select e from " + Event.class.getSimpleName() + " e " +
" join e.resource component where e.name<>:version AND e.category='Version' AND component.id=:resourceId ORDER BY e.date DESC";

List<Event> events = session.createQuery(hql)
.setParameter("version", currentVersion)

+ 3
- 2
sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java View File

@@ -41,7 +41,7 @@ public class EventPersister {
}

public List<Event> getEvents(Resource resource) {
return session.getResults(Event.class, "resourceId", resource.getId());
return session.getResults(Event.class, "componentUuid", resource.getUuid());
}

public void deleteEvent(Event event) {
@@ -56,8 +56,9 @@ public class EventPersister {
event.setCreatedAt(new Date(system2.now()));
if (event.getDate() == null) {
event.setSnapshot(batchResource.snapshot());
event.setComponentUuid(batchResource.resource().getUuid());
} else {
event.setResourceId(batchResource.resource().getId());
event.setComponentUuid(batchResource.resource().getUuid());
}

session.save(event);

+ 5
- 5
sonar-batch/src/test/resources/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersionTest/no-previous-version.xml View File

@@ -1,7 +1,7 @@
<dataset>

<projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
root_id="[null]"
root_id="[null]" uuid="ABCD"
description="[null]"
enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/>

@@ -30,13 +30,13 @@
scope="PRJ" qualifier="TRK" created_at="1226235480000" build_date="1226235480000" version="1.2-SNAPSHOT" path=""
status="U" islast="true" depth="0" />
<events id="2" name="Foo" resource_id="1" snapshot_id="1000" category="Other" event_date="1225717080000" created_at="1225717080000" description=""
<events id="2" name="Foo" component_uuid="ABCD" snapshot_id="1000" category="Other" event_date="1225717080000" created_at="1225717080000" description=""
event_data="[null]"/>
<events id="4" name="Bar" resource_id="1" snapshot_id="1001" category="Other" event_date="1225889880000" created_at="1225889880000" description=""
<events id="4" name="Bar" component_uuid="ABCD" snapshot_id="1001" category="Other" event_date="1225889880000" created_at="1225889880000" description=""
event_data="[null]"/>
<events id="5" name="Uhh" resource_id="1" snapshot_id="1002" category="Other" event_date="1226062680000" created_at="1226062680000" description=""
<events id="5" name="Uhh" component_uuid="ABCD" snapshot_id="1002" category="Other" event_date="1226062680000" created_at="1226062680000" description=""
event_data="[null]"/>
<events id="6" name="1.2-SNAPSHOT" resource_id="1" snapshot_id="1003" category="Version" event_date="1226235480000" created_at="1226235480000" description=""
<events id="6" name="1.2-SNAPSHOT" component_uuid="ABCD" snapshot_id="1003" category="Version" event_date="1226235480000" created_at="1226235480000" description=""
event_data="[null]"/>

</dataset>

+ 7
- 7
sonar-batch/src/test/resources/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersionTest/with-previous-version-deleted.xml View File

@@ -1,7 +1,7 @@
<dataset>

<projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
root_id="[null]"
root_id="[null]" uuid="ABCD"
description="[null]"
enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/>

@@ -30,17 +30,17 @@
scope="PRJ" qualifier="TRK" created_at="1226235480000" build_date="1226235480000" version="1.2-SNAPSHOT" path=""
status="U" islast="true" depth="0" />
<events id="1" name="1.0" resource_id="1" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description=""
<events id="1" name="1.0" component_uuid="ABCD" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description=""
event_data="[null]"/>
<events id="2" name="Foo" resource_id="1" snapshot_id="1000" category="Other" event_date="1225717080000" created_at="1225717080000" description=""
<events id="2" name="Foo" component_uuid="ABCD" snapshot_id="1000" category="Other" event_date="1225717080000" created_at="1225717080000" description=""
event_data="[null]"/>
<!-- The "1.1" version was deleted from the history : -->
<!-- events id="3" name="1.1" resource_id="1" snapshot_id="1001" category="Version" event_date="2008-11-04 13:58:00.00" created_at="2008-11-04 13:58:00.00" description=""/-->
<events id="4" name="Bar" resource_id="1" snapshot_id="1001" category="Other" event_date="1225889880000" created_at="1225889880000" description=""
<!-- events id="3" name="1.1" component_uuid="ABCD" snapshot_id="1001" category="Version" event_date="2008-11-04 13:58:00.00" created_at="2008-11-04 13:58:00.00" description=""/-->
<events id="4" name="Bar" component_uuid="ABCD" snapshot_id="1001" category="Other" event_date="1225889880000" created_at="1225889880000" description=""
event_data="[null]"/>
<events id="5" name="Uhh" resource_id="1" snapshot_id="1002" category="Other" event_date="1226062680000" created_at="1226062680000" description=""
<events id="5" name="Uhh" component_uuid="ABCD" snapshot_id="1002" category="Other" event_date="1226062680000" created_at="1226062680000" description=""
event_data="[null]"/>
<events id="6" name="1.2-SNAPSHOT" resource_id="1" snapshot_id="1003" category="Version" event_date="1226235480000" created_at="1226235480000" description=""
<events id="6" name="1.2-SNAPSHOT" component_uuid="ABCD" snapshot_id="1003" category="Version" event_date="1226235480000" created_at="1226235480000" description=""
event_data="[null]"/>

</dataset>

+ 7
- 7
sonar-batch/src/test/resources/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersionTest/with-previous-version.xml View File

@@ -1,7 +1,7 @@
<dataset>

<projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
root_id="[null]"
root_id="[null]" uuid="ABCD"
description="[null]"
enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/>

@@ -30,11 +30,11 @@
scope="PRJ" qualifier="TRK" created_at="1226235480000" build_date="1226235480000" version="1.2-SNAPSHOT" path=""
status="U" islast="true" depth="0" />
<events id="1" name="1.0" resource_id="1" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description="" event_data="[null]"/>
<events id="2" name="Foo" resource_id="1" snapshot_id="1000" category="Other" event_date="1225717080000" created_at="1225717080000" description="" event_data="[null]"/>
<events id="3" name="1.1" resource_id="1" snapshot_id="1001" category="Version" event_date="1225803480000" created_at="1225803480000" description="" event_data="[null]"/>
<events id="4" name="Bar" resource_id="1" snapshot_id="1001" category="Other" event_date="1225889880000" created_at="1225889880000" description="" event_data="[null]"/>
<events id="5" name="Uhh" resource_id="1" snapshot_id="1002" category="Other" event_date="1226062680000" created_at="1226062680000" description="" event_data="[null]"/>
<events id="6" name="1.2-SNAPSHOT" resource_id="1" snapshot_id="1003" category="Version" event_date="1226235480000" created_at="1226235480000" description="" event_data="[null]"/>
<events id="1" name="1.0" component_uuid="ABCD" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description="" event_data="[null]"/>
<events id="2" name="Foo" component_uuid="ABCD" snapshot_id="1000" category="Other" event_date="1225717080000" created_at="1225717080000" description="" event_data="[null]"/>
<events id="3" name="1.1" component_uuid="ABCD" snapshot_id="1001" category="Version" event_date="1225803480000" created_at="1225803480000" description="" event_data="[null]"/>
<events id="4" name="Bar" component_uuid="ABCD" snapshot_id="1001" category="Other" event_date="1225889880000" created_at="1225889880000" description="" event_data="[null]"/>
<events id="5" name="Uhh" component_uuid="ABCD" snapshot_id="1002" category="Other" event_date="1226062680000" created_at="1226062680000" description="" event_data="[null]"/>
<events id="6" name="1.2-SNAPSHOT" component_uuid="ABCD" snapshot_id="1003" category="Version" event_date="1226235480000" created_at="1226235480000" description="" event_data="[null]"/>

</dataset>

+ 132
- 0
sonar-core/src/main/java/org/sonar/core/event/EventDto.java View File

@@ -0,0 +1,132 @@
/*
* 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.core.event;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

public class EventDto {

public static final String CATEGORY_VERSION = "Version";
public static final String CATEGORY_ALERT = "Alert";
public static final String CATEGORY_PROFILE = "Profile";

private Long id;

private String name;

private String description;

private String category;

private Long date;

private Long createdAt;

private String data;

private Long snapshotId;

private String componentUuid;

public Long getId() {
return id;
}

public EventDto setId(Long id) {
this.id = id;
return this;
}

public String getCategory() {
return category;
}

public EventDto setCategory(String category) {
this.category = category;
return this;
}

public String getComponentUuid() {
return componentUuid;
}

public EventDto setComponentUuid(String componentUuid) {
this.componentUuid = componentUuid;
return this;
}

public Long getCreatedAt() {
return createdAt;
}

public EventDto setCreatedAt(Long createdAt) {
this.createdAt = createdAt;
return this;
}

@CheckForNull
public String getData() {
return data;
}

public EventDto setData(@Nullable String data) {
this.data = data;
return this;
}

public Long getDate() {
return date;
}

public EventDto setDate(Long date) {
this.date = date;
return this;
}

@CheckForNull
public String getDescription() {
return description;
}

public EventDto setDescription(@Nullable String description) {
this.description = description;
return this;
}

public String getName() {
return name;
}

public EventDto setName(String name) {
this.name = name;
return this;
}

public Long getSnapshotId() {
return snapshotId;
}

public EventDto setSnapshotId(Long snapshotId) {
this.snapshotId = snapshotId;
return this;
}
}

+ 35
- 0
sonar-core/src/main/java/org/sonar/core/event/db/EventMapper.java View File

@@ -0,0 +1,35 @@
/*
* 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.core.event.db;

import org.sonar.core.event.EventDto;

import java.util.List;

public interface EventMapper {

List<EventDto> selectByComponentUuid(String uuid);

void insert(EventDto dto);

void delete(long id);

}

+ 24
- 0
sonar-core/src/main/java/org/sonar/core/event/db/package-info.java View File

@@ -0,0 +1,24 @@
/*
* 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.core.event.db;

import javax.annotation.ParametersAreNonnullByDefault;

+ 24
- 0
sonar-core/src/main/java/org/sonar/core/event/package-info.java View File

@@ -0,0 +1,24 @@
/*
* 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.core.event;

import javax.annotation.ParametersAreNonnullByDefault;

+ 1
- 1
sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java View File

@@ -33,7 +33,7 @@ import java.util.List;
*/
public class DatabaseVersion implements BatchComponent, ServerComponent {

public static final int LAST_VERSION = 902;
public static final int LAST_VERSION = 905;

/**
* List of all the tables.n

+ 4
- 1
sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java View File

@@ -50,6 +50,8 @@ import org.sonar.core.dependency.ResourceSnapshotDto;
import org.sonar.core.dependency.ResourceSnapshotMapper;
import org.sonar.core.duplication.DuplicationMapper;
import org.sonar.core.duplication.DuplicationUnitDto;
import org.sonar.core.event.EventDto;
import org.sonar.core.event.db.EventMapper;
import org.sonar.core.graph.jdbc.GraphDto;
import org.sonar.core.graph.jdbc.GraphDtoMapper;
import org.sonar.core.issue.db.*;
@@ -184,6 +186,7 @@ public class MyBatis implements BatchComponent, ServerComponent {
loadAlias(conf, "IdUuidPair", IdUuidPair.class);
loadAlias(conf, "FilePathWithHash", FilePathWithHashDto.class);
loadAlias(conf, "UuidWithProjectUuid", UuidWithProjectUuidDto.class);
loadAlias(conf, "Event", EventDto.class);

// AuthorizationMapper has to be loaded before IssueMapper because this last one used it
loadMapper(conf, "org.sonar.core.user.AuthorizationMapper");
@@ -202,7 +205,7 @@ public class MyBatis implements BatchComponent, ServerComponent {
NotificationQueueMapper.class, CharacteristicMapper.class,
GroupMembershipMapper.class, QualityProfileMapper.class, ActiveRuleMapper.class,
MeasureMapper.class, MetricMapper.class, QualityGateMapper.class, QualityGateConditionMapper.class, ComponentMapper.class, SnapshotMapper.class,
ProjectQgateAssociationMapper.class,
ProjectQgateAssociationMapper.class, EventMapper.class,
AnalysisReportMapper.class, ComponentIndexMapper.class, ComponentLinkMapper.class,
Migration45Mapper.class, Migration50Mapper.class
};

+ 3
- 3
sonar-core/src/main/java/org/sonar/core/purge/PurgeCommands.java View File

@@ -125,9 +125,9 @@ class PurgeCommands {
session.commit();
profiler.stop();

profiler.start("deleteResourceEvents (events)");
for (List<Long> partResourceIds : componentIdPartitions) {
purgeMapper.deleteResourceEvents(partResourceIds);
profiler.start("deleteComponentEvents (events)");
for (List<String> componentUuidPartition : componentUuidsPartitions) {
purgeMapper.deleteComponentEvents(componentUuidPartition);
}
session.commit();
profiler.stop();

+ 1
- 1
sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java View File

@@ -79,7 +79,7 @@ public interface PurgeMapper {

void deleteResourceManualMeasures(@Param("resourceIds") List<Long> resourceIds);

void deleteResourceEvents(@Param("resourceIds") List<Long> resourceIds);
void deleteComponentEvents(@Param("componentUuids") List<String> componentUuids);

void deleteResourceActionPlans(@Param("resourceIds") List<Long> resourceIds);


+ 35
- 0
sonar-core/src/main/resources/org/sonar/core/event/db/EventMapper.xml View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.sonar.core.event.db.EventMapper">

<sql id="eventColumns">
e.id,
e.name,
e.category,
e.description,
e.event_data as "data",
e.event_date as "date",
e.component_uuid as "componentUuid",
e.snapshot_id as "snapshotId",
e.created_at as "createdAt"
</sql>

<select id="selectByComponentUuid" parameterType="String" resultType="Event">
SELECT <include refid="eventColumns"/>
FROM events e
<where>
AND e.component_uuid=#{uuid}
</where>
</select>

<insert id="insert" parameterType="Event" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
INSERT INTO events (name, category, description, event_data, event_date, component_uuid, snapshot_id, created_at)
VALUES (#{name}, #{category}, #{description}, #{data}, #{date}, #{componentUuid}, #{snapshotId}, #{createdAt})
</insert>

<delete id="delete">
DELETE FROM events WHERE id=#{id}
</delete>

</mapper>


+ 3
- 0
sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql View File

@@ -326,6 +326,9 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('796');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('900');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('901');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('902');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('903');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('904');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('905');

INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482', null, null);
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;

+ 2
- 2
sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl View File

@@ -164,7 +164,7 @@ CREATE TABLE "WIDGET_PROPERTIES" (
CREATE TABLE "EVENTS" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"NAME" VARCHAR(400),
"RESOURCE_ID" INTEGER,
"COMPONENT_UUID" VARCHAR(50),
"SNAPSHOT_ID" INTEGER,
"CATEGORY" VARCHAR(50),
"EVENT_DATE" BIGINT NOT NULL,
@@ -599,7 +599,7 @@ CREATE UNIQUE INDEX "METRICS_UNIQUE_NAME" ON "METRICS" ("NAME");

CREATE INDEX "EVENTS_SNAPSHOT_ID" ON "EVENTS" ("SNAPSHOT_ID");

CREATE INDEX "EVENTS_RESOURCE_ID" ON "EVENTS" ("RESOURCE_ID");
CREATE INDEX "EVENTS_COMPONENT_UUID" ON "EVENTS" ("COMPONENT_UUID");

CREATE INDEX "WIDGETS_WIDGETKEY" ON "WIDGETS" ("WIDGET_KEY");


+ 4
- 4
sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml View File

@@ -238,10 +238,10 @@
</foreach>
</delete>

<delete id="deleteResourceEvents" parameterType="map">
delete from events where resource_id in
<foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
#{resourceId}
<delete id="deleteComponentEvents" parameterType="map">
delete from events where component_uuid in
<foreach collection="componentUuids" open="(" close=")" item="componentUuid" separator=",">
#{componentUuid}
</foreach>
</delete>


+ 3
- 3
sonar-core/src/test/resources/org/sonar/core/persistence/PreviewDatabaseFactoryTest/should_create_database.xml View File

@@ -22,9 +22,9 @@

<project_measures id="1" value="10" metric_id="1" snapshot_id="1000" />

<events id="1" name="1.0-SNAPSHOT" resource_id="123" event_data="[null]"/>
<events id="2" name="2.0-SNAPSHOT" resource_id="123" event_data="[null]" />
<events id="3" name="1.0-SNAPSHOT" resource_id="456" event_data="[null]" />
<events id="1" name="1.0-SNAPSHOT" component_uuid="123" event_data="[null]"/>
<events id="2" name="2.0-SNAPSHOT" component_uuid="123" event_data="[null]" />
<events id="3" name="1.0-SNAPSHOT" component_uuid="456" event_data="[null]" />

<users id="1" login="julien" name="Julien" crypted_password="foo" active="1" />
<users id="2" login="simon" name="Simon" active="1" />

+ 1
- 1
sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldDeleteResource.xml View File

@@ -15,7 +15,7 @@
build_date="1228222680000"
version="[null]" path="[null]"/>

<events id="1" name="Version 1.0" resource_id="1" snapshot_id="1" category="VERSION" description="[null]"
<events id="1" name="Version 1.0" component_uuid="1" snapshot_id="1" category="VERSION" description="[null]"
event_date="1228222680000" created_at="1228222680000" event_data="[null]"/>

<issues id="1" kee="ABCDE" component_uuid="1" project_uuid="1" status="CLOSED" resolution="[null]" line="200"

+ 1
- 1
sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldDeleteSnapshot-result.xml View File

@@ -25,7 +25,7 @@
<dependencies id="1" from_resource_id="1" from_snapshot_id="1" to_resource_id="30" to_snapshot_id="30"
parent_dependency_id="[null]" project_snapshot_id="1"
dep_usage="USES" dep_weight="1" from_scope="PRJ" to_scope="LIB"/>
<events id="1" name="Version 1.0" resource_id="1" snapshot_id="1" category="VERSION" description="[null]"
<events id="1" name="Version 1.0" component_uuid="1" snapshot_id="1" category="VERSION" description="[null]"
event_date="1228222680000" created_at="1228222680000" event_data="[null]"/>
<duplications_index id="1" project_snapshot_id="1" snapshot_id="1" hash="bb" index_in_file="0" start_line="0"
end_line="0"/>

+ 2
- 2
sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldDeleteSnapshot.xml View File

@@ -24,7 +24,7 @@
<dependencies id="1" from_resource_id="1" from_snapshot_id="1" to_resource_id="30" to_snapshot_id="30"
parent_dependency_id="[null]" project_snapshot_id="1"
dep_usage="USES" dep_weight="1" from_scope="PRJ" to_scope="LIB"/>
<events id="1" name="Version 1.0" resource_id="1" snapshot_id="1" category="VERSION" description="[null]"
<events id="1" name="Version 1.0" component_uuid="1" snapshot_id="1" category="VERSION" description="[null]"
event_date="1228222680000" created_at="1228222680000" event_data="[null]"/>
<duplications_index id="1" project_snapshot_id="1" snapshot_id="1" hash="bb" index_in_file="0" start_line="0"
end_line="0"/>
@@ -57,7 +57,7 @@
<dependencies id="3" from_resource_id="5" from_snapshot_id="5" to_resource_id="300" to_snapshot_id="300"
parent_dependency_id="[null]" project_snapshot_id="5"
dep_usage="USES" dep_weight="1" from_scope="PRJ" to_scope="LIB"/>
<events id="2" name="Version 1.0" resource_id="5" snapshot_id="5" category="VERSION" description="[null]"
<events id="2" name="Version 1.0" component_uuid="5" snapshot_id="5" category="VERSION" description="[null]"
event_date="1228222680000" created_at="1228222680000" event_data="[null]"/>
<duplications_index id="2" project_snapshot_id="5" snapshot_id="5" hash="bb" index_in_file="0" start_line="0"
end_line="0"/>

+ 2
- 2
sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldPurgeSnapshot-result.xml View File

@@ -41,7 +41,7 @@ Note that measures, events and reviews are not deleted.
<!--parent_dependency_id="[null]" project_snapshot_id="2"-->
<!--dep_usage="USES" dep_weight="1" from_scope="LIB" to_scope="PRJ"/>-->

<events id="1" resource_id="1" snapshot_id="1"
<events id="1" component_uuid="1" snapshot_id="1"
category="VERSION" description="[null]" name="Version 1.0" event_date="1228222680000"
created_at="1228222680000"
event_data="[null]"/>
@@ -80,7 +80,7 @@ Note that measures, events and reviews are not deleted.
parent_dependency_id="[null]" project_snapshot_id="2"
dep_usage="USES" dep_weight="1" from_scope="LIB" to_scope="PRJ"/>

<events id="2" resource_id="2" snapshot_id="2"
<events id="2" component_uuid="2" snapshot_id="2"
category="VERSION" description="[null]" name="Version 1.0" event_date="1228222680000"
created_at="1228222680000"
event_data="[null]"/>

+ 2
- 2
sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldPurgeSnapshot.xml View File

@@ -26,7 +26,7 @@
parent_dependency_id="[null]" project_snapshot_id="2"
dep_usage="USES" dep_weight="1" from_scope="LIB" to_scope="PRJ"/>

<events id="1" resource_id="1" snapshot_id="1"
<events id="1" component_uuid="1" snapshot_id="1"
category="VERSION" description="[null]" name="Version 1.0" event_date="1228222680000"
created_at="1228222680000"
event_data="[null]"/>
@@ -64,7 +64,7 @@
parent_dependency_id="[null]" project_snapshot_id="2"
dep_usage="USES" dep_weight="1" from_scope="LIB" to_scope="PRJ"/>

<events id="2" resource_id="2" snapshot_id="2"
<events id="2" component_uuid="2" snapshot_id="2"
category="VERSION" description="[null]" name="Version 1.0" event_date="1228222680000"
created_at="1228222680000"
event_data="[null]"/>

+ 1
- 1
sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldSelectPurgeableSnapshots.xml View File

@@ -55,7 +55,7 @@
period5_mode="[null]" period5_param="[null]" period5_date="[null]"
depth="[null]" scope="PRJ" qualifier="TRK" created_at="1228222680000" build_date="1228222680000" version="[null]" path="[null]"/>

<events id="2" resource_id="1" snapshot_id="5"
<events id="2" component_uuid="1" snapshot_id="5"
category="Version" description="[null]" name="Version 1.0" event_date="1228222680000" created_at="1228222680000"
event_data="[null]"/>


+ 22
- 9
sonar-plugin-api/src/main/java/org/sonar/api/batch/Event.java View File

@@ -21,9 +21,11 @@ package org.sonar.api.batch;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.sonar.api.database.BaseIdentifiable;
import org.sonar.api.database.model.ResourceModel;
import org.sonar.api.database.model.Snapshot;

import javax.persistence.*;

import java.util.Date;

import static com.google.common.base.Preconditions.checkNotNull;
@@ -61,8 +63,12 @@ public class Event extends BaseIdentifiable {
@JoinColumn(name = "snapshot_id", updatable = true, nullable = true)
private Snapshot snapshot;

@Column(name = "resource_id", updatable = true, nullable = true)
private Integer resourceId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "component_uuid", referencedColumnName = "uuid", insertable = false, updatable = false, nullable = false)
private ResourceModel resource;

@Column(name = "component_uuid", updatable = true, nullable = true)
private String componentUuid;

public Event() {
}
@@ -128,16 +134,23 @@ public class Event extends BaseIdentifiable {
public final void setSnapshot(Snapshot snapshot) {
this.snapshot = checkNotNull(snapshot, "it is not possible to set a null snapshot linked to an event");
this.date = snapshot.getCreatedAtMs();
this.resourceId = snapshot.getResourceId();
// this.resourceId = snapshot.getResourceId();
}

public ResourceModel getResource() {
return resource;
}

public void setResource(ResourceModel resource) {
this.resource = resource;
}

public Integer getResourceId() {
return resourceId;
public String getComponentUuid() {
return componentUuid;
}

public Event setResourceId(Integer resourceId) {
this.resourceId = resourceId;
return this;
public void setComponentUuid(String componentUuid) {
this.componentUuid = componentUuid;
}

public String getData() {
@@ -155,7 +168,7 @@ public class Event extends BaseIdentifiable {
.append("categ", category)
.append("date", date)
.append("snapshot", snapshot)
.append("resource", resourceId)
.append("resource", resource)
.toString();
}
}

+ 2
- 1
sonar-plugin-api/src/main/java/org/sonar/api/database/model/ResourceModel.java View File

@@ -30,6 +30,7 @@ import org.sonar.api.resources.Resource;
import javax.annotation.Nullable;
import javax.persistence.*;

import java.io.Serializable;
import java.util.Date;

/**
@@ -37,7 +38,7 @@ import java.util.Date;
*/
@Entity
@Table(name = "projects")
public class ResourceModel extends BaseIdentifiable implements Cloneable {
public class ResourceModel extends BaseIdentifiable implements Cloneable, Serializable {

public static final String SCOPE_PROJECT = "PRJ";
public static final String QUALIFIER_PROJECT_TRUNK = "TRK";

Loading…
Cancel
Save