summaryrefslogtreecommitdiffstats
path: root/sonar-core
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2014-06-23 14:52:56 +0200
committerSimon Brandhof <simon.brandhof@sonarsource.com>2014-06-23 14:58:08 +0200
commit56554cc77e5f0eba7fc75e7d6b340cdc7c2e4698 (patch)
treeb6a8d69f19f1d53d10e4d94204481f4bdd450ba5 /sonar-core
parentf206ca12ae3b445697e88fea1864c29c791196d0 (diff)
downloadsonarqube-56554cc77e5f0eba7fc75e7d6b340cdc7c2e4698.tar.gz
sonarqube-56554cc77e5f0eba7fc75e7d6b340cdc7c2e4698.zip
SONAR-5216 compare quality profile dates when batch detects profile changes
Diffstat (limited to 'sonar-core')
-rw-r--r--sonar-core/pom.xml7
-rw-r--r--sonar-core/src/main/java/org/sonar/core/UtcDateUtils.java54
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/dialect/DialectUtils.java5
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/Migration44Mapper.java22
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/QProfileDto44.java60
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/package-info.java24
-rw-r--r--sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDao.java10
-rw-r--r--sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDto.java22
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/persistence/migration/v44/Migration44Mapper.xml8
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl2
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/QualityProfileMapper.xml13
-rw-r--r--sonar-core/src/test/java/org/sonar/core/UtcDateUtilsTest.java46
-rw-r--r--sonar-core/src/test/java/org/sonar/core/qualityprofile/db/QualityProfileDaoTest.java12
13 files changed, 263 insertions, 22 deletions
diff --git a/sonar-core/pom.xml b/sonar-core/pom.xml
index 631bf0b1a95..331c28cede2 100644
--- a/sonar-core/pom.xml
+++ b/sonar-core/pom.xml
@@ -156,14 +156,7 @@
<dependency>
<groupId>com.google.code.bean-matchers</groupId>
<artifactId>bean-matchers</artifactId>
- <version>0.9</version>
<scope>test</scope>
- <exclusions>
- <exclusion>
- <groupId>org.hamcrest</groupId>
- <artifactId>hamcrest-core</artifactId>
- </exclusion>
- </exclusions>
</dependency>
diff --git a/sonar-core/src/main/java/org/sonar/core/UtcDateUtils.java b/sonar-core/src/main/java/org/sonar/core/UtcDateUtils.java
new file mode 100644
index 00000000000..298fda02e34
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/UtcDateUtils.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import org.sonar.api.utils.DateUtils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class UtcDateUtils {
+
+ private UtcDateUtils() {
+ // only static stuff
+ }
+
+ public static String formatDateTime(Date date) {
+ SimpleDateFormat format = newFormat();
+ return format.format(date);
+ }
+
+ public static Date parseDateTime(String s) {
+ try {
+ SimpleDateFormat format = newFormat();
+ return format.parse(s);
+ } catch (ParseException e) {
+ throw new IllegalArgumentException("Fail to parse date: " + s, e);
+ }
+ }
+
+ private static SimpleDateFormat newFormat() {
+ SimpleDateFormat format = new SimpleDateFormat(DateUtils.DATETIME_FORMAT);
+ format.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return format;
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/dialect/DialectUtils.java b/sonar-core/src/main/java/org/sonar/core/persistence/dialect/DialectUtils.java
index 9c9579932b6..1ad06d54415 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/dialect/DialectUtils.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/dialect/DialectUtils.java
@@ -24,12 +24,14 @@ import com.google.common.collect.Iterators;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.utils.SonarException;
+import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import java.util.NoSuchElementException;
public final class DialectUtils {
private DialectUtils() {
+ // only static stuff
}
private static final Dialect[] DIALECTS = new Dialect[] {new H2(), new MySql(), new Oracle(), new PostgreSql(), new MsSql()};
@@ -42,6 +44,7 @@ public final class DialectUtils {
return match;
}
+ @CheckForNull
private static Dialect findByJdbcUrl(final String jdbcConnectionUrl) {
return findDialect(new Predicate<Dialect>() {
public boolean apply(@Nullable Dialect dialect) {
@@ -50,6 +53,7 @@ public final class DialectUtils {
});
}
+ @CheckForNull
private static Dialect findById(final String dialectId) {
return findDialect(new Predicate<Dialect>() {
public boolean apply(@Nullable Dialect dialect) {
@@ -58,6 +62,7 @@ public final class DialectUtils {
});
}
+ @CheckForNull
private static Dialect findDialect(Predicate<Dialect> predicate) {
try {
return Iterators.find(Iterators.forArray(DIALECTS), predicate);
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/Migration44Mapper.java b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/Migration44Mapper.java
index d27b8c95c4e..d3bde433e58 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/Migration44Mapper.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/Migration44Mapper.java
@@ -22,6 +22,7 @@ package org.sonar.core.persistence.migration.v44;
import org.apache.ibatis.annotations.Param;
import javax.annotation.CheckForNull;
+
import java.util.Date;
import java.util.List;
@@ -29,14 +30,27 @@ public interface Migration44Mapper {
// migration of measures "profile" and "profile_version"
List<ProfileMeasure> selectProfileMeasures();
+
int selectProfileVersion(long snapshotId);
- @CheckForNull Date selectProfileVersionDate(@Param("profileId") int profileId, @Param("profileVersion") int profileVersion);
+
+ @CheckForNull
+ Date selectProfileVersionDate(@Param("profileId") int profileId, @Param("profileVersion") int profileVersion);
+
void updateProfileMeasure(@Param("measureId") long measureId, @Param("json") String json);
+ @CheckForNull
+ QProfileDto44 selectProfileById(int id);
+
// creation of columns RULES_PROFILES.CREATED_AT and UPDATED_AT
- @CheckForNull Date selectProfileCreatedAt(int profileId);
- @CheckForNull Date selectProfileUpdatedAt(int profileId);
- void updateProfileDates(@Param("profileId") int profileId, @Param("createdAt") Date createdAt, @Param("updatedAt") Date updatedAt);
+ @CheckForNull
+ Date selectProfileCreatedAt(int profileId);
+
+ @CheckForNull
+ Date selectProfileUpdatedAt(int profileId);
+
+ void updateProfileDates(@Param("profileId") int profileId,
+ @Param("createdAt") Date createdAt, @Param("updatedAt") Date updatedAt,
+ @Param("rulesUpdatedAt") String rulesUpdatedAt);
// migrate changeLog to Activities
List<ChangeLog> selectActiveRuleChange(@Param("enabled") Boolean enabled);
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/QProfileDto44.java b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/QProfileDto44.java
new file mode 100644
index 00000000000..e69d23c1cb5
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/QProfileDto44.java
@@ -0,0 +1,60 @@
+/*
+ * 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.persistence.migration.v44;
+
+public class QProfileDto44 {
+
+ private Integer id;
+ private String kee;
+ private String name;
+ private String language;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getKee() {
+ return kee;
+ }
+
+ public void setKee(String kee) {
+ this.kee = kee;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/package-info.java b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/package-info.java
new file mode 100644
index 00000000000..efd32c18d20
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/migration/v44/package-info.java
@@ -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.persistence.migration.v44;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDao.java b/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDao.java
index 25724a1459f..45189d64df9 100644
--- a/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDao.java
+++ b/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDao.java
@@ -23,6 +23,7 @@ package org.sonar.core.qualityprofile.db;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.sonar.api.ServerComponent;
+import org.sonar.api.utils.System2;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.persistence.DaoComponent;
import org.sonar.core.persistence.DbSession;
@@ -30,14 +31,17 @@ import org.sonar.core.persistence.MyBatis;
import javax.annotation.CheckForNull;
+import java.util.Date;
import java.util.List;
public class QualityProfileDao implements ServerComponent, DaoComponent {
private final MyBatis mybatis;
+ private final System2 system;
- public QualityProfileDao(MyBatis mybatis) {
+ public QualityProfileDao(MyBatis mybatis, System2 system) {
this.mybatis = mybatis;
+ this.system = system;
}
@CheckForNull
@@ -67,6 +71,9 @@ public class QualityProfileDao implements ServerComponent, DaoComponent {
private void doInsert(QualityProfileMapper mapper, QualityProfileDto profile) {
Preconditions.checkArgument(profile.getId() == null, "Quality profile is already persisted (got id %d)", profile.getId());
+ Date now = new Date(system.now());
+ profile.setCreatedAt(now);
+ profile.setUpdatedAt(now);
mapper.insert(profile);
}
@@ -94,6 +101,7 @@ public class QualityProfileDao implements ServerComponent, DaoComponent {
private void doUpdate(QualityProfileMapper mapper, QualityProfileDto profile) {
Preconditions.checkArgument(profile.getId() != null, "Quality profile is not persisted");
+ profile.setUpdatedAt(new Date(system.now()));
mapper.update(profile);
}
diff --git a/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDto.java b/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDto.java
index bc7224a5fc3..030d67973dc 100644
--- a/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDto.java
+++ b/sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileDto.java
@@ -20,6 +20,7 @@
package org.sonar.core.qualityprofile.db;
+import org.sonar.core.UtcDateUtils;
import org.sonar.core.persistence.Dto;
import javax.annotation.CheckForNull;
@@ -33,7 +34,8 @@ public class QualityProfileDto extends Dto<String> {
private String name;
private String language;
private String parentKee;
- private Date createdAt, updatedAt, rulesUpdatedAt;
+ private Date createdAt, updatedAt;
+ private String rulesUpdatedAt;
/**
* @deprecated use {@link #createFor(String)}
@@ -114,6 +116,24 @@ public class QualityProfileDto extends Dto<String> {
this.updatedAt = updatedAt;
}
+ public String getRulesUpdatedAt() {
+ return rulesUpdatedAt;
+ }
+
+ public Date getRulesUpdatedAtAsDate() {
+ return UtcDateUtils.parseDateTime(rulesUpdatedAt);
+ }
+
+ public QualityProfileDto setRulesUpdatedAt(String s) {
+ this.rulesUpdatedAt = s;
+ return this;
+ }
+
+ public QualityProfileDto setRulesUpdatedAt(Date d) {
+ this.rulesUpdatedAt = UtcDateUtils.formatDateTime(d);
+ return this;
+ }
+
public static QualityProfileDto createFor(String key) {
return new QualityProfileDto().setKee(key);
}
diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/migration/v44/Migration44Mapper.xml b/sonar-core/src/main/resources/org/sonar/core/persistence/migration/v44/Migration44Mapper.xml
index 8adb47e20c7..48669de583b 100644
--- a/sonar-core/src/main/resources/org/sonar/core/persistence/migration/v44/Migration44Mapper.xml
+++ b/sonar-core/src/main/resources/org/sonar/core/persistence/migration/v44/Migration44Mapper.xml
@@ -7,7 +7,7 @@
select pm.id as id, pm.value as profileId, pm.snapshot_id as snapshotId
from project_measures pm
inner join metrics m on m.id=pm.metric_id and m.name='profile'
- inner join snapshots s on s.islast=#{_true} and pm.snapshot_id=s.id and s.scope='PRJ'
+ inner join snapshots s on s.islast=${_true} and pm.snapshot_id=s.id and s.scope='PRJ'
where pm.value is not null
</select>
@@ -18,6 +18,12 @@
where pm.value is not null and s.id=#{id}
</select>
+ <select id="selectProfileById" resultType="org.sonar.core.persistence.migration.v44.QProfileDto44" parameterType="int">
+ select id, kee, name, language
+ from rules_profiles
+ where id=#{id}
+ </select>
+
<select id="selectProfileVersionDate" resultType="date" parameterType="map">
select max(change_date) from active_rule_changes
where profile_id=#{profileId} and profile_version=#{profileVersion}
diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl b/sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl
index bdafd6a0deb..028bfb8749b 100644
--- a/sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl
+++ b/sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl
@@ -51,7 +51,7 @@ CREATE TABLE "RULES_PROFILES" (
"LANGUAGE" VARCHAR(20),
"KEE" VARCHAR(255) NOT NULL,
"PARENT_KEE" VARCHAR(255),
- "RULES_UPDATED_AT" TIMESTAMP,
+ "RULES_UPDATED_AT" VARCHAR(24),
"CREATED_AT" TIMESTAMP,
"UPDATED_AT" TIMESTAMP
);
diff --git a/sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/QualityProfileMapper.xml b/sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/QualityProfileMapper.xml
index 2593e1a7dbe..e6ad1eaf7c8 100644
--- a/sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/QualityProfileMapper.xml
+++ b/sonar-core/src/main/resources/org/sonar/core/qualityprofile/db/QualityProfileMapper.xml
@@ -8,19 +8,24 @@
p.kee as kee,
p.name as name,
p.language as language,
- p.parent_kee as parentKee
+ p.parent_kee as parentKee,
+ p.created_at as createdAt,
+ p.updated_at as updatedAt,
+ p.rules_updated_at as rulesUpdatedAt
</sql>
<insert id="insert" parameterType="QualityProfile" keyColumn="id" useGeneratedKeys="true" keyProperty="id" lang="raw">
- INSERT INTO rules_profiles (kee, parent_kee, name, language)
- VALUES (#{kee}, #{parentKee}, #{name}, #{language})
+ INSERT INTO rules_profiles (kee, parent_kee, name, language, created_at, updated_at, rules_updated_at)
+ VALUES (#{kee}, #{parentKee}, #{name}, #{language}, #{createdAt}, #{updatedAt}, #{rulesUpdatedAt,})
</insert>
<update id="update" parameterType="QualityProfile" lang="raw">
UPDATE rules_profiles SET
name=#{name},
language=#{language},
- parent_kee=#{parentKee}
+ parent_kee=#{parentKee},
+ updated_at=#{updatedAt},
+ rules_updated_at=#{rulesUpdatedAt}
WHERE id=#{id}
</update>
diff --git a/sonar-core/src/test/java/org/sonar/core/UtcDateUtilsTest.java b/sonar-core/src/test/java/org/sonar/core/UtcDateUtilsTest.java
new file mode 100644
index 00000000000..c4d77d23034
--- /dev/null
+++ b/sonar-core/src/test/java/org/sonar/core/UtcDateUtilsTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import org.junit.Test;
+
+import java.util.Date;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
+public class UtcDateUtilsTest {
+
+ @Test
+ public void parse_then_format() throws Exception {
+ Date date = UtcDateUtils.parseDateTime("2014-01-14T14:00:00+0200");
+ assertThat(UtcDateUtils.formatDateTime(date)).isEqualTo("2014-01-14T12:00:00+0000");
+ }
+
+ @Test
+ public void fail_if_bad_format() throws Exception {
+ try {
+ UtcDateUtils.parseDateTime("2014-01-14");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Fail to parse date: 2014-01-14");
+ }
+ }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/qualityprofile/db/QualityProfileDaoTest.java b/sonar-core/src/test/java/org/sonar/core/qualityprofile/db/QualityProfileDaoTest.java
index ecb8862342f..1f1c8554acf 100644
--- a/sonar-core/src/test/java/org/sonar/core/qualityprofile/db/QualityProfileDaoTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/qualityprofile/db/QualityProfileDaoTest.java
@@ -22,20 +22,26 @@ package org.sonar.core.qualityprofile.db;
import org.junit.Before;
import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.core.UtcDateUtils;
import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.persistence.DbSession;
import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class QualityProfileDaoTest extends AbstractDaoTestCase {
QualityProfileDao dao;
+ System2 system = mock(System2.class);
@Before
public void createDao() {
- dao = new QualityProfileDao(getMyBatis());
+ dao = new QualityProfileDao(getMyBatis(), system);
+ when(system.now()).thenReturn(UtcDateUtils.parseDateTime("2014-01-20T12:00:00+0000").getTime());
}
@Test
@@ -48,7 +54,7 @@ public class QualityProfileDaoTest extends AbstractDaoTestCase {
dao.insert(dto);
- checkTables("insert", "rules_profiles");
+ checkTables("insert", new String[]{"created_at", "updated_at", "rules_updated_at"}, "rules_profiles");
}
@Test
@@ -63,7 +69,7 @@ public class QualityProfileDaoTest extends AbstractDaoTestCase {
dao.update(dto);
- checkTables("update", "rules_profiles");
+ checkTables("update", new String[]{"created_at", "updated_at", "rules_updated_at"}, "rules_profiles");
}
@Test