At my current job I’m being asked to send a list of trac tickets I’ve been working on in the previous 2 weeks. After reading this post I figured out that it can be easily done with Rake (well, as everything else you can dream about).

Since we’re using an svn hook that adds notes to the related trac tickets on commit, each revision associated with a ticket has its number in the comments. So all I (Rake task) have to do is to collect all my commit commets, pull ticket numbers from them (typical commit comment can look like this: “refs #786”) and display a list, ordered by date.

I didn’t play with command line svn client much previously, but when I’ve started to write the task I’ve figured out that we can get the svn log in xml using the “—xml” option. Even better!

So I’ve ended up with this:

namespace :svn do namespace :log do desc 'Displays commints by user in the specified period of time. Usage: rake svn:log:by_user USER=username PASSWORD=pass [URL=repo_url] PERIOD=period_option. Where valid period_options: m - current month, 2w - previous 2 working weeks (monday - friday)' task :by_user => :environment do url = ENV['URL'].to_s password = ENV['PASSWORD'].to_s period = ['m', '2w'].include?(ENV['PERIOD']) ? ENV['PERIOD'] : '2w' #USER parameter is mandatory raise 'use rake:svn:log:by_user USER=svn_username' unless user = ENV['USER'] case period when 'm' start_date = Time.now.beginning_of_month.gmtime end_date = Time.now.gmtime when '2w' start_date = (Time.now.beginning_of_week - 2.weeks).gmtime end_date = Time.now.beginning_of_week.gmtime end #datetime format used by svn log TF = '%Y-%m-%d %H:%M:%S +0000' #we'll use this var to store commits for each day days = {} require 'rexml/document' log = REXML::Document.new(`svn log #{url} --xml -r "{#{start_date.strftime(TF)}}:{#{end_date.strftime(TF)}}" --username #{user} --password #{password}`) log.root.each_element do |log_entry| #save each revision entry to a hash revision = {:number => log_entry.attributes['revision']} log_entry.each_element { |log_detail| revision[log_detail.name.to_sym] = log_detail.text } #is it my revision? if revision[:author] == user day = Time.parse(revision[:date]).strftime('%y.%m.%d') #for each day we want a list of trac tickets affected or revision number #trac tickets numbers are included in the comment like this: #687 #so we'll try to find such numbers using regexp #if there are no tickets numbers we'll simply use revision number like this: [1235] tickets = revision[:msg].to_s.scan(/#\d+/) tickets << "[#{revision[:number]}]" if tickets.empty? (days[day] ||= []) << tickets.join(', ') end end #and we simply output all commits day by day days.keys.sort.each do |day| puts "#{day} | #{days[day].join(', ')}" end end end end

The task takes 4 parameters: USER (mandatory) – well, obvious, PASSWORD (mandatory), URL (optional) – can be provided if rails app is not a working copy of repository you’d like to get a log from and PERIOD – “m” to use the revisions made in this month only and “2w” (default) to use revisions made in the previous 2 working weeks. So I can run it like this:

rake svn:log:by_user USER=eugene.bolshakov PASSWORD=secret PERIOD=m

and get something like this:

... 07.07.23 | [2256], [2264], [2265] 07.07.24 | #787, #801, #783 07.07.25 | #786, #823 07.07.26 | [2346] ...

The numbers with sharp are ticket numbers and those in square brackets are the revision numbers. They are displayed if the revision is not related to any trac ticket. Yeah, I know it could be done easier with xpath, but my knowledge of it is poor :(

Leave a Reply