From 9d6b148aea0128fbf5d92a9abdb56031b10de972 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Tue, 7 May 2013 10:05:19 +0200 Subject: [PATCH] SONAR-3755 Add query to get open and closed action plan stats --- .../sonar/core/issue/ActionPlanFinder.java | 18 ++++- .../core/issue/db/ActionPlanStatsDao.java | 13 ++- .../core/issue/db/ActionPlanStatsMapper.java | 2 +- .../core/issue/db/ActionPlanStatsMapper.xml | 21 ++++- .../core/issue/ActionPlanFinderTest.java | 26 ++++-- .../core/issue/db/ActionPlanStatsDaoTest.java | 20 ++++- ....xml => should_find_closed_by_project.xml} | 29 ++++++- .../should_find_open_by_project.xml | 81 +++++++++++++++++++ .../sonar/server/issue/WebIssuesInternal.java | 12 ++- .../issues_action_plans_controller.rb | 6 +- .../issues_action_plans/_progress.html.erb | 4 +- 11 files changed, 204 insertions(+), 28 deletions(-) rename sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/{should_find_by_project.xml => should_find_closed_by_project.xml} (65%) create mode 100644 sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_open_by_project.xml diff --git a/sonar-core/src/main/java/org/sonar/core/issue/ActionPlanFinder.java b/sonar-core/src/main/java/org/sonar/core/issue/ActionPlanFinder.java index 2a4b97c79b7..0164c96c088 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/ActionPlanFinder.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/ActionPlanFinder.java @@ -68,12 +68,26 @@ public class ActionPlanFinder implements ServerComponent { return toActionPlans(actionPlanDtos); } - public List findActionPlanStats(String projectKey) { + public List findOpenActionPlanStats(String projectKey) { ResourceDto resourceDto = resourceDao.getResource(ResourceQuery.create().setKey(projectKey)); if (resourceDto == null) { throw new IllegalArgumentException("Project " + projectKey + " does not exists."); } - Collection actionPlanStatsDtos = actionPlanStatsDao.findByProjectId(resourceDto.getId()); + Collection actionPlanStatsDtos = actionPlanStatsDao.findOpenByProjectId(resourceDto.getId()); + return newArrayList(Iterables.transform(actionPlanStatsDtos, new Function() { + @Override + public ActionPlanStats apply(ActionPlanStatsDto actionPlanStatsDto) { + return actionPlanStatsDto.toActionPlanStat(); + } + })); + } + + public List findClosedActionPlanStats(String projectKey) { + ResourceDto resourceDto = resourceDao.getResource(ResourceQuery.create().setKey(projectKey)); + if (resourceDto == null) { + throw new IllegalArgumentException("Project " + projectKey + " does not exists."); + } + Collection actionPlanStatsDtos = actionPlanStatsDao.findClosedByProjectId(resourceDto.getId()); return newArrayList(Iterables.transform(actionPlanStatsDtos, new Function() { @Override public ActionPlanStats apply(ActionPlanStatsDto actionPlanStatsDto) { diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsDao.java b/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsDao.java index 443b23f9f8a..a6e5d7fad9f 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsDao.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsDao.java @@ -23,6 +23,7 @@ package org.sonar.core.issue.db; import org.apache.ibatis.session.SqlSession; import org.sonar.api.BatchComponent; import org.sonar.api.ServerComponent; +import org.sonar.api.issue.ActionPlan; import org.sonar.core.persistence.MyBatis; import java.util.Collection; @@ -38,13 +39,21 @@ public class ActionPlanStatsDao implements BatchComponent, ServerComponent { this.mybatis = mybatis; } - public Collection findByProjectId(Long projectId) { + private Collection findByProjectId(Long projectId, String status, String sort, boolean asc) { SqlSession session = mybatis.openSession(); try { - return session.getMapper(ActionPlanStatsMapper.class).findByProjectId(projectId); + return session.getMapper(ActionPlanStatsMapper.class).findByProjectId(projectId, status, sort, asc); } finally { MyBatis.closeQuietly(session); } } + public Collection findOpenByProjectId(Long projectId) { + return findByProjectId(projectId, ActionPlan.STATUS_OPEN, "DEADLINE", true); + } + + public Collection findClosedByProjectId(Long projectId) { + return findByProjectId(projectId, ActionPlan.STATUS_CLOSED, "DEADLINE", false); + } + } diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsMapper.java b/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsMapper.java index 7fc910f6af4..e1fceaac7fb 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsMapper.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/db/ActionPlanStatsMapper.java @@ -32,5 +32,5 @@ public interface ActionPlanStatsMapper { /** * @since3.6 */ - Collection findByProjectId(@Param("projectId") Long projectId); + Collection findByProjectId(@Param("projectId") Long projectId, @Param("status")String status, @Param("sort")String sort, @Param("asc")boolean asc); } diff --git a/sonar-core/src/main/resources/org/sonar/core/issue/db/ActionPlanStatsMapper.xml b/sonar-core/src/main/resources/org/sonar/core/issue/db/ActionPlanStatsMapper.xml index 32e916baf9f..dd359fece9b 100644 --- a/sonar-core/src/main/resources/org/sonar/core/issue/db/ActionPlanStatsMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/issue/db/ActionPlanStatsMapper.xml @@ -17,15 +17,32 @@ ap.updated_at as updatedAt - select , count(total_issues.id) as totalIssues, count(open_issues.id) as openIssues from action_plans ap left join issues total_issues on total_issues.action_plan_key = ap.kee - left join issues open_issues on open_issues.id = total_issues.id and open_issues.status != 'CLOSED' + left join issues open_issues on open_issues.id = total_issues.id and open_issues.resolution is null and ap.project_id = #{projectId} + and ap.status = #{status} group by ap.id, ap.kee, ap.name, ap.description, ap.user_login, ap.project_id, ap.status, ap.deadline, ap.created_at, ap.updated_at + + order by + + + ap.deadline + + + + + asc + + + desc + + + \ No newline at end of file diff --git a/sonar-core/src/test/java/org/sonar/core/issue/ActionPlanFinderTest.java b/sonar-core/src/test/java/org/sonar/core/issue/ActionPlanFinderTest.java index 084004c405f..e858359bf60 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/ActionPlanFinderTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/ActionPlanFinderTest.java @@ -75,19 +75,35 @@ public class ActionPlanFinderTest { } @Test - public void should_find_action_plan_stats(){ + public void should_find_open_action_plan_stats(){ when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(new ResourceDto().setId(1L).setKey("org.sonar.Sample")); - when(actionPlanStatsDao.findByProjectId(1L)).thenReturn(newArrayList(new ActionPlanStatsDto())); + when(actionPlanStatsDao.findOpenByProjectId(1L)).thenReturn(newArrayList(new ActionPlanStatsDto())); - Collection results = actionPlanFinder.findActionPlanStats("org.sonar.Sample"); + Collection results = actionPlanFinder.findOpenActionPlanStats("org.sonar.Sample"); assertThat(results).hasSize(1); } @Test(expected = IllegalArgumentException.class) - public void should_throw_exception_if_project_not_found_when_find_action_plan_stats(){ + public void should_throw_exception_if_project_not_found_when_find_open_action_plan_stats(){ when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(null); - actionPlanFinder.findActionPlanStats("org.sonar.Sample"); + actionPlanFinder.findOpenActionPlanStats("org.sonar.Sample"); + } + + @Test + public void should_find_closed_action_plan_stats(){ + when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(new ResourceDto().setId(1L).setKey("org.sonar.Sample")); + when(actionPlanStatsDao.findClosedByProjectId(1L)).thenReturn(newArrayList(new ActionPlanStatsDto())); + + Collection results = actionPlanFinder.findClosedActionPlanStats("org.sonar.Sample"); + assertThat(results).hasSize(1); + } + + @Test(expected = IllegalArgumentException.class) + public void should_throw_exception_if_project_not_found_when_find_closed_action_plan_stats(){ + when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(null); + + actionPlanFinder.findClosedActionPlanStats("org.sonar.Sample"); } } diff --git a/sonar-core/src/test/java/org/sonar/core/issue/db/ActionPlanStatsDaoTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/ActionPlanStatsDaoTest.java index f90831d7513..2161ab28904 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/db/ActionPlanStatsDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/ActionPlanStatsDaoTest.java @@ -38,14 +38,26 @@ public class ActionPlanStatsDaoTest extends AbstractDaoTestCase { } @Test - public void should_find_by_project() { - setupData("should_find_by_project"); + public void should_find_open_by_project() { + setupData("should_find_open_by_project"); - Collection result = dao.findByProjectId(1l); + Collection result = dao.findOpenByProjectId(1l); assertThat(result).isNotEmpty(); ActionPlanStatsDto actionPlanStatsDto = result.iterator().next(); - assertThat(actionPlanStatsDto.getTotalIssues()).isEqualTo(2); + assertThat(actionPlanStatsDto.getTotalIssues()).isEqualTo(3); + assertThat(actionPlanStatsDto.getOpenIssues()).isEqualTo(1); + } + + @Test + public void should_find_closed_by_project() { + setupData("should_find_closed_by_project"); + + Collection result = dao.findClosedByProjectId(1l); + assertThat(result).isNotEmpty(); + + ActionPlanStatsDto actionPlanStatsDto = result.iterator().next(); + assertThat(actionPlanStatsDto.getTotalIssues()).isEqualTo(3); assertThat(actionPlanStatsDto.getOpenIssues()).isEqualTo(1); } diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_by_project.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_closed_by_project.xml similarity index 65% rename from sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_by_project.xml rename to sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_closed_by_project.xml index b31d0d7b13f..ec95313fff9 100644 --- a/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_by_project.xml +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_closed_by_project.xml @@ -1,7 +1,7 @@ + user_login="igor" status="CLOSED" created_at="[null]" updated_at="[null]" /> + + diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_open_by_project.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_open_by_project.xml new file mode 100644 index 00000000000..6596479511f --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/issue/db/ActionPlanStatsDaoTest/should_find_open_by_project.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + diff --git a/sonar-server/src/main/java/org/sonar/server/issue/WebIssuesInternal.java b/sonar-server/src/main/java/org/sonar/server/issue/WebIssuesInternal.java index 10cf0e8e469..c87cabcc822 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/WebIssuesInternal.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/WebIssuesInternal.java @@ -94,12 +94,16 @@ public class WebIssuesInternal implements ServerComponent { return actions.create((DefaultIssue) issue, UserSession.get()); } - List actionPlanStats(String projectKey) { - return actionPlanFinder.findActionPlanStats(projectKey); - } - Collection openActionPlans(String projectKey) { return actionPlanFinder.findOpenByProjectKey(projectKey); } + List openActionPlanStats(String projectKey) { + return actionPlanFinder.findOpenActionPlanStats(projectKey); + } + + List closedActionPlanStats(String projectKey) { + return actionPlanFinder.findClosedActionPlanStats(projectKey); + } + } diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_action_plans_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_action_plans_controller.rb index 1929d4ff32d..8450956786e 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_action_plans_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issues_action_plans_controller.rb @@ -95,10 +95,8 @@ class IssuesActionPlansController < ApplicationController end def load_action_plans - # TODO sort open by deadline ASC and closed by deadline DESC - action_plans = Internal.issues.actionPlanStats(@resource.key) - @open_action_plans = action_plans.select {|action_plan| action_plan.isOpen()} - @closed_action_plans = action_plans.select {|action_plan| !action_plan.isOpen()} + @open_action_plans = Internal.issues.openActionPlanStats(@resource.key) + @closed_action_plans = Internal.issues.closedActionPlanStats(@resource.key) end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issues_action_plans/_progress.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issues_action_plans/_progress.html.erb index 656a348a995..24fdaf37f09 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issues_action_plans/_progress.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issues_action_plans/_progress.html.erb @@ -4,8 +4,8 @@ options = {:controller => 'project_reviews', :action => 'index', :action_plan_id => action_plan.id} resolved_reviews_link = action_plan.resolvedIssues().to_s - resolved_reviews_link = link_to action_plan.resolvedIssues().to_s, options.merge({:statuses => "#{Review::STATUS_RESOLVED},#{Review::STATUS_CLOSED}"}) unless action_plan.resolvedIssues()==0 - total_reviews_link = link_to action_plan.totalIssues().to_s, options + #resolved_reviews_link = link_to action_plan.resolvedIssues().to_s, options.merge({:statuses => "#{Review::STATUS_RESOLVED},#{Review::STATUS_CLOSED}"}) unless action_plan.resolvedIssues()==0 + #total_reviews_link = link_to action_plan.totalIssues().to_s, options total_reviews_link = action_plan.totalIssues().to_s if action_plan.resolvedIssues() > 0 -- 2.39.5