diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2012-02-22 00:33:15 +0100 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2012-02-22 00:33:15 +0100 |
commit | 323ace33d564b236e17bce37c8513ee0148aa262 (patch) | |
tree | 76197f8c44109aaa24904f30a49fabe91f5c7507 | |
parent | 58d94501900849959346beb5988454122c623470 (diff) | |
download | sonarqube-323ace33d564b236e17bce37c8513ee0148aa262.tar.gz sonarqube-323ace33d564b236e17bce37c8513ee0148aa262.zip |
SONAR-3208 new extension point to declare tree of resource types
* new extension point org.sonar.api.resources.ResourceTypeTree
* new component org.sonar.api.resources.ResourceTypes to access resource types
* fix compatibility of hotspots, clouds and treemaps with PROJECT_MEASURES.PERSON_ID
* ApplicationController share ruby methods to load the selected resource
44 files changed, 700 insertions, 365 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index 1bbb8c29ecb..75766f58560 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -37,8 +37,6 @@ import org.sonar.plugins.core.colorizers.JavaColorizerFormat; import org.sonar.plugins.core.dashboards.HotspotsDashboard; import org.sonar.plugins.core.dashboards.DefaultDashboard; import org.sonar.plugins.core.dashboards.ReviewsDashboard; -import org.sonar.plugins.core.metrics.UserManagedMetrics; -import org.sonar.plugins.core.resources.DefaultResources; import org.sonar.plugins.core.security.ApplyProjectRolesDecorator; import org.sonar.plugins.core.sensors.*; import org.sonar.plugins.core.testdetailsviewer.TestsViewerDefinition; @@ -227,7 +225,8 @@ public class CorePlugin extends SonarPlugin { public List getExtensions() { List extensions = Lists.newLinkedList(); - extensions.add(DefaultResources.class); + extensions.add(DefaultResourceTypes.class); + extensions.add(UserManagedMetrics.class); extensions.add(ProjectFileSystemLogger.class); // maven @@ -236,9 +235,6 @@ public class CorePlugin extends SonarPlugin { // languages extensions.add(Java.class); - // metrics - extensions.add(UserManagedMetrics.class); - // pages extensions.add(TestsViewerDefinition.class); extensions.add(Lcom4Viewer.class); diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java new file mode 100644 index 00000000000..aed659ccdfe --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java @@ -0,0 +1,54 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 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.core; + +import org.sonar.api.BatchExtension; +import org.sonar.api.ExtensionProvider; +import org.sonar.api.ServerExtension; +import org.sonar.api.batch.InstantiationStrategy; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.resources.ResourceType; +import org.sonar.api.resources.ResourceTypeTree; + +@InstantiationStrategy(InstantiationStrategy.PER_BATCH) +public final class DefaultResourceTypes extends ExtensionProvider implements BatchExtension, ServerExtension { + + @Override + public ResourceTypeTree provide() { + return ResourceTypeTree.builder() + + .addType(ResourceType.builder(Qualifiers.PROJECT).build()) + .addType(ResourceType.builder(Qualifiers.MODULE).build()) + .addType(ResourceType.builder(Qualifiers.DIRECTORY).build()) + .addType(ResourceType.builder(Qualifiers.PACKAGE).build()) + .addType(ResourceType.builder(Qualifiers.FILE).hasSourceCode().build()) + .addType(ResourceType.builder(Qualifiers.CLASS).hasSourceCode().build()) + .addType(ResourceType.builder(Qualifiers.UNIT_TEST_FILE).hasSourceCode().build()) + + .addRelations(Qualifiers.PROJECT, Qualifiers.MODULE) + .addRelations(Qualifiers.MODULE, Qualifiers.DIRECTORY, Qualifiers.PACKAGE) + .addRelations(Qualifiers.DIRECTORY, Qualifiers.FILE, Qualifiers.UNIT_TEST_FILE) + .addRelations(Qualifiers.PACKAGE, Qualifiers.CLASS, Qualifiers.UNIT_TEST_FILE) + + .build(); + + } + +} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/metrics/UserManagedMetrics.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/UserManagedMetrics.java index 16020746737..8b1aa5e33f7 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/metrics/UserManagedMetrics.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/UserManagedMetrics.java @@ -17,8 +17,9 @@ * 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.core.metrics; +package org.sonar.plugins.core; +import com.google.common.collect.ImmutableList; import org.sonar.api.measures.Metric; import org.sonar.api.measures.Metrics; @@ -29,7 +30,7 @@ public final class UserManagedMetrics implements Metrics { private static final String DOMAIN = "Management"; public List<Metric> getMetrics() { - return Arrays.asList( + return ImmutableList.of( new Metric.Builder("burned_budget", "Burned budget", Metric.ValueType.FLOAT) .setDirection(Metric.DIRECTION_NONE) .setQualitative(false) diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/resources/DefaultResources.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/resources/DefaultResources.java deleted file mode 100644 index e2ae90b40bd..00000000000 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/resources/DefaultResources.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 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.core.resources; - -import org.sonar.api.BatchExtension; -import org.sonar.api.ExtensionProvider; -import org.sonar.api.ServerExtension; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.ResourceDefinition; - -import java.util.Arrays; -import java.util.List; - -public class DefaultResources extends ExtensionProvider implements BatchExtension, ServerExtension { - - @Override - public List<ResourceDefinition> provide() { - return Arrays.asList( - ResourceDefinition.builder(Qualifiers.VIEW).build(), - ResourceDefinition.builder(Qualifiers.SUBVIEW).build(), - ResourceDefinition.builder(Qualifiers.PROJECT).build(), - ResourceDefinition.builder(Qualifiers.MODULE).build(), - ResourceDefinition.builder(Qualifiers.DIRECTORY).build(), - ResourceDefinition.builder(Qualifiers.PACKAGE).build(), - ResourceDefinition.builder(Qualifiers.FILE).hasSourceCode().build(), - ResourceDefinition.builder(Qualifiers.CLASS).hasSourceCode().build(), - ResourceDefinition.builder(Qualifiers.UNIT_TEST_FILE).hasSourceCode().build(), - ResourceDefinition.builder(Qualifiers.LIBRARY).build()); - } - -} diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/hotspots/hotspot_metric.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/hotspots/hotspot_metric.html.erb index 48935341c98..38137a1446c 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/hotspots/hotspot_metric.html.erb +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/hotspots/hotspot_metric.html.erb @@ -6,15 +6,15 @@ title = message('widget.hotspot_metric.hotspots_by_x', :params => metric.short_name) if title.blank? snapshots = nil - if metric.numeric? - snapshots_conditions=["snapshots.scope = 'FIL'", "snapshots.islast=:islast", "snapshots.status = 'P'"] - snapshots_values={:islast => true} + if metric.numeric? && !@snapshot.leaves_qualifiers.empty? + snapshots_conditions=["snapshots.qualifier in (:qualifiers)", "snapshots.islast=:islast", "snapshots.status = 'P'"] + snapshots_values={:qualifiers => @snapshot.leaves_qualifiers, :islast => true} snapshots_conditions << '(snapshots.id=:sid OR (snapshots.root_snapshot_id=:root_sid AND snapshots.path LIKE :path))' snapshots_values[:sid]=@snapshot.id snapshots_values[:root_sid] = (@snapshot.root_snapshot_id || @snapshot.id) snapshots_values[:path]="#{@snapshot.path}#{@snapshot.id}.%" - measures_conditions = ["project_measures.rule_id IS NULL", "project_measures.characteristic_id IS NULL"] + measures_conditions = ["project_measures.rule_id IS NULL", "project_measures.characteristic_id IS NULL", "project_measures.person_id IS NULL"] measures_values = {} measures_conditions << "project_measures.metric_id = :m_id" measures_values[:m_id] = metric.id diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/hotspots/hotspot_most_violated_resources.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/hotspots/hotspot_most_violated_resources.html.erb index 38495ee908b..c3cde4869f1 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/hotspots/hotspot_most_violated_resources.html.erb +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/hotspots/hotspot_most_violated_resources.html.erb @@ -2,15 +2,14 @@ limit = widget_properties["numberOfLines"] metric = Metric.by_key('weighted_violations') - snapshots_conditions=["snapshots.scope = 'FIL'", "snapshots.islast=:islast", "snapshots.status = 'P'"] - snapshots_values={:islast => true} - snapshots_conditions << "(snapshots.qualifier = 'CLA' OR snapshots.qualifier = 'FIL' OR snapshots.qualifier = 'TRK')" + snapshots_conditions=["snapshots.qualifier in (:qualifiers)", "snapshots.islast=:islast", "snapshots.status = 'P'"] + snapshots_values={:qualifiers => @snapshot.leaves_qualifiers, :islast => true} snapshots_conditions << '(snapshots.id=:sid OR (snapshots.root_snapshot_id=:root_sid AND snapshots.path LIKE :path))' snapshots_values[:sid]=@snapshot.id snapshots_values[:root_sid] = (@snapshot.root_snapshot_id || @snapshot.id) snapshots_values[:path]="#{@snapshot.path}#{@snapshot.id}.%" - measures_conditions = ["project_measures.rule_id IS NULL", "project_measures.characteristic_id IS NULL"] + measures_conditions = ["project_measures.rule_id IS NULL", "project_measures.characteristic_id IS NULL", "project_measures.person_id IS NULL"] measures_values = {} measures_conditions << "project_measures.metric_id = :m_id" measures_values[:m_id] = metric.id diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/time_machine.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/time_machine.html.erb index c2677939d40..e78d6d2fed1 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/time_machine.html.erb +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/time_machine.html.erb @@ -23,8 +23,10 @@ snapshots=Snapshot.for_timemachine_widget(@resource, number_of_columns, options) sids = snapshots.collect { |s| s.id }.uniq measures=ProjectMeasure.find(:all, - :conditions => ["snapshot_id IN (:snapshot_id) AND metric_id IN (:metric_id) AND rule_id IS NULL AND characteristic_id IS NULL", - {:snapshot_id => sids, :metric_id => metric_ids}] + :conditions => + ["snapshot_id IN (:snapshot_id) AND metric_id IN (:metric_id) AND rule_id IS NULL AND characteristic_id IS NULL AND person_id IS NULL", + {:snapshot_id => sids, :metric_id => metric_ids} + ] ) # And prepare the rows to display diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/resources/DefaultResourcesTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/DefaultResourceTypesTest.java index 3120c17d488..9bf732c734c 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/resources/DefaultResourcesTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/DefaultResourceTypesTest.java @@ -17,20 +17,22 @@ * 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.core.resources; +package org.sonar.plugins.core; import org.junit.Test; -import org.sonar.api.resources.ResourceDefinition; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.resources.ResourceTypeTree; -import java.util.List; - -import static org.hamcrest.core.Is.is; +import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; +import static org.junit.internal.matchers.IsCollectionContaining.hasItem; -public class DefaultResourcesTest { +public class DefaultResourceTypesTest { @Test public void provide() { - List<ResourceDefinition> defs = new DefaultResources().provide(); - assertThat(defs.isEmpty(), is(false)); + ResourceTypeTree tree = new DefaultResourceTypes().provide(); + assertThat(tree.getTypes().size(), is(7)); + assertThat(tree.getChildren(Qualifiers.PROJECT).size(), is(1)); + assertThat(tree.getChildren(Qualifiers.PROJECT), hasItem(Qualifiers.MODULE)); } } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/metrics/UserManagedMetricsTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/UserManagedMetricsTest.java index e2f729cf33a..ce69d01e43e 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/metrics/UserManagedMetricsTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/UserManagedMetricsTest.java @@ -17,7 +17,7 @@ * 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.core.metrics; +package org.sonar.plugins.core; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; @@ -25,6 +25,7 @@ import static org.junit.Assert.assertThat; import org.junit.Test; import org.sonar.api.measures.Metric; +import org.sonar.plugins.core.UserManagedMetrics; import java.util.List; diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java index bc7516ae550..d4ebebb4889 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchModule.java @@ -23,6 +23,7 @@ import org.sonar.api.Plugins; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; import org.sonar.api.resources.Project; +import org.sonar.api.resources.ResourceTypes; import org.sonar.api.utils.ServerHttpClient; import org.sonar.batch.DefaultFileLinesContextFactory; import org.sonar.batch.DefaultResourceCreationLock; @@ -82,6 +83,7 @@ public class BatchModule extends Module { addCoreSingleton(PastSnapshotFinder.class); addCoreSingleton(DefaultNotificationManager.class); addCoreSingleton(DefaultUserFinder.class); + addCoreSingleton(ResourceTypes.class); addCoreMetrics(); addBatchExtensions(); } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceDefinition.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceType.java index a3d89ce7e25..b040ef1378c 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceDefinition.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceType.java @@ -22,8 +22,9 @@ package org.sonar.api.resources; import com.google.common.annotations.Beta; import com.google.common.base.Preconditions; import com.google.common.base.Strings; -import org.sonar.api.BatchExtension; -import org.sonar.api.ServerExtension; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; /** * Experimental extension to declare types of resources. @@ -31,7 +32,8 @@ import org.sonar.api.ServerExtension; * @since 2.14 */ @Beta -public final class ResourceDefinition implements BatchExtension, ServerExtension { +@Immutable +public final class ResourceType { public static class Builder { private String qualifier; @@ -46,7 +48,7 @@ public final class ResourceDefinition implements BatchExtension, ServerExtension /** * @param iconPath path to icon, relative to context of web-application (e.g. "/images/q/DIR.png") */ - public Builder setIconPath(String iconPath) { + public Builder setIconPath(@Nullable String iconPath) { this.iconPath = iconPath; return this; } @@ -61,17 +63,17 @@ public final class ResourceDefinition implements BatchExtension, ServerExtension return this; } - public ResourceDefinition build() { + public ResourceType build() { if (Strings.isNullOrEmpty(iconPath)) { iconPath = "/images/q/" + qualifier + ".png"; } - return new ResourceDefinition(this); + return new ResourceType(this); } } public static Builder builder(String qualifier) { Preconditions.checkNotNull(qualifier); - Preconditions.checkArgument(qualifier.length() <= 10, "Qualifier is limited to 10 characters in database"); + Preconditions.checkArgument(qualifier.length() <= 10, "Qualifier is limited to 10 characters"); return new Builder(qualifier); } @@ -80,13 +82,16 @@ public final class ResourceDefinition implements BatchExtension, ServerExtension private final boolean hasSourceCode; private final boolean availableForFilters; - private ResourceDefinition(Builder builder) { + private ResourceType(Builder builder) { this.qualifier = builder.qualifier; this.iconPath = builder.iconPath; this.availableForFilters = builder.availableForFilters; this.hasSourceCode = builder.hasSourceCode; } + /** + * Qualifier is the unique key + */ public String getQualifier() { return qualifier; } @@ -102,4 +107,22 @@ public final class ResourceDefinition implements BatchExtension, ServerExtension public boolean hasSourceCode() { return hasSourceCode; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ResourceType that = (ResourceType) o; + return qualifier.equals(that.qualifier); + } + + @Override + public int hashCode() { + return qualifier.hashCode(); + } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypeTree.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypeTree.java new file mode 100644 index 00000000000..7fbdac2e7e2 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypeTree.java @@ -0,0 +1,98 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 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.api.resources; + +import com.google.common.annotations.Beta; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.*; +import org.apache.commons.lang.ArrayUtils; +import org.sonar.api.BatchExtension; +import org.sonar.api.ServerExtension; +import org.sonar.api.batch.InstantiationStrategy; + +import javax.annotation.concurrent.Immutable; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +/** + * @since 2.14 + */ +@Beta +@Immutable +@InstantiationStrategy(InstantiationStrategy.PER_BATCH) +public final class ResourceTypeTree implements BatchExtension, ServerExtension { + + private List<ResourceType> types; + private SetMultimap<String, String> relations; + + private ResourceTypeTree(Builder builder) { + this.types = ImmutableList.copyOf(builder.types); + this.relations = ImmutableSetMultimap.copyOf(builder.relations); + } + + public List<ResourceType> getTypes() { + return types; + } + + public Set<String> getChildren(String qualifier) { + return relations.get(qualifier); + } + + public List<String> getLeaves() { + return ImmutableList.copyOf(Collections2.filter(relations.values(), new Predicate<String>() { + public boolean apply(String qualifier) { + return relations.get(qualifier).isEmpty(); + } + })); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private List<ResourceType> types = Lists.newArrayList(); + private SetMultimap<String, String> relations = HashMultimap.create(); + + private Builder() { + } + + public Builder addType(ResourceType type) { + Preconditions.checkNotNull(type); + Preconditions.checkArgument(!types.contains(type), String.format("%s is already registered", type.getQualifier())); + types.add(type); + return this; + } + + public Builder addRelations(String parentQualifier, String... childQualifiers) { + Preconditions.checkNotNull(parentQualifier); + Preconditions.checkArgument(ArrayUtils.isNotEmpty(childQualifiers), "childQualifiers can't be empty"); + relations.putAll(parentQualifier, Arrays.asList(childQualifiers)); + return this; + } + + public ResourceTypeTree build() { + return new ResourceTypeTree(this); + } + } + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypes.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypes.java new file mode 100644 index 00000000000..526ba1909a0 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypes.java @@ -0,0 +1,110 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 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.api.resources; + +import com.google.common.annotations.Beta; +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import org.sonar.api.BatchComponent; +import org.sonar.api.ServerComponent; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +/** + * @since 2.14 + */ +@Beta +public final class ResourceTypes implements BatchComponent, ServerComponent { + + public static final Predicate<ResourceType> AVAILABLE_FOR_FILTERS = new Predicate<ResourceType>() { + public boolean apply(ResourceType input) { + return input.isAvailableForFilters(); + } + }; + + private final Map<String, ResourceTypeTree> treeByQualifier; + private final Map<String, ResourceType> typeByQualifier; + + public ResourceTypes(ResourceTypeTree[] trees) { + Preconditions.checkNotNull(trees); + + Map<String, ResourceTypeTree> treeMap = Maps.newHashMap(); + Map<String, ResourceType> typeMap = Maps.newHashMap(); + + for (ResourceTypeTree tree : trees) { + for (ResourceType type : tree.getTypes()) { + if (treeMap.containsKey(type.getQualifier())) { + throw new IllegalStateException("Qualifier " + type.getQualifier() + " is defined in several trees"); + } + treeMap.put(type.getQualifier(), tree); + typeMap.put(type.getQualifier(), type); + } + } + treeByQualifier = ImmutableMap.copyOf(treeMap); + typeByQualifier = ImmutableMap.copyOf(typeMap); + } + + public ResourceType get(String qualifier) { + ResourceType type = typeByQualifier.get(qualifier); + return type != null ? type : ResourceType.builder(qualifier).build(); + } + + public Collection<ResourceType> getAll() { + return typeByQualifier.values(); + } + + public Collection<ResourceType> getAll(Predicate<ResourceType> predicate) { + return Collections2.filter(typeByQualifier.values(), predicate); + } + + public Collection<String> getChildrenQualifiers(String qualifier) { + ResourceTypeTree tree = getTree(qualifier); + if (tree != null) { + return tree.getChildren(qualifier); + } + return Collections.emptyList(); + } + + public Collection<ResourceType> getChildren(String qualifier) { + return Collections2.transform(getChildrenQualifiers(qualifier), new Function<String, ResourceType>() { + public ResourceType apply(String s) { + return typeByQualifier.get(s); + } + }); + } + + public Collection<String> getLeavesQualifiers(String qualifier) { + ResourceTypeTree tree = getTree(qualifier); + if (tree != null) { + return tree.getLeaves(); + } + return Collections.emptyList(); + } + + public ResourceTypeTree getTree(String qualifier) { + return treeByQualifier.get(qualifier); + } +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceDefinitionTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypeTest.java index 1c86725afe4..c8bcfecc335 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceDefinitionTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypeTest.java @@ -24,11 +24,11 @@ import org.junit.Test; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; -public class ResourceDefinitionTest { +public class ResourceTypeTest { @Test public void shouldCreateWithDefaults() { - ResourceDefinition def = ResourceDefinition.builder("qualifier") + ResourceType def = ResourceType.builder("qualifier") .build(); assertThat(def.getQualifier(), is("qualifier")); assertThat(def.getIconPath(), is("/images/q/qualifier.png")); @@ -37,16 +37,33 @@ public class ResourceDefinitionTest { @Test public void shouldCreate() { - ResourceDefinition def = ResourceDefinition.builder("qualifier") + ResourceType def = ResourceType.builder("qualifier") .setIconPath("/custom-icon.png") + .availableForFilters() + .hasSourceCode() .build(); assertThat(def.getQualifier(), is("qualifier")); assertThat(def.getIconPath(), is("/custom-icon.png")); + assertThat(def.isAvailableForFilters(), is(true)); + assertThat(def.hasSourceCode(), is(true)); } @Test(expected = IllegalArgumentException.class) public void shouldCheckQualifierLength() { - ResourceDefinition.builder("qualifier bigger than 10 characters"); + ResourceType.builder("qualifier bigger than 10 characters"); + } + + @Test + public void testEqualsAndHashCode() { + ResourceType foo1 = ResourceType.builder("FOO").build(); + ResourceType foo2 = ResourceType.builder("FOO").build(); + ResourceType bar = ResourceType.builder("BAR").build(); + + assertThat(foo1.equals(foo1), is(true)); + assertThat(foo1.equals(foo2), is(true)); + assertThat(foo1.equals(bar), is(false)); + + assertThat(foo1.hashCode(), is(foo1.hashCode())); } } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypeTreeTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypeTreeTest.java new file mode 100644 index 00000000000..486330d7d00 --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypeTreeTest.java @@ -0,0 +1,64 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 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.api.resources; + +import org.junit.Test; + +import static org.hamcrest.collection.IsCollectionContaining.hasItems; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; +import static org.sonar.api.resources.ResourceTypesTest.qualifiers; + +public class ResourceTypeTreeTest { + private final ResourceTypeTree tree = ResourceTypeTree.builder() + .addType(ResourceType.builder("TRK").build()) + .addType(ResourceType.builder("DIR").build()) + .addType(ResourceType.builder("FIL").build()) + .addType(ResourceType.builder("UTS").build()) + .addRelations("TRK", "DIR") + .addRelations("DIR", "FIL") + .addRelations("DIR", "UTS") + .build(); + + + @Test + public void getTypes() { + assertThat(tree.getTypes().size(), is(4)); + assertThat(qualifiers(tree.getTypes()), hasItems("TRK", "DIR", "FIL", "UTS")); + } + + @Test + public void getChildren() { + assertThat(tree.getChildren("TRK").size(), is(1)); + assertThat(tree.getChildren("TRK"), hasItems("DIR")); + + assertThat(tree.getChildren("DIR").size(), is(2)); + assertThat(tree.getChildren("DIR"), hasItems("FIL", "UTS")); + + assertThat(tree.getChildren("FIL").size(), is(0)); + } + + @Test + public void getLeaves() { + assertThat(tree.getLeaves().size(), is(2)); + assertThat(tree.getLeaves(), hasItems("FIL", "UTS")); + } + +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypesTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypesTest.java new file mode 100644 index 00000000000..4da61fa537e --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypesTest.java @@ -0,0 +1,129 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 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.api.resources; + +import com.google.common.base.Function; +import com.google.common.collect.Collections2; +import org.junit.Test; + +import java.util.Collection; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNull.nullValue; +import static org.junit.Assert.assertThat; +import static org.junit.internal.matchers.IsCollectionContaining.hasItem; +import static org.junit.internal.matchers.IsCollectionContaining.hasItems; + +public class ResourceTypesTest { + + private ResourceTypeTree viewsTree = ResourceTypeTree.builder() + .addType(ResourceType.builder(Qualifiers.VIEW).availableForFilters().build()) + .addType(ResourceType.builder(Qualifiers.SUBVIEW).build()) + .addRelations(Qualifiers.VIEW, Qualifiers.SUBVIEW) + .addRelations(Qualifiers.SUBVIEW, Qualifiers.PROJECT) + .build(); + + private ResourceTypeTree defaultTree = ResourceTypeTree.builder() + .addType(ResourceType.builder(Qualifiers.PROJECT).availableForFilters().build()) + .addType(ResourceType.builder(Qualifiers.DIRECTORY).build()) + .addType(ResourceType.builder(Qualifiers.FILE).build()) + .addRelations(Qualifiers.PROJECT, Qualifiers.DIRECTORY) + .addRelations(Qualifiers.DIRECTORY, Qualifiers.FILE) + .build(); + + private ResourceTypes types = new ResourceTypes(new ResourceTypeTree[]{viewsTree, defaultTree}); + + @Test + public void get() { + assertThat(types.get(Qualifiers.PROJECT).getQualifier(), is(Qualifiers.PROJECT)); + + // does not return null + assertThat(types.get("xxx").getQualifier(), is("xxx")); + } + + @Test + public void getAll() { + assertThat(types.getAll().size(), is(5)); + assertThat(qualifiers(types.getAll()), hasItems( + Qualifiers.PROJECT, Qualifiers.DIRECTORY, Qualifiers.FILE, Qualifiers.VIEW, Qualifiers.SUBVIEW)); + } + + @Test + public void getAll_predicate() { + Collection<ResourceType> forFilters = types.getAll(ResourceTypes.AVAILABLE_FOR_FILTERS); + assertThat(forFilters.size(), is(2)); + assertThat(qualifiers(forFilters), hasItems(Qualifiers.PROJECT, Qualifiers.VIEW)); + } + + @Test + public void getChildrenQualifiers() { + assertThat(types.getChildrenQualifiers(Qualifiers.PROJECT).size(), is(1)); + assertThat(types.getChildrenQualifiers(Qualifiers.PROJECT), hasItem(Qualifiers.DIRECTORY)); + assertThat(types.getChildrenQualifiers(Qualifiers.SUBVIEW), hasItem(Qualifiers.PROJECT)); + assertThat(types.getChildrenQualifiers("xxx").isEmpty(), is(true)); + assertThat(types.getChildrenQualifiers(Qualifiers.FILE).isEmpty(), is(true)); + } + + @Test + public void getChildren() { + assertThat(qualifiers(types.getChildren(Qualifiers.PROJECT)), hasItem(Qualifiers.DIRECTORY)); + assertThat(qualifiers(types.getChildren(Qualifiers.SUBVIEW)), hasItem(Qualifiers.PROJECT)); + } + + @Test + public void getLeavesQualifiers() { + assertThat(types.getLeavesQualifiers(Qualifiers.PROJECT).size(), is(1)); + assertThat(types.getLeavesQualifiers(Qualifiers.PROJECT), hasItem(Qualifiers.FILE)); + + assertThat(types.getLeavesQualifiers(Qualifiers.DIRECTORY).size(), is(1)); + assertThat(types.getLeavesQualifiers(Qualifiers.DIRECTORY), hasItem(Qualifiers.FILE)); + + assertThat(types.getLeavesQualifiers(Qualifiers.VIEW).size(), is(1)); + assertThat(types.getLeavesQualifiers(Qualifiers.VIEW), hasItem(Qualifiers.PROJECT)); + + assertThat(types.getLeavesQualifiers("xxx").size(), is(0)); + } + + @Test + public void getTree() { + assertThat(qualifiers(types.getTree(Qualifiers.VIEW).getTypes()), hasItems(Qualifiers.VIEW, Qualifiers.SUBVIEW)); + assertThat(types.getTree("xxx"), nullValue()); + } + + @Test(expected = IllegalStateException.class) + public void failOnDuplicatedQualifier() { + ResourceTypeTree tree1 = ResourceTypeTree.builder() + .addType(ResourceType.builder("foo").build()) + .build(); + ResourceTypeTree tree2 = ResourceTypeTree.builder() + .addType(ResourceType.builder("foo").build()) + .build(); + + new ResourceTypes(new ResourceTypeTree[]{tree1, tree2}); + } + + static Collection<String> qualifiers(Collection<ResourceType> types) { + return Collections2.transform(types, new Function<ResourceType, String>() { + public String apply(ResourceType type) { + return type.getQualifier(); + } + }); + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java index 439c51b2183..13f29b6b079 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java @@ -28,6 +28,7 @@ import org.sonar.api.profiles.AnnotationProfileParser; import org.sonar.api.profiles.XMLProfileParser; import org.sonar.api.profiles.XMLProfileSerializer; import org.sonar.api.resources.Languages; +import org.sonar.api.resources.ResourceTypes; import org.sonar.api.rules.AnnotationRuleParser; import org.sonar.api.rules.DefaultRulesManager; import org.sonar.api.rules.XMLRuleParser; @@ -66,7 +67,10 @@ import org.sonar.server.qualitymodel.DefaultModelManager; import org.sonar.server.rules.ProfilesConsole; import org.sonar.server.rules.RulesConsole; import org.sonar.server.startup.*; -import org.sonar.server.ui.*; +import org.sonar.server.ui.CodeColorizers; +import org.sonar.server.ui.JRubyI18n; +import org.sonar.server.ui.SecurityRealmFactory; +import org.sonar.server.ui.Views; import javax.servlet.ServletContext; @@ -205,7 +209,7 @@ public final class Platform { servicesContainer.addSingleton(I18nManager.class); servicesContainer.addSingleton(RuleI18nManager.class); servicesContainer.addSingleton(GwtI18n.class); - servicesContainer.addSingleton(ResourceDefinitionRepository.class); + servicesContainer.addSingleton(ResourceTypes.class); // Notifications servicesContainer.addSingleton(NotificationService.class); diff --git a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java index d20f65a6cb5..5ec0171e4ef 100644 --- a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java +++ b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java @@ -29,7 +29,8 @@ import org.sonar.api.platform.PluginRepository; import org.sonar.api.profiles.ProfileExporter; import org.sonar.api.profiles.ProfileImporter; import org.sonar.api.resources.Language; -import org.sonar.api.resources.ResourceDefinition; +import org.sonar.api.resources.ResourceType; +import org.sonar.api.resources.ResourceTypes; import org.sonar.api.rules.RulePriority; import org.sonar.api.rules.RuleRepository; import org.sonar.api.utils.ValidationMessages; @@ -73,14 +74,22 @@ public final class JRubyFacade { return getContainer().getComponentByType(FilterExecutor.class).execute(filter); } - public Collection<ResourceDefinition> getResourceDefinitionsForFilter() { - return getContainer().getComponentByType(ResourceDefinitionRepository.class).getForFilter(); + public Collection<ResourceType> getResourceTypesForFilter() { + return getContainer().getComponentByType(ResourceTypes.class).getAll(ResourceTypes.AVAILABLE_FOR_FILTERS); } - public ResourceDefinition getResourceDefinition(String qualifier) { - return getContainer().getComponentByType(ResourceDefinitionRepository.class).get(qualifier); + public ResourceType getResourceType(String qualifier) { + return getContainer().getComponentByType(ResourceTypes.class).get(qualifier); } + public Collection<String> getResourceLeavesQualifiers(String qualifier) { + return getContainer().getComponentByType(ResourceTypes.class).getLeavesQualifiers(qualifier); + } + + public Collection<String> getResourceChildrenQualifiers(String qualifier) { + return getContainer().getComponentByType(ResourceTypes.class).getChildrenQualifiers(qualifier); + } + // UPDATE CENTER ------------------------------------------------------------ public void downloadPlugin(String pluginKey, String pluginVersion) { @@ -259,7 +268,7 @@ public final class JRubyFacade { public void ruleSeverityChanged(int parentProfileId, int activeRuleId, int oldSeverityId, int newSeverityId, String userName) { getProfilesManager().ruleSeverityChanged(parentProfileId, activeRuleId, RulePriority.values()[oldSeverityId], - RulePriority.values()[newSeverityId], userName); + RulePriority.values()[newSeverityId], userName); } public void ruleDeactivated(int parentProfileId, int deactivatedRuleId, String userName) { diff --git a/sonar-server/src/main/java/org/sonar/server/ui/ResourceDefinitionRepository.java b/sonar-server/src/main/java/org/sonar/server/ui/ResourceDefinitionRepository.java deleted file mode 100644 index 8f79ca0b526..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/ui/ResourceDefinitionRepository.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 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.server.ui; - -import com.google.common.annotations.Beta; -import com.google.common.base.Predicate; -import com.google.common.collect.Collections2; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import org.sonar.api.BatchComponent; -import org.sonar.api.ServerComponent; -import org.sonar.api.resources.ResourceDefinition; - -import java.util.Collection; -import java.util.Map; - -/** - * @since 2.14 - */ -@Beta -public class ResourceDefinitionRepository implements BatchComponent, ServerComponent { - - private final Map<String, ResourceDefinition> descriptionsByQualifier; - - public ResourceDefinitionRepository(ResourceDefinition[] descriptions) { - ImmutableMap.Builder<String, ResourceDefinition> map = ImmutableMap.builder(); - for (ResourceDefinition description : descriptions) { - map.put(description.getQualifier(), description); - } - descriptionsByQualifier = map.build(); - } - - public ResourceDefinition get(String qualifier) { - ResourceDefinition result = descriptionsByQualifier.get(qualifier); - if (result != null) { - return result; - } - // to avoid NPE on ruby side - return ResourceDefinition.builder(qualifier).build(); - } - - public Collection<ResourceDefinition> getAll() { - return descriptionsByQualifier.values(); - } - - public Collection<ResourceDefinition> getForFilter() { - return ImmutableList.copyOf(Collections2.filter(descriptionsByQualifier.values(), IS_AVAILABLE_FOR_FILTER)); - } - - private static final Predicate<ResourceDefinition> IS_AVAILABLE_FOR_FILTER = new Predicate<ResourceDefinition>() { - public boolean apply(ResourceDefinition input) { - return input.isAvailableForFilters(); - } - }; - -} diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/application_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/application_controller.rb index 9339498e20a..a705aed664d 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/application_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/application_controller.rb @@ -147,4 +147,26 @@ class ApplicationController < ActionController::Base end end + + # + # FILTERS + # + def init_resource_for_user_role + init_resource_for_role :user + end + + def init_resource_for_admin_role + init_resource_for_role :admin + end + + def init_resource_for_role(role) + @resource=Project.by_key(params[:id]) + not_found("Project not found") unless @resource + @resource=@resource.permanent_resource + + @snapshot=@resource.last_snapshot + not_found("Snapshot not found") unless @snapshot + + access_denied unless has_role?(role, @resource) + end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/cloud_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/cloud_controller.rb index fb046bb9f9a..5ca6f0925e4 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/cloud_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/cloud_controller.rb @@ -20,14 +20,9 @@ class CloudController < ApplicationController SECTION=Navigation::SECTION_RESOURCE + before_filter :init_resource_for_user_role def index - resource_key = params[:id] - @project = resource_key ? Project.by_key(resource_key) : nil - not_found("Project not found") unless @project - access_denied unless has_role?(:user, @project) - @snapshot=@project.last_snapshot - @size_metric=Metric.by_key(params[:size]||'ncloc') @color_metric=Metric.by_key(params[:color]||'coverage') @@ -35,11 +30,11 @@ class CloudController < ApplicationController @color_metric=Metric.by_key('violations_density') end - snapshot_conditions='snapshots.islast=:islast AND snapshots.scope=:scope AND snapshots.qualifier!=:test_qualifier AND + snapshot_conditions='snapshots.islast=:islast AND snapshots.qualifier in (:qualifiers) AND snapshots.qualifier!=:test_qualifier AND (snapshots.id=:sid OR (snapshots.root_snapshot_id=:root_sid AND snapshots.path LIKE :path))' snapshot_values={ :islast => true, - :scope => 'FIL', + :qualifiers => @snapshot.leaves_qualifiers, :test_qualifier => 'UTS', :sid => @snapshot.id, :root_sid => (@snapshot.root_snapshot_id || @snapshot.id), @@ -57,7 +52,7 @@ class CloudController < ApplicationController color_measures=ProjectMeasure.find(:all, :select => 'project_measures.id,project_measures.value,project_measures.metric_id,project_measures.snapshot_id,project_measures.rule_id,project_measures.rule_priority,project_measures.text_value,project_measures.characteristic_id,project_measures.alert_status', :joins => :snapshot, - :conditions => [snapshot_conditions + " AND project_measures.metric_id=#{@color_metric.id}", snapshot_values], + :conditions => [snapshot_conditions + " AND project_measures.metric_id=#{@color_metric.id} AND project_measures.rule_id IS NULL AND "+ "project_measures.characteristic_id IS NULL AND project_measures.person_id IS NULL", snapshot_values], :order => 'project_measures.value') @size_measure_by_sid={}, @color_measure_by_sid={} diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/components_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/components_controller.rb index 92c1b0bb427..9e8e23cc0f8 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/components_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/components_controller.rb @@ -33,12 +33,9 @@ class ComponentsController < ApplicationController TREEMAP_COLOR_METRIC_PROPERTY = 'sonar.core.treemap.colormetric' def index + init_resource_for_user_role @components_configuration = Sonar::ComponentsConfiguration.new - @project = Project.by_key(params[:id]) - not_found("Project not found") unless @project - access_denied unless has_role?(:user, @project) - @snapshot = @project.last_snapshot @snapshots = Snapshot.find(:all, :include => 'project', :conditions => ['snapshots.parent_snapshot_id=? and snapshots.qualifier<>? and projects.qualifier<>?', @snapshot.id, Snapshot::QUALIFIER_UNIT_TEST_CLASS, Snapshot::QUALIFIER_UNIT_TEST_CLASS]) @columns = @components_configuration.selected_columns diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/dashboard_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/dashboard_controller.rb index f089ad08464..83a3d3dfb88 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/dashboard_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/dashboard_controller.rb @@ -182,16 +182,8 @@ class DashboardController < ApplicationController end def load_resource - @resource=Project.by_key(params[:id]) - not_found("Resource not found") unless @resource - - @resource=@resource.switch_resource if @resource.switch_resource - - access_denied unless has_role?(:user, @resource) - @snapshot = @resource.last_snapshot - not_found("Snapshot not found") unless @snapshot - - @project=@resource # variable name used in old widgets + init_resource_for_user_role + @project=@resource # for backward compatibility with old widgets end def load_authorized_widget_definitions diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/drilldown_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/drilldown_controller.rb index 44e001d1d9a..848e046f371 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/drilldown_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/drilldown_controller.rb @@ -18,7 +18,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 # class DrilldownController < ApplicationController - before_filter :init_project + before_filter :init_resource_for_user_role helper ProjectHelper, DashboardHelper @@ -54,14 +54,14 @@ class DrilldownController < ApplicationController end # load data - @drilldown = Drilldown.new(@project, @metric, selected_rids, options) + @drilldown = Drilldown.new(@resource, @metric, selected_rids, options) @highlighted_resource=@drilldown.highlighted_resource if @highlighted_resource.nil? && @drilldown.columns.empty? - @highlighted_resource=@project + @highlighted_resource=@resource end - @display_viewers=display_metric_viewers?(@highlighted_resource||@project, @highlighted_metric.key) + @display_viewers=display_metric_viewers?(@highlighted_resource||@resource, @highlighted_metric.key) end def violations @@ -112,11 +112,11 @@ class DrilldownController < ApplicationController end # load data - @drilldown = Drilldown.new(@project, @metric, @selected_rids, options) + @drilldown = Drilldown.new(@resource, @metric, @selected_rids, options) @highlighted_resource=@drilldown.highlighted_resource if @highlighted_resource.nil? && @drilldown.columns.empty? - @highlighted_resource=@project + @highlighted_resource=@resource end @@ -143,16 +143,6 @@ class DrilldownController < ApplicationController private - def init_project - project_key = params[:id] - @project = project_key ? Project.by_key(project_key) : nil - # For security reasons, we must not return 404 not found. It would be an information that the resource exists. - not_found("Resource not found") unless @project - - @snapshot = @project.last_snapshot - access_denied unless has_role?(:user, @snapshot) - end - def select_metric(metric_key, default_key) metric=nil if metric_key diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/manual_measures_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/manual_measures_controller.rb index 148153659f6..56344f3de57 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/manual_measures_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/manual_measures_controller.rb @@ -20,7 +20,7 @@ class ManualMeasuresController < ApplicationController SECTION=Navigation::SECTION_RESOURCE - before_filter :load_resource + before_filter :init_resource_for_admin_role verify :method => :post, :only => [:save, :delete], :redirect_to => {:action => :index} helper MetricsHelper @@ -66,13 +66,6 @@ class ManualMeasuresController < ApplicationController private - def load_resource - @resource=Project.by_key(params[:id]) - return redirect_to home_path unless @resource - access_denied unless has_role?(:admin, @resource) - @snapshot=@resource.last_snapshot - end - def load_measures @measures=ManualMeasure.find(:all, :conditions => ['resource_id=?', @resource.id]).select { |m| m.metric.enabled } end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/plugins/resource_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/plugins/resource_controller.rb index 61ffbcd6c9d..4b835e19d4b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/plugins/resource_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/plugins/resource_controller.rb @@ -23,10 +23,11 @@ class Plugins::ResourceController < ApplicationController helper :project def index - @project = ::Project.by_key(params[:id]) - not_found("Not found") unless @project + @resource = ::Project.by_key(params[:id]) + not_found("Not found") unless @resource + @project=@resource # for backward-compatibility - @snapshot=@project.last_snapshot + @snapshot=@resource.last_snapshot page_id=params[:page] @page_proxy=java_facade.getPage(page_id) @@ -36,7 +37,7 @@ class Plugins::ResourceController < ApplicationController authorized=@page_proxy.getUserRoles().size==0 unless authorized @page_proxy.getUserRoles().each do |role| - authorized= (role=='user') || (role=='viewer') || has_role?(role, @project) + authorized= (role=='user') || (role=='viewer') || has_role?(role, @resource) break if authorized end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb index 087771bc59c..304b410e35a 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb @@ -32,6 +32,7 @@ class ResourceController < ApplicationController def index @resource = Project.by_key(params[:id]) not_found("Resource not found") unless @resource + @resource=@resource.permanent_resource access_denied unless has_role?(:user, @resource) params[:layout]='false' diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/timemachine_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/timemachine_controller.rb index 0fa2ae57dad..271849f291f 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/timemachine_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/timemachine_controller.rb @@ -28,11 +28,7 @@ class TimemachineController < ApplicationController MAX_SNAPSHOTS = 5 def index - @project = Project.by_key(params[:id]) - return redirect_to home_url unless @project - @snapshot=@project.last_snapshot - - access_denied unless is_user?(@snapshot) + init_resource_for_user_role if params[:sid] @sids = params[:sid].split(',').collect {|s| s.to_i} @@ -42,9 +38,9 @@ class TimemachineController < ApplicationController # @snapshots=Snapshot.find(:all, :include => 'events', - :conditions => {:id => @sids, :project_id => @project.id, :scope => @project.scope, :qualifier => @project.qualifier}, :order => 'snapshots.created_at ASC') + :conditions => {:id => @sids, :project_id => @resource.id, :scope => @resource.scope, :qualifier => @resource.qualifier}, :order => 'snapshots.created_at ASC') else - @snapshots=Snapshot.for_timemachine_matrix(@project) + @snapshots=Snapshot.for_timemachine_matrix(@resource) @sids = @snapshots.collect{|s| s.id}.uniq end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/treemap_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/treemap_controller.rb index 1406b0e2a8d..eda7f53536b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/treemap_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/treemap_controller.rb @@ -44,6 +44,8 @@ class TreemapController < ApplicationController bad_request('Unknown resource: ' + params[:resource]) unless resource bad_request('Data not available') unless resource.last_snapshot access_denied unless has_role?(:user, resource) + resource = resource.permanent_resource + elsif params[:filter] filter=::Filter.find(params[:filter]) bad_request('Unknown filter: ' + params[:filter]) unless filter diff --git a/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb b/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb index 81c4a3915c5..2197090c2c0 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/helpers/application_helper.rb @@ -38,11 +38,11 @@ module ApplicationHelper end end + # TODO this method should be moved in resourceable.rb def qualifier_icon(object) qualifier=(object.respond_to?('qualifier') ? object.qualifier : object.to_s) if qualifier - definition = Java::OrgSonarServerUi::JRubyFacade.getInstance().getResourceDefinition(qualifier) - image_tag definition.getIconPath(), :alt => '', :size => '16x16' + image_tag Java::OrgSonarServerUi::JRubyFacade.getInstance().getResourceType(qualifier).getIconPath(), :alt => '', :size => '16x16' else image_tag 'e16.gif' end @@ -198,8 +198,8 @@ module ApplicationHelper def url_for_resource_gwt(page, options={}) if options[:resource] "#{ApplicationController.root_context}/plugins/resource/#{options[:resource]}?page=#{page}" - elsif @project - "#{ApplicationController.root_context}/plugins/resource/#{@project.id}?page=#{page}" + elsif @resource + "#{ApplicationController.root_context}/plugins/resource/#{@resource.id}?page=#{page}" else '' end @@ -220,7 +220,7 @@ module ApplicationHelper # url_for_drilldown('ncloc', {:resource => 'org.apache.struts:struts-parent'}) # def url_for_drilldown(metric_or_measure, options={}) - if options[:resource].nil? && !@project + if options[:resource].nil? && !@resource return '' end @@ -232,7 +232,7 @@ module ApplicationHelper metric_key = metric_or_measure end - url_params={:controller => 'drilldown', :action => 'measures', :metric => metric_key, :id => options[:resource]||@project.id} + url_params={:controller => 'drilldown', :action => 'measures', :metric => metric_key, :id => options[:resource]||@resource.id} url_for(options.merge(url_params)) end @@ -328,7 +328,8 @@ module ApplicationHelper period_index=nil if period_index && period_index<=0 if resource.display_dashboard? if options[:dashboard] - link_to(name || resource.name, {:overwrite_params => {:controller => 'dashboard', :action => 'index', :id => resource.id, :period => period_index, :tab => options[:tab], :rule => options[:rule]}}, :title => options[:title]) + link_to(name || resource.name, {:overwrite_params => {:controller => 'dashboard', :action => 'index', :id => resource.id, :period => period_index, + :tab => options[:tab], :rule => options[:rule]}}, :title => options[:title]) else # stay on the same page (for example components) link_to(name || resource.name, {:overwrite_params => {:id => resource.id, :period => period_index, :tab => options[:tab], :rule => options[:rule]}}, :title => options[:title]) @@ -415,7 +416,7 @@ module ApplicationHelper def link_to_favourite(resource, options={}) return '' unless (logged_in?) return '' if resource.nil? - resource_id=(resource.is_a?(Fixnum) ? resource : resource.switch_resource_or_self.id) + resource_id=(resource.is_a?(Fixnum) ? resource : resource.permanent_id) html_id=options['html_id'] || "fav#{resource_id}" initial_class='notfav' initial_tooltip=message('click_to_add_to_favourites') diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/drilldown.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/drilldown.rb index 1104067b628..40f1a3eadf9 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/drilldown.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/drilldown.rb @@ -19,24 +19,6 @@ # class Drilldown - DEFAULT=[['TRK'], ['BRC'], ['DIR', 'PAC'], ['FIL', 'CLA', 'UTS']] - VIEWS=[['VW'], ['SVW'], ['TRK']] - PERSONS=[['PERSON'], ['PERSON_PRJ']] - TREES=[DEFAULT, VIEWS, PERSONS] - - def self.qualifier_children(q) - return [] if q==nil - TREES.each do |tree| - tree.each_with_index do |qualifiers, index| - if qualifiers==q || qualifiers.include?(q) - return index+1<tree.size ? tree[index+1] : [] - end - end - end - [] - end - - attr_reader :resource, :metric, :selected_resource_ids attr_reader :snapshot, :columns, :highlighted_resource, :highlighted_snapshot @@ -85,13 +67,13 @@ class DrilldownColumn # switch if @base_snapshot.resource.copy_resource @base_snapshot=@base_snapshot.resource.copy_resource.last_snapshot - @qualifiers = Drilldown.qualifier_children(@base_snapshot.qualifier) + @qualifiers = @base_snapshot.children_qualifiers elsif previous_column - @qualifiers=Drilldown.qualifier_children(previous_column.qualifiers) + @qualifiers=previous_column.qualifiers.map {|q| Java::OrgSonarServerUi::JRubyFacade.getInstance().getResourceChildrenQualifiers(q).to_a}.flatten else - @qualifiers=Drilldown.qualifier_children(drilldown.snapshot.qualifier) + @qualifiers=drilldown.snapshot.children_qualifiers end @resource_per_sid={} end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/project.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/project.rb index 9770cd07802..fd185edcc55 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/project.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/project.rb @@ -54,9 +54,9 @@ class Project < ActiveRecord::Base def root_project @root_project ||= - begin - parent_module(self) - end + begin + parent_module(self) + end end # bottom-up array of projects, @@ -66,26 +66,30 @@ class Project < ActiveRecord::Base nodes end - def switch_resource - @switch_resource ||= - begin - (copy_resource && copy_resource.qualifier==qualifier) ? copy_resource : nil - end + def resource_link + @resource_link ||= + begin + (copy_resource && copy_resource.qualifier==qualifier) ? copy_resource : nil + end end - def switch_resource_or_self - switch_resource||self + def permanent_resource + resource_link||self + end + + def permanent_id + permanent_resource.id end def last_snapshot @last_snapshot ||= - begin - snapshot=Snapshot.find(:first, :conditions => {:islast => true, :project_id => id}) - if snapshot - snapshot.project=self + begin + snapshot=Snapshot.find(:first, :conditions => {:islast => true, :project_id => id}) + if snapshot + snapshot.project=self + end + snapshot end - snapshot - end end def events_with_snapshot @@ -115,13 +119,13 @@ class Project < ActiveRecord::Base def chart_measures(metric_id) sql = Project.send(:sanitize_sql, ['select s.created_at as created_at, m.value as value ' + - ' from project_measures m, snapshots s ' + - ' where s.id=m.snapshot_id and ' + - " s.status='%s' and " + - ' s.project_id=%s and m.metric_id=%s ', Snapshot::STATUS_PROCESSED, self.id, metric_id]) + - ' and m.rule_id IS NULL and m.rule_priority IS NULL' + - ' and m.person_id IS NULL' + - ' order by s.created_at' + ' from project_measures m, snapshots s ' + + ' where s.id=m.snapshot_id and ' + + " s.status='%s' and " + + ' s.project_id=%s and m.metric_id=%s ', Snapshot::STATUS_PROCESSED, self.id, metric_id]) + + ' and m.rule_id IS NULL and m.rule_priority IS NULL' + + ' and m.person_id IS NULL' + + ' order by s.created_at' create_chart_measures(Project.connection.select_all(sql), 'created_at', 'value') end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap.rb index 3bfbc684303..ceea573b8d8 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/sonar/treemap.rb @@ -77,7 +77,7 @@ class Sonar::Treemap metric_ids << @color_metric.id if @color_metric && @color_metric.id!=@size_metric.id sql_conditions = 'snapshots.islast=? AND project_measures.characteristic_id IS NULL and project_measures.rule_id IS NULL ' + - 'and project_measures.rule_priority IS NULL and project_measures.metric_id in (?)' + 'and project_measures.rule_priority IS NULL and project_measures.person_id IS NULL and project_measures.metric_id in (?)' sql_values = [true, metric_ids] if @root_snapshot sql_conditions += " AND snapshots.parent_snapshot_id=?" @@ -107,7 +107,7 @@ class Sonar::Treemap :title => escape_javascript(resource.name(true)), :tooltip => tooltip(resource, size_measure, color_measure), :color => html_color(color_measure), - :rid => resource.switch_resource_or_self.id, + :rid => resource.id, :leaf => resource.source_code?) node.add_child(child) end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/cloud/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/cloud/index.html.erb index d7ac85e483a..39287cc2681 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/cloud/index.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/cloud/index.html.erb @@ -18,7 +18,7 @@ </script> <div> - <form id="cloudform" action="<%= ApplicationController.root_context -%>/cloud/index/<%= @project.id -%>" method="GET"> + <form id="cloudform" action="<%= ApplicationController.root_context -%>/cloud/index/<%= @resource.id -%>" method="GET"> <ul class="headerLine"> <li> <span><%= message('color') -%>:</span> @@ -53,7 +53,11 @@ size_measure=@size_measure_by_sid[s.id] if size_measure && size_measure.value color_measure=@color_measure_by_sid[s.id] - link="of(#{s.project_id})" + if s.source_code? + link="of(#{s.project_id})" + else + link="ov(#{s.project_id})" + end title="#{s.resource.long_name} | #{@size_metric.short_name}: #{size_measure.formatted_value}" if color_measure && color_measure.value diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/components/_list_edit_mode_controls.rhtml b/sonar-server/src/main/webapp/WEB-INF/app/views/components/_list_edit_mode_controls.rhtml index 9af86fae226..5416e7d7f92 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/components/_list_edit_mode_controls.rhtml +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/components/_list_edit_mode_controls.rhtml @@ -10,7 +10,7 @@ <td width="1%" nowrap><%= message('add_a_column') -%></td> <td> <form action="<%= url_for :controller => "columns", :action => "add" -%>" > - <input type="hidden" name="rid" value="<%= @project.id if @project %>" /> + <input type="hidden" name="rid" value="<%= @resource.id if @resource %>" /> <select name="id" onchange="$('add_column_loading').show();submit();" id="select_add_column"> <option value=""></option> <% addeable_columns.keys.sort.each do |domain| %> @@ -30,7 +30,7 @@ <td width="1%" nowrap><%= message('default_sort_on') -%> </td> <td> <form action="<%= url_for :controller => "columns", :action => "default_sorting" -%>"> - <input type="hidden" name="rid" value="<%= @project.id if @project %>" /> + <input type="hidden" name="rid" value="<%= @resource.id if @resource %>" /> <select name="id" onchange="$('sort_column_loading').show();submit();" id="select_default_sorting"> <option value="project" <%= 'selected' if components_configuration.sorted_by_project_name? -%>><%= message('project_name') -%></option> <% configured_columns.sort_by{|col| col.name}.each do |column| @@ -46,9 +46,9 @@ <tr> <td colspan="2"> <%= link_to( message('enable_treemap'), - {:controller => "columns", :action => "toggle_treemap", :rid => @project.id}, {:class => 'action'} ) if (!components_configuration.treemap_enabled?) %> + {:controller => "columns", :action => "toggle_treemap", :rid => @resource.id}, {:class => 'action'} ) if (!components_configuration.treemap_enabled?) %> <%= link_to( message('disable_treemap'), - {:controller => "columns", :action => "toggle_treemap", :rid => @project.id}, {:class => 'action'} ) if components_configuration.treemap_enabled? %> + {:controller => "columns", :action => "toggle_treemap", :rid => @resource.id}, {:class => 'action'} ) if components_configuration.treemap_enabled? %> <%= image_tag("treemap_icon.png") %> </td> </tr> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/components/_list_table_header_edit_mode.rhtml b/sonar-server/src/main/webapp/WEB-INF/app/views/components/_list_table_header_edit_mode.rhtml index f1f943fcb7d..eb573f153ca 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/components/_list_table_header_edit_mode.rhtml +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/components/_list_table_header_edit_mode.rhtml @@ -16,11 +16,11 @@ <% configured_columns.each do |column| %> <th class="right nosort" nowrap="nowrap"> <%= link_to( image_tag("controls/resultset_previous.png", :alt => message('move_left'), :id => "move_left_" + column.id), - {:controller => "columns", :action => "left", :id => column.id, :rid => @project.id}, :class => 'nolink') if column.position > 0 %> + {:controller => "columns", :action => "left", :id => column.id, :rid => @resource.id}, :class => 'nolink') if column.position > 0 %> <%= link_to( image_tag("bin_closed.png", :alt => message('remove_column'), :id => "remove_" + column.id), - {:controller => "columns", :action => "delete", :id => column.id, :rid => @project.id}, :class => 'nolink') %> + {:controller => "columns", :action => "delete", :id => column.id, :rid => @resource.id}, :class => 'nolink') %> <%= link_to( image_tag("controls/resultset_next.png", :alt => message('move_right'), :id => "move_right_" + column.id), - {:controller => "columns", :action => "right", :id => column.id, :rid => @project.id}, :class => 'nolink') if column.position != configured_columns.size - 1 %> + {:controller => "columns", :action => "right", :id => column.id, :rid => @resource.id}, :class => 'nolink') if column.position != configured_columns.size - 1 %> </th> <% end %> </tr> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/components/_treemap_settings.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/components/_treemap_settings.html.erb index 5d3a0be68ea..54846aa3560 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/components/_treemap_settings.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/components/_treemap_settings.html.erb @@ -1,6 +1,6 @@ <div id="treemap_set_default"> <%= render :partial => 'components/treemap_set_default', - :locals => {:controller => 'components', :size_metric => @treemap.size_metric.key, :color_metric => @treemap.color_metric.key, :rid => @project.id } %> + :locals => {:controller => 'components', :size_metric => @treemap.size_metric.key, :color_metric => @treemap.color_metric.key, :rid => @resource.id } %> </div> <table class="spaced"> <tr> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/components/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/components/index.html.erb index 5077905767d..4ea90f9441a 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/components/index.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/components/index.html.erb @@ -17,7 +17,7 @@ <% if has_role?(:admin) && configuring? %> <%= render :partial => 'list_edit_mode_controls', :locals => {:configured_columns => @columns, :components_configuration => @components_configuration} %> <% end %> -<% if @snapshots.empty? && @project.nil? %> +<% if @snapshots.empty? && @resource.nil? %> <h3><%= message('components.no_projects_have_been_analysed') -%>No projects have been analysed.</h3> <p><%= message('components.explanation_launch_sonar_to_have_results') -%></p> <% else %> @@ -69,7 +69,7 @@ <td width="<%= @treemap.width -%>" valign="top"> <script> new Treemap(1, '<%= @treemap.size_metric ? @treemap.size_metric.key : '' -%>', '<%= @treemap.color_metric ? @treemap.color_metric.key : '' -%>', 100.0).init('resource', - <%= @project.id -%>); + <%= @resource.id -%>); </script> <div id="tm-1" class="treemap" style="height:<%= @treemap.height %>px"> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/drilldown/_header.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/drilldown/_header.html.erb index ad5fc2cb940..3ceb11fb1ce 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/drilldown/_header.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/drilldown/_header.html.erb @@ -10,7 +10,7 @@ if (display_title == undefined) { display_title = true; } - new Ajax.Updater('resource_container', baseUrl + '/resource/index/' + resourceId + '?metric=<%= @metric.id if @metric -%>&rule=<%= @rule ? @rule.id : @severity -%>&period=<%= @period -%>&project=<%= @project.id -%>&display_title=' + display_title, {asynchronous:true, evalScripts:true}); + new Ajax.Updater('resource_container', baseUrl + '/resource/index/' + resourceId + '?metric=<%= @metric.id if @metric -%>&rule=<%= @rule ? @rule.id : @severity -%>&period=<%= @period -%>&project=<%= @resource.id -%>&display_title=' + display_title, {asynchronous:true, evalScripts:true}); return false; } </script> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/drilldown/_severity.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/drilldown/_severity.html.erb index 0162ea7fa98..0703dd90da9 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/drilldown/_severity.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/drilldown/_severity.html.erb @@ -2,7 +2,7 @@ <tr class="<%= css -%> <%= 'selected' if selected -%>"> <td><%= image_tag "priority/#{severity}.png" %></td> <td> - <%= link_to message("severity.#{severity}"), {:controller => 'drilldown', :action => 'violations', :id => @project.id, :severity => (selected ? nil : severity), :period => @period} %> + <%= link_to message("severity.#{severity}"), {:controller => 'drilldown', :action => 'violations', :id => @resource.id, :severity => (selected ? nil : severity), :period => @period} %> </td> <td style="padding-left: 10px;" align="right" nowrap> <%= @period ? format_variation(measure, :index => @period, :style => 'light') : format_measure(measure) -%> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/filters/new.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/filters/new.html.erb index dc1b9b21f28..a8ec9cb8a0c 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/filters/new.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/filters/new.html.erb @@ -49,14 +49,6 @@ table#columns td { <td> <% qualifiers=(@filter.criterion('qualifier') ? @filter.criterion('qualifier').text_values : []) %> - <% if controller.java_facade.hasPlugin('views') %> - <input type="checkbox" name="qualifiers[]" value="VW" <%= 'checked' if qualifiers.include?('VW') -%> id="q-VW"></input> <label for="q-VW"><%= message('qualifiers.VW') -%></label> - <span class="spacer"> </span> - - <input type="checkbox" name="qualifiers[]" value="SVW" <%= 'checked' if qualifiers.include?('SVW') -%> id="q-SVW"></input> <label for="q-SVW"><%= message('qualifiers.SVW') -%></label> - <span class="spacer"> </span> - <% end %> - <input type="checkbox" name="qualifiers[]" value="TRK" <%= 'checked' if qualifiers.include?('TRK') -%> id="q-TRK"></input> <label for="q-TRK"><%= message('qualifiers.TRK') -%></label> <span class="spacer"> </span> @@ -72,7 +64,7 @@ table#columns td { <input type="checkbox" name="qualifiers[]" value="UTS" <%= 'checked' if qualifiers.include?('UTS') -%> id="q-UTS"></input> <label for="q-UTS"><%= message('qualifiers.UTS') -%></label> <span class="spacer"> </span> - <% for desc in controller.java_facade.getResourceDefinitionsForFilter() + <% for desc in controller.java_facade.getResourceTypesForFilter() qualifier = desc.getQualifier() %> <input type="checkbox" name="qualifiers[]" value="<%= qualifier -%>" <%= 'checked' if qualifiers.include?(qualifier) -%> id="q-<%= qualifier -%>"></input> <label for="q-<%= qualifier -%>"><%= message("qualifiers.#{qualifier}") -%></label> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/timemachine/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/timemachine/index.html.erb index 5aada6364a2..97a323568ae 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/timemachine/index.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/timemachine/index.html.erb @@ -56,7 +56,7 @@ } function refreshTimeMachineChart(jumpToChart) { - var url="<%= url_for :controller => 'charts', :action => 'trends', :id => @project.id, :locale => I18n.locale -%>&sids=" + selectedSnapshots + "&metrics=" + collectSelectedMetrics() + "&format=png&ts=" + (new Date()).getTime(); + var url="<%= url_for :controller => 'charts', :action => 'trends', :id => @resource.id, :locale => I18n.locale -%>&sids=" + selectedSnapshots + "&metrics=" + collectSelectedMetrics() + "&format=png&ts=" + (new Date()).getTime(); $('timemachine_chart').src=url; if (jumpToChart) { @@ -70,11 +70,11 @@ </center> <br/><br/> -<% form_for( :compare, :html => { :id => 'timemachine_form', :method => 'get' }, :url => { :controller => 'timemachine', :action => 'index', :id => @project.id}) do |form| %> +<% form_for( :compare, :html => { :id => 'timemachine_form', :method => 'get' }, :url => { :controller => 'timemachine', :action => 'index', :id => @resource.id}) do |form| %> <input type="hidden" name="sid" id="sid" value=""/> <input type="hidden" name="metrics" id="timemachine_form_metrics" value=""/> <% end %> -<% form_for( :compare, :html => { :id => 'chart_defaults_form', :method => 'post' }, :url => { :controller => 'timemachine', :action => 'set_default_chart_metrics', :id => @project.id}) do |form| %> +<% form_for( :compare, :html => { :id => 'chart_defaults_form', :method => 'post' }, :url => { :controller => 'timemachine', :action => 'set_default_chart_metrics', :id => @resource.id}) do |form| %> <input type="hidden" name="metrics" id="chart_defaults_form_metrics" value=""/> <% end %> <table id="timemachine_matrix" class="matrix"> @@ -87,7 +87,7 @@ <div id="calContainer"> </div> </div><br/> <% - selectable_events = @project.events_with_snapshot.select{|event| !(@sids.include?(event.snapshot_id))} + selectable_events = @resource.events_with_snapshot.select{|event| !(@sids.include?(event.snapshot_id))} unless selectable_events.empty? %> <%= message('time_machine.show_event') -%> @@ -201,7 +201,7 @@ <script type="text/javascript"> var snapshots = new Hash(); - <% @project.processed_snapshots.each do |snapshot| + <% @resource.processed_snapshots.each do |snapshot| date = snapshot.created_at js_date = date.year.to_s + "," + (date.month - 1).to_s + "," + date.day.to_s %> snapshots.set(<%= snapshot.id.to_s %>,new Date(<%= js_date %>)); diff --git a/sonar-server/src/main/webapp/WEB-INF/lib/resourceable.rb b/sonar-server/src/main/webapp/WEB-INF/lib/resourceable.rb index c232c7fc8dd..18daee64fe8 100644 --- a/sonar-server/src/main/webapp/WEB-INF/lib/resourceable.rb +++ b/sonar-server/src/main/webapp/WEB-INF/lib/resourceable.rb @@ -37,16 +37,16 @@ module Resourceable QUALIFIER_LIB='LIB' QUALIFIERS=[QUALIFIER_VIEW, QUALIFIER_SUBVIEW, QUALIFIER_PROJECT, QUALIFIER_MODULE, QUALIFIER_DIRECTORY, QUALIFIER_PACKAGE, QUALIFIER_FILE, QUALIFIER_CLASS, QUALIFIER_UNIT_TEST_CLASS, QUALIFIER_LIB] QUALIFIER_NAMES={ - QUALIFIER_VIEW => 'view', - QUALIFIER_SUBVIEW => 'sub_view', - QUALIFIER_PROJECT => 'project', - QUALIFIER_MODULE => 'sub_project', - QUALIFIER_DIRECTORY => 'directory', - QUALIFIER_PACKAGE => 'package', - QUALIFIER_FILE => 'file', - QUALIFIER_CLASS => 'class', - QUALIFIER_UNIT_TEST_CLASS => 'unit_test', - QUALIFIER_LIB => 'library' + QUALIFIER_VIEW => 'view', + QUALIFIER_SUBVIEW => 'sub_view', + QUALIFIER_PROJECT => 'project', + QUALIFIER_MODULE => 'sub_project', + QUALIFIER_DIRECTORY => 'directory', + QUALIFIER_PACKAGE => 'package', + QUALIFIER_FILE => 'file', + QUALIFIER_CLASS => 'class', + QUALIFIER_UNIT_TEST_CLASS => 'unit_test', + QUALIFIER_LIB => 'library' } def set? @@ -90,18 +90,32 @@ module Resourceable end def source_code? - java_definition.hasSourceCode() + java_resource_type.hasSourceCode() end def display_dashboard? !source_code? end - def java_definition - @java_definition ||= - begin - Java::OrgSonarServerUi::JRubyFacade.getInstance().getResourceDefinition(qualifier) - end + def leaves_qualifiers + @leaves_qualifiers ||= + begin + Java::OrgSonarServerUi::JRubyFacade.getInstance().getResourceLeavesQualifiers(qualifier) + end + end + + def children_qualifiers + @children_qualifiers ||= + begin + Java::OrgSonarServerUi::JRubyFacade.getInstance().getResourceChildrenQualifiers(qualifier) + end + end + + def java_resource_type + @java_resource_type ||= + begin + Java::OrgSonarServerUi::JRubyFacade.getInstance().getResourceType(qualifier) + end end def self.qualifier_name(qualifier) diff --git a/sonar-server/src/test/java/org/sonar/server/ui/ResourceDefinitionRepositoryTest.java b/sonar-server/src/test/java/org/sonar/server/ui/ResourceDefinitionRepositoryTest.java deleted file mode 100644 index d514fb15ede..00000000000 --- a/sonar-server/src/test/java/org/sonar/server/ui/ResourceDefinitionRepositoryTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2008-2012 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.server.ui; - -import org.junit.Test; -import org.sonar.api.resources.ResourceDefinition; - -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; - -public class ResourceDefinitionRepositoryTest { - - @Test - public void test() { - ResourceDefinition def1 = ResourceDefinition.builder("1").build(); - ResourceDefinition def2 = ResourceDefinition.builder("2").availableForFilters().build(); - ResourceDefinitionRepository repository = new ResourceDefinitionRepository(new ResourceDefinition[] {def1, def2}); - assertThat(repository.getAll(), hasItems(def1, def2)); - assertThat(repository.getForFilter(), hasItem(def2)); - assertThat(repository.get("1"), is(def1)); - assertThat(repository.get("unknown"), notNullValue()); - } - -} |