]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-3750 Add ability to share Exclusion rules between several projects
authorDavid Gageot <david@gageot.net>
Fri, 21 Sep 2012 08:23:37 +0000 (10:23 +0200)
committerDavid Gageot <david@gageot.net>
Fri, 21 Sep 2012 10:26:14 +0000 (12:26 +0200)
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties
sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java
sonar-plugin-api/src/test/java/org/sonar/api/resources/DefaultProjectFileSystemTest.java
sonar-plugin-api/src/test/java/org/sonar/api/resources/ProjectTest.java
sonar-server/src/main/webapp/WEB-INF/app/controllers/project_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_layout.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/project/exclusions.html.erb [deleted file]

index af0279a478d3f1aa2f5c0bc97887a69d73b7a841..5fcbd453d7332979457ba6af8122f84d6ce352aa 100644 (file)
@@ -130,6 +130,14 @@ import java.util.List;
     project = false,
     global = true,
     category = CoreProperties.CATEGORY_GENERAL),
+  @Property(
+    key = CoreProperties.PROJECT_EXCLUSIONS_PROPERTY,
+    name = "Exclusions",
+    description = "Exclude sources from code analysis. Changes will be applied during next code analysis.",
+    project = true,
+    global = false,
+    multiValues = true,
+    category = CoreProperties.CATEGORY_EXCLUSIONS),
   @Property(
     key = CoreProperties.CORE_COVERAGE_PLUGIN_PROPERTY,
     defaultValue = "jacoco",
index d684f7b7e5932bf05ea75e6bbae077b652493c3b..4c32642d60963b53536675c56716b9979cf0bba9 100644 (file)
@@ -576,6 +576,83 @@ property.category.codeCoverage=Code Coverage
 property.category.duplications=Duplications
 property.category.localization=Localization
 property.category.server_id=Server ID
+property.category.exclusions=Exclusions
+property.sonar.exclusions.name=Exclusions
+property.sonar.exclusions.description=Exclude sources from code analysis. Changes will be applied during next code analysis.
+property.sonar.exclusions.help=<h2>Wildcards</h2>\
+ <p>Following rules are applied:</p>\
+ <table class="data">\
+   <thead><tr><th colspan="2"></th></tr></thead>\
+   <tr class="odd">\
+     <td>*</td>\
+     <td>Match zero or more characters</td>\
+   </tr>\
+   <tr class="even">\
+     <td>**</td>\
+     <td>Match zero or more directories</td>\
+   </tr>\
+   <tr class="odd">\
+     <td>?</td>\
+     <td>Match a single character</td>\
+   </tr>\
+ </table>\
+ <p>Examples:</p>\
+ <table class="data">\
+   <thead><tr><th>Filter</th><th>Description</th><th>Matches</th></tr></thead>\
+   <tr class="odd">\
+     <td>org/mycompany/*.java</td>\
+     <td>matches all <code>.java</code> files in the <code>org/mycompany</code> directory</td>\
+     <td>\
+       <ul>\
+         <li>org/mycompany/Foo.java</li>\
+         <li>org/mycompany/Bar.java</li>\
+       </ul>\
+     </td>\
+   </tr>\
+   <tr class="even">\
+     <td>org/*Model*.java</td>\
+     <td>matches all <code>.java</code> files with <code>Model</code> in filename and in the<code>org</code> directory</td>\
+     <td>\
+       <ul>\
+         <li>org/Model.java</li>\
+         <li>org/FirstModel.java</li>\
+         <li>org/ModelTest.java</li>\
+       </ul>\
+     </td>\
+   </tr>\
+   <tr class="odd">\
+     <td>org/**</td>\
+     <td>matches all files underneath the <code>org</code> directory</td>\
+     <td>\
+       <ul>\
+         <li>org/Foo.java</li>\
+         <li>org/foo/bar.jsp</li>\
+       </ul>\
+     </td>\
+   </tr>\
+   <tr class="even">\
+     <td>org/**/Dummy.java</td>\
+     <td>matches all <code>Dummy.java</code> files underneath the <code>org</code> directory</td>\
+     <td>\
+       <ul>\
+         <li>org/Dummy.java</li>\
+         <li>org/foo/Dummy.java</li>\
+         <li>org/foo/bar/Dummy.java</li>\
+       </ul>\
+     </td>\
+   </tr>\
+   <tr class="odd">\
+     <td>org/**/*.java</td>\
+     <td>matches all <code>.java</code> files underneath the <code>org</code> directory</td>\
+     <td>\
+       <ul>\
+         <li>org/Foo.java</li>\
+         <li>org/foo/Bar.java</li>\
+         <li>org/foo/bar/Baz.java</li>\
+       </ul>\
+     </td>\
+   </tr>\
+ </table>
 
 property.error.notBoolean=Valid options are "true" and "false"
 property.error.notInteger=Only digits are allowed
index 17e0c48776e44783a2eaa21684adcc70c81a282a..b3b55b5ab039b1e1d90d01d5b2d4e32973ee52aa 100644 (file)
@@ -67,6 +67,11 @@ public interface CoreProperties {
    */
   String CATEGORY_DIFFERENTIAL_VIEWS = "differentialViews";
 
+  /**
+   * @since 3.3
+   */
+  String CATEGORY_EXCLUSIONS = "exclusions";
+
   /* Global settings */
   String SONAR_HOME = "SONAR_HOME";
   String PROJECT_BRANCH_PROPERTY = "sonar.branch";
@@ -98,8 +103,11 @@ public interface CoreProperties {
    * Value format is yyyy-MM-dd
    */
   String PROJECT_DATE_PROPERTY = "sonar.projectDate";
+
   String PROJECT_LANGUAGE_PROPERTY = "sonar.language";
   String DYNAMIC_ANALYSIS_PROPERTY = "sonar.dynamicAnalysis";
+
+  /* Exclusions */
   String PROJECT_EXCLUSIONS_PROPERTY = "sonar.exclusions";
 
   /**
index f3cc76ba934b7bf7b050575c9df50fa843efbded..fd8f9304d534933bafea4d8030e3e4c49ce441a1 100644 (file)
  */
 package org.sonar.api.resources;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.Matchers.endsWith;
-import static org.hamcrest.Matchers.hasItem;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
 import org.apache.commons.configuration.PropertiesConfiguration;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.SystemUtils;
@@ -37,6 +29,7 @@ import org.hamcrest.Matchers;
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.Before;
 import org.junit.Test;
+import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.FileFilter;
 import org.sonar.api.test.MavenTestUtils;
 
@@ -45,6 +38,12 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 public class DefaultProjectFileSystemTest {
 
   private Project project = null;
@@ -81,7 +80,7 @@ public class DefaultProjectFileSystemTest {
     assertThat(fs.hasJavaSourceFiles(), is(true));
 
     PropertiesConfiguration conf = new PropertiesConfiguration();
-    conf.setProperty("sonar.exclusions", "**/*.java");
+    conf.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*.java");
     project.setConfiguration(conf);
     assertThat(fs.hasJavaSourceFiles(), is(false));
   }
@@ -97,7 +96,7 @@ public class DefaultProjectFileSystemTest {
   @Test
   public void applyExclusionPatternsToSourceFiles() {
     PropertiesConfiguration conf = new PropertiesConfiguration();
-    conf.setProperty("sonar.exclusions", "**/B*.java");
+    conf.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/B*.java");
     project.setConfiguration(conf);
 
     final DefaultProjectFileSystem fs = newDefaultProjectFileSystem(project);
@@ -112,7 +111,7 @@ public class DefaultProjectFileSystemTest {
   @Test
   public void exclusionPatternOnAjFiles() {
     PropertiesConfiguration conf = new PropertiesConfiguration();
-    conf.setProperty("sonar.exclusions", "**/*.aj");
+    conf.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*.aj");
     project.setConfiguration(conf);
 
     final DefaultProjectFileSystem fs = newDefaultProjectFileSystem(project);
@@ -125,7 +124,7 @@ public class DefaultProjectFileSystemTest {
   @Test
   public void doNotApplyExclusionPatternsToTestFiles() {
     PropertiesConfiguration conf = new PropertiesConfiguration();
-    conf.setProperty("sonar.exclusions", "**/B*.java");
+    conf.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/B*.java");
     project.setConfiguration(conf);
 
     final DefaultProjectFileSystem fs = newDefaultProjectFileSystem(project);
@@ -220,7 +219,7 @@ public class DefaultProjectFileSystemTest {
   @Test
   public void testSelectiveFileFilter() {
     DefaultProjectFileSystem.FileSelectionFilter filter = new DefaultProjectFileSystem.FileSelectionFilter(
-        Arrays.asList(new File("foo/Bar.java"), new File("hello/Bar.java"), new File("hello/World.java")));
+      Arrays.asList(new File("foo/Bar.java"), new File("hello/Bar.java"), new File("hello/World.java")));
     assertThat(filter.accept(new File("foo/Bar.java")), Matchers.is(true));
     assertThat(filter.accept(new File("hello/Bar.java")), Matchers.is(true));
     assertThat(filter.accept(new File("hello/World.java")), Matchers.is(true));
index d88ea57e211e3ac7c3f404bae49267beed2d6d6e..6bc15f8f79c6fcb54c32a4dbfff42a0289521566 100644 (file)
@@ -59,7 +59,7 @@ public class ProjectTest {
   @Test
   public void shouldTrimExclusionPatterns() {
     Configuration conf = new PropertiesConfiguration();
-    conf.setProperty("sonar.exclusions", "  **/*Foo.java   , **/Bar.java    ");
+    conf.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "  **/*Foo.java   , **/Bar.java    ");
     Project project = new Project("foo").setConfiguration(conf);
 
     String[] exclusions = project.getExclusionPatterns();
index 76918622d64fb1f2f9c45fb981f40a513ee603b0..e4eb8537e9f32d7436c8e16094d279ccbf283f69 100644 (file)
@@ -272,38 +272,6 @@ class ProjectController < ApplicationController
     render :action => 'events', :layout => !request.xhr?
   end
 
-
-  def exclusions
-    @project = get_current_project(params[:id])
-
-    @snapshot=@project.last_snapshot
-    if !@project.project? && !@project.module?
-      redirect_to :action => 'index', :id => params[:id]
-    end
-  end
-
-  def set_exclusions
-    @project = get_current_project(params[:id])
-
-    patterns=params['patterns'].reject { |p| p.blank? }.uniq
-    if patterns.empty?
-      Property.clear('sonar.exclusions', @project.id)
-    else
-      # Trim spaces in patterns before merging into one String - see http://jira.codehaus.org/browse/SONAR-2261
-      Property.set('sonar.exclusions', patterns.collect { |x| x.strip }.join(','), @project.id)
-    end
-    flash[:notice]='Filters added'
-    redirect_to :action => 'exclusions', :id => @project.id
-  end
-
-  def delete_exclusions
-    @project = get_current_project(params[:id])
-
-    Property.clear('sonar.exclusions', @project.id)
-    flash[:notice]='Filters deleted'
-    redirect_to :action => 'exclusions', :id => @project.id
-  end
-
   def update_version
     snapshot=Snapshot.find(params[:sid])
     not_found("Snapshot not found") unless snapshot
index 77295ad8bf20b99011afd6ca2aa95e7dc6165c9d..f3c886790be5fdea2d63922f6106cf31a254d93c 100644 (file)
             <% end %>
             <% if (@project.project? || @project.module?) %>
               <li class="<%= 'selected' if request.request_uri.include?('/project/settings') -%>">
-                <a href="<%= ApplicationController.root_context -%>/project/settings/<%= @project.id -%>"><%= message('project_settings.page') -%></a></li>
-            <% end %>
-            <% if (@project.project? || @project.module?) %>
-              <li class="<%= 'selected' if request.request_uri.include?('/project/exclusions') -%>">
-                <a href="<%= ApplicationController.root_context -%>/project/exclusions/<%= @project.id -%>"><%= message('project_exclusions.page') -%></a></li>
+                <a href="<%= ApplicationController.root_context -%>/project/settings/<%= @project.id -%>"><%= message('project_settings.page') -%></a>
+              </li>
             <% end %>
             <% if (@project.project?) %>
               <li class="<%= 'selected' if request.request_uri.include?('/project/links') -%>">
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/project/exclusions.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/project/exclusions.html.erb
deleted file mode 100644 (file)
index 8941c3f..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-<h1><%= message('project_exclusions.page') -%></h1>
-
-<p style="margin: 15px 0px">
-  Exclude sources from code analysis. Changes will be applied during next code analysis.
-</p>
-
-<div class="yui-g widget" id="widget_exclusions">
-
-  <div class="yui-u first">
-    <% form_for( 'set_exclusions', :url => { :action => 'set_exclusions', :id => @project.id } ) do |form| 
-       pattern_index=0
-    %>
-    <table class="spaced">
-      <% patterns = Property.value('sonar.exclusions', @project.id, '').split(',')
-         patterns.each do |pattern|
-      %>
-      <tr>
-        <td class=left>
-          <input id="exclusion_pattern_<%= pattern_index -%>" name="patterns[]" size="50" value="<%= pattern -%>" type="text">
-        </td>
-      </tr>
-      <%  pattern_index += 1
-         end
-      %>
-      <tr><td class=left>
-        <input name="patterns[]" size="50" value="" type="text" id="exclusion_pattern_<%= pattern_index-%>">
-      </td></tr>
-      <tr><td class=left>
-        <input name="patterns[]" size="50" value="" type="text" id="exclusion_pattern_<%= pattern_index + 1-%>"><br/>
-      </td></tr>
-      <tr><td class=left>
-        <%= submit_tag( "Save exclusion filters", :id => 'submit_exclusions') %>
-        <input type="submit" value="Delete all exclusion filters" id="delete_exclusions" class="action red-button"
-               onclick="if (confirm('Are you sure you want to delete all exclusion filters ?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = '<%= url_for :action => "delete_exclusions", :id => @project.id -%>';f.submit(); };return false;">
-        </td></tr>
-    </table>
-    <% end %>
-  </div>
-
-  <div class="yui-u">
-    <div class="help">
-      <h2>Wildcards</h2>
-      <p>
-      Following rules are applied:
-      <table class="data">
-        <thead><tr><th colspan="2"></th></tr></thead>
-        <tr class="odd">
-          <td>*</td>
-          <td>Match zero or more characters</td>
-        </tr>
-        <tr class="even">
-          <td>**</td>
-          <td>Match zero or more directories</td>
-        </tr>
-        <tr class="odd">
-          <td>?</td>
-          <td>Match a single character</td>
-        </tr>
-      </table>
-      </p>
-      <p>
-      Examples:
-      <table class="data">
-        <thead>
-        <tr>
-          <th>Filter</th>
-          <th>Description</th>
-          <th>Matches</th>
-        </tr>
-        </thead>
-        <tr class="odd">
-          <td>org/mycompany/*.java</td>
-          <td>matches all <code>.java</code> files in the <code>org/mycompany</code> directory</td>
-          <td><ul>
-            <li>org/mycompany/Foo.java</li>
-            <li>org/mycompany/Bar.java</li>
-          </ul></td>
-        </tr>
-        <tr class="even">
-          <td>org/*Model*.java</td>
-          <td>matches all <code>.java</code> files with <code>Model</code> in filename and in the <code>org</code> directory</td>
-          <td><ul>
-            <li>org/Model.java</li>
-            <li>org/FirstModel.java</li>
-            <li>org/ModelTest.java</li>
-          </ul></td>
-        </tr>
-        <tr class="odd">
-          <td>org/**</td>
-          <td>matches all files underneath the <code>org</code> directory</td>
-          <td><ul>
-            <li>org/Foo.java</li>
-            <li>org/foo/bar.jsp</li>
-          </ul></td>
-        </tr>
-        <tr class="even">
-          <td>org/**/Dummy.java</td>
-          <td>matches all <code>Dummy.java</code> files underneath the <code>org</code> directory</td>
-          <td><ul>
-            <li>org/Dummy.java</li>
-            <li>org/foo/Dummy.java</li>
-            <li>org/foo/bar/Dummy.java</li>
-          </ul></td>
-        </tr>
-        <tr class="odd">
-          <td>org/**/*.java</td>
-          <td>matches all <code>.java</code> files underneath the <code>org</code> directory</td>
-          <td><ul>
-            <li>org/Foo.java</li>
-            <li>org/foo/Bar.java</li>
-            <li>org/foo/bar/Baz.java</li>
-          </ul></td>
-        </tr>
-      </table>
-      </p>
-    </div>
-  </div>
-</div>