diff options
author | simonbrandhof <simon.brandhof@gmail.com> | 2011-05-19 16:14:21 +0200 |
---|---|---|
committer | simonbrandhof <simon.brandhof@gmail.com> | 2011-05-19 16:14:21 +0200 |
commit | ff3117718a1642e99d97416b88b2db702d1b96f8 (patch) | |
tree | aa3afbd405482ee72453b9dca17266b5465d8e66 /plugins | |
parent | 1dfe5d781675f0a7dfe19dce93757a47262abbae (diff) | |
download | sonarqube-ff3117718a1642e99d97416b88b2db702d1b96f8.tar.gz sonarqube-ff3117718a1642e99d97416b88b2db702d1b96f8.zip |
Fix merge of release 2.8
Diffstat (limited to 'plugins')
8 files changed, 269 insertions, 25 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CloseReviewsDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CloseReviewsDecorator.java index b46108b8840..0b32e50b288 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CloseReviewsDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CloseReviewsDecorator.java @@ -19,6 +19,8 @@ */ package org.sonar.plugins.core.sensors; +import javax.persistence.Query; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.Decorator; @@ -29,10 +31,9 @@ import org.sonar.api.database.DatabaseSession; import org.sonar.api.database.model.Snapshot; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; +import org.sonar.api.resources.ResourceUtils; import org.sonar.batch.index.ResourcePersister; -import javax.persistence.Query; - /** * Decorator that currently only closes a review when its corresponding violation has been fixed. */ @@ -50,7 +51,7 @@ public class CloseReviewsDecorator implements Decorator { } public boolean shouldExecuteOnProject(Project project) { - return true; + return project.isLatestAnalysis(); } public void decorate(Resource resource, DecoratorContext context) { @@ -58,16 +59,32 @@ public class CloseReviewsDecorator implements Decorator { if (currentSnapshot != null) { int resourceId = currentSnapshot.getResourceId(); int snapshotId = currentSnapshot.getId(); - Query query = databaseSession.createNativeQuery(generateSqlRequest(resourceId, snapshotId)); + Query query = databaseSession.createNativeQuery(generateUpdateOnResourceSqlRequest(resourceId, snapshotId)); int rowUpdated = query.executeUpdate(); LOG.debug("- {} reviews set to 'closed' on resource #{}", rowUpdated, resourceId); + + if (ResourceUtils.isRootProject(resource)) { + query = databaseSession.createNativeQuery(generateUpdateOnProjectSqlRequest(resourceId, currentSnapshot.getId())); + query.setParameter(1, Boolean.TRUE); + rowUpdated = query.executeUpdate(); + LOG.debug("- {} reviews set to 'closed' on project #{}", rowUpdated, resourceId); + } + databaseSession.commit(); } } - String generateSqlRequest(int resourceId, int snapshotId) { - return "UPDATE reviews SET status='CLOSED' WHERE resource_id = " + resourceId + " AND rule_failure_permanent_id NOT IN " - + "(SELECT permanent_id FROM rule_failures WHERE snapshot_id = " + snapshotId + " AND permanent_id IS NOT NULL)"; + protected String generateUpdateOnResourceSqlRequest(int resourceId, int snapshotId) { + return "UPDATE reviews SET status='CLOSED', updated_at=CURRENT_TIMESTAMP WHERE resource_id = " + resourceId + + " AND rule_failure_permanent_id NOT IN " + "(SELECT permanent_id FROM rule_failures WHERE snapshot_id = " + snapshotId + + " AND permanent_id IS NOT NULL)"; + } + + protected String generateUpdateOnProjectSqlRequest(int projectId, int projectSnapshotId) { + return "UPDATE reviews SET status='CLOSED', updated_at=CURRENT_TIMESTAMP WHERE status='OPEN' AND project_id=" + projectId + + " AND resource_id IN ( SELECT prev.project_id FROM snapshots prev WHERE prev.root_project_id=" + projectId + + " AND prev.islast=? AND NOT EXISTS ( SELECT cur.id FROM snapshots cur WHERE cur.root_snapshot_id=" + projectSnapshotId + + " AND cur.created_at > prev.created_at AND cur.root_project_id=" + projectId + " AND cur.project_id=prev.project_id ) )"; } } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/CloseReviewsDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/CloseReviewsDecoratorTest.java index 493352c1147..2ea8a7c1de4 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/CloseReviewsDecoratorTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/CloseReviewsDecoratorTest.java @@ -21,25 +21,47 @@ package org.sonar.plugins.core.sensors; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.sql.Statement; +import junit.framework.ComparisonFailure; + import org.junit.Test; +import org.sonar.api.resources.Project; import org.sonar.test.persistence.DatabaseTestCase; public class CloseReviewsDecoratorTest extends DatabaseTestCase { @Test + public void testShouldExecuteOnProject() throws Exception { + Project project = mock(Project.class); + when(project.isLatestAnalysis()).thenReturn(true); + CloseReviewsDecorator reviewsDecorator = new CloseReviewsDecorator(null, null); + assertTrue(reviewsDecorator.shouldExecuteOnProject(project)); + } + + @Test public void shouldCloseReviewWithoutCorrespondingViolation() throws Exception { setupData("fixture"); CloseReviewsDecorator reviewsDecorator = new CloseReviewsDecorator(null, null); - String sqlRequest = reviewsDecorator.generateSqlRequest(666, 222); - + String sqlRequest = reviewsDecorator.generateUpdateOnResourceSqlRequest(666, 222); + Statement stmt = getConnection().createStatement(); int count = stmt.executeUpdate(sqlRequest); assertThat(count, is(1)); - assertTables("shouldCloseReviewWithoutCorrespondingViolation", "reviews"); + assertTables("shouldCloseReviewWithoutCorrespondingViolation", new String[] { "reviews" }, new String[] { "updated_at" }); + + try { + assertTables("shouldCloseReviewWithoutCorrespondingViolation", new String[] { "reviews" }); + fail("'updated_at' columns are identical whereas they should be different."); + } catch (ComparisonFailure e) { + // "updated_at" column must be different, so the comparison should raise this exception + } } } diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/sensors/CloseReviewsDecoratorTest/shouldCloseReviewWithoutCorrespondingViolation-result.xml b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/sensors/CloseReviewsDecoratorTest/shouldCloseReviewWithoutCorrespondingViolation-result.xml index d46429ddf3d..db7bf76f0e0 100644 --- a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/sensors/CloseReviewsDecoratorTest/shouldCloseReviewWithoutCorrespondingViolation-result.xml +++ b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/sensors/CloseReviewsDecoratorTest/shouldCloseReviewWithoutCorrespondingViolation-result.xml @@ -5,18 +5,18 @@ status="OPEN" rule_failure_permanent_id="1" resource_id="555" - created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]"/> + created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]" project_id="[null]"/> <reviews id="2" status="CLOSED" rule_failure_permanent_id="2" resource_id="666" - created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]"/> + created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]" project_id="[null]"/> <reviews id="3" status="OPEN" rule_failure_permanent_id="3" resource_id="666" - created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]"/> + created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]" project_id="[null]"/> </dataset>
\ No newline at end of file diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java index f38a6c39b20..a02d8d0a308 100644 --- a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java +++ b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/DbCleanerPlugin.java @@ -19,30 +19,41 @@ */ package org.sonar.plugins.dbcleaner; +import java.util.Arrays; +import java.util.List; + import org.sonar.api.Properties; import org.sonar.api.Property; import org.sonar.api.SonarPlugin; import org.sonar.plugins.dbcleaner.api.DbCleanerConstants; import org.sonar.plugins.dbcleaner.period.DefaultPeriodCleaner; import org.sonar.plugins.dbcleaner.period.PeriodPurge; -import org.sonar.plugins.dbcleaner.purges.*; +import org.sonar.plugins.dbcleaner.purges.PurgeDeletedResources; +import org.sonar.plugins.dbcleaner.purges.PurgeDependencies; +import org.sonar.plugins.dbcleaner.purges.PurgeDeprecatedLast; +import org.sonar.plugins.dbcleaner.purges.PurgeDisabledResources; +import org.sonar.plugins.dbcleaner.purges.PurgeEntities; +import org.sonar.plugins.dbcleaner.purges.PurgeEventOrphans; +import org.sonar.plugins.dbcleaner.purges.PurgeOrphanResources; +import org.sonar.plugins.dbcleaner.purges.PurgeOrphanReviews; +import org.sonar.plugins.dbcleaner.purges.PurgePropertyOrphans; +import org.sonar.plugins.dbcleaner.purges.PurgeResourceRoles; +import org.sonar.plugins.dbcleaner.purges.PurgeRuleMeasures; +import org.sonar.plugins.dbcleaner.purges.PurgeUnprocessed; import org.sonar.plugins.dbcleaner.runner.PurgeRunner; -import java.util.Arrays; -import java.util.List; - @Properties({ - @Property(key = DbCleanerConstants.MONTHS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_WEEK, - defaultValue = DbCleanerConstants.ONE_MONTH, name = "Number of months before starting to keep only one snapshot by week", + @Property(key = DbCleanerConstants.MONTHS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_WEEK, defaultValue = DbCleanerConstants.ONE_MONTH, + name = "Number of months before starting to keep only one snapshot by week", description = "After this number of months, if there are several snapshots during the same week, " + "the DbCleaner keeps the first one and fully delete the other ones.", global = true, project = true), - @Property(key = DbCleanerConstants.MONTHS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_MONTH, - defaultValue = DbCleanerConstants.ONE_YEAR, name = "Number of months before starting to keep only one snapshot by month", + @Property(key = DbCleanerConstants.MONTHS_BEFORE_KEEPING_ONLY_ONE_SNAPSHOT_BY_MONTH, defaultValue = DbCleanerConstants.ONE_YEAR, + name = "Number of months before starting to keep only one snapshot by month", description = "After this number of months, if there are several snapshots during the same month, " + "the DbCleaner keeps the first one and fully delete the other ones.", global = true, project = true), @Property(key = DbCleanerConstants.MONTHS_BEFORE_DELETING_ALL_SNAPSHOTS, defaultValue = DbCleanerConstants.FIVE_YEARS, name = "Number of months before starting to delete all remaining snapshots", - description = "After this number of months, all snapshots are fully deleted.", global = true, project = true)}) + description = "After this number of months, all snapshots are fully deleted.", global = true, project = true) }) public final class DbCleanerPlugin extends SonarPlugin { public List getExtensions() { @@ -51,9 +62,9 @@ public final class DbCleanerPlugin extends SonarPlugin { DefaultPeriodCleaner.class, // purges - PurgeOrphanResources.class, PurgeEntities.class, PurgeRuleMeasures.class, PurgeUnprocessed.class, - PurgeDeletedResources.class, PurgeDeprecatedLast.class, PurgeDisabledResources.class, - PurgeResourceRoles.class, PurgeEventOrphans.class, PurgePropertyOrphans.class, PeriodPurge.class, PurgeDependencies.class, + PurgeOrphanResources.class, PurgeEntities.class, PurgeRuleMeasures.class, PurgeUnprocessed.class, PurgeDeletedResources.class, + PurgeDeprecatedLast.class, PurgeDisabledResources.class, PurgeResourceRoles.class, PurgeEventOrphans.class, + PurgePropertyOrphans.class, PeriodPurge.class, PurgeDependencies.class, PurgeOrphanReviews.class, // post-job PurgeRunner.class); diff --git a/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviews.java b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviews.java new file mode 100644 index 00000000000..8e52416b767 --- /dev/null +++ b/plugins/sonar-dbcleaner-plugin/src/main/java/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviews.java @@ -0,0 +1,66 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.dbcleaner.purges; + +import javax.persistence.Query; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.database.DatabaseSession; +import org.sonar.plugins.dbcleaner.api.Purge; +import org.sonar.plugins.dbcleaner.api.PurgeContext; + +/** + * Purge Review that are attached to projects that have been deleted. + * + * @since 2.8 + */ +public final class PurgeOrphanReviews extends Purge { + + private static final Logger LOG = LoggerFactory.getLogger(PurgeOrphanReviews.class); + + public PurgeOrphanReviews(DatabaseSession session) { + super(session); + } + + public void purge(PurgeContext context) { + DatabaseSession session = getSession(); + + // delete reviews + Query query = session.createNativeQuery(getDeleteReviewsSqlRequest()); + int rowDeleted = query.executeUpdate(); + LOG.debug("- {} reviews deleted.", rowDeleted); + + // and delete review comments + query = session.createNativeQuery(getDeleteReviewCommentsSqlRequest()); + rowDeleted = query.executeUpdate(); + LOG.debug("- {} review comments deleted.", rowDeleted); + + session.commit(); + } + + protected String getDeleteReviewsSqlRequest() { + return "DELETE FROM reviews WHERE project_id not in (SELECT id FROM projects WHERE scope = 'PRJ' and qualifier = 'TRK')"; + } + + protected String getDeleteReviewCommentsSqlRequest() { + return "DELETE FROM review_comments WHERE review_id not in (SELECT id FROM reviews)"; + } +} diff --git a/plugins/sonar-dbcleaner-plugin/src/test/java/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviewsTest.java b/plugins/sonar-dbcleaner-plugin/src/test/java/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviewsTest.java new file mode 100644 index 00000000000..de1632ac757 --- /dev/null +++ b/plugins/sonar-dbcleaner-plugin/src/test/java/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviewsTest.java @@ -0,0 +1,46 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.dbcleaner.purges; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import java.sql.Statement; + +import org.junit.Test; +import org.sonar.test.persistence.DatabaseTestCase; + +public class PurgeOrphanReviewsTest extends DatabaseTestCase { + + @Test + public void shouldCloseReviewWithoutCorrespondingViolation() throws Exception { + setupData("purgeOrphanReviews"); + + Statement stmt = getConnection().createStatement(); + int count = stmt.executeUpdate(new PurgeOrphanReviews(null).getDeleteReviewsSqlRequest()); + assertThat(count, is(1)); + + count = stmt.executeUpdate(new PurgeOrphanReviews(null).getDeleteReviewCommentsSqlRequest()); + assertThat(count, is(1)); + + assertTables("purgeOrphanReviews", "reviews"); + } + +} diff --git a/plugins/sonar-dbcleaner-plugin/src/test/resources/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviewsTest/purgeOrphanReviews-result.xml b/plugins/sonar-dbcleaner-plugin/src/test/resources/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviewsTest/purgeOrphanReviews-result.xml new file mode 100644 index 00000000000..7680bdd39c0 --- /dev/null +++ b/plugins/sonar-dbcleaner-plugin/src/test/resources/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviewsTest/purgeOrphanReviews-result.xml @@ -0,0 +1,43 @@ +<dataset> + <projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="other-project" name="other-project" + root_id="[null]" profile_id="[null]" + description="[null]" + enabled="true" language="java" copy_resource_id="[null]"/> + + <!-- project1 has been removed from UI --> + <!--<projects long_name="[null]" id="2" scope="PRJ" qualifier="TRK" kee="project1" name="project1"--> + <!--root_id="[null]"--> + <!--description="[null]"--> + <!--enabled="true" language="java" copy_resource_id="[null]"/>--> + + <reviews + id="1" + status="OPEN" + rule_failure_permanent_id="1" + resource_id="555" + project_id="1" + created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]"/> + + <!-- Following must have been deleted + <reviews + id="2" + status="CLOSED" + rule_failure_permanent_id="2" + resource_id="666" + project_id="2" + created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]"/> + --> + + <review_comments + id="1" + review_id="1" + created_at="[null]" updated_at="[null]" user_id="[null]" review_text=""/> + + <!-- Following must have been deleted + <review_comments + id="2" + review_id="2" + created_at="[null]" updated_at="[null]" user_id="[null]" review_text=""/> + --> + +</dataset>
\ No newline at end of file diff --git a/plugins/sonar-dbcleaner-plugin/src/test/resources/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviewsTest/purgeOrphanReviews.xml b/plugins/sonar-dbcleaner-plugin/src/test/resources/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviewsTest/purgeOrphanReviews.xml new file mode 100644 index 00000000000..01da1669b40 --- /dev/null +++ b/plugins/sonar-dbcleaner-plugin/src/test/resources/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviewsTest/purgeOrphanReviews.xml @@ -0,0 +1,39 @@ +<dataset> + <projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="other-project" name="other-project" + root_id="[null]" profile_id="[null]" + description="[null]" + enabled="true" language="java" copy_resource_id="[null]"/> + + <!-- project1 has been removed from UI --> + <!--<projects long_name="[null]" id="2" scope="PRJ" qualifier="TRK" kee="project1" name="project1"--> + <!--root_id="[null]"--> + <!--description="[null]"--> + <!--enabled="true" language="java" copy_resource_id="[null]"/>--> + + <reviews + id="1" + status="OPEN" + rule_failure_permanent_id="1" + resource_id="555" + project_id="1" + created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]"/> + <reviews + id="2" + status="CLOSED" + rule_failure_permanent_id="2" + resource_id="666" + project_id="2" + created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]"/> + + <review_comments + id="1" + review_id="1" + created_at="[null]" updated_at="[null]" user_id="[null]" review_text=""/> + + <review_comments + id="2" + review_id="2" + created_at="[null]" updated_at="[null]" user_id="[null]" review_text=""/> + + +</dataset>
\ No newline at end of file |