8ball-media

little pieces from everything

RCov::VerifyTask "threshold" auto-update monitor

When developing TDD or BDD in Ruby (1.9.2) using the RCov::VerifyTask you need to fullfill a certain threshold to make a build successful.

It can be quite annoying to update the (hopefully) increased threshold of the RCov::VerifyTask in your Rakefile after each successful build. So I did some experiments and the following script is the result.

A common RCov::VerifyTask setup might look like:

 Spec::Rake::SpecTask.new('rcov') do |t|
   t.spec_files  = FileList['spec/**/*.rb']
   t.rcov        = true
   t.rcov_opts   = ['--exclude', 'lib', '--exclude', 'gems']
   t.libs        << Dir["lib/**/*"]
 end


 RCov::VerifyTask.new(:verify_rcov) do |t|
   t.threshold   = 10.00                     # to get started
   t.index_html  = 'coverage/index.html'     # the path to html report
 end

It uses another :task to capture the output of the actual RCov::VerifyTask and writes the threshold into a coverage.yml file. This threshold value is taken into comparison at the next build and updated at next build if its value has increased.

First the method to read and write the threshold value from/to a ./coverage.yml.

 # the `log' file in `yaml' format
 #
 COVERAGE_YML   = 'coverage.yml'

 # read the last 'threshold' from the .yml file
 # and return `10.0' as value if the file isn't existant
 #
 def read_yaml_threshold

   threshold = 10.0

   return threshold unless File.exist? COVERAGE_YML

   yaml  = read_yaml_file COVERAGE_YML

   threshold = yaml["THRESHOLD"].to_s

   threshold.to_f
 end


 # write the given `value' in `yaml' format
 # back into `log' file.
 #
 def write_yaml_threshold value
   File.open(COVERAGE_YML, 'w') do |f|
     f.write({"THRESHOLD" => value}.to_yaml)
   end
 end

Now the updated rake tasks.

 # read the previous threshold once and
 # reuse it in tasks to reduce file-access
 #
 @old_threshold = read_yaml_threshold


 # the SpecTask from above
 #
 desc "Run all rspec tests with RCOV"
 Spec::Rake::SpecTask.new('rcov') do |t|
   t.spec_files  = FileList['spec/**/*.rb']
   t.rcov        = true
   t.rcov_opts   = ['--exclude', 'lib', '--exclude', 'gems']
   t.libs        << Dir["lib/**/*"]
 end


 # the "verify" task which is still executable
 # because the`threshold' property contains the
 # current `threhold' value from `coverage.yml'
 #
 desc "Check code-coverage of project"
 RCov::VerifyTask.new(:verify_rcov) do |t|

   threshold   = @old_threshold

   Rake::Task['rcov'].execute

   t.threshold   = threshold
   t.index_html  = 'coverage/index.html'
 end


 # the actual 'capture and update' task which retrieves the 'previous'
 # threshold and executes the `VerifyTask' and captures the 'new' threshold
 # and finally compares them. if `new' threshold has increased the
 # `coverage.yml' is updated.
 #
 task :run_verify do |t|

     old_threshold = @old_threshold

     log = `rake verify_rcov -f #{__FILE__}` # | tee coverage_log.txt`

     new_threshold = threshold_from log

     if new_threshold.to_f > old_threshold.to_f

       begin
         write_yaml_threshold new_threshold
       rescue => e
         puts "ERROR #{e.message} "
       end

       puts "Finished ..."

     else
       if new_threshold.to_f >= old_threshold.to_f
         puts "Finished with `coverage' of #{new_threshold}% ..."
       else
         puts "Failed to finish with `coverage' of #{old_threshold}% => #{new_threshold}% ..."
       end
     end
 end

Although i’m quite happy with it as it works for me i would like to see if either there’s a more convenient or `nerdy’ way to implement this. I’m still learning and every input is highly appreciated. :)

If you found this useful feel free to share or comment.

Regards
~David