*/
package org.sonar.server.activity;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
import java.util.LinkedHashMap;
import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
public class Activity {
private Type type;
private String action;
private String message;
- private final Map<String,Object> data = new LinkedHashMap<>();
+ private String profileKey;
+ private final Map<String, Object> data = new LinkedHashMap<>();
public Type getType() {
return type;
this.data.put(key, val);
return this;
}
+
+ public String getProfileKey() {
+ return profileKey;
+ }
+
+ public Activity setProfileKey(String profileKey) {
+ this.profileKey = profileKey;
+ return this;
+ }
}
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.core.util.Uuids;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
import org.sonar.db.activity.ActivityDto;
import org.sonar.server.activity.index.ActivityIndexer;
-import org.sonar.db.DbClient;
import org.sonar.server.user.UserSession;
public class ActivityService {
.setAction(activity.getAction())
.setMessage(activity.getMessage())
.setData(KeyValueFormat.format(activity.getData()))
+ .setProfileKey(activity.getProfileKey())
.setType(activity.getType().name());
- dbClient.activityDao().insert(dto);
- indexer.index();
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ dbClient.activityDao().insert(dbSession, dto);
+ dbSession.commit();
+ indexer.index();
+ } finally {
+ dbClient.closeSession(dbSession);
+ }
}
}
Activity activity = new Activity();
activity.setType(Activity.Type.QPROFILE);
activity.setAction(type.name());
+ activity.setProfileKey(getKey().qProfile());
activity.setData("key", getKey().toString());
activity.setData("ruleKey", getKey().ruleKey().toString());
activity.setData("profileKey", getKey().qProfile());
activity.setAction("THE_ACTION");
activity.setMessage("THE_MSG");
activity.setData("foo", "bar");
+ activity.setData("profileKey", "PROFILE_KEY");
+ activity.setProfileKey("PROFILE_KEY");
service.save(activity);
Map<String, Object> dbMap = db.selectFirst("select log_type as \"type\", log_action as \"action\", log_message as \"msg\", data_field as \"data\" from activities");
assertThat(dbMap).containsEntry("type", "ANALYSIS_REPORT");
assertThat(dbMap).containsEntry("action", "THE_ACTION");
assertThat(dbMap).containsEntry("msg", "THE_MSG");
- assertThat(dbMap.get("data")).isEqualTo("foo=bar");
+ assertThat(dbMap.get("data")).isEqualTo("foo=bar;profileKey=PROFILE_KEY");
List<ActivityDoc> docs = es.getDocuments("activities", "activity", ActivityDoc.class);
assertThat(docs).hasSize(1);
assertThat(docs.get(0).getKey()).isNotEmpty();
assertThat(docs.get(0).getAction()).isEqualTo("THE_ACTION");
assertThat(docs.get(0).getMessage()).isEqualTo("THE_MSG");
- assertThat(docs.get(0).getDetails()).containsOnly(MapEntry.entry("foo", "bar"));
+ assertThat(docs.get(0).getDetails()).containsOnly(MapEntry.entry("foo", "bar"), MapEntry.entry("profileKey", "PROFILE_KEY"));
}
}
import static org.assertj.core.api.Assertions.assertThat;
-
public class ActivityResultSetIteratorTest {
@Rule
import org.sonar.server.ws.WsTester;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.test.JsonAssert.assertJson;
public class ActivitiesWsMediumTest {
activity.setAction("THE_ACTION");
activity.setMessage("THE_MSG");
activity.setData("foo", "bar");
- service.save(activity);
+ activity.setProfileKey("PROFILE_KEY");
+ service.save(activity);
WsTester.TestRequest request = tester.wsTester().newGetRequest("api/activities", "search");
- WsTester.Result result = request.execute();
- assertThat(result.outputAsString()).contains("\"total\":1");
- assertThat(result.outputAsString()).contains("\"type\":\"ANALYSIS_REPORT\"");
- assertThat(result.outputAsString()).contains("\"details\":{\"foo\":\"bar\"}");
+
+ String result = request.execute().outputAsString();
+ assertJson(result).isSimilarTo(
+ "{" +
+ " \"total\": 1," +
+ " \"p\": 1," +
+ " \"ps\": 10," +
+ " \"logs\": [" +
+ " {" +
+ " \"type\": \"ANALYSIS_REPORT\"," +
+ " \"action\": \"THE_ACTION\"," +
+ " \"message\": \"THE_MSG\"," +
+ " \"details\": {" +
+ " \"profileKey\": \"PROFILE_KEY\"," +
+ " \"foo\": \"bar\"" +
+ " }" +
+ " }" +
+ " ]" +
+ "}");
}
}
<dataset>
<activities id="1" log_key="UUID1" log_type="ANALYSIS_REPORT" log_action="THE_ACTION" log_message="THE_MSG"
- created_at="2014-01-01" data_field="foo=bar" user_login="THE_AUTHOR"/>
+ created_at="2014-01-01" data_field="foo=bar" user_login="THE_AUTHOR" profile_key="PROFILE_KEY"/>
<activities id="2" log_key="UUID2" log_type="ANALYSIS_REPORT" log_action="THE_ACTION" log_message="THE_MSG"
- created_at="2015-01-01" data_field="foo=bar" user_login="THE_AUTHOR"/>
+ created_at="2015-01-01" data_field="foo=bar" user_login="THE_AUTHOR" profile_key="PROFILE_KEY"/>
</dataset>
--- /dev/null
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+# SonarQube 6.0
+# SONAR-7794
+#
+class AddProfileKeyToActivities < ActiveRecord::Migration
+ def self.up
+ execute_java_migration('org.sonar.db.version.v60.AddProfileKeyToActivities')
+ end
+end
super(mybatis, system);
}
- public void insert(ActivityDto dto) {
- DbSession session = myBatis().openSession(false);
- try {
- insert(session, dto);
- session.commit();
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
public void insert(DbSession session, ActivityDto dto) {
dto.setCreatedAt(new Date(now()));
session.getMapper(ActivityMapper.class).insert(dto);
public class ActivityDto {
private String key;
+ private String profileKey;
private String message;
private String type;
private String action;
return key;
}
+ public String getProfileKey() {
+ return profileKey;
+ }
+
+ public ActivityDto setProfileKey(String profileKey) {
+ this.profileKey = profileKey;
+ return this;
+ }
+
public Date getCreatedAt() {
return createdAt;
}
public class DatabaseVersion {
- public static final int LAST_VERSION = 1_258;
+ public static final int LAST_VERSION = 1_259;
/**
* The minimum supported version which can be upgraded. Lower
import org.sonar.db.version.v60.AddComponentUuidColumnToMeasures;
import org.sonar.db.version.v60.AddComponentUuidColumnsToSnapshots;
import org.sonar.db.version.v60.AddLastUsedColumnToRulesProfiles;
+import org.sonar.db.version.v60.AddProfileKeyToActivities;
import org.sonar.db.version.v60.AddUuidColumnToSnapshots;
import org.sonar.db.version.v60.AddUuidColumnsToProjects;
import org.sonar.db.version.v60.AddUuidColumnsToResourceIndex;
DropIdColumnsFromProjects.class,
AddLastUsedColumnToRulesProfiles.class,
PopulateLastUsedColumnOfRulesProfiles.class,
+ AddProfileKeyToActivities.class,
// SNAPSHOTS.UUID
AddUuidColumnToSnapshots.class,
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.db.version.v60;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.version.AddColumnsBuilder;
+import org.sonar.db.version.DdlChange;
+
+import static org.sonar.db.version.VarcharColumnDef.newVarcharColumnDefBuilder;
+
+public class AddProfileKeyToActivities extends DdlChange {
+
+ private static final String TABLE_ACTIVITIES = "activities";
+
+ public AddProfileKeyToActivities(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute(new AddColumnsBuilder(getDatabase().getDialect(), TABLE_ACTIVITIES)
+ .addColumn(newVarcharColumnDefBuilder().setColumnName("profile_key").setLimit(255).setIsNullable(true).build())
+ .build());
+ }
+
+}
<insert id="insert" parameterType="Activity" useGeneratedKeys="false">
insert into activities
- (created_at, log_key, log_type, log_action, user_login, data_field, log_message)
+ (created_at, log_key, log_type, log_action, user_login, data_field, log_message, profile_key)
values (#{createdAt,jdbcType=TIMESTAMP}, #{key,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
#{action,jdbcType=VARCHAR},
- #{author,jdbcType=VARCHAR}, #{data,jdbcType=VARCHAR}, #{message,jdbcType=VARCHAR})
+ #{author,jdbcType=VARCHAR}, #{data,jdbcType=VARCHAR}, #{message,jdbcType=VARCHAR}, #{profileKey, jdbcType=VARCHAR})
</insert>
</mapper>
CREATE TABLE "ACTIVITIES" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"LOG_KEY" VARCHAR(250),
+ "PROFILE_KEY" VARCHAR(255),
"CREATED_AT" TIMESTAMP,
"USER_LOGIN" VARCHAR(255),
"LOG_TYPE" VARCHAR(250),
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
+import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-
public class ActivityDaoTest {
System2 system = mock(System2.class);
@Rule
public DbTester dbTester = DbTester.create(system);
+ DbSession dbSession = dbTester.getSession();
ActivityDao underTest = dbTester.getDbClient().activityDao();
public void insert() {
when(system.now()).thenReturn(1_500_000_000_000L);
ActivityDto dto = new ActivityDto()
- .setKey("UUID_1").setAction("THE_ACTION").setType("THE_TYPE")
- .setAuthor("THE_AUTHOR").setData("THE_DATA");
- underTest.insert(dto);
+ .setKey("UUID_1")
+ .setAction("THE_ACTION")
+ .setType("THE_TYPE")
+ .setAuthor("THE_AUTHOR")
+ .setData("THE_DATA")
+ .setProfileKey("PROFILE_KEY");
+ underTest.insert(dbSession, dto);
+ dbSession.commit();
- Map<String, Object> map = dbTester.selectFirst("select created_at as \"createdAt\", log_action as \"action\", data_field as \"data\" from activities where log_key='UUID_1'");
+ Map<String, Object> map = dbTester.selectFirst("select created_at as \"createdAt\", log_action as \"action\", " +
+ "data_field as \"data\", profile_key as \"profileKey\" " +
+ "from activities where log_key='UUID_1'");
assertThat(map.get("action")).isEqualTo("THE_ACTION");
// not possible to check exact date yet. dbTester#selectFirst() uses ResultSet#getObject(), which returns
// non-JDBC interface in Oracle driver.
assertThat(map.get("createdAt")).isNotNull();
assertThat(map.get("data")).isEqualTo("THE_DATA");
+ assertThat(map.get("profileKey")).isEqualTo("PROFILE_KEY");
}
}
public void verify_count_of_added_MigrationStep_types() {
ComponentContainer container = new ComponentContainer();
new MigrationStepModule().configure(container);
- assertThat(container.size()).isEqualTo(114);
+ assertThat(container.size()).isEqualTo(115);
}
}
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.activity.ActivityDto;
import org.sonar.db.version.MigrationStep;
public class RemoveAnalysisReportsFromActivitiesTest {
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
+ DbClient dbClient = db.getDbClient();
+ DbSession dbSession = db.getSession();
MigrationStep underTest = new RemoveAnalysisReportsFromActivities(db.database());
@Test
public void test() throws Exception {
- db.getDbClient().activityDao().insert(new ActivityDto().setType("ANALYSIS_REPORT").setKey("1"));
- db.getDbClient().activityDao().insert(new ActivityDto().setType("ANALYSIS_REPORT").setKey("2"));
- db.getDbClient().activityDao().insert(new ActivityDto().setType("PROFILE_CHANGE").setKey("3"));
+ dbClient.activityDao().insert(dbSession, new ActivityDto().setType("ANALYSIS_REPORT").setKey("1"));
+ dbClient.activityDao().insert(dbSession, new ActivityDto().setType("ANALYSIS_REPORT").setKey("2"));
+ dbClient.activityDao().insert(dbSession, new ActivityDto().setType("PROFILE_CHANGE").setKey("3"));
underTest.execute();
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.db.version.v60;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+
+public class AddProfileKeyToActivitiesTest {
+
+ @Rule
+ public DbTester db = DbTester.createForSchema(System2.INSTANCE, AddProfileKeyToActivitiesTest.class, "activities.sql");
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private AddProfileKeyToActivities underTest = new AddProfileKeyToActivities(db.database());
+
+ @Test
+ public void migration_adds_column_to_empty_table() throws SQLException {
+ underTest.execute();
+
+ verifyAddedColumns();
+ }
+
+ @Test
+ public void migration_adds_column_to_populated_table() throws SQLException {
+ for (int i = 0; i < 9; i++) {
+ db.executeInsert(
+ "activities",
+ "log_key", "LOG_KEY_" + i,
+ "user_login", "login");
+ }
+ db.commit();
+
+ underTest.execute();
+
+ verifyAddedColumns();
+ }
+
+ @Test
+ public void migration_is_not_reentrant() throws SQLException {
+ underTest.execute();
+
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Fail to execute ");
+ underTest.execute();
+ }
+
+ private void verifyAddedColumns() {
+ db.assertColumnDefinition("activities", "profile_key", Types.VARCHAR, 255, true);
+ }
+
+}
--- /dev/null
+CREATE TABLE "ACTIVITIES" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "LOG_KEY" VARCHAR(250),
+ "CREATED_AT" TIMESTAMP,
+ "USER_LOGIN" VARCHAR(255),
+ "LOG_TYPE" VARCHAR(250),
+ "LOG_ACTION" VARCHAR(250),
+ "LOG_MESSAGE" VARCHAR(250),
+ "DATA_FIELD" CLOB(2147483647)
+);