aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java21
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml2
-rw-r--r--sonar-core/src/test/java/org/sonar/core/component/ComponentDtoTest.java4
-rw-r--r--sonar-server/src/main/java/org/sonar/server/component/ws/ComponentAppAction.java38
-rw-r--r--sonar-server/src/main/resources/org/sonar/server/component/ws/components-app-example-show.json3
-rw-r--r--sonar-server/src/test/java/org/sonar/server/component/persistence/ComponentDaoTest.java4
-rw-r--r--sonar-server/src/test/java/org/sonar/server/component/ws/ComponentAppActionTest.java55
-rw-r--r--sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java3
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/component/persistence/ComponentDaoTest/shared.xml6
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/component/ws/ComponentAppActionTest/app_with_extensions.json17
10 files changed, 146 insertions, 7 deletions
diff --git a/sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java b/sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java
index 71b48a6eb3f..a106603b7bf 100644
--- a/sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java
+++ b/sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java
@@ -33,6 +33,8 @@ public class ComponentDto extends Dto<String> implements Component {
private String name;
private String longName;
private String qualifier;
+ private String scope;
+ private String language;
private Long projectId;
private Long subProjectId;
@@ -96,6 +98,25 @@ public class ComponentDto extends Dto<String> implements Component {
return this;
}
+ public String scope() {
+ return scope;
+ }
+
+ public ComponentDto setScope(String scope) {
+ this.scope = scope;
+ return this;
+ }
+
+ @CheckForNull
+ public String language() {
+ return language;
+ }
+
+ public ComponentDto setLanguage(@Nullable String language) {
+ this.language = language;
+ return this;
+ }
+
public Long projectId() {
return projectId;
}
diff --git a/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml b/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml
index 27ab64ac750..a604fea396b 100644
--- a/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml
+++ b/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml
@@ -8,6 +8,8 @@
p.name as name,
p.long_name as longName,
p.qualifier as qualifier,
+ p.scope as scope,
+ p.language as language,
s.root_project_id as projectId,
p.root_id as subProjectId,
p.path as path
diff --git a/sonar-core/src/test/java/org/sonar/core/component/ComponentDtoTest.java b/sonar-core/src/test/java/org/sonar/core/component/ComponentDtoTest.java
index 1b2ea6a641f..b71779f0e06 100644
--- a/sonar-core/src/test/java/org/sonar/core/component/ComponentDtoTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/component/ComponentDtoTest.java
@@ -34,6 +34,8 @@ public class ComponentDtoTest {
.setName("RequestContext.java")
.setLongName("org.struts.RequestContext")
.setQualifier("FIL")
+ .setScope("FIL")
+ .setLanguage("java")
.setPath("src/org/struts/RequestContext.java")
.setProjectId(2L)
.setSubProjectId(3L);
@@ -43,7 +45,9 @@ public class ComponentDtoTest {
assertThat(componentDto.name()).isEqualTo("RequestContext.java");
assertThat(componentDto.longName()).isEqualTo("org.struts.RequestContext");
assertThat(componentDto.qualifier()).isEqualTo("FIL");
+ assertThat(componentDto.scope()).isEqualTo("FIL");
assertThat(componentDto.path()).isEqualTo("src/org/struts/RequestContext.java");
+ assertThat(componentDto.language()).isEqualTo("java");
assertThat(componentDto.projectId()).isEqualTo(2L);
assertThat(componentDto.subProjectId()).isEqualTo(3L);
}
diff --git a/sonar-server/src/main/java/org/sonar/server/component/ws/ComponentAppAction.java b/sonar-server/src/main/java/org/sonar/server/component/ws/ComponentAppAction.java
index 7b74b9549dd..47d8e4daca0 100644
--- a/sonar-server/src/main/java/org/sonar/server/component/ws/ComponentAppAction.java
+++ b/sonar-server/src/main/java/org/sonar/server/component/ws/ComponentAppAction.java
@@ -35,6 +35,8 @@ import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.Durations;
import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.api.web.NavigationSection;
+import org.sonar.api.web.Page;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.measure.db.MeasureDto;
@@ -49,6 +51,8 @@ import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.issue.IssueService;
import org.sonar.server.issue.RulesAggregation;
import org.sonar.server.source.SourceService;
+import org.sonar.server.ui.ViewProxy;
+import org.sonar.server.ui.Views;
import org.sonar.server.user.UserSession;
import javax.annotation.CheckForNull;
@@ -67,14 +71,16 @@ public class ComponentAppAction implements RequestHandler {
private final IssueService issueService;
private final SourceService sourceService;
+ private final Views views;
private final Periods periods;
private final Durations durations;
private final I18n i18n;
- public ComponentAppAction(DbClient dbClient, IssueService issueService, SourceService sourceService, Periods periods, Durations durations, I18n i18n) {
+ public ComponentAppAction(DbClient dbClient, IssueService issueService, SourceService sourceService, Views views, Periods periods, Durations durations, I18n i18n) {
this.dbClient = dbClient;
this.issueService = issueService;
this.sourceService = sourceService;
+ this.views = views;
this.periods = periods;
this.durations = durations;
this.i18n = i18n;
@@ -116,6 +122,7 @@ public class ComponentAppAction implements RequestHandler {
appendPeriods(json, component.projectId(), session);
appendIssuesAggregation(json, component.key(), session);
appendMeasures(json, component, session);
+ appendExtensions(json, component, userSession);
} finally {
MyBatis.closeQuietly(session);
}
@@ -228,6 +235,35 @@ public class ComponentAppAction implements RequestHandler {
json.endArray();
}
+ private void appendExtensions(JsonWriter json, ComponentDto component, UserSession userSession) {
+ List<ViewProxy<Page>> extensionPages = views.getPages(NavigationSection.RESOURCE_TAB, component.scope(), component.qualifier(), component.language(), null);
+ List<String> extensions = extensions(extensionPages, component, userSession);
+ if (!extensions.isEmpty()) {
+ json.name("extensions").beginArray();
+ json.values(extensions);
+ json.endArray();
+ }
+ }
+
+ private List<String> extensions(List<ViewProxy<Page>> extensions, ComponentDto component, UserSession userSession){
+ List<String> result = newArrayList();
+ List<String> providedExtensions = newArrayList("tests_viewer", "coverage", "duplications", "issues", "source");
+ for (ViewProxy<Page> page : extensions) {
+ if (!providedExtensions.contains(page.getId())) {
+ if (page.getUserRoles().length == 0) {
+ result.add(page.getId());
+ } else {
+ for (String userRole : page.getUserRoles()) {
+ if (userSession.hasComponentPermission(userRole, component.key())) {
+ result.add(page.getId());
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+
@CheckForNull
private Component componentById(@Nullable Long componentId, DbSession session) {
if (componentId != null) {
diff --git a/sonar-server/src/main/resources/org/sonar/server/component/ws/components-app-example-show.json b/sonar-server/src/main/resources/org/sonar/server/component/ws/components-app-example-show.json
index 5798fdac578..a5561d06187 100644
--- a/sonar-server/src/main/resources/org/sonar/server/component/ws/components-app-example-show.json
+++ b/sonar-server/src/main/resources/org/sonar/server/component/ws/components-app-example-show.json
@@ -45,5 +45,6 @@
"fDebt": "4h",
"fIssues": "4",
"fInfoIssues": "4"
- }
+ },
+ "extensions": ["metricsTab"]
}
diff --git a/sonar-server/src/test/java/org/sonar/server/component/persistence/ComponentDaoTest.java b/sonar-server/src/test/java/org/sonar/server/component/persistence/ComponentDaoTest.java
index 2e8f075c82b..9d1cc0fcecf 100644
--- a/sonar-server/src/test/java/org/sonar/server/component/persistence/ComponentDaoTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/component/persistence/ComponentDaoTest.java
@@ -56,6 +56,8 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
assertThat(result.name()).isEqualTo("RequestContext.java");
assertThat(result.longName()).isEqualTo("org.struts.RequestContext");
assertThat(result.qualifier()).isEqualTo("FIL");
+ assertThat(result.scope()).isEqualTo("FIL");
+ assertThat(result.language()).isEqualTo("java");
assertThat(result.subProjectId()).isEqualTo(2);
assertThat(result.projectId()).isEqualTo(1);
@@ -73,6 +75,8 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
assertThat(result.name()).isEqualTo("Struts");
assertThat(result.longName()).isEqualTo("Apache Struts");
assertThat(result.qualifier()).isEqualTo("TRK");
+ assertThat(result.scope()).isEqualTo("PRJ");
+ assertThat(result.language()).isNull();
assertThat(result.subProjectId()).isNull();
assertThat(result.projectId()).isEqualTo(1);
}
diff --git a/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentAppActionTest.java b/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentAppActionTest.java
index 84e20e69d8f..c059072f2d6 100644
--- a/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentAppActionTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentAppActionTest.java
@@ -34,6 +34,8 @@ import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
+import org.sonar.api.web.NavigationSection;
+import org.sonar.api.web.Page;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.measure.db.MeasureDto;
@@ -52,6 +54,8 @@ import org.sonar.server.issue.IssueService;
import org.sonar.server.issue.RulesAggregation;
import org.sonar.server.measure.persistence.MeasureDao;
import org.sonar.server.source.SourceService;
+import org.sonar.server.ui.ViewProxy;
+import org.sonar.server.ui.Views;
import org.sonar.server.user.MockUserSession;
import org.sonar.server.ws.WsTester;
@@ -96,6 +100,9 @@ public class ComponentAppActionTest {
SourceService sourceService;
@Mock
+ Views views;
+
+ @Mock
Periods periods;
@Mock
@@ -124,7 +131,7 @@ public class ComponentAppActionTest {
when(issueService.findRulesByComponent(anyString(), eq(session))).thenReturn(mock(RulesAggregation.class));
when(measureDao.findByComponentKeyAndMetricKeys(anyString(), anyListOf(String.class), eq(session))).thenReturn(measures);
- tester = new WsTester(new ComponentsWs(new ComponentAppAction(dbClient, issueService, sourceService, periods, durations, i18n)));
+ tester = new WsTester(new ComponentsWs(new ComponentAppAction(dbClient, issueService, sourceService, views, periods, durations, i18n)));
}
@Test
@@ -263,6 +270,18 @@ public class ComponentAppActionTest {
request.execute().assertJson(getClass(), "app_with_rules.json");
}
+ @Test
+ public void app_with_extensions() throws Exception {
+ MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, PROJECT_KEY, COMPONENT_KEY);
+ addComponent();
+
+ when(views.getPages(anyString(), anyString(), anyString(), anyString(), any(String[].class))).thenReturn(
+ newArrayList(new ViewProxy<Page>(new MyExtension()), new ViewProxy<Page>(new MyExtensionWithRole()), new ViewProxy<Page>(new ProvidedExtension())));
+
+ WsTester.TestRequest request = tester.newGetRequest("api/components", "app").setParam("key", COMPONENT_KEY);
+ request.execute().assertJson(getClass(), "app_with_extensions.json");
+ }
+
private void addComponent() {
ComponentDto file = new ComponentDto().setId(10L).setQualifier("FIL").setKey(COMPONENT_KEY).setName("Plugin.java")
.setPath("src/main/java/org/sonar/api/Plugin.java").setSubProjectId(5L).setProjectId(1L);
@@ -281,4 +300,38 @@ public class ComponentAppActionTest {
when(i18n.formatDouble(any(Locale.class), eq(value))).thenReturn(Double.toString(value));
}
+ @NavigationSection(NavigationSection.RESOURCE_TAB)
+ private static class MyExtension implements Page {
+ public String getId() {
+ return "my-extension";
+ }
+
+ public String getTitle() {
+ return "my-extension";
+ }
+ }
+
+ @NavigationSection(NavigationSection.RESOURCE_TAB)
+ @UserRole(UserRole.CODEVIEWER)
+ private static class MyExtensionWithRole implements Page {
+ public String getId() {
+ return "my-extension-with-role";
+ }
+
+ public String getTitle() {
+ return "my-extension-with-role";
+ }
+ }
+
+ @NavigationSection(NavigationSection.RESOURCE_TAB)
+ private static class ProvidedExtension implements Page {
+ public String getId() {
+ return "issues";
+ }
+
+ public String getTitle() {
+ return "issues";
+ }
+ }
+
}
diff --git a/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java b/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java
index dc952770f8a..b61e0a2de9f 100644
--- a/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java
@@ -30,6 +30,7 @@ import org.sonar.core.timemachine.Periods;
import org.sonar.server.db.DbClient;
import org.sonar.server.issue.IssueService;
import org.sonar.server.source.SourceService;
+import org.sonar.server.ui.Views;
import org.sonar.server.ws.WsTester;
import static org.fest.assertions.Assertions.assertThat;
@@ -41,7 +42,7 @@ public class ComponentsWsTest {
@Before
public void setUp() throws Exception {
- WsTester tester = new WsTester(new ComponentsWs(new ComponentAppAction(mock(DbClient.class), mock(IssueService.class), mock(SourceService.class),
+ WsTester tester = new WsTester(new ComponentsWs(new ComponentAppAction(mock(DbClient.class), mock(IssueService.class), mock(SourceService.class), mock(Views.class),
mock(Periods.class), mock(Durations.class), mock(I18n.class))));
controller = tester.controller("api/components");
}
diff --git a/sonar-server/src/test/resources/org/sonar/server/component/persistence/ComponentDaoTest/shared.xml b/sonar-server/src/test/resources/org/sonar/server/component/persistence/ComponentDaoTest/shared.xml
index c86f8c33061..05861ec543f 100644
--- a/sonar-server/src/test/resources/org/sonar/server/component/persistence/ComponentDaoTest/shared.xml
+++ b/sonar-server/src/test/resources/org/sonar/server/component/persistence/ComponentDaoTest/shared.xml
@@ -7,7 +7,7 @@
<!-- root project -->
<projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
description="the description" long_name="Apache Struts"
- enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]"/>
+ enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]"/>
<snapshots id="1" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
status="P" islast="[true]" purge_status="[null]"
period1_mode="[null]" period1_param="[null]" period1_date="[null]"
@@ -30,7 +30,7 @@
<!-- module -->
<projects id="2" root_id="1" kee="org.struts:struts-core" name="Struts Core"
scope="PRJ" qualifier="BRC" long_name="Struts Core"
- description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"/>
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"/>
<snapshots id="2" project_id="2" parent_snapshot_id="1" root_project_id="1" root_snapshot_id="1"
status="P" islast="[true]" purge_status="[null]"
period1_mode="[null]" period1_param="[null]" period1_date="[null]"
@@ -45,7 +45,7 @@
<projects long_name="org.struts" id="3" scope="DIR" qualifier="DIR" kee="org.struts:struts-core:src/org/struts"
name="src/org/struts" root_id="2"
description="[null]"
- enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts"/>
+ enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="src/org/struts"/>
<snapshots id="3" project_id="3" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1"
status="P" islast="[true]" purge_status="[null]"
period1_mode="[null]" period1_param="[null]" period1_date="[null]"
diff --git a/sonar-server/src/test/resources/org/sonar/server/component/ws/ComponentAppActionTest/app_with_extensions.json b/sonar-server/src/test/resources/org/sonar/server/component/ws/ComponentAppActionTest/app_with_extensions.json
new file mode 100644
index 00000000000..a8b2efcb113
--- /dev/null
+++ b/sonar-server/src/test/resources/org/sonar/server/component/ws/ComponentAppActionTest/app_with_extensions.json
@@ -0,0 +1,17 @@
+{
+ "key": "org.codehaus.sonar:sonar-plugin-api:src/main/java/org/sonar/api/Plugin.java",
+ "path": "src/main/java/org/sonar/api/Plugin.java",
+ "name": "Plugin.java",
+ "q": "FIL",
+ "subProjectName": "SonarQube :: Plugin API",
+ "projectName": "SonarQube",
+ "fav": false,
+ "scmAvailable": false,
+ "canMarkAsFavourite": false,
+ "canBulkChange": false,
+ "periods": [],
+ "severities": [],
+ "rules": [],
+ "measures": {},
+ "extensions": ["my-extension", "my-extension-with-role"]
+}