#!/usr/local/bin/ruby
# == Synopsis
#
# overlaps: graph files that are edited by multiple users per day using a stem and leaf plot
#
# == Usage
#
# overlaps [ -p port ] [ -u user ] ( [ -s date ] | [ -w weeks ] | [ -d date ] ) [ -e date ] [ -v ] [ -m minimum ] <Perforce path>
#
# Flagged files may be candidates for splitting into multiple files or refactoring
#
# * -s Start date. Incompatible with -w. One week before end date by default.
# * -e End date. Today by default.
# * -w Number of weeks before end date to go examine.
# * -v Show detailed list of overlapping files.
# * -d Date. Gives overlaps for a single day. Overrides all other date related flags.
# * -m Minimum number of overlaps required to be flagged. 2 by default.
$:.unshift File.join( File.dirname( $0 ), "p4ruby", RUBY_PLATFORM )
require 'date'
require 'P4'
require 'getoptlong'
require 'rdoc/usage'
def getOverLappingChanges( date, showDetails = false )
today = date
tomorrow = date + 1
fileDict = {}
# get the changes for the day
changes = $p4.run( "changes",
"-s", "submitted",
$path + '@>' + today.strftime( "%Y/%m/%d" ) + ',@<' + tomorrow.strftime( "%Y/%m/%d" ) )
# run 'describe' on each change to get the list of files and user
changes.each do | c |
files = $p4.run( "describe", c["change"] );
if( files[0]["depotFile"] == nil )
next
end
# lazily rely on hashes to determine uniquenss of file path and users
files[0]["depotFile"].each do |f|
if( !fileDict.has_key?( f ) )
fileDict[ f ] = {}
end
fileDict[ f ].merge!( { c["user"] => 1 } )
end
end
# start building up our plot string
result = today.strftime( '%Y/%m/%d' ) + "\t"
# sort by count for stem and leaf plot so that large overlaps
# don't get lost in the forest of numbers
oc = fileDict.sort {|x,y| y[1].keys.length<=>x[1].keys.length}
oc.each{ |f|
if( f[1].keys.length >= $min )
result += f[1].keys.length.to_s()
end
}
puts result
# sort detailed output by path so that related files are adjacent
oc = fileDict.sort {|x,y| x[0] <=> y[0]}
if( showDetails )
oc.each{ |f|
if( f[1].keys.length >= $min )
puts f[1].keys.length.to_s() + "\t\t" + f[0]
end
}
end
end
begin
# unreasonable defaults
port = ""
user = ""
weeks = 1
$min = 2
details = false
last = start = Date.today
$path = "//..."
# get the command line options if any, overriding the defaults
opts = GetoptLong.new(
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
[ '--user', '-u', GetoptLong::REQUIRED_ARGUMENT ],
[ '--port', '-p', GetoptLong::REQUIRED_ARGUMENT ],
[ '--date', '-d', GetoptLong::REQUIRED_ARGUMENT ],
[ '--weeks', '-w', GetoptLong::REQUIRED_ARGUMENT ],
[ '--min', '-m', GetoptLong::REQUIRED_ARGUMENT ],
[ '--start', '-s', GetoptLong::REQUIRED_ARGUMENT ],
[ '--end', '-e', GetoptLong::REQUIRED_ARGUMENT ],
[ '--details', '-v', GetoptLong::NO_ARGUMENT ]
)
optDict = {}
opts.each{ | opt, arg |
optDict[ opt ] = arg
}
optDict.each do |opt, arg|
case opt
when '--help'
RDoc::usage
when '--user'
user = arg
when '--port'
port = arg
when '--date'
last = start = Date.parse( arg )
when '--weeks'
weeks = arg.to_i()
when '--min'
$min = arg.to_i()
when '--details'
details = true
when '--start'
start = Date.parse( arg )
when '--end'
last = Date.parse( arg )
end
end
if( !optDict.has_key?( '--start' ) && !optDict.has_key?( '--date' ) )
start = last - 7 * weeks
end
if( ARGV.length == 1 )
$path = ARGV[0]
end
# time to get the party started
$p4 = P4.new()
$p4.prog = "overlaps"
# override environment variables if needs be
if( port != "" )
$p4.port = port
end
if( user != "" )
$p4.user = user
end
$p4.connect()
start.upto( last ) { |d|
getOverLappingChanges( d, details )
}
$p4.disconnect
end
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #1 | 8311 | Matt Attaway | Move the overlaps tool out into its own project | ||
| //guest/matt_attaway/scripts/overlaps.rb | |||||
| #1 | 7329 | Matt Attaway |
Add new overlapping changes detection script. See wiki for details |
||