diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2014-06-23 14:52:56 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@sonarsource.com> | 2014-06-23 14:58:08 +0200 |
commit | 56554cc77e5f0eba7fc75e7d6b340cdc7c2e4698 (patch) | |
tree | b6a8d69f19f1d53d10e4d94204481f4bdd450ba5 /sonar-core | |
parent | f206ca12ae3b445697e88fea1864c29c791196d0 (diff) | |
download | sonarqube-56554cc77e5f0eba7fc75e7d6b340cdc7c2e4698.tar.gz sonarqube-56554cc77e5f0eba7fc75e7d6b340cdc7c2e4698.zip |
SONAR-5216 compare quality profile dates when batch detects profile changes
Diffstat (limited to 'sonar-core')
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 |