You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildr.apache.org by vb...@apache.org on 2008/02/26 03:14:46 UTC

svn commit: r631067 - in /incubator/buildr/trunk: CHANGELOG doc/pages/more_stuff.textile lib/buildr/cobertura.rb

Author: vborja
Date: Mon Feb 25 18:14:43 2008
New Revision: 631067

URL: http://svn.apache.org/viewvc?rev=631067&view=rev
Log:
Cobertura can exclude specified classes from instrumentation.
Cobertura tasks can be invoked for a single project using project name as prefix to cobetura tasks.

Modified:
    incubator/buildr/trunk/CHANGELOG
    incubator/buildr/trunk/doc/pages/more_stuff.textile
    incubator/buildr/trunk/lib/buildr/cobertura.rb

Modified: incubator/buildr/trunk/CHANGELOG
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/CHANGELOG?rev=631067&r1=631066&r2=631067&view=diff
==============================================================================
--- incubator/buildr/trunk/CHANGELOG (original)
+++ incubator/buildr/trunk/CHANGELOG Mon Feb 25 18:14:43 2008
@@ -1,4 +1,6 @@
 1.3.0 (Pending)
+* Added: Cobertura tasks can be invoked for a single project using project name as prefix to cobetura tasks.
+* Added: Cobertura can exclude specified classes from instrumentation.
 * Fixed: More typos/documentation fixes by Lacton
 * Changed: Upgraded to Antwrap 0.7.0, thanks to Caleb Powel for relicensing under Apache License.
 * Added: ArchiveTask#clean can be used to remove content from a package. 

Modified: incubator/buildr/trunk/doc/pages/more_stuff.textile
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/doc/pages/more_stuff.textile?rev=631067&r1=631066&r2=631067&view=diff
==============================================================================
--- incubator/buildr/trunk/doc/pages/more_stuff.textile (original)
+++ incubator/buildr/trunk/doc/pages/more_stuff.textile Mon Feb 25 18:14:43 2008
@@ -94,6 +94,26 @@
 
 As you can guess, the other task is @cobertura:xml@.
 
+If you want to generate cobertura reports only for a specific project, you
+can do so by using the project name as prefix to cobertura tasks. 
+
+{{{!sh
+$ buildr subModule:cobertura:html
+}}}
+
+Each project can specify which classes to include or exclude from cobertura
+instrumentation by giving a class-name regexp to the @cobertura.include@ or 
+@cobertura.exclude@ methods:
+
+{{{!ruby
+define 'someModule' do 
+  cobertura.include 'some.package.*'
+  cobertura.include /some.(foo|bar).*/
+  cobertura.exclude 'some.foo.util.SimpleUtil'
+  cobertura.exclude /*.Const(ants)?/i
+end
+}}}
+
 You can use "JDepend":http://clarkware.com/software/JDepend.html on to
 generate design quality metrics.  There are three tasks this time, the eye
 candy one:

Modified: incubator/buildr/trunk/lib/buildr/cobertura.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/buildr/cobertura.rb?rev=631067&r1=631066&r2=631067&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/buildr/cobertura.rb (original)
+++ incubator/buildr/trunk/lib/buildr/cobertura.rb Mon Feb 25 18:14:43 2008
@@ -18,6 +18,22 @@
 
   # Addes the <code>cobertura:html</code> and <code>cobertura:xml</code> tasks.
   # Require explicitly using <code>require "buildr/cobertura"</code>.
+  #
+  # You can generate cobertura reports for a single project 
+  # using the project name as prefix:
+  #
+  #   project_name:cobertura:html
+  #
+  # You can also specify which classes to include/exclude from instrumentation by 
+  # passing a class name regexp to the <code>cobertura.include</code> or 
+  # <code>cobertura.exclude</code> methods. 
+  # 
+  #   define 'someModule' do 
+  #      cobertura.include 'some.package.*'
+  #      cobertura.include /some.(foo|bar).*/
+  #      cobertura.exclude 'some.foo.util.SimpleUtil'
+  #      cobertura.exclude /*.Const(ants)?/i
+  #   end
   module Cobertura
 
     class << self
@@ -38,60 +54,168 @@
       end
 
     end
+    
+    class CoberturaConfig # :nodoc:
+      
+      def initialize(project)
+        @project = project
+      end
+      
+      attr_reader :project
+      private :project
 
-    namespace "cobertura" do
+      attr_writer :data_file, :instrumented_dir, :report_dir
+      
+      def data_file
+        @data_file ||= project.path_to(:reports, 'cobertura.ser')
+      end
 
-      task "instrument" do
-        Buildr.projects.each do |project|
-          unless project.compile.sources.empty?
-            # Instrumented bytecode goes in a different directory. This task creates before running the test
-            # cases and monitors for changes in the generate bytecode.
-            instrumented = project.file(project.path_to(:target, :instrumented, :classes)=>project.compile.target) do |task|
+      def instrumented_dir
+        @instrumented_dir ||= project.path_to(:target, :instrumented, :classes)
+      end
+
+      def report_dir
+        @report_dir ||= project.path_to(:reports, :cobertura)
+      end
+
+      def report_to(file = nil)
+        File.expand_path(File.join(*[report_dir, file.to_s].compact))
+      end
+
+      # :call-seq:
+      #   project.cobertura.include(*classPatterns)
+      #
+      def include(*classPatterns)
+        includes.push(*classPatterns.map { |p| String === p ? Regexp.new(p) : p })
+        self
+      end
+      
+      def includes
+        @includeClasses ||= []
+      end
+
+      # :call-seq:
+      #   project.cobertura.exclude(*classPatterns)
+      #
+      def exclude(*classPatterns)
+        excludes.push(*classPatterns.map { |p| String === p ? Regexp.new(p) : p })
+        self
+      end
+
+      def excludes
+        @excludeClasses ||= []
+      end
+
+      def sources
+        project.compile.sources
+      end
+    end
+
+    module CoberturaExtension # :nodoc:
+      include Buildr::Extension
+
+      def cobertura
+        @cobertura_config ||= CoberturaConfig.new(self)
+      end
+
+      after_define do |project|
+        cobertura = project.cobertura
+        
+        namespace 'cobertura' do
+          # Instrumented bytecode goes in a different directory. This task creates before running the test
+          # cases and monitors for changes in the generate bytecode.
+          instrumented = project.file(cobertura.instrumented_dir => file(project.compile.target)) do |task|
+            mkdir_p task.to_s, :verbose => false
+            unless project.compile.sources.empty?
+              puts "Instrumenting classes with cobertura data file #{cobertura.data_file}"
               Buildr.ant "cobertura" do |ant|
-                ant.taskdef :classpath=>requires.join(File::PATH_SEPARATOR), :resource=>"tasks.properties"
-                ant.send "cobertura-instrument", :todir=>task.to_s, :datafile=>data_file do
-                  ant.fileset(:dir=>project.compile.target.to_s) { ant.include :name=>"**/*.class" }
+                ant.taskdef :classpath=>Cobertura.requires.join(File::PATH_SEPARATOR), :resource=>"tasks.properties"
+                ant.send "cobertura-instrument", :todir=>task.to_s, :datafile=>cobertura.data_file do
+                  includes, excludes = cobertura.includes, cobertura.excludes
+                  
+                  classes_dir = project.compile.target.to_s
+                  if includes.empty? && excludes.empty? 
+                    ant.fileset :dir => classes_dir do 
+                      ant.include :name => "**/*.class"
+                    end
+                  else
+                    includes = [//] if includes.empty?
+                    Dir.glob(File.join(classes_dir, "**/*.class")) do |cls|
+                      cls_name = cls.gsub(/#{classes_dir}\/?|\.class$/, '').gsub('/', '.')
+                      if includes.any? { |p| p === cls_name } && !excludes.any? { |p| p === cls_name }
+                        ant.fileset :file => cls
+                      end
+                    end
+                  end
                 end
               end
-              touch task.to_s, :verbose=>false
             end
-            # We now have two target directories with bytecode. It would make sense to remove compile.target
-            # and add instrumented instead, but apparently Cobertura only creates some of the classes, so
-            # we need both directories and instrumented must come first.
-            project.test.dependencies.unshift instrumented
-            project.test.with requires
-            project.test.options[:properties]["net.sourceforge.cobertura.datafile"] = data_file
-            project.clean { rm_rf instrumented.to_s, :verbose=>false }
+            touch task.to_s, :verbose=>false
           end
-        end
-      end
 
-      desc "Run the test cases and produce code coverage reports in #{report_to(:html)}"
-      task "html"=>["instrument", "test"] do
-        puts "Creating test coverage reports in #{report_to(:html)}"
-        Buildr.ant "cobertura" do |ant|
-          ant.taskdef :classpath=>requires.join(File::PATH_SEPARATOR), :resource=>"tasks.properties"
-          ant.send "cobertura-report", :destdir=>report_to(:html), :format=>"html", :datafile=>data_file do
-            Buildr.projects.map(&:compile).map(&:sources).flatten.each do |src|
-              ant.fileset(:dir=>src.to_s) { ant.include :name=>"**/*.java" } if File.exist?(src.to_s)
+          task 'instrument' => instrumented
+          [:xml, :html].each do |format|
+            task format => ['instrument', 'test'] do 
+              puts "Creating test coverage reports in #{cobertura.report_to(format)}"
+              Buildr.ant "cobertura" do |ant|
+                ant.taskdef :classpath=>Cobertura.requires.join(File::PATH_SEPARATOR), :resource=>"tasks.properties"
+                ant.send "cobertura-report", :format=>format, 
+                         :destdir=>cobertura.report_to(format), :datafile=>cobertura.data_file do
+                  cobertura.sources.flatten.each do |src|
+                    ant.fileset(:dir=>src.to_s) if File.exist?(src.to_s)
+                  end
+                end
+              end
             end
           end
+          
         end
+
+        # We now have two target directories with bytecode. It would make sense to remove compile.target
+        # and add instrumented instead, but apparently Cobertura only creates some of the classes, so
+        # we need both directories and instrumented must come first.
+        project.test.dependencies.unshift cobertura.instrumented_dir
+        project.test.with Cobertura.requires
+        project.test.options[:properties]["net.sourceforge.cobertura.datafile"] = cobertura.data_file
+        
+        project.clean do
+          rm_rf [cobertura.report_to, cobertura.data_file, cobertura.instrumented_dir], :verbose=>false
+        end
+        
       end
+      
+    end
 
-      desc "Run the test cases and produce code coverage reports in #{report_to(:xml)}"
-      task "xml"=>["instrument", "test"] do
-        puts "Creating test coverage reports in #{report_to(:xml)}"
-        Buildr.ant "cobertura" do |ant|
-          ant.taskdef :classpath=>requires.join(File::PATH_SEPARATOR), :resource=>"tasks.properties"
-          ant.send "cobertura-report", :destdir=>report_to(:xml), :format=>"xml", :datafile=>data_file do
-            Buildr.projects.map(&:compile).map(&:sources).flatten.each do |src|
-              ant.fileset :dir=>src.to_s if File.exist?(src.to_s)
+    class Buildr::Project
+      include CoberturaExtension
+    end
+
+    namespace "cobertura" do
+
+      task "instrument" do
+        Buildr.projects.each do |project|
+          project.cobertura.data_file = data_file
+          project.test.options[:properties]["net.sourceforge.cobertura.datafile"] = data_file
+          project.task('cobertura:instrument').invoke
+        end
+      end
+      
+      [:xml, :html].each do |format|
+        report_target = report_to(format)
+        desc "Run the test cases and produce code coverage reports in #{report_target}"
+        task format => ["instrument", "test"] do
+          puts "Creating test coverage reports in #{report_target}"
+          Buildr.ant "cobertura" do |ant|
+            ant.taskdef :classpath=>requires.join(File::PATH_SEPARATOR), :resource=>"tasks.properties"
+            ant.send "cobertura-report", :destdir=>report_target, :format=>format, :datafile=>data_file do
+              Buildr.projects.map(&:cobertura).map(&:sources).flatten.each do |src|
+                ant.fileset :dir=>src.to_s if File.exist?(src.to_s)
+              end
             end
           end
         end
       end
-
+      
       task "clean" do
         rm_rf [report_to, data_file], :verbose=>false
       end