Rake Task to Display SVN Commits by User
July 26th, 2007
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